Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataForm: enable fields to declare a different layout #66531

Merged
merged 34 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2f49a88
Add DataFormProvider for fields
louwie17 Oct 4, 2024
7fc515a
Add dataform layout component and inline layout
louwie17 Oct 28, 2024
2190773
Fix label in panel view
louwie17 Oct 28, 2024
35fa64c
Remove unneeded line
louwie17 Oct 28, 2024
c848178
Update `field` to FormField as well
louwie17 Oct 28, 2024
7824f36
Remove combinedFields usage
louwie17 Oct 31, 2024
01da3c5
Remove old use of View
louwie17 Oct 31, 2024
6eae567
Add label and move field type check to 'getFieldDefinition'
louwie17 Oct 31, 2024
d22d764
Create types of each view
louwie17 Oct 31, 2024
9235f5e
Add sticky example
louwie17 Oct 31, 2024
d017417
Update combined fields story
louwie17 Oct 31, 2024
ecf42e8
Fix change I missed during rebase
louwie17 Oct 31, 2024
7cf260b
Remove old status_and_visibility field
louwie17 Nov 4, 2024
3ec2fd1
Rename fields to children for clarity
louwie17 Nov 4, 2024
8b96c7e
Add children support to regular layout
louwie17 Nov 4, 2024
b30b780
Replace inline with labelPosition
louwie17 Nov 5, 2024
f333902
Remove field type checking within dataform layouts
louwie17 Nov 5, 2024
40963fe
Update DataForm context to align more with DataViews context
louwie17 Nov 6, 2024
6c0a927
Add seperated combined form field type
louwie17 Nov 6, 2024
1b76afa
Simplify: use always id
oandregal Nov 15, 2024
bce9399
Use the new API for configuring feature image
oandregal Nov 15, 2024
ad94776
Remove unnecessary layout for field
oandregal Nov 15, 2024
2b71c33
Feature image: default label position
oandregal Nov 15, 2024
b52ef79
Implement labelPosition none for panel layout
oandregal Nov 18, 2024
53c84b4
Implement labelPosition none for regular layout
oandregal Nov 18, 2024
0a4be12
Panel layout: improve button spacing when labelPosition is none or top
oandregal Nov 18, 2024
0f6399b
Panel layout: do not style the label as a base control.
oandregal Nov 18, 2024
7c1004f
Style for layout regular label
oandregal Nov 19, 2024
2b27db1
Panel: better spacing
oandregal Nov 19, 2024
b201728
Destructure all props
oandregal Nov 19, 2024
695b629
DataFormLayout: props are data, form, onChange, children
oandregal Nov 19, 2024
fa872ee
Extract FieldLayoutProps as a common interface for all layouts
oandregal Nov 19, 2024
3f709f9
Introduce normalizeFormFields & form.labelPosition
oandregal Nov 19, 2024
a813725
Storybook: remove toFormField
oandregal Nov 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
/**
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a DataForm context to store the field definitions. This way I can more easily manage the layout on a field level without having to make sure I drill down the field definitions.

* 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(
oandregal marked this conversation as resolved.
Show resolved Hide resolved
() => 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 } ) } )
}
/>
);
},
},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added sticky example, which flows nicer for the inline example.

] 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
Loading