Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
gigitux committed Nov 28, 2024
1 parent 114ecf1 commit 46d6832
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 73 deletions.
24 changes: 15 additions & 9 deletions packages/dataviews/src/dataform-controls/text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export default function Text< Item >( {
field,
onChange,
hideLabelFromVision,
errorMessage,
}: DataFormControlProps< Item > ) {
const { id, label, placeholder } = field;
const value = field.getValue( { item: data } );
Expand All @@ -27,14 +28,19 @@ export default function Text< Item >( {
);

return (
<TextControl
label={ label }
placeholder={ placeholder }
value={ value ?? '' }
onChange={ onChangeControl }
__next40pxDefaultSize
__nextHasNoMarginBottom
hideLabelFromVision={ hideLabelFromVision }
/>
<>
<TextControl
label={ label }
placeholder={ placeholder }
value={ value ?? '' }
onChange={ onChangeControl }
__next40pxDefaultSize
__nextHasNoMarginBottom
hideLabelFromVision={ hideLabelFromVision }
/>
{ errorMessage && (
<p className="dataform-control-error">{ errorMessage }</p>
) }
</>
);
}
38 changes: 20 additions & 18 deletions packages/dataviews/src/dataform-hooks/use-form.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { useEffect, useState } from 'react';
import { FormField } from '../types';
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';

export const useForm = ( supportedFields: Record< string, FormField > ) => {
/**
* Internal dependencies
*/
import type { FormField } from '../types';

export const useForm = < Item >(
supportedFields: Record< string, FormField >
) => {
const [ form, setForm ] = useState( {
fields: supportedFields,
touchedFields: [] as string[],
errors: {},
messageErrors: {},
} );

const setTouchedFields = ( touchedFields: string[] ) => {
Expand All @@ -15,33 +24,26 @@ export const useForm = ( supportedFields: Record< string, FormField > ) => {
} );
};

const setError = ( field: string, error: string ) => {
const setErrors = ( field: string, error: string | undefined ) => {
setForm( {
...form,
errors: {
...form.errors,
messageErrors: {
...form.messageErrors,
[ field ]: error,
},
} );
};

const isFormValid = () => {
const isFormValid = ( data: Item ) => {
return Object.entries( form.fields ).every( ( [ , field ] ) => {
if (
field.validation.validateWhenDirty === true &&
form.touchedFields.includes( field.id )
) {
return field.validation.callback().isValid;
}

return field.validation.callback().isValid;
return field.validation.callback( data ).isValid;
} );
};

return {
...form,
setTouchedFields,
setError,
isFormValid: isFormValid(),
setErrors,
isFormValid,
};
};
55 changes: 34 additions & 21 deletions packages/dataviews/src/dataforms-layouts/data-form-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* WordPress dependencies
*/
import { __experimentalVStack as VStack } from '@wordpress/components';
import { useContext, useMemo } from '@wordpress/element';
import { useContext, useEffect, useMemo } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -28,6 +28,7 @@ export function DataFormLayout< Item >( {
field: FormField;
onChange: ( value: any ) => void;
hideLabelFromVision?: boolean;
errorMessage: string | undefined;
} ) => React.JSX.Element | null,
field: FormField
) => React.JSX.Element;
Expand All @@ -47,8 +48,20 @@ export function DataFormLayout< Item >( {
[ form ]
);

// @ts-ignore
const { setTouchedFields, setError, touchedFields } = form;
const { setTouchedFields, setErrors, touchedFields, messageErrors } = form;

useEffect( () => {
normalizedFormFields.forEach( ( formField ) => {
const { isValid, errorMessage } = formField.validation.callback( {
...data,
} );
if ( ! isValid ) {
setErrors( formField.id, errorMessage );
} else {
setErrors( formField.id, undefined );
}
} );
}, [ data, normalizedFormFields, setErrors ] );

return (
<VStack spacing={ 2 }>
Expand Down Expand Up @@ -81,6 +94,14 @@ export function DataFormLayout< Item >( {
key={ formField.id }
data={ data }
field={ formField }
errorMessage={
( formField.validation.showErrorOnlyWhenDirty &&
touchedFields.includes( formField.id ) ) ||
( ! formField.validation.showErrorOnlyWhenDirty &&
messageErrors[ formField.id ] )
? messageErrors[ formField.id ]
: undefined
}
onChange={ ( value ) => {
if ( ! touchedFields.includes( formField.id ) ) {
setTouchedFields( [
Expand All @@ -90,26 +111,18 @@ export function DataFormLayout< Item >( {
] );
}

if (
( formField.validation.validateWhenDirty &&
// @ts-ignore
form.touchedFields.includes(
formField.id
) ) ||
! formField.validation.validateWhenDirty
) {
const { isValid, message } =
formField.validation.callback();

if ( ! isValid ) {
setError( formField.id, message );
}
}

onChange( value );
const { isValid, errorMessage } =
formField.validation.callback( {
...data,
...value,
} );
if ( ! isValid ) {
setErrors( formField.id, errorMessage );
} else {
setErrors( formField.id, undefined );
}
} }
// @ts-ignore
message={ form.errors[ formField.id ] }
/>
);
} ) }
Expand Down
5 changes: 2 additions & 3 deletions packages/dataviews/src/dataforms-layouts/is-combined-field.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
/**
* Internal dependencies
*/
import { NormalizedFormField } from '../normalize-form-fields';
import type { FormField, CombinedFormField, NormalizedField } from '../types';
import type { FormField, CombinedFormField } from '../types';

export function isCombinedField(
field: FormField | NormalizedFormField
field: FormField
): field is CombinedFormField {
return ( field as CombinedFormField ).children !== undefined;
}
7 changes: 7 additions & 0 deletions packages/dataviews/src/dataforms-layouts/panel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ function PanelDropdown< Item >( {
data,
onChange,
field,
errorMessage,
}: {
fieldDefinition: NormalizedField< Item >;
popoverAnchor: HTMLElement | null;
labelPosition: 'side' | 'top' | 'none';
data: Item;
onChange: ( value: any ) => void;
field: FormField;
errorMessage: string | undefined;
} ) {
const fieldLabel = isCombinedField( field )
? field.label
Expand Down Expand Up @@ -158,6 +160,7 @@ function PanelDropdown< Item >( {
hideLabelFromVision={
( form?.fields ?? [] ).length < 2
}
errorMessage={ errorMessage }
/>
) }
</DataFormLayout>
Expand All @@ -171,6 +174,7 @@ export default function FormPanelField< Item >( {
data,
field,
onChange,
errorMessage,
}: FieldLayoutProps< Item > ) {
const { fields } = useContext( DataFormContext );
const fieldDefinition = fields.find( ( fieldDef ) => {
Expand Down Expand Up @@ -221,6 +225,7 @@ export default function FormPanelField< Item >( {
data={ data }
onChange={ onChange }
labelPosition={ labelPosition }
errorMessage={ errorMessage }
/>
</div>
</VStack>
Expand All @@ -237,6 +242,7 @@ export default function FormPanelField< Item >( {
data={ data }
onChange={ onChange }
labelPosition={ labelPosition }
errorMessage={ errorMessage }
/>
</div>
);
Expand All @@ -259,6 +265,7 @@ export default function FormPanelField< Item >( {
data={ data }
onChange={ onChange }
labelPosition={ labelPosition }
errorMessage={ errorMessage }
/>
</div>
</HStack>
Expand Down
3 changes: 3 additions & 0 deletions packages/dataviews/src/dataforms-layouts/regular/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default function FormRegularField< Item >( {
field,
onChange,
hideLabelFromVision,
errorMessage,
}: FieldLayoutProps< Item > ) {
const { fields } = useContext( DataFormContext );

Expand Down Expand Up @@ -93,6 +94,7 @@ export default function FormRegularField< Item >( {
key={ fieldDefinition.id }
data={ data }
field={ fieldDefinition }
errorMessage={ errorMessage }
onChange={ onChange }
hideLabelFromVision
/>
Expand All @@ -106,6 +108,7 @@ export default function FormRegularField< Item >( {
<fieldDefinition.Edit
data={ data }
field={ fieldDefinition }
errorMessage={ errorMessage }
onChange={ onChange }
hideLabelFromVision={
labelPosition === 'none' ? true : hideLabelFromVision
Expand Down
4 changes: 2 additions & 2 deletions packages/dataviews/src/normalize-form-fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export default function normalizeFormFields(
validation: {
callback: () => ( {
isValid: true,
message: '',
errorMessage: '',
} ),
validateWhenDirty: false,
showErrorOnlyWhenDirty: true,
},
};
}
Expand Down
21 changes: 15 additions & 6 deletions packages/dataviews/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ export type DataFormControlProps< Item > = {
field: NormalizedField< Item >;
onChange: ( value: Record< string, any > ) => void;
hideLabelFromVision?: boolean;
errorMessage: string | undefined;
};

export type DataViewRenderFieldProps< Item > = {
Expand Down Expand Up @@ -552,18 +553,20 @@ export type CombinedFormField = {
children: Array< FormField | string >;
} & { validation: FormFieldValidation };

export type ValidationResult = {
isValid: boolean;
errorMessage: string | undefined;
};

export type FormFieldValidation = {
/**
* The validation message.
* The validation should be triggered only when the field is dirty.
*/
validateWhenDirty: boolean;
showErrorOnlyWhenDirty: boolean;
/**
* The validation function.
*/
callback: () => {
isValid: boolean;
message: string;
};
callback: ( data: any ) => ValidationResult;
};

export type FormField = SimpleFormField | CombinedFormField;
Expand All @@ -574,6 +577,11 @@ export type Form = {
type?: 'regular' | 'panel';
fields?: Array< FormField | string >;
labelPosition?: 'side' | 'top' | 'none';
touchedFields: string[];
messageErrors: Record< string, string | undefined >;
setTouchedFields: ( touchedFields: string[] ) => void;
setErrors: ( field: string, error: string | undefined ) => void;
isFormValid: ( data: Record< string, any > ) => boolean;
};

export interface DataFormProps< Item > {
Expand All @@ -588,4 +596,5 @@ export interface FieldLayoutProps< Item > {
field: FormField;
onChange: ( value: any ) => void;
hideLabelFromVision?: boolean;
errorMessage: string | undefined;
}
6 changes: 2 additions & 4 deletions packages/fields/src/actions/duplicate-post.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ import type { BasePost, CoreDataError } from '../types';
import { getItemTitle } from './utils';

const fields = [ titleField ];
const formDuplicateAction = {
fields: [ 'title' ],
};

const duplicatePost: Action< BasePost > = {
id: 'duplicate-post',
Expand Down Expand Up @@ -139,7 +136,8 @@ const duplicatePost: Action< BasePost > = {
<DataForm
data={ item }
fields={ fields }
form={ formDuplicateAction }
// @ts-ignore
form={ form }
onChange={ ( changes ) =>
setItem( ( prev ) => ( {
...prev,
Expand Down
4 changes: 3 additions & 1 deletion packages/fields/src/actions/reorder-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function ReorderModal( {

async function onOrder( event: React.FormEvent ) {
event.preventDefault();

// @ts-ignore
if ( ! isItemValid( item, fields, formOrderAction ) ) {
return;
}
Expand Down Expand Up @@ -68,6 +68,7 @@ function ReorderModal( {
} );
}
}
// @ts-ignore
const isSaveDisabled = ! isItemValid( item, fields, formOrderAction );
return (
<form onSubmit={ onOrder }>
Expand All @@ -80,6 +81,7 @@ function ReorderModal( {
<DataForm
data={ item }
fields={ fields }
// @ts-ignore
form={ formOrderAction }
onChange={ ( changes ) =>
setItem( {
Expand Down
Loading

0 comments on commit 46d6832

Please sign in to comment.