Remove the wc combobox component, it is no longer used (#50975)
This commit is contained in:
parent
a0cb19b550
commit
115d4f16c9
|
@ -1,162 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
import { useEffect, useId, useRef } from '@wordpress/element';
|
|
||||||
import { ComboboxControl } from 'wordpress-components';
|
|
||||||
import { ValidationInputError } from '@woocommerce/blocks-components';
|
|
||||||
import { isObject } from '@woocommerce/types';
|
|
||||||
import { useDispatch, useSelect } from '@wordpress/data';
|
|
||||||
import { VALIDATION_STORE_KEY } from '@woocommerce/block-data';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
export interface ComboboxControlOption {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ComboboxProps {
|
|
||||||
autoComplete?: string | undefined;
|
|
||||||
className?: string;
|
|
||||||
errorId: string | null;
|
|
||||||
errorMessage?: string | undefined;
|
|
||||||
id: string;
|
|
||||||
instanceId?: string;
|
|
||||||
label?: string | undefined;
|
|
||||||
onChange: ( filterValue: string ) => void;
|
|
||||||
options: ComboboxControlOption[];
|
|
||||||
required?: boolean | undefined;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for the WordPress ComboboxControl which supports validation.
|
|
||||||
*/
|
|
||||||
const Combobox = ( {
|
|
||||||
id,
|
|
||||||
className,
|
|
||||||
label,
|
|
||||||
onChange,
|
|
||||||
options,
|
|
||||||
value,
|
|
||||||
required = false,
|
|
||||||
errorId: incomingErrorId,
|
|
||||||
autoComplete = 'off',
|
|
||||||
errorMessage = __( 'Please select a valid option', 'woocommerce' ),
|
|
||||||
}: ComboboxProps ): JSX.Element => {
|
|
||||||
const controlRef = useRef< HTMLDivElement >( null );
|
|
||||||
const fallbackId = useId();
|
|
||||||
const controlId = id || 'control-' + fallbackId;
|
|
||||||
const errorId = incomingErrorId || controlId;
|
|
||||||
|
|
||||||
const { setValidationErrors, clearValidationError } =
|
|
||||||
useDispatch( VALIDATION_STORE_KEY );
|
|
||||||
|
|
||||||
const { error, validationErrorId } = useSelect( ( select ) => {
|
|
||||||
const store = select( VALIDATION_STORE_KEY );
|
|
||||||
return {
|
|
||||||
error: store.getValidationError( errorId ),
|
|
||||||
validationErrorId: store.getValidationErrorId( errorId ),
|
|
||||||
};
|
|
||||||
} );
|
|
||||||
|
|
||||||
useEffect( () => {
|
|
||||||
if ( ! required || value ) {
|
|
||||||
clearValidationError( errorId );
|
|
||||||
} else {
|
|
||||||
setValidationErrors( {
|
|
||||||
[ errorId ]: {
|
|
||||||
message: errorMessage,
|
|
||||||
hidden: true,
|
|
||||||
},
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
clearValidationError( errorId );
|
|
||||||
};
|
|
||||||
}, [
|
|
||||||
clearValidationError,
|
|
||||||
value,
|
|
||||||
errorId,
|
|
||||||
errorMessage,
|
|
||||||
required,
|
|
||||||
setValidationErrors,
|
|
||||||
] );
|
|
||||||
|
|
||||||
// @todo Remove patch for ComboboxControl once https://github.com/WordPress/gutenberg/pull/33928 is released
|
|
||||||
// Also see https://github.com/WordPress/gutenberg/pull/34090
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
id={ controlId }
|
|
||||||
className={ clsx( 'wc-block-components-combobox', className, {
|
|
||||||
'is-active': value,
|
|
||||||
'has-error': error?.message && ! error?.hidden,
|
|
||||||
} ) }
|
|
||||||
ref={ controlRef }
|
|
||||||
>
|
|
||||||
<ComboboxControl
|
|
||||||
className={ 'wc-block-components-combobox-control' }
|
|
||||||
label={ label }
|
|
||||||
onChange={ onChange }
|
|
||||||
onFilterValueChange={ ( filterValue: string ) => {
|
|
||||||
if ( filterValue.length ) {
|
|
||||||
// If we have a value and the combobox is not focussed, this could be from browser autofill.
|
|
||||||
const activeElement = isObject( controlRef.current )
|
|
||||||
? controlRef.current.ownerDocument.activeElement
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
if (
|
|
||||||
activeElement &&
|
|
||||||
isObject( controlRef.current ) &&
|
|
||||||
controlRef.current.contains( activeElement )
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to match.
|
|
||||||
const normalizedFilterValue =
|
|
||||||
filterValue.toLocaleUpperCase();
|
|
||||||
|
|
||||||
// Try to find an exact match first using values.
|
|
||||||
const foundValue = options.find(
|
|
||||||
( option ) =>
|
|
||||||
option.value.toLocaleUpperCase() ===
|
|
||||||
normalizedFilterValue
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( foundValue ) {
|
|
||||||
onChange( foundValue.value );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to a label match.
|
|
||||||
const foundOption = options.find( ( option ) =>
|
|
||||||
option.label
|
|
||||||
.toLocaleUpperCase()
|
|
||||||
.startsWith( normalizedFilterValue )
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( foundOption ) {
|
|
||||||
onChange( foundOption.value );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} }
|
|
||||||
options={ options }
|
|
||||||
value={ value || '' }
|
|
||||||
allowReset={ false }
|
|
||||||
autoComplete={ autoComplete }
|
|
||||||
// Note these aria properties are ignored by ComboboxControl. When we replace ComboboxControl we should support them.
|
|
||||||
aria-invalid={ error?.message && ! error?.hidden }
|
|
||||||
aria-errormessage={ validationErrorId }
|
|
||||||
/>
|
|
||||||
<ValidationInputError propertyName={ errorId } />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Combobox;
|
|
|
@ -1,188 +0,0 @@
|
||||||
// For when the Combobox is being used as a select custom field.
|
|
||||||
.wc-block-components-select-input {
|
|
||||||
position: relative;
|
|
||||||
margin-top: $gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wc-block-components-form .wc-block-components-combobox,
|
|
||||||
.wc-block-components-combobox {
|
|
||||||
.wc-block-components-combobox-control {
|
|
||||||
@include reset-typography();
|
|
||||||
@include reset-box();
|
|
||||||
|
|
||||||
// Fixes width in the editor.
|
|
||||||
.components-flex {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-base-control__field {
|
|
||||||
@include reset-box();
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.components-combobox-control__suggestions-container {
|
|
||||||
@include reset-typography();
|
|
||||||
@include reset-box();
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
input.components-combobox-control__input {
|
|
||||||
@include reset-typography();
|
|
||||||
@include font-size(regular);
|
|
||||||
padding: em($gap + $gap-smaller) em($gap-smaller) em($gap-smaller);
|
|
||||||
line-height: em($gap);
|
|
||||||
box-sizing: border-box;
|
|
||||||
outline: inherit;
|
|
||||||
border: 1px solid $input-border-gray;
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: none;
|
|
||||||
color: $input-text-active;
|
|
||||||
font-family: inherit;
|
|
||||||
font-weight: normal;
|
|
||||||
letter-spacing: inherit;
|
|
||||||
text-align: left;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
text-transform: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
width: 100%;
|
|
||||||
opacity: initial;
|
|
||||||
border-radius: $universal-border-radius;
|
|
||||||
height: 50px;
|
|
||||||
|
|
||||||
&[aria-expanded="true"],
|
|
||||||
&:focus {
|
|
||||||
background-color: #fff;
|
|
||||||
color: $input-text-active;
|
|
||||||
outline: 0;
|
|
||||||
box-shadow: 0 0 0 1px $input-border-gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[aria-expanded="true"] {
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.has-dark-controls & {
|
|
||||||
background-color: $input-background-dark;
|
|
||||||
border-color: $input-border-dark;
|
|
||||||
color: $input-text-dark;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background-color: $input-background-dark;
|
|
||||||
color: $input-text-dark;
|
|
||||||
box-shadow: 0 0 0 1px $input-border-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.components-form-token-field__suggestions-list {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
|
||||||
background-color: $select-dropdown-light;
|
|
||||||
border: 1px solid $input-border-gray;
|
|
||||||
border-top: 0;
|
|
||||||
border-bottom: 0;
|
|
||||||
margin: 3em 0 0 0;
|
|
||||||
padding: 0;
|
|
||||||
max-height: 300px;
|
|
||||||
min-width: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
color: currentColor;
|
|
||||||
border-bottom-left-radius: $universal-border-radius;
|
|
||||||
border-bottom-right-radius: $universal-border-radius;
|
|
||||||
box-shadow: 0 1px 0 1px $input-border-gray;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.has-dark-controls & {
|
|
||||||
background-color: $select-dropdown-dark;
|
|
||||||
color: $input-text-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-form-token-field__suggestion {
|
|
||||||
@include font-size(regular);
|
|
||||||
color: $gray-700;
|
|
||||||
cursor: default;
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: em($gap-smallest) $gap;
|
|
||||||
|
|
||||||
&.is-selected {
|
|
||||||
background-color: $gray-300;
|
|
||||||
.has-dark-controls & {
|
|
||||||
background-color: $select-item-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force empty rows to have a height.
|
|
||||||
&::after {
|
|
||||||
content: " ";
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&.is-highlighted,
|
|
||||||
&:active {
|
|
||||||
background-color: #00669e;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label.components-base-control__label {
|
|
||||||
@include reset-typography();
|
|
||||||
@include font-size(regular);
|
|
||||||
position: absolute;
|
|
||||||
transform: translateY(em($gap));
|
|
||||||
line-height: 1.25; // =20px when font-size is 16px.
|
|
||||||
left: em($gap-smaller);
|
|
||||||
top: -2px;
|
|
||||||
transform-origin: top left;
|
|
||||||
transition: all 200ms ease;
|
|
||||||
color: $universal-body-low-emphasis;
|
|
||||||
z-index: 1;
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
max-width: calc(100% - #{2 * $gap});
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
.has-dark-controls & {
|
|
||||||
color: $input-placeholder-dark;
|
|
||||||
}
|
|
||||||
@media screen and (prefers-reduced-motion: reduce) {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wc-block-components-combobox-control:has(input:-webkit-autofill) {
|
|
||||||
label {
|
|
||||||
transform: translateY(#{$gap-smallest}) scale(0.75);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-active,
|
|
||||||
&:focus-within {
|
|
||||||
.wc-block-components-combobox-control
|
|
||||||
label.components-base-control__label {
|
|
||||||
transform: translateY(#{$gap-smallest}) scale(0.75);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.has-error {
|
|
||||||
.wc-block-components-combobox-control {
|
|
||||||
label.components-base-control__label {
|
|
||||||
color: $alert-red;
|
|
||||||
}
|
|
||||||
input.components-combobox-control__input {
|
|
||||||
&,
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
border-color: $alert-red;
|
|
||||||
}
|
|
||||||
&:focus {
|
|
||||||
box-shadow: 0 0 0 1px $alert-red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,10 @@
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { ComboboxProps } from '../combobox';
|
import { SelectProps } from '../select';
|
||||||
import { countries } from './stories/countries-filler';
|
import { countries } from './stories/countries-filler';
|
||||||
|
|
||||||
export interface CountryInputProps extends Omit< ComboboxProps, 'options' > {
|
export interface CountryInputProps extends Omit< SelectProps, 'options' > {
|
||||||
/**
|
/**
|
||||||
* Classes to assign to the wrapper component of the input
|
* Classes to assign to the wrapper component of the input
|
||||||
*/
|
*/
|
||||||
|
@ -12,7 +12,7 @@ export interface CountryInputProps extends Omit< ComboboxProps, 'options' > {
|
||||||
/**
|
/**
|
||||||
* Whether input elements can by default have their values automatically completed by the browser.
|
* Whether input elements can by default have their values automatically completed by the browser.
|
||||||
*
|
*
|
||||||
* This value gets assigned to both the wrapper `Combobox` and the wrapped input element.
|
* This value gets assigned to both the wrapper `Select` and the wrapped input element.
|
||||||
*/
|
*/
|
||||||
autoComplete?: string | undefined;
|
autoComplete?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
@import "node_modules/@wordpress/base-styles/breakpoints";
|
@import "node_modules/@wordpress/base-styles/breakpoints";
|
||||||
@import "node_modules/@wordpress/base-styles/mixins";
|
@import "node_modules/@wordpress/base-styles/mixins";
|
||||||
@import "node_modules/wordpress-components/src/combobox-control/style";
|
|
||||||
|
|
||||||
.wc-block-components-country-input {
|
.wc-block-components-country-input {
|
||||||
margin-top: $gap;
|
margin-top: $gap;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
export { default as BlockErrorBoundary } from './block-error-boundary';
|
export { default as BlockErrorBoundary } from './block-error-boundary';
|
||||||
export * from './button';
|
export * from './button';
|
||||||
export * from './cart-checkout';
|
export * from './cart-checkout';
|
||||||
export * from './combobox';
|
|
||||||
export * from './country-input';
|
export * from './country-input';
|
||||||
export * from './drawer';
|
export * from './drawer';
|
||||||
export { default as FilterElementLabel } from './filter-element-label';
|
export { default as FilterElementLabel } from './filter-element-label';
|
||||||
|
|
|
@ -20,7 +20,7 @@ export type SelectOption = {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SelectProps = Omit<
|
export type SelectProps = Omit<
|
||||||
React.SelectHTMLAttributes< HTMLSelectElement >,
|
React.SelectHTMLAttributes< HTMLSelectElement >,
|
||||||
'onChange'
|
'onChange'
|
||||||
> & {
|
> & {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { ComboboxControlOption } from '@woocommerce/base-components/combobox';
|
|
||||||
import type { AllHTMLAttributes, AriaAttributes } from 'react';
|
import type { AllHTMLAttributes, AriaAttributes } from 'react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { getSetting } from './utils';
|
import { getSetting } from './utils';
|
||||||
|
import { SelectOption } from '../../base/components';
|
||||||
|
|
||||||
// A list of attributes that can be added to a custom field when registering it.
|
// A list of attributes that can be added to a custom field when registering it.
|
||||||
type CustomFieldAttributes = Pick<
|
type CustomFieldAttributes = Pick<
|
||||||
|
@ -39,7 +39,7 @@ export interface FormField {
|
||||||
// The type of input to render. Defaults to text.
|
// The type of input to render. Defaults to text.
|
||||||
type?: string;
|
type?: string;
|
||||||
// The options if this is a select field
|
// The options if this is a select field
|
||||||
options?: ComboboxControlOption[];
|
options?: SelectOption[];
|
||||||
// The placeholder for the field, only applicable for select fields.
|
// The placeholder for the field, only applicable for select fields.
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
// Additional attributes added when registering a field. String in key is required for data attributes.
|
// Additional attributes added when registering a field. String in key is required for data attributes.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: dev
|
||||||
|
|
||||||
|
Remove @wooocommerce `Combobox` component that is no longer used.
|
Loading…
Reference in New Issue