Skip to content

Commit

Permalink
DataForm: enable fields to declare a different layout (#66531)
Browse files Browse the repository at this point in the history
Co-authored-by: louwie17 <[email protected]>
Co-authored-by: oandregal <[email protected]>
Co-authored-by: gigitux <[email protected]>
Co-authored-by: youknowriad <[email protected]>
  • Loading branch information
5 people authored Nov 20, 2024
1 parent 944e6b8 commit c38610a
Show file tree
Hide file tree
Showing 18 changed files with 645 additions and 379 deletions.
69 changes: 0 additions & 69 deletions packages/dataviews/src/components/dataform-combined-edit/index.tsx

This file was deleted.

This file was deleted.

30 changes: 30 additions & 0 deletions packages/dataviews/src/components/dataform-context/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* WordPress dependencies
*/
import { createContext } from '@wordpress/element';

/**
* Internal dependencies
*/
import type { NormalizedField } from '../../types';

type DataFormContextType< Item > = {
fields: NormalizedField< Item >[];
};

const DataFormContext = createContext< DataFormContextType< any > >( {
fields: [],
} );

export function DataFormProvider< Item >( {
fields,
children,
}: React.PropsWithChildren< { fields: NormalizedField< Item >[] } > ) {
return (
<DataFormContext.Provider value={ { fields } }>
{ children }
</DataFormContext.Provider>
);
}

export default DataFormContext;
27 changes: 22 additions & 5 deletions packages/dataviews/src/components/dataform/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';

/**
* Internal dependencies
*/
import type { DataFormProps } from '../../types';
import { getFormLayout } from '../../dataforms-layouts';
import { DataFormProvider } from '../dataform-context';
import { normalizeFields } from '../../normalize-fields';
import { DataFormLayout } from '../../dataforms-layouts/data-form-layout';

export default function DataForm< Item >( {
data,
form,
...props
fields,
onChange,
}: DataFormProps< Item > ) {
const layout = getFormLayout( form.type ?? 'regular' );
if ( ! layout ) {
const normalizedFields = useMemo(
() => normalizeFields( fields ),
[ fields ]
);

if ( ! form.fields ) {
return null;
}

return <layout.component form={ form } { ...props } />;
return (
<DataFormProvider fields={ normalizedFields }>
<DataFormLayout data={ data } form={ form } onChange={ onChange } />
</DataFormProvider>
);
}
137 changes: 88 additions & 49 deletions packages/dataviews/src/components/dataform/stories/index.story.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
import { useMemo, useState } from '@wordpress/element';
import { ToggleControl } from '@wordpress/components';

/**
* Internal dependencies
*/
import DataForm from '../index';
import type { CombinedFormField, Field } from '../../../types';
import type { Field, Form } from '../../../types';

type SamplePost = {
title: string;
Expand All @@ -27,8 +28,13 @@ const meta = {
type: {
control: { type: 'select' },
description:
'Chooses the layout of the form. "regular" is the default layout.',
options: [ 'regular', 'panel' ],
'Chooses the default layout of each field. "regular" is the default layout.',
options: [ 'default', 'regular', 'panel' ],
},
labelPosition: {
control: { type: 'select' },
description: 'Chooses the label position of the layout.',
options: [ 'default', 'top', 'side', 'none' ],
},
},
};
Expand Down Expand Up @@ -97,9 +103,33 @@ const fields = [
return item.status !== 'private';
},
},
{
id: 'sticky',
label: 'Sticky',
type: 'integer',
Edit: ( { field, onChange, data, hideLabelFromVision } ) => {
const { id, getValue } = field;
return (
<ToggleControl
__nextHasNoMarginBottom
label={ hideLabelFromVision ? '' : field.label }
checked={ getValue( { item: data } ) }
onChange={ () =>
onChange( { [ id ]: ! getValue( { item: data } ) } )
}
/>
);
},
},
] as Field< SamplePost >[];

export const Default = ( { type }: { type: 'panel' | 'regular' } ) => {
export const Default = ( {
type,
labelPosition,
}: {
type: 'default' | 'regular' | 'panel';
labelPosition: 'default' | 'top' | 'side' | 'none';
} ) => {
const [ post, setPost ] = useState( {
title: 'Hello, World!',
order: 2,
Expand All @@ -108,29 +138,36 @@ export const Default = ( { type }: { type: 'panel' | 'regular' } ) => {
reviewer: 'fulano',
date: '2021-01-01T12:00:00',
birthdate: '1950-02-23T12:00:00',
sticky: false,
} );

const form = {
fields: [
'title',
'order',
'author',
'reviewer',
'status',
'password',
'date',
'birthdate',
],
};
const form = useMemo(
() => ( {
type,
labelPosition,
fields: [
'title',
'order',
{
id: 'sticky',
layout: 'regular',
labelPosition: 'side',
},
'author',
'reviewer',
'password',
'date',
'birthdate',
],
} ),
[ type, labelPosition ]
) as Form;

return (
<DataForm< SamplePost >
data={ post }
fields={ fields }
form={ {
...form,
type,
} }
form={ form }
onChange={ ( edits ) =>
setPost( ( prev ) => ( {
...prev,
Expand All @@ -142,40 +179,45 @@ export const Default = ( { type }: { type: 'panel' | 'regular' } ) => {
};

const CombinedFieldsComponent = ( {
type = 'regular',
combinedFieldDirection = 'vertical',
type,
labelPosition,
}: {
type: 'panel' | 'regular';
combinedFieldDirection: 'vertical' | 'horizontal';
type: 'default' | 'regular' | 'panel';
labelPosition: 'default' | 'top' | 'side' | 'none';
} ) => {
const [ post, setPost ] = useState( {
const [ post, setPost ] = useState< SamplePost >( {
title: 'Hello, World!',
order: 2,
author: 1,
status: 'draft',
reviewer: 'fulano',
date: '2021-01-01T12:00:00',
birthdate: '1950-02-23T12:00:00',
} );

const form = {
fields: [ 'title', 'status_and_visibility', 'order', 'author' ],
combinedFields: [
{
id: 'status_and_visibility',
label: 'Status & Visibility',
children: [ 'status', 'password' ],
direction: combinedFieldDirection,
render: ( { item } ) => item.status,
},
] as CombinedFormField< any >[],
};
const form = useMemo(
() => ( {
type,
labelPosition,
fields: [
'title',
{
id: 'status',
label: 'Status & Visibility',
children: [ 'status', 'password' ],
},
'order',
'author',
],
} ),
[ type, labelPosition ]
) as Form;

return (
<DataForm
<DataForm< SamplePost >
data={ post }
fields={ fields }
form={ {
...form,
type,
} }
form={ form }
onChange={ ( edits ) =>
setPost( ( prev ) => ( {
...prev,
Expand All @@ -191,11 +233,8 @@ export const CombinedFields = {
render: CombinedFieldsComponent,
argTypes: {
...meta.argTypes,
combinedFieldDirection: {
control: { type: 'select' },
description:
'Chooses the direction of the combined field. "vertical" is the default layout.',
options: [ 'vertical', 'horizontal' ],
},
},
args: {
type: 'panel',
},
};
Loading

1 comment on commit c38610a

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in c38610a.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/11936764631
📝 Reported issues:

Please sign in to comment.