/**
* WordPress dependencies
*/
import { useMemo, useState, useRef, useEffect } from '@wordpress/element';
import { Stack } from '@wordpress/ui';
/**
* Internal dependencies
*/
import type { Meta, StoryObj } from '@storybook/react-vite';
import DataForm from '../index';
import useFormValidity from '../../hooks/use-form-validity';
import type { Field, Form } from '../../types';
const meta: Meta< typeof DataForm > = {
title: 'DataViews/DataForm/Content',
component: DataForm,
parameters: {
controls: { disable: true },
},
tags: [ '!dev' /* Hide individual story pages from sidebar */ ],
};
export default meta;
type Story = StoryObj< typeof DataForm >;
type SampleData = {
name: string;
email: string;
phone: string;
};
export const Labels: Story = {
render: () => {
const [ data, setData ] = useState< SampleData >( {
name: '',
email: '',
phone: '',
} );
const fields: Field< SampleData >[] = useMemo(
() => [
{
id: 'name',
label: 'Name',
type: 'text',
},
{
id: 'email',
label: 'Email',
type: 'email',
},
{
id: 'phone',
label: 'Phone number',
type: 'telephone',
},
],
[]
);
const form: Form = useMemo(
() => ( {
layout: { type: 'regular' },
fields: [ 'name', 'email', 'phone' ],
} ),
[]
);
return (
data={ data }
fields={ fields }
form={ form }
onChange={ ( edits ) =>
setData( ( prev ) => ( { ...prev, ...edits } ) )
}
/>
);
},
};
type HelpTextData = {
name: string;
email: string;
phone: string;
};
export const HelpText: Story = {
render: () => {
const [ data, setData ] = useState< HelpTextData >( {
name: '',
email: '',
phone: '',
} );
const fields: Field< HelpTextData >[] = useMemo(
() => [
{
id: 'name',
label: 'Name',
type: 'text',
placeholder: 'Jane Doe',
description:
'Enter your full legal name as it appears on official documents.',
},
{
id: 'email',
label: 'Email',
type: 'email',
placeholder: 'you@example.com',
description:
'We will use this to send you important account notifications and updates.',
},
{
id: 'phone',
label: 'Phone number',
type: 'telephone',
placeholder: '+1 (555) 123-4567',
description:
'Include your country code. This number will be used for account verification.',
},
],
[]
);
const form: Form = useMemo(
() => ( {
layout: { type: 'regular' },
fields: [ 'name', 'email', 'phone' ],
} ),
[]
);
return (
data={ data }
fields={ fields }
form={ form }
onChange={ ( edits ) =>
setData( ( prev ) => ( { ...prev, ...edits } ) )
}
/>
);
},
};
type ValidationMessagesData = {
name: string;
email: string;
phone: string;
};
export const ValidationMessages: Story = {
render: () => {
const [ data, setData ] = useState< ValidationMessagesData >( {
name: '',
email: 'invalid-email',
phone: '123',
} );
const fields: Field< ValidationMessagesData >[] = useMemo(
() => [
{
id: 'name',
label: 'Name',
type: 'text',
placeholder: 'Jane Doe',
isValid: {
required: true,
},
},
{
id: 'email',
label: 'Email',
type: 'email',
placeholder: 'you@example.com',
isValid: {
required: true,
custom: ( item ) => {
if ( ! item.email ) {
return null;
}
if ( ! item.email.includes( '@' ) ) {
return 'Please enter a valid email address.';
}
return null;
},
},
},
{
id: 'phone',
label: 'Phone number',
type: 'telephone',
placeholder: '+1 (555) 123-4567',
isValid: {
required: true,
custom: ( item ) => {
if ( ! item.phone ) {
return null;
}
if ( item.phone.length < 10 ) {
return 'Phone number must be at least 10 digits long.';
}
return null;
},
},
},
],
[]
);
const form: Form = useMemo(
() => ( {
layout: { type: 'regular' },
fields: [ 'name', 'email', 'phone' ],
} ),
[]
);
const { validity } = useFormValidity( data, fields, form );
const containerRef = useRef< HTMLDivElement >( null );
// Show validation messages on load without focusing
useEffect( () => {
if ( validity && containerRef.current ) {
const inputs = containerRef.current.querySelectorAll( 'input' );
inputs.forEach( ( input ) => {
// Dispatch 'invalid' event to trigger the validation message display
input.dispatchEvent(
new Event( 'invalid', { bubbles: false } )
);
} );
}
}, [ validity ] );
return (
data={ data }
fields={ fields }
form={ form }
validity={ validity }
onChange={ ( edits ) =>
setData( ( prev ) => ( { ...prev, ...edits } ) )
}
/>
);
},
};
type HighLevelHelpTextData = {
name: string;
email: string;
phone: string;
};
export const HighLevelHelpText: Story = {
render: () => {
const [ data, setData ] = useState< HighLevelHelpTextData >( {
name: '',
email: '',
phone: '',
} );
const fields: Field< HighLevelHelpTextData >[] = useMemo(
() => [
{
id: 'name',
label: 'Name',
type: 'text',
},
{
id: 'email',
label: 'Email',
type: 'email',
},
{
id: 'phone',
label: 'Phone number',
type: 'telephone',
},
],
[]
);
const form: Form = useMemo(
() => ( {
layout: { type: 'regular' },
fields: [
{
id: 'accountForm',
label: 'Account Information',
description:
'We collect this information to create your account and provide personalized services. Your data will be kept secure and used only for account management and service improvements.',
children: [ 'name', 'email', 'phone' ],
layout: {
isCollapsible: false,
summary: 'account-form',
type: 'card',
withHeader: true,
},
},
],
} ),
[]
);
return (
data={ data }
fields={ fields }
form={ form }
onChange={ ( edits ) =>
setData( ( prev ) => ( { ...prev, ...edits } ) )
}
/>
);
},
};
type PlaceholdersData = {
name: string;
email: string;
phone: string;
};
export const Placeholders: Story = {
render: () => {
const [ data, setData ] = useState< PlaceholdersData >( {
name: '',
email: '',
phone: '',
} );
const fields: Field< PlaceholdersData >[] = useMemo(
() => [
{
id: 'name',
label: 'Name',
type: 'text',
placeholder: 'Jane Doe',
},
{
id: 'email',
label: 'Email',
type: 'email',
placeholder: 'you@example.com',
},
{
id: 'phone',
label: 'Phone number',
type: 'telephone',
placeholder: '+1 (555) 123-4567',
},
],
[]
);
const form: Form = useMemo(
() => ( {
layout: { type: 'regular' },
fields: [ 'name', 'email', 'phone' ],
} ),
[]
);
return (
data={ data }
fields={ fields }
form={ form }
onChange={ ( edits ) =>
setData( ( prev ) => ( { ...prev, ...edits } ) )
}
/>
);
},
};