From 49eb22001219b2d585fba8ad0fbe38cd937d2c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:54:35 +0200 Subject: [PATCH 01/20] Add initial DataForm structure --- packages/dataviews/src/dataform.tsx | 52 +++++++++++++++++++ packages/dataviews/src/index.ts | 1 + packages/editor/package.json | 1 + .../src/components/post-actions/actions.js | 35 +++---------- 4 files changed, 62 insertions(+), 27 deletions(-) create mode 100644 packages/dataviews/src/dataform.tsx diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx new file mode 100644 index 0000000000000..1e925b49154d5 --- /dev/null +++ b/packages/dataviews/src/dataform.tsx @@ -0,0 +1,52 @@ +/** + * WordPress dependencies + */ +import { __, _x } from '@wordpress/i18n'; +import { + Button, + TextControl, + __experimentalHStack as HStack, + __experimentalVStack as VStack, +} from '@wordpress/components'; + +type DataFormProps = { + title: any; + setTitle: any; + createPage: any; + closeModal: any; + isCreatingPage: any; +}; + +export default function DataForm( { + createPage, + title, + setTitle, + closeModal, + isCreatingPage, +}: DataFormProps ) { + return ( +
+ + + + + + + +
+ ); +} diff --git a/packages/dataviews/src/index.ts b/packages/dataviews/src/index.ts index 31f44e5ed9750..f4750bbbd2cd5 100644 --- a/packages/dataviews/src/index.ts +++ b/packages/dataviews/src/index.ts @@ -2,3 +2,4 @@ export { default as DataViews } from './dataviews'; export { VIEW_LAYOUTS } from './layouts'; export { filterSortAndPaginate } from './filter-and-sort-data-view'; export type * from './types'; +export { default as DataForm } from './dataform'; diff --git a/packages/editor/package.json b/packages/editor/package.json index 932be1a1799fc..bdda258d1453f 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -42,6 +42,7 @@ "@wordpress/compose": "file:../compose", "@wordpress/core-data": "file:../core-data", "@wordpress/data": "file:../data", + "@wordpress/dataviews": "file:../dataviews", "@wordpress/date": "file:../date", "@wordpress/deprecated": "file:../deprecated", "@wordpress/dom": "file:../dom", diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 535e474aafff1..dcd449825fcf4 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -11,7 +11,7 @@ import { store as noticesStore } from '@wordpress/notices'; import { useMemo, useState } from '@wordpress/element'; import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; import { parse } from '@wordpress/blocks'; - +import { DataForm } from '@wordpress/dataviews'; import { Button, TextControl, @@ -754,32 +754,13 @@ const useDuplicatePostAction = ( postType ) => { } } return ( -
- - - - - - - -
+ ); }, }, From 0adcfcb8fefcb2f61d8bb4b115b58b2c95a24fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:07:48 +0200 Subject: [PATCH 02/20] Absorb onSubmit, closeForm, isBusy. --- packages/dataviews/src/dataform.tsx | 25 +++++++++++-------- .../src/components/post-actions/actions.js | 6 ++--- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 1e925b49154d5..aded05c3c7b92 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import type { FormEventHandler } from 'react'; // TODO: how to import FormEventHandler? + /** * WordPress dependencies */ @@ -12,20 +17,20 @@ import { type DataFormProps = { title: any; setTitle: any; - createPage: any; - closeModal: any; - isCreatingPage: any; + onSubmit: FormEventHandler; + closeForm: any; + isBusy: any; }; export default function DataForm( { - createPage, title, setTitle, - closeModal, - isCreatingPage, + onSubmit, + closeForm, + isBusy, }: DataFormProps ) { return ( -
+ - diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index dcd449825fcf4..f6a3fc6d67581 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -757,9 +757,9 @@ const useDuplicatePostAction = ( postType ) => { ); }, From f896aae0ce22bbfeb961870f7d19e2fbf76a749b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:41:48 +0200 Subject: [PATCH 03/20] Absorb title, setTitle. --- packages/dataviews/src/dataform.tsx | 29 ++++++++++----- .../src/components/post-actions/actions.js | 35 ++++++++++--------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index aded05c3c7b92..c76a6a237cf75 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -13,30 +13,43 @@ import { __experimentalHStack as HStack, __experimentalVStack as VStack, } from '@wordpress/components'; +import { useCallback, useState } from '@wordpress/element'; type DataFormProps = { - title: any; - setTitle: any; - onSubmit: FormEventHandler; + item: any; + onUpdateItem: ( item: any ) => void; closeForm: any; isBusy: any; }; export default function DataForm( { - title, - setTitle, - onSubmit, + item: initialItem, + onUpdateItem, closeForm, isBusy, }: DataFormProps ) { + const [ item, setItem ] = useState( initialItem ); + const onSubmit: FormEventHandler< HTMLFormElement > = useCallback( + ( event ) => { + event.preventDefault(); + + onUpdateItem( item ); + }, + [ item ] + ); + + const onChange = useCallback( ( title: string ) => { + setItem( { ...item, title } ); + }, [] ); + return ( diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 868a3efe87468..57f5b9bc66f4a 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -766,13 +766,20 @@ const useDuplicatePostAction = ( postType ) => { } ), [ items ] ); + const form = useMemo( + () => ( { + closeForm: closeModal, + isBusy: isCreatingPage, + onSubmitLabel: _x( 'Duplicate', 'action label' ), + } ), + [ closeModal, isCreatingPage ] + ); return ( ); }, From 04942f981459afecbda571e27ec8394103a74358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:41:49 +0200 Subject: [PATCH 06/20] Add TODO --- packages/dataviews/src/dataform.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 0752280b0a243..5ea520c4afa4c 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -48,6 +48,7 @@ export default function DataForm< Item >( { [ item ] ); + // TODO: make it work for all fields. const onChange = useCallback( ( title: string ) => { setItem( { ...item, title } ); }, [] ); From dac856716f4306b2720c8c1f36ccda5c2ff853fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Mon, 1 Jul 2024 19:08:49 +0200 Subject: [PATCH 07/20] Simplify DataForms API --- packages/dataviews/src/dataform.tsx | 10 +++++----- packages/editor/src/components/post-actions/actions.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 5ea520c4afa4c..3d1a7f80cd6f9 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -21,8 +21,8 @@ import { useCallback, useMemo, useState } from '@wordpress/element'; import type { NormalizedField } from './types'; type DataFormProps< Item > = { - item: Item; - onUpdateItem: ( item: Item ) => void; + data: Item; + onUpdate: ( item: Item ) => void; fields: NormalizedField< Item >[]; // TODO: use Field. Normalize them first. form: { closeForm: () => void; @@ -33,8 +33,8 @@ type DataFormProps< Item > = { }; export default function DataForm< Item >( { - item: data, - onUpdateItem, + data, + onUpdate, fields, form: { closeForm, isBusy, onCancelLabel, onSubmitLabel }, }: DataFormProps< Item > ) { @@ -43,7 +43,7 @@ export default function DataForm< Item >( { ( event ) => { event.preventDefault(); - onUpdateItem( item ); + onUpdate( item ); }, [ item ] ); diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 57f5b9bc66f4a..0854420277dec 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -776,8 +776,8 @@ const useDuplicatePostAction = ( postType ) => { ); return ( From d1cb3853ba9fef592c660cd443e5adc8633bc8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Tue, 2 Jul 2024 08:35:36 +0200 Subject: [PATCH 08/20] Make onChange work for any field --- packages/dataviews/src/dataform.tsx | 45 ++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 3d1a7f80cd6f9..6f92c31924be0 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -32,13 +32,42 @@ type DataFormProps< Item > = { }; }; +type DataFormTextControlProps< Item > = { + field: NormalizedField< Item >; + item: Item; + setItem: any; // TODO: fix type. +}; + +function DataFormTextControl< Item >( { + field, + item, + setItem, +}: DataFormTextControlProps< Item > ) { + const { id, header, placeholder, getValue } = field; + + const onChange = useCallback( + ( value: string ) => + setItem( ( prevItem: any ) => ( { ...prevItem, [ id ]: value } ) ), + [ id, setItem ] + ); + + return ( + + ); +} + export default function DataForm< Item >( { data, onUpdate, fields, form: { closeForm, isBusy, onCancelLabel, onSubmitLabel }, }: DataFormProps< Item > ) { - const [ item, setItem ] = useState( data ); + const [ item, setItem ] = useState< Item >( data ); const onSubmit: FormEventHandler< HTMLFormElement > = useCallback( ( event ) => { event.preventDefault(); @@ -48,21 +77,15 @@ export default function DataForm< Item >( { [ item ] ); - // TODO: make it work for all fields. - const onChange = useCallback( ( title: string ) => { - setItem( { ...item, title } ); - }, [] ); - const components = useMemo( () => fields.map( ( field ) => { if ( field.type === 'text' ) { return ( - ); } From caeef9f841264f5c40e859aa6d4f5fe2708ba5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Tue, 2 Jul 2024 09:51:18 +0200 Subject: [PATCH 09/20] Scope down DataForm as a control generator (no submit/cancel operations) --- packages/dataviews/src/dataform.tsx | 106 +++++------------- .../src/components/post-actions/actions.js | 63 ++++++----- 2 files changed, 66 insertions(+), 103 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 6f92c31924be0..130f358326ef3 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -1,19 +1,9 @@ -/** - * External dependencies - */ -import type { FormEventHandler } from 'react'; // TODO: how to import FormEventHandler? - /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { - Button, - TextControl, - __experimentalHStack as HStack, - __experimentalVStack as VStack, -} from '@wordpress/components'; -import { useCallback, useMemo, useState } from '@wordpress/element'; +import { TextControl } from '@wordpress/components'; +import { useCallback } from '@wordpress/element'; /** * Internal dependencies @@ -22,40 +12,38 @@ import type { NormalizedField } from './types'; type DataFormProps< Item > = { data: Item; - onUpdate: ( item: Item ) => void; fields: NormalizedField< Item >[]; // TODO: use Field. Normalize them first. - form: { - closeForm: () => void; - isBusy: boolean; - onSubmitLabel?: string; - onCancelLabel?: string; - }; + onUpdate: any; // TODO: fix this type. }; type DataFormTextControlProps< Item > = { + data: Item; field: NormalizedField< Item >; - item: Item; - setItem: any; // TODO: fix type. + onUpdate: any; // TODO: fix this type. }; function DataFormTextControl< Item >( { + data, field, - item, - setItem, + onUpdate, }: DataFormTextControlProps< Item > ) { - const { id, header, placeholder, getValue } = field; + const { id, header, placeholder } = field; + const value = field.getValue( { item: data } ); const onChange = useCallback( - ( value: string ) => - setItem( ( prevItem: any ) => ( { ...prevItem, [ id ]: value } ) ), - [ id, setItem ] + ( newValue: string ) => + onUpdate( ( prevItem: any ) => ( { + ...prevItem, + [ id ]: newValue, + } ) ), + [ id, onUpdate ] ); return ( ); @@ -63,55 +51,19 @@ function DataFormTextControl< Item >( { export default function DataForm< Item >( { data, - onUpdate, fields, - form: { closeForm, isBusy, onCancelLabel, onSubmitLabel }, + onUpdate, }: DataFormProps< Item > ) { - const [ item, setItem ] = useState< Item >( data ); - const onSubmit: FormEventHandler< HTMLFormElement > = useCallback( - ( event ) => { - event.preventDefault(); - - onUpdate( item ); - }, - [ item ] - ); - - const components = useMemo( - () => - fields.map( ( field ) => { - if ( field.type === 'text' ) { - return ( - - ); - } - return null; - } ), - [ fields, item ] - ); - - return ( - - - { components } - - - - - - - ); + return fields.map( ( field ) => { + if ( field.type === 'text' ) { + return ( + + ); + } + return null; + } ); } diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 0854420277dec..ca86f2db0d34b 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -660,6 +660,15 @@ const useDuplicatePostAction = ( postType ) => { return status !== 'trash'; }, RenderModal: ( { items, closeModal, onActionPerformed } ) => { + const [ item, setItem ] = useState( { + ...items[ 0 ], + title: sprintf( + /* translators: %s: Existing template title */ + __( '%s (Copy)' ), + getItemTitle( items[ 0 ] ) + ), + } ); + const [ isCreatingPage, setIsCreatingPage ] = useState( false ); @@ -667,7 +676,9 @@ const useDuplicatePostAction = ( postType ) => { const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore ); - async function createPage( item ) { + async function createPage( event ) { + event.preventDefault(); + if ( isCreatingPage ) { return; } @@ -755,32 +766,32 @@ const useDuplicatePostAction = ( postType ) => { } } - const item = useMemo( - () => ( { - ...items[ 0 ], - title: sprintf( - /* translators: %s: Existing template title */ - __( '%s (Copy)' ), - getItemTitle( items[ 0 ] ) - ), - } ), - [ items ] - ); - const form = useMemo( - () => ( { - closeForm: closeModal, - isBusy: isCreatingPage, - onSubmitLabel: _x( 'Duplicate', 'action label' ), - } ), - [ closeModal, isCreatingPage ] - ); return ( - +
+ + + + + + + +
); }, }, From a88fa6c85aecdc0eaa3ea0ef9cb906f685d7d7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Tue, 2 Jul 2024 10:02:08 +0200 Subject: [PATCH 10/20] Debounce input --- packages/dataviews/src/dataform.tsx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 130f358326ef3..05d6a526a7c21 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -3,7 +3,8 @@ */ import { __ } from '@wordpress/i18n'; import { TextControl } from '@wordpress/components'; -import { useCallback } from '@wordpress/element'; +import { useEffect } from '@wordpress/element'; +import { useDebouncedInput } from '@wordpress/compose'; /** * Internal dependencies @@ -28,23 +29,23 @@ function DataFormTextControl< Item >( { onUpdate, }: DataFormTextControlProps< Item > ) { const { id, header, placeholder } = field; - const value = field.getValue( { item: data } ); - - const onChange = useCallback( - ( newValue: string ) => - onUpdate( ( prevItem: any ) => ( { - ...prevItem, - [ id ]: newValue, - } ) ), - [ id, onUpdate ] + const [ value, setValue, debouncedValue ] = useDebouncedInput( + field.getValue( { item: data } ) ); + useEffect( () => { + onUpdate( ( prevItem: any ) => ( { + ...prevItem, + [ id ]: debouncedValue, + } ) ); + }, [ debouncedValue ] ); + return ( ); } From 4ec608cca849457c657c96491099a567011b4f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Tue, 2 Jul 2024 10:17:00 +0200 Subject: [PATCH 11/20] Update package-lock --- package-lock.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package-lock.json b/package-lock.json index 80317039b1f09..c93815597de63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54370,6 +54370,7 @@ "@wordpress/compose": "file:../compose", "@wordpress/core-data": "file:../core-data", "@wordpress/data": "file:../data", + "@wordpress/dataviews": "file:../dataviews", "@wordpress/date": "file:../date", "@wordpress/deprecated": "file:../deprecated", "@wordpress/dom": "file:../dom", @@ -69493,6 +69494,7 @@ "@wordpress/compose": "file:../compose", "@wordpress/core-data": "file:../core-data", "@wordpress/data": "file:../data", + "@wordpress/dataviews": "file:../dataviews", "@wordpress/date": "file:../date", "@wordpress/deprecated": "file:../deprecated", "@wordpress/dom": "file:../dom", From 287e0ff892b6c30345ab2081ff5ee654c2bf90e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Tue, 2 Jul 2024 10:29:00 +0200 Subject: [PATCH 12/20] Form API: add visibleFields --- packages/dataviews/src/dataform.tsx | 21 +++++++++++++++---- packages/dataviews/src/types.ts | 7 +++++++ .../src/components/post-actions/actions.js | 5 +++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 05d6a526a7c21..98ef6df291302 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -3,17 +3,19 @@ */ import { __ } from '@wordpress/i18n'; import { TextControl } from '@wordpress/components'; -import { useEffect } from '@wordpress/element'; +import { useEffect, useMemo } from '@wordpress/element'; import { useDebouncedInput } from '@wordpress/compose'; /** * Internal dependencies */ -import type { NormalizedField } from './types'; +import type { Form, Field, NormalizedField } from './types'; +import { normalizeFields } from './normalize-fields'; type DataFormProps< Item > = { data: Item; - fields: NormalizedField< Item >[]; // TODO: use Field. Normalize them first. + fields: Field< Item >[]; + form: Form; onUpdate: any; // TODO: fix this type. }; @@ -53,9 +55,20 @@ function DataFormTextControl< Item >( { export default function DataForm< Item >( { data, fields, + form, onUpdate, }: DataFormProps< Item > ) { - return fields.map( ( field ) => { + const visibleFields = useMemo( + () => + normalizeFields( + fields.filter( + ( { id } ) => !! form.visibleFields?.includes( id ) + ) + ), + [ fields, form.visibleFields ] + ); + + return visibleFields.map( ( field ) => { if ( field.type === 'text' ) { return ( = Field< Item >[]; export type Data< Item > = Item[]; +/** + * The form configuration. + */ +export type Form = { + visibleFields?: string[]; +}; + /** * The filters applied to the dataset. */ diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index ca86f2db0d34b..b9d07524cd0c4 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -50,6 +50,10 @@ const fields = [ }, ]; +const form = { + visibleFields: [ 'title' ], +}; + /** * Check if a template is removable. * @@ -772,6 +776,7 @@ const useDuplicatePostAction = ( postType ) => { From 1979c74ebfe26807d8e89b174637468e1a8d95e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:14:32 +0200 Subject: [PATCH 13/20] Revert debounce input --- packages/dataviews/src/dataform.tsx | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 98ef6df291302..db0c621cc5566 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -3,8 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { TextControl } from '@wordpress/components'; -import { useEffect, useMemo } from '@wordpress/element'; -import { useDebouncedInput } from '@wordpress/compose'; +import { useCallback, useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -31,23 +30,23 @@ function DataFormTextControl< Item >( { onUpdate, }: DataFormTextControlProps< Item > ) { const { id, header, placeholder } = field; - const [ value, setValue, debouncedValue ] = useDebouncedInput( - field.getValue( { item: data } ) - ); + const value = field.getValue( { item: data } ); - useEffect( () => { - onUpdate( ( prevItem: any ) => ( { - ...prevItem, - [ id ]: debouncedValue, - } ) ); - }, [ debouncedValue ] ); + const onChange = useCallback( + ( newValue: string ) => + onUpdate( ( prevItem: any ) => ( { + ...prevItem, + [ id ]: newValue, + } ) ), + [ id, onUpdate ] + ); return ( ); } From bc13a9b71039696d19feba723ea1425a90106115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:28:08 +0200 Subject: [PATCH 14/20] Create a static and private registry for controls --- packages/dataviews/src/dataform.tsx | 43 +++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index db0c621cc5566..3ca845b2576dc 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -18,7 +18,7 @@ type DataFormProps< Item > = { onUpdate: any; // TODO: fix this type. }; -type DataFormTextControlProps< Item > = { +type DataFormControlProps< Item > = { data: Item; field: NormalizedField< Item >; onUpdate: any; // TODO: fix this type. @@ -28,7 +28,7 @@ function DataFormTextControl< Item >( { data, field, onUpdate, -}: DataFormTextControlProps< Item > ) { +}: DataFormControlProps< Item > ) { const { id, header, placeholder } = field; const value = field.getValue( { item: data } ); @@ -51,6 +51,26 @@ function DataFormTextControl< Item >( { ); } +const controls: { + [ key: string ]: < Item >( + props: DataFormControlProps< Item > + ) => JSX.Element; +} = { + text: DataFormTextControl, +}; + +function getControlForField< Item >( field: NormalizedField< Item > ) { + if ( ! field.type ) { + return null; + } + + if ( ! Object.keys( controls ).includes( field.type ) ) { + return null; + } + + return controls[ field.type ]; +} + export default function DataForm< Item >( { data, fields, @@ -68,15 +88,14 @@ export default function DataForm< Item >( { ); return visibleFields.map( ( field ) => { - if ( field.type === 'text' ) { - return ( - - ); - } - return null; + const DataFormControl = getControlForField( field ); + return DataFormControl ? ( + + ) : null; } ); } From 9287a11c8cdc7d724406897ed36a213cf28ada0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:23:12 +0200 Subject: [PATCH 15/20] Introduce FieldType type --- packages/dataviews/src/types.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index 50eaf9a64cfeb..9e140f686d65f 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -44,6 +44,8 @@ export type Operator = export type ItemRecord = Record< string, unknown >; +export type FieldType = 'text'; + /** * A dataview field for a specific property of a data type. */ @@ -51,7 +53,7 @@ export type Field< Item > = { /** * Type of the fields. */ - type?: string; // TODO: provide a enum-like list for valid values. + type?: FieldType; /** * The unique identifier of the field. From ffab101fb8ef1a8923d4ca508505139054af276b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:29:53 +0200 Subject: [PATCH 16/20] Type onUpdate updater function --- packages/dataviews/src/dataform.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 3ca845b2576dc..1109bd09357e0 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import type { Dispatch, SetStateAction } from 'react'; + /** * WordPress dependencies */ @@ -15,13 +20,13 @@ type DataFormProps< Item > = { data: Item; fields: Field< Item >[]; form: Form; - onUpdate: any; // TODO: fix this type. + onUpdate: Dispatch< SetStateAction< Item > >; }; type DataFormControlProps< Item > = { data: Item; field: NormalizedField< Item >; - onUpdate: any; // TODO: fix this type. + onUpdate: Dispatch< SetStateAction< Item > >; }; function DataFormTextControl< Item >( { @@ -34,7 +39,7 @@ function DataFormTextControl< Item >( { const onChange = useCallback( ( newValue: string ) => - onUpdate( ( prevItem: any ) => ( { + onUpdate( ( prevItem: Item ) => ( { ...prevItem, [ id ]: newValue, } ) ), From 374702023d68c87eee292d4134af19b622728938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:33:09 +0200 Subject: [PATCH 17/20] Rename onUpdate to onChange --- packages/dataviews/src/dataform.tsx | 18 +++++++++--------- .../src/components/post-actions/actions.js | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/dataviews/src/dataform.tsx b/packages/dataviews/src/dataform.tsx index 1109bd09357e0..e96e0e13dc051 100644 --- a/packages/dataviews/src/dataform.tsx +++ b/packages/dataviews/src/dataform.tsx @@ -20,30 +20,30 @@ type DataFormProps< Item > = { data: Item; fields: Field< Item >[]; form: Form; - onUpdate: Dispatch< SetStateAction< Item > >; + onChange: Dispatch< SetStateAction< Item > >; }; type DataFormControlProps< Item > = { data: Item; field: NormalizedField< Item >; - onUpdate: Dispatch< SetStateAction< Item > >; + onChange: Dispatch< SetStateAction< Item > >; }; function DataFormTextControl< Item >( { data, field, - onUpdate, + onChange, }: DataFormControlProps< Item > ) { const { id, header, placeholder } = field; const value = field.getValue( { item: data } ); - const onChange = useCallback( + const onChangeControl = useCallback( ( newValue: string ) => - onUpdate( ( prevItem: Item ) => ( { + onChange( ( prevItem: Item ) => ( { ...prevItem, [ id ]: newValue, } ) ), - [ id, onUpdate ] + [ id, onChange ] ); return ( @@ -51,7 +51,7 @@ function DataFormTextControl< Item >( { label={ header } placeholder={ placeholder } value={ value } - onChange={ onChange } + onChange={ onChangeControl } /> ); } @@ -80,7 +80,7 @@ export default function DataForm< Item >( { data, fields, form, - onUpdate, + onChange, }: DataFormProps< Item > ) { const visibleFields = useMemo( () => @@ -99,7 +99,7 @@ export default function DataForm< Item >( { key={ field.id } data={ data } field={ field } - onUpdate={ onUpdate } + onChange={ onChange } /> ) : null; } ); diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index b9d07524cd0c4..e38c64ddb3d7e 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -777,7 +777,7 @@ const useDuplicatePostAction = ( postType ) => { data={ item } fields={ fields } form={ form } - onUpdate={ setItem } + onChange={ setItem } />