Skip to content

Commit

Permalink
DataForm: enable fields to declare a different layout (WordPress#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

0 comments on commit c38610a

Please sign in to comment.