Skip to content
1 change: 1 addition & 0 deletions packages/dataviews/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Documentation: surface better the `type` property in the documentation. [#73349](https://github.com/WordPress/gutenberg/pull/73349)
- Documentation: improve DataView's `layout` prop. [#73470](https://github.com/WordPress/gutenberg/pull/73470)
- DataForm Panel Layout: Focus the first input element when the panel opens. [#72322](https://github.com/WordPress/gutenberg/pull/72322)
- DataForm: Pattern validation is now supported on all fields that browsers support it in. [#73156](https://github.com/WordPress/gutenberg/pull/73156)

### Bug fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default function getCustomValidity< Item >(
customValidity = validity?.required?.message
? validity.required
: undefined;
} else if ( isValid?.pattern && validity?.pattern ) {
customValidity = validity.pattern;
} else if ( isValid?.elements && validity?.elements ) {
customValidity = validity.elements;
} else if ( validity?.custom ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export default function ValidatedText< Item >( {
type={ type }
prefix={ prefix }
suffix={ suffix }
pattern={ isValid?.pattern }
__next40pxDefaultSize
/>
);
Expand Down
36 changes: 36 additions & 0 deletions packages/dataviews/src/hooks/use-form-validity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,42 @@ function validateFormField< Item >(
};
}

// Validate the field: isValid.pattern
if (
!! formField.field &&
formField.field.isValid.pattern &&
( formField.field.type === 'text' ||
formField.field.type === 'email' ||
formField.field.type === 'url' ||
formField.field.type === 'telephone' ||
formField.field.type === 'password' )
) {
const value = formField.field.getValue( { item } );
// Only validate pattern if the value is not empty
if ( ! isEmptyNullOrUndefined( value ) ) {
try {
const regex = new RegExp( formField.field.isValid.pattern );
if ( ! regex.test( String( value ) ) ) {
return {
pattern: {
type: 'invalid',
message: __(
'Value does not match the required pattern.'
),
},
};
}
} catch ( error ) {
return {
pattern: {
type: 'invalid',
message: __( 'Invalid pattern configuration.' ),
},
};
}
}
}

// Validate the field: isValid.elements (static)
if (
!! formField.field &&
Expand Down
38 changes: 38 additions & 0 deletions packages/dataviews/src/stories/dataform.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -553,10 +553,12 @@ const ValidationComponent = ( {
required,
elements,
custom,
pattern,
}: {
required: boolean;
elements: 'sync' | 'async' | 'none';
custom: 'sync' | 'async' | 'none';
pattern: boolean;
} ) => {
type ValidatedItem = {
text: string;
Expand Down Expand Up @@ -912,10 +914,15 @@ const ValidationComponent = ( {
id: 'text',
type: 'text',
label: 'Text',
placeholder: pattern ? 'user_name123' : undefined,
description: pattern
? 'Must contain only letters, numbers, and underscores'
: undefined,
isValid: {
required,
elements: elements !== 'none' ? true : false,
custom: maybeCustomRule( customTextRule ),
pattern: pattern ? '^[a-zA-Z0-9_]+$' : undefined,
},
},
{
Expand Down Expand Up @@ -974,30 +981,51 @@ const ValidationComponent = ( {
id: 'email',
type: 'email',
label: 'e-mail',
placeholder: pattern ? 'user@company.com' : undefined,
description: pattern
? 'Email must be from @company.com domain'
: undefined,
isValid: {
required,
elements: elements !== 'none' ? true : false,
custom: maybeCustomRule( customEmailRule ),
pattern: pattern ? '^[a-zA-Z0-9]+@company.com$' : undefined,
},
},
{
id: 'telephone',
type: 'telephone',
label: 'telephone',
placeholder: pattern ? '+1-555-123-4567' : undefined,
description: pattern
? 'US phone format with country code'
: undefined,
isValid: {
required,
elements: elements !== 'none' ? true : false,
custom: maybeCustomRule( customTelephoneRule ),
pattern: pattern
? '^\\+1-\\d{3}-\\d{3}-\\d{4}$'
: undefined,
},
},
{
id: 'url',
type: 'url',
label: 'URL',
placeholder: pattern
? 'https://github.com/user/repo'
: undefined,
description: pattern
? 'Must be a GitHub repository URL'
: undefined,
isValid: {
required,
elements: elements !== 'none' ? true : false,
custom: maybeCustomRule( customUrlRule ),
pattern: pattern
? '^https:\\/\\/github\\.com\\/.*'
: undefined,
},
},
{
Expand Down Expand Up @@ -1080,10 +1108,14 @@ const ValidationComponent = ( {
id: 'password',
type: 'password',
label: 'Password',
description: pattern
? 'Must have 8 numbers or letters'
: undefined,
isValid: {
required,
elements: elements !== 'none' ? true : false,
custom: maybeCustomRule( customPasswordRule ),
pattern: pattern ? '^[0-9a-zA-Z]{8}$' : undefined,
},
},
{
Expand Down Expand Up @@ -2084,11 +2116,17 @@ export const Validation = {
description: 'Whether or not the custom validation rule is active.',
options: [ 'sync', 'async', 'none' ],
},
pattern: {
control: { type: 'boolean' },
description:
'Whether or not the pattern validation rule is active.',
},
},
args: {
required: true,
elements: 'sync',
custom: 'sync',
pattern: false,
},
};

Expand Down
Loading
Loading