/** * WordPress dependencies */ import { useContext, useMemo } from '@wordpress/element'; import { Stack } from '@wordpress/ui'; /** * Internal dependencies */ import type { FieldValidity, FormValidity, NormalizedForm, NormalizedFormField, } from '../../types'; import { getFormFieldLayout } from './index'; import DataFormContext from '../dataform-context'; const DEFAULT_WRAPPER = ( { children }: { children: React.ReactNode } ) => ( { children } ); export function DataFormLayout< Item >( { data, form, onChange, validity, children, as, }: { data: Item; form: NormalizedForm; onChange: ( value: any ) => void; validity?: FormValidity; children?: ( FieldLayout: ( props: { data: Item; field: NormalizedFormField; onChange: ( value: any ) => void; hideLabelFromVision?: boolean; markWhenOptional?: boolean; validity?: FieldValidity; } ) => React.JSX.Element | null, childField: NormalizedFormField, childFieldValidity?: FieldValidity, markWhenOptional?: boolean ) => React.JSX.Element; as?: React.ComponentType< { children: React.ReactNode } >; } ) { const { fields: fieldDefinitions } = useContext( DataFormContext ); // Auto-compute: mark the minority of fields // When counts are equal, mark required fields const markWhenOptional = useMemo( () => { const requiredCount = fieldDefinitions.filter( ( f ) => !! f.isValid?.required ).length; const optionalCount = fieldDefinitions.length - requiredCount; return requiredCount > optionalCount; }, [ fieldDefinitions ] ); function getFieldDefinition( field: NormalizedFormField ) { return fieldDefinitions.find( ( fieldDefinition ) => fieldDefinition.id === field.id ); } const Wrapper = as ?? getFormFieldLayout( form.layout.type )?.wrapper ?? DEFAULT_WRAPPER; return ( { form.fields.map( ( formField ) => { const FieldLayout = getFormFieldLayout( formField.layout.type ) ?.component; if ( ! FieldLayout ) { return null; } const fieldDefinition = ! formField.children ? getFieldDefinition( formField ) : undefined; if ( fieldDefinition && fieldDefinition.isVisible && ! fieldDefinition.isVisible( data ) ) { return null; } if ( children ) { return children( FieldLayout, formField, validity?.[ formField.id ], markWhenOptional ); } return ( ); } ) } ); }