From b300fd43119ca26c300311a668a5249ca0992192 Mon Sep 17 00:00:00 2001 From: Lourens Schep Date: Tue, 1 Oct 2024 14:09:25 +0200 Subject: [PATCH 1/6] Add isVisible callback for form fields --- .../dataform-field-visibility/index.tsx | 35 +++++++++++++++++++ .../src/dataforms-layouts/panel/index.tsx | 12 +++++-- .../src/dataforms-layouts/regular/index.tsx | 12 +++++-- packages/dataviews/src/types.ts | 10 ++++++ 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 packages/dataviews/src/components/dataform-field-visibility/index.tsx diff --git a/packages/dataviews/src/components/dataform-field-visibility/index.tsx b/packages/dataviews/src/components/dataform-field-visibility/index.tsx new file mode 100644 index 00000000000000..965e874ac56886 --- /dev/null +++ b/packages/dataviews/src/components/dataform-field-visibility/index.tsx @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import type { NormalizedField } from '../../types'; + +type DataFormFieldVisibilityProps< Item > = React.PropsWithChildren< { + field: NormalizedField< Item >; + data: Item; +} >; + +export default function DataFormFieldVisibility< Item >( { + data, + field, + children, +}: DataFormFieldVisibilityProps< Item > ) { + const dependencies = field.dependencies + ? field.dependencies.map( ( dep ) => data[ dep ] ) + : [ field?.getValue( { item: data } ) ]; + const isVisible = useMemo( () => { + if ( field.isVisible ) { + return field.isVisible( data ); + } + return true; + }, [ field.isVisible, ...dependencies ] ); + + if ( ! isVisible ) { + return null; + } + return children; +} diff --git a/packages/dataviews/src/dataforms-layouts/panel/index.tsx b/packages/dataviews/src/dataforms-layouts/panel/index.tsx index 4a43d25436fe74..b3e863509153f2 100644 --- a/packages/dataviews/src/dataforms-layouts/panel/index.tsx +++ b/packages/dataviews/src/dataforms-layouts/panel/index.tsx @@ -19,6 +19,7 @@ import { closeSmall } from '@wordpress/icons'; import { normalizeFields } from '../../normalize-fields'; import { getVisibleFields } from '../get-visible-fields'; import type { DataFormProps, NormalizedField } from '../../types'; +import DataFormFieldVisibility from '../../components/dataform-field-visibility'; interface FormFieldProps< Item > { data: Item; @@ -156,12 +157,17 @@ export default function FormPanel< Item >( { { visibleFields.map( ( field ) => { return ( - + > + + ); } ) } diff --git a/packages/dataviews/src/dataforms-layouts/regular/index.tsx b/packages/dataviews/src/dataforms-layouts/regular/index.tsx index 57aa163b890e5f..f5b7157a47d467 100644 --- a/packages/dataviews/src/dataforms-layouts/regular/index.tsx +++ b/packages/dataviews/src/dataforms-layouts/regular/index.tsx @@ -10,6 +10,7 @@ import { useMemo } from '@wordpress/element'; import { normalizeFields } from '../../normalize-fields'; import { getVisibleFields } from '../get-visible-fields'; import type { DataFormProps } from '../../types'; +import DataFormFieldVisibility from '../../components/dataform-field-visibility'; export default function FormRegular< Item >( { data, @@ -33,12 +34,17 @@ export default function FormRegular< Item >( { { visibleFields.map( ( field ) => { return ( - + > + + ); } ) } diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index 2a335dce3af32b..894503ed728c41 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -123,6 +123,16 @@ export type Field< Item > = { */ isValid?: ( item: Item, context?: ValidationContext ) => boolean; + /** + * Callback used to display the field. + */ + isVisible?: ( item: Item ) => boolean; + + /** + * Dependency list for triggering isVisible. + */ + dependencies?: Array< keyof Item >; + /** * Whether the field is sortable. */ From f24a74245a374000f278ac3a0925336616d81d42 Mon Sep 17 00:00:00 2001 From: Lourens Schep Date: Tue, 1 Oct 2024 14:09:42 +0200 Subject: [PATCH 2/6] Update storybook to add visibility example --- .../dataform/stories/index.story.tsx | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/packages/dataviews/src/components/dataform/stories/index.story.tsx b/packages/dataviews/src/components/dataform/stories/index.story.tsx index c929c21f1c21a9..6aa4e386c72374 100644 --- a/packages/dataviews/src/components/dataform/stories/index.story.tsx +++ b/packages/dataviews/src/components/dataform/stories/index.story.tsx @@ -1,13 +1,25 @@ /** * WordPress dependencies */ -import { useState } from '@wordpress/element'; +import { useMemo, useState } from '@wordpress/element'; /** * Internal dependencies */ import DataForm from '../index'; -import type { CombinedFormField } from '../../../types'; +import type { CombinedFormField, Field } from '../../../types'; + +type SamplePost = { + title: string; + order: number; + author: number; + status: string; + reviewer: string; + date: string; + birthdate: string; + sampleField?: string; + password?: string; +}; const meta = { title: 'DataViews/DataForm', @@ -19,6 +31,22 @@ const meta = { 'Chooses the layout of the form. "regular" is the default layout.', options: [ 'regular', 'panel' ], }, + sampleFieldType: { + name: 'Sample Field Type', + control: { type: 'select' }, + description: 'Chooses the type of the sample field.', + options: [ 'text', 'integer', 'datetime' ], + }, + additionalSampleFieldDependency: { + name: 'Additional Sample Field Dependency', + control: { type: 'select' }, + description: + 'Choose an additional dependency of the sample field for visiblity.', + options: [ 'order', 'author', 'status' ], + }, + }, + args: { + sampleFieldType: 'text', }, }; export default meta; @@ -75,16 +103,47 @@ const fields = [ elements: [ { value: 'draft', label: 'Draft' }, { value: 'published', label: 'Published' }, + { value: 'private', label: 'Private' }, ], }, { id: 'password', label: 'Password', type: 'text' as const, + isVisible: ( item: SamplePost ) => { + return item.status !== 'private'; + }, + dependencies: [ 'status' ], }, -]; +] as Field< SamplePost >[]; -export const Default = ( { type }: { type: 'panel' | 'regular' } ) => { +export const Default = ( { + type, + sampleFieldType = 'text', + additionalSampleFieldDependency, +}: { + type: 'panel' | 'regular'; + sampleFieldType: 'text' | 'integer' | 'datetime'; + additionalSampleFieldDependency?: keyof SamplePost; +} ) => { + const visibileFields = useMemo( () => { + const dependencies = [ 'sampleField' ]; + if ( additionalSampleFieldDependency ) { + dependencies.push( additionalSampleFieldDependency ); + } + return [ + ...fields, + { + id: 'sampleField', + label: 'Sample Field', + type: sampleFieldType, + isVisible: ( item: SamplePost ) => { + return item.order < 3 && item.sampleField !== 'hide'; + }, + dependencies, + }, + ] as Field< SamplePost >[]; + }, [ sampleFieldType, additionalSampleFieldDependency ] ); const [ post, setPost ] = useState( { title: 'Hello, World!', order: 2, @@ -98,19 +157,21 @@ export const Default = ( { type }: { type: 'panel' | 'regular' } ) => { const form = { fields: [ 'title', + 'sampleField', 'order', 'author', 'reviewer', 'status', + 'password', 'date', 'birthdate', ], }; return ( - data={ post } - fields={ fields } + fields={ visibileFields } form={ { ...form, type, From adf30465807f351de84b14600704cba8f05c2ff8 Mon Sep 17 00:00:00 2001 From: Lourens Schep Date: Wed, 2 Oct 2024 13:27:44 +0200 Subject: [PATCH 3/6] Update isVisible comment doc --- packages/dataviews/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index 894503ed728c41..cb7585b0c20cc8 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -124,7 +124,7 @@ export type Field< Item > = { isValid?: ( item: Item, context?: ValidationContext ) => boolean; /** - * Callback used to display the field. + * Callback used to decide if a field should be displayed. */ isVisible?: ( item: Item ) => boolean; From 3f73afb6da4a850088ada24bbbb21e85665935e5 Mon Sep 17 00:00:00 2001 From: Lourens Schep Date: Mon, 28 Oct 2024 15:26:20 +0000 Subject: [PATCH 4/6] Removed depedency config and renamed visibility component --- .../components/dataform/stories/index.story.tsx | 17 +---------------- .../index.tsx | 11 ++++------- .../src/dataforms-layouts/panel/index.tsx | 6 +++--- .../src/dataforms-layouts/regular/index.tsx | 6 +++--- packages/dataviews/src/types.ts | 5 ----- 5 files changed, 11 insertions(+), 34 deletions(-) rename packages/dataviews/src/components/{dataform-field-visibility => form-field-visibility}/index.tsx (54%) diff --git a/packages/dataviews/src/components/dataform/stories/index.story.tsx b/packages/dataviews/src/components/dataform/stories/index.story.tsx index 6aa4e386c72374..c3556db3107a47 100644 --- a/packages/dataviews/src/components/dataform/stories/index.story.tsx +++ b/packages/dataviews/src/components/dataform/stories/index.story.tsx @@ -37,13 +37,6 @@ const meta = { description: 'Chooses the type of the sample field.', options: [ 'text', 'integer', 'datetime' ], }, - additionalSampleFieldDependency: { - name: 'Additional Sample Field Dependency', - control: { type: 'select' }, - description: - 'Choose an additional dependency of the sample field for visiblity.', - options: [ 'order', 'author', 'status' ], - }, }, args: { sampleFieldType: 'text', @@ -113,24 +106,17 @@ const fields = [ isVisible: ( item: SamplePost ) => { return item.status !== 'private'; }, - dependencies: [ 'status' ], }, ] as Field< SamplePost >[]; export const Default = ( { type, sampleFieldType = 'text', - additionalSampleFieldDependency, }: { type: 'panel' | 'regular'; sampleFieldType: 'text' | 'integer' | 'datetime'; - additionalSampleFieldDependency?: keyof SamplePost; } ) => { const visibileFields = useMemo( () => { - const dependencies = [ 'sampleField' ]; - if ( additionalSampleFieldDependency ) { - dependencies.push( additionalSampleFieldDependency ); - } return [ ...fields, { @@ -140,10 +126,9 @@ export const Default = ( { isVisible: ( item: SamplePost ) => { return item.order < 3 && item.sampleField !== 'hide'; }, - dependencies, }, ] as Field< SamplePost >[]; - }, [ sampleFieldType, additionalSampleFieldDependency ] ); + }, [ sampleFieldType ] ); const [ post, setPost ] = useState( { title: 'Hello, World!', order: 2, diff --git a/packages/dataviews/src/components/dataform-field-visibility/index.tsx b/packages/dataviews/src/components/form-field-visibility/index.tsx similarity index 54% rename from packages/dataviews/src/components/dataform-field-visibility/index.tsx rename to packages/dataviews/src/components/form-field-visibility/index.tsx index 965e874ac56886..8cea59f11b7aea 100644 --- a/packages/dataviews/src/components/dataform-field-visibility/index.tsx +++ b/packages/dataviews/src/components/form-field-visibility/index.tsx @@ -8,25 +8,22 @@ import { useMemo } from '@wordpress/element'; */ import type { NormalizedField } from '../../types'; -type DataFormFieldVisibilityProps< Item > = React.PropsWithChildren< { +type FormFieldVisibilityProps< Item > = React.PropsWithChildren< { field: NormalizedField< Item >; data: Item; } >; -export default function DataFormFieldVisibility< Item >( { +export default function FormFieldVisibility< Item >( { data, field, children, -}: DataFormFieldVisibilityProps< Item > ) { - const dependencies = field.dependencies - ? field.dependencies.map( ( dep ) => data[ dep ] ) - : [ field?.getValue( { item: data } ) ]; +}: FormFieldVisibilityProps< Item > ) { const isVisible = useMemo( () => { if ( field.isVisible ) { return field.isVisible( data ); } return true; - }, [ field.isVisible, ...dependencies ] ); + }, [ field.isVisible, data ] ); if ( ! isVisible ) { return null; diff --git a/packages/dataviews/src/dataforms-layouts/panel/index.tsx b/packages/dataviews/src/dataforms-layouts/panel/index.tsx index b3e863509153f2..b74e5e4667d4b1 100644 --- a/packages/dataviews/src/dataforms-layouts/panel/index.tsx +++ b/packages/dataviews/src/dataforms-layouts/panel/index.tsx @@ -19,7 +19,7 @@ import { closeSmall } from '@wordpress/icons'; import { normalizeFields } from '../../normalize-fields'; import { getVisibleFields } from '../get-visible-fields'; import type { DataFormProps, NormalizedField } from '../../types'; -import DataFormFieldVisibility from '../../components/dataform-field-visibility'; +import FormFieldVisibility from '../../components/form-field-visibility'; interface FormFieldProps< Item > { data: Item; @@ -157,7 +157,7 @@ export default function FormPanel< Item >( { { visibleFields.map( ( field ) => { return ( - ( { field={ field } onChange={ onChange } /> - + ); } ) } diff --git a/packages/dataviews/src/dataforms-layouts/regular/index.tsx b/packages/dataviews/src/dataforms-layouts/regular/index.tsx index f5b7157a47d467..6a340a50584df4 100644 --- a/packages/dataviews/src/dataforms-layouts/regular/index.tsx +++ b/packages/dataviews/src/dataforms-layouts/regular/index.tsx @@ -10,7 +10,7 @@ import { useMemo } from '@wordpress/element'; import { normalizeFields } from '../../normalize-fields'; import { getVisibleFields } from '../get-visible-fields'; import type { DataFormProps } from '../../types'; -import DataFormFieldVisibility from '../../components/dataform-field-visibility'; +import FormFieldVisibility from '../../components/form-field-visibility'; export default function FormRegular< Item >( { data, @@ -34,7 +34,7 @@ export default function FormRegular< Item >( { { visibleFields.map( ( field ) => { return ( - ( { field={ field } onChange={ onChange } /> - + ); } ) } diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index cb7585b0c20cc8..0ea0965704d18c 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -128,11 +128,6 @@ export type Field< Item > = { */ isVisible?: ( item: Item ) => boolean; - /** - * Dependency list for triggering isVisible. - */ - dependencies?: Array< keyof Item >; - /** * Whether the field is sortable. */ From 480309415a7c997f70086fe5d2a323832f5d0eea Mon Sep 17 00:00:00 2001 From: Lourens Schep Date: Mon, 28 Oct 2024 15:26:45 +0000 Subject: [PATCH 5/6] Intergrated visibility component with combined edit component --- .../components/dataform-combined-edit/index.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/dataviews/src/components/dataform-combined-edit/index.tsx b/packages/dataviews/src/components/dataform-combined-edit/index.tsx index 6b2a752fa8de52..90a92ac861bdd1 100644 --- a/packages/dataviews/src/components/dataform-combined-edit/index.tsx +++ b/packages/dataviews/src/components/dataform-combined-edit/index.tsx @@ -12,6 +12,7 @@ import { * Internal dependencies */ import type { DataFormCombinedEditProps, NormalizedField } from '../../types'; +import FormFieldVisibility from '../form-field-visibility'; function Header( { title }: { title: string } ) { return ( @@ -41,13 +42,15 @@ function DataFormCombinedEdit< Item >( { ); const children = visibleChildren.map( ( child ) => { return ( -
- -
+ +
+ +
+
); } ); From 7f0fe61e2abbb3a9ca1549d628cc0ca5bc5e084a Mon Sep 17 00:00:00 2001 From: Lourens Schep Date: Mon, 28 Oct 2024 15:35:04 +0000 Subject: [PATCH 6/6] Remove sample field example --- .../dataform/stories/index.story.tsx | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/packages/dataviews/src/components/dataform/stories/index.story.tsx b/packages/dataviews/src/components/dataform/stories/index.story.tsx index c3556db3107a47..b59d79063200bf 100644 --- a/packages/dataviews/src/components/dataform/stories/index.story.tsx +++ b/packages/dataviews/src/components/dataform/stories/index.story.tsx @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useMemo, useState } from '@wordpress/element'; +import { useState } from '@wordpress/element'; /** * Internal dependencies @@ -17,7 +17,6 @@ type SamplePost = { reviewer: string; date: string; birthdate: string; - sampleField?: string; password?: string; }; @@ -31,15 +30,6 @@ const meta = { 'Chooses the layout of the form. "regular" is the default layout.', options: [ 'regular', 'panel' ], }, - sampleFieldType: { - name: 'Sample Field Type', - control: { type: 'select' }, - description: 'Chooses the type of the sample field.', - options: [ 'text', 'integer', 'datetime' ], - }, - }, - args: { - sampleFieldType: 'text', }, }; export default meta; @@ -109,26 +99,7 @@ const fields = [ }, ] as Field< SamplePost >[]; -export const Default = ( { - type, - sampleFieldType = 'text', -}: { - type: 'panel' | 'regular'; - sampleFieldType: 'text' | 'integer' | 'datetime'; -} ) => { - const visibileFields = useMemo( () => { - return [ - ...fields, - { - id: 'sampleField', - label: 'Sample Field', - type: sampleFieldType, - isVisible: ( item: SamplePost ) => { - return item.order < 3 && item.sampleField !== 'hide'; - }, - }, - ] as Field< SamplePost >[]; - }, [ sampleFieldType ] ); +export const Default = ( { type }: { type: 'panel' | 'regular' } ) => { const [ post, setPost ] = useState( { title: 'Hello, World!', order: 2, @@ -142,7 +113,6 @@ export const Default = ( { const form = { fields: [ 'title', - 'sampleField', 'order', 'author', 'reviewer', @@ -156,7 +126,7 @@ export const Default = ( { return ( data={ post } - fields={ visibileFields } + fields={ fields } form={ { ...form, type,