[Experimental] Handle adding attributes during fields registration (#43379)

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Thomas Roberts 2024-01-15 14:59:36 -08:00 committed by GitHub
parent f7e8b676d6
commit 23db3eff69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 21 deletions

View File

@ -113,6 +113,20 @@ const Form = < T extends AddressFormValues | ContactFormValues >( {
if ( field.hidden ) {
return null;
}
const fieldProps = {
id: `${ id }-${ field.key }`,
errorId: `${ addressType }_${ field.key }`,
label: field.required ? field.label : field.optionalLabel,
// These may come from core locale settings or the attributes option on custom fields.
autoCapitalize: field.autocapitalize,
autoComplete: field.autocomplete,
errorMessage: field.errorMessage,
required: field.required,
className: `wc-block-components-address-form__${ field.key }`,
...field.attributes,
};
if ( field.type === 'checkbox' ) {
return (
<CheckboxControl
@ -126,19 +140,10 @@ const Form = < T extends AddressFormValues | ContactFormValues >( {
[ field.key ]: checked,
} );
} }
{ ...fieldProps }
/>
);
}
const fieldProps = {
id: `${ id }-${ field.key }`,
errorId: `${ addressType }_${ field.key }`,
label: field.required ? field.label : field.optionalLabel,
autoCapitalize: field.autocapitalize,
autoComplete: field.autocomplete,
errorMessage: field.errorMessage,
required: field.required,
className: `wc-block-components-address-form__${ field.key }`,
};
if (
field.key === 'country' &&

View File

@ -2,12 +2,25 @@
* External dependencies
*/
import { ComboboxControlOption } from '@woocommerce/base-components/combobox';
import type { AllHTMLAttributes, AriaAttributes } from 'react';
/**
* Internal dependencies
*/
import { getSetting } from './utils';
// A list of attributes that can be added to a custom field when registering it.
type CustomFieldAttributes = Pick<
AllHTMLAttributes< HTMLInputElement >,
| 'maxLength'
| 'readOnly'
| 'pattern'
| 'title'
| 'autoCapitalize'
| 'autoComplete'
> &
AriaAttributes;
export interface FormField {
// The label for the field.
label: string;
@ -27,6 +40,8 @@ export interface FormField {
type?: string;
// The options if this is a select field
options?: ComboboxControlOption[];
// Additional attributes added when registering a field. String in key is required for data attributes.
attributes?: Record< keyof CustomFieldAttributes, string >;
}
export interface LocaleSpecificFormField extends Partial< FormField > {

View File

@ -17,7 +17,7 @@ export type CheckboxControlProps = {
children?: React.ReactChildren;
hasError?: boolean;
checked?: boolean;
disabled?: boolean;
disabled?: string | boolean | undefined;
};
/**
@ -33,7 +33,7 @@ export const CheckboxControl = ( {
checked = false,
disabled = false,
...rest
}: CheckboxControlProps ): JSX.Element => {
}: CheckboxControlProps & Record< string, unknown > ): JSX.Element => {
const instanceId = useInstanceId( CheckboxControl );
const checkboxId = id || `checkbox-control-${ instanceId }`;
@ -55,7 +55,7 @@ export const CheckboxControl = ( {
onChange={ ( event ) => onChange( event.target.checked ) }
aria-invalid={ hasError === true }
checked={ checked }
disabled={ disabled }
disabled={ !! disabled }
{ ...rest }
/>
<svg

View File

@ -0,0 +1,4 @@
Significance: patch
Type: add
Comment: Allow adding attributes when registering custom checkout fields in the Checkout block.

View File

@ -304,19 +304,18 @@ class CheckoutFields {
}
$field_data = array(
'label' => $options['label'],
'hidden' => false,
'type' => $type,
'optionalLabel' => empty( $options['optionalLabel'] ) ? sprintf(
/* translators: %s Field label. */
'label' => $options['label'],
'hidden' => false,
'type' => $type,
'optionalLabel' => empty( $options['optionalLabel'] ) ? sprintf(
/* translators: %s Field label. */
__( '%s (optional)', 'woocommerce' ),
$options['label']
) : $options['optionalLabel'],
'required' => empty( $options['required'] ) ? false : $options['required'],
'autocomplete' => empty( $options['autocomplete'] ) ? '' : $options['autocomplete'],
'autocapitalize' => empty( $options['autocapitalize'] ) ? '' : $options['autocapitalize'],
'required' => empty( $options['required'] ) ? false : $options['required'],
);
$field_data['attributes'] = $this->register_field_attributes( $id, $options['attributes'] ?? [] );
/**
* Handle Checkbox fields.
*/
@ -383,6 +382,64 @@ class CheckoutFields {
$this->fields_locations[ $location ][] = $id;
}
/**
* Processes the attributes supplied during field registration.
*
* @param array $id The field ID.
* @param array $attributes The attributes supplied during field registration.
*
* @return array The processed attributes.
*/
private function register_field_attributes( $id, $attributes ) {
// We check if attributes are valid. This is done to prevent too much nesting and also to allow field registration
// even if the attributes property is invalid. We can just skip it and register the field without attributes.
$has_attributes = false;
if ( empty( $attributes ) ) {
return [];
}
if ( ! is_array( $attributes ) || 0 === count( $attributes ) ) {
$message = sprintf( 'An invalid attributes value was supplied when registering field with id: "%s". %s', $id, 'Attributes must be a non-empty array.' );
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
return [];
}
// These are formatted in camelCase because React components expect them that way.
$allowed_attributes = array(
'maxLength',
'readOnly',
'pattern',
'autocomplete',
'autocapitalize',
'title',
);
$valid_attributes = array_filter(
$attributes,
function( $_, $key ) use ( $allowed_attributes ) {
return in_array( $key, $allowed_attributes, true ) || strpos( $key, 'aria-' ) === 0 || strpos( $key, 'data-' ) === 0;
},
ARRAY_FILTER_USE_BOTH
);
// Any invalid attributes should show a doing_it_wrong warning. It shouldn't stop field registration, though.
if ( count( $attributes ) !== count( $valid_attributes ) ) {
$invalid_attributes = array_keys( array_diff_key( $attributes, $valid_attributes ) );
$message = sprintf( 'Invalid attribute found when registering field with id: "%s". Attributes: %s are not allowed.', $id, implode( ', ', $invalid_attributes ) );
_doing_it_wrong( 'woocommerce_blocks_register_checkout_field', esc_html( $message ), '8.6.0' );
}
// Escape attributes to remove any malicious code and return them.
return array_map(
function( $value ) {
return esc_attr( $value );
},
$valid_attributes
);
}
/**
* Returns an array of all core fields.
*