diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 21cf13bd53aa51..df2dc40c3dd130 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -39,6 +39,7 @@ ### Internal - Remove `ValidatedCheckboxControl` from the private APIs; it now lives internally in `@wordpress/dataviews`, its only consumer ([#81435](https://github.com/WordPress/gutenberg/pull/81435)). +- Remove `ValidatedComboboxControl` from the private APIs; it now lives internally in `@wordpress/dataviews`, its only consumer ([#81449](https://github.com/WordPress/gutenberg/pull/81449)). - Remove `ValidatedNumberControl` from the private APIs; it now lives internally in `@wordpress/dataviews`, its only consumer ([#81433](https://github.com/WordPress/gutenberg/pull/81433)). - Remove `ValidatedRadioControl` from the private APIs; it now lives internally in `@wordpress/dataviews`, its only consumer ([#81434](https://github.com/WordPress/gutenberg/pull/81434)). - Remove `ValidatedSelectControl` from the private APIs; it now lives internally in `@wordpress/dataviews`, its only consumer ([#81391](https://github.com/WordPress/gutenberg/pull/81391)). diff --git a/packages/components/src/private-apis.ts b/packages/components/src/private-apis.ts index fe92ca5ac29b53..0cd33af8670286 100644 --- a/packages/components/src/private-apis.ts +++ b/packages/components/src/private-apis.ts @@ -6,7 +6,6 @@ import { Tabs } from './tabs'; import { lock } from './lock-unlock'; import Badge from './badge'; import { - ValidatedComboboxControl, ValidatedInputControl, ValidatedContentEditableControl, ValidatedTextareaControl, @@ -26,7 +25,6 @@ lock( privateApis, { Badge, useDrag, ValidatedInputControl, - ValidatedComboboxControl, ValidatedContentEditableControl, ValidatedTextareaControl, ValidatedToggleControl, diff --git a/packages/components/src/validated-form-controls/components/index.ts b/packages/components/src/validated-form-controls/components/index.ts index d19f6bc4bfea7a..b1732c65fc0a85 100644 --- a/packages/components/src/validated-form-controls/components/index.ts +++ b/packages/components/src/validated-form-controls/components/index.ts @@ -1,4 +1,3 @@ -export * from './combobox-control'; export * from './custom-select-control'; export * from './form-token-field'; export * from './input-control'; diff --git a/packages/components/src/validated-form-controls/components/stories/combobox-control.story.tsx b/packages/components/src/validated-form-controls/components/stories/combobox-control.story.tsx deleted file mode 100644 index f6cd97682592bd..00000000000000 --- a/packages/components/src/validated-form-controls/components/stories/combobox-control.story.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { useState } from '@wordpress/element'; -import type { StoryObj, Meta } from '@storybook/react-vite'; -import { ValidatedComboboxControl } from '../combobox-control'; -import { formDecorator } from './story-utils'; - -const meta: Meta< typeof ValidatedComboboxControl > = { - title: 'Components/Selection & Input/Validated Form Controls/ValidatedComboboxControl', - id: 'components-validatedcomboboxcontrol', - component: ValidatedComboboxControl, - tags: [ 'status-private' ], - decorators: formDecorator, - args: { onChange: () => {} }, - argTypes: { - value: { control: false }, - }, -}; -export default meta; - -export const Default: StoryObj< typeof ValidatedComboboxControl > = { - render: function Template( { onChange, ...args } ) { - const [ value, setValue ] = - useState< - React.ComponentProps< - typeof ValidatedComboboxControl - >[ 'value' ] - >(); - - return ( - { - setValue( newValue ); - onChange?.( newValue ); - } } - customValidity={ - value === 'a' - ? { - type: 'invalid', - message: 'Option A is not allowed.', - } - : undefined - } - /> - ); - }, -}; -Default.args = { - required: true, - label: 'Combobox', - help: 'Option A is not allowed.', - options: [ - { value: 'a', label: 'Option A (not allowed)' }, - { value: 'b', label: 'Option B' }, - ], -}; diff --git a/packages/components/src/validated-form-controls/style.scss b/packages/components/src/validated-form-controls/style.scss index e3d5503a104ecd..8639440a152f3b 100644 --- a/packages/components/src/validated-form-controls/style.scss +++ b/packages/components/src/validated-form-controls/style.scss @@ -16,13 +16,6 @@ --wp-components-color-accent: #{$alert-red}; border-color: $alert-red; } - - // For ComboboxControl - .components-combobox-control__suggestions-container:has( - input:invalid[data-validity-visible] -):not(:has([aria-expanded="true"])) { - --wp-admin-theme-color: #{$alert-red}; - } } .components-validated-control__wrapper-with-error-delegate { diff --git a/packages/dataviews/CHANGELOG.md b/packages/dataviews/CHANGELOG.md index 2de086ac930b7e..9e002e62681902 100644 --- a/packages/dataviews/CHANGELOG.md +++ b/packages/dataviews/CHANGELOG.md @@ -11,6 +11,7 @@ - DataViews: Replace the inlined `kebabCase` utility with the new `@wordpress/kebab-case` package. [#81294](https://github.com/WordPress/gutenberg/pull/81294) - DataForm: Internalize `ValidatedSelectControl` and its `ControlWithError` foundation instead of unlocking them from the `@wordpress/components` private APIs. The foundation is a temporary copy slated to be replaced by the upcoming `@wordpress/ui` implementation. [#81391](https://github.com/WordPress/gutenberg/pull/81391) - DataForm: Internalize `ValidatedCheckboxControl` instead of unlocking it from the `@wordpress/components` private APIs. [#81435](https://github.com/WordPress/gutenberg/pull/81435) +- DataForm: Internalize `ValidatedComboboxControl` instead of unlocking it from the `@wordpress/components` private APIs. [#81449](https://github.com/WordPress/gutenberg/pull/81449) - DataForm: Internalize `ValidatedNumberControl` instead of unlocking it from the `@wordpress/components` private APIs. [#81433](https://github.com/WordPress/gutenberg/pull/81433) - DataForm: Internalize `ValidatedRadioControl` instead of unlocking it from the `@wordpress/components` private APIs. [#81434](https://github.com/WordPress/gutenberg/pull/81434) diff --git a/packages/dataviews/src/components/dataform-controls/combobox.tsx b/packages/dataviews/src/components/dataform-controls/combobox.tsx index 8109dcad825cec..720ed381a7f3ba 100644 --- a/packages/dataviews/src/components/dataform-controls/combobox.tsx +++ b/packages/dataviews/src/components/dataform-controls/combobox.tsx @@ -1,12 +1,10 @@ -import { privateApis, Spinner } from '@wordpress/components'; +import { Spinner } from '@wordpress/components'; import { useCallback } from '@wordpress/element'; import type { DataFormControlProps } from '../../types'; import useElements from '../../hooks/use-elements'; -import { unlock } from '../../lock-unlock'; +import { ValidatedComboboxControl } from '../validated-form-controls'; import getCustomValidity from './utils/get-custom-validity'; -const { ValidatedComboboxControl } = unlock( privateApis ); - export default function Combobox< Item >( { data, field, @@ -19,7 +17,7 @@ export default function Combobox< Item >( { const value = getValue( { item: data } ) ?? ''; const onChangeControl = useCallback( - ( newValue: string | null ) => + ( newValue: string | null | undefined ) => onChange( setValue( { item: data, value: newValue ?? '' } ) ), [ data, onChange, setValue ] ); diff --git a/packages/components/src/validated-form-controls/components/combobox-control.tsx b/packages/dataviews/src/components/validated-form-controls/combobox-control.tsx similarity index 70% rename from packages/components/src/validated-form-controls/components/combobox-control.tsx rename to packages/dataviews/src/components/validated-form-controls/combobox-control.tsx index 81938bac9c3ec6..1af359817e6548 100644 --- a/packages/components/src/validated-form-controls/components/combobox-control.tsx +++ b/packages/dataviews/src/components/validated-form-controls/combobox-control.tsx @@ -1,8 +1,16 @@ -import { useMergeRefs } from '@wordpress/compose'; import { forwardRef, useEffect, useRef } from '@wordpress/element'; -import { ControlWithError } from '../control-with-error'; +import { useMergeRefs } from '@wordpress/compose'; +import { ComboboxControl } from '@wordpress/components'; +import { ControlWithError } from './control-with-error'; import type { ValidatedControlProps } from './types'; -import ComboboxControl from '../../combobox-control'; + +type ComboboxControlProps = React.ComponentProps< typeof ComboboxControl >; + +type ValidatedComboboxControlProps = Omit< + ComboboxControlProps, + '__next40pxDefaultSize' +> & + ValidatedControlProps; const UnforwardedValidatedComboboxControl = ( { @@ -10,11 +18,7 @@ const UnforwardedValidatedComboboxControl = ( customValidity, markWhenOptional, ...restProps - }: Omit< - React.ComponentProps< typeof ComboboxControl >, - '__next40pxDefaultSize' - > & - ValidatedControlProps, + }: ValidatedComboboxControlProps, forwardedRef: React.ForwardedRef< HTMLInputElement > ) => { const validityTargetRef = useRef< HTMLInputElement >( null ); @@ -50,7 +54,8 @@ const UnforwardedValidatedComboboxControl = ( ); }; -export const ValidatedComboboxControl = forwardRef( - UnforwardedValidatedComboboxControl -); +export const ValidatedComboboxControl: React.ForwardRefExoticComponent< + React.PropsWithoutRef< ValidatedComboboxControlProps > & + React.RefAttributes< HTMLInputElement > +> = forwardRef( UnforwardedValidatedComboboxControl ); ValidatedComboboxControl.displayName = 'ValidatedComboboxControl'; diff --git a/packages/dataviews/src/components/validated-form-controls/index.ts b/packages/dataviews/src/components/validated-form-controls/index.ts index e9e1b3566f63f9..b73f573d9de8e7 100644 --- a/packages/dataviews/src/components/validated-form-controls/index.ts +++ b/packages/dataviews/src/components/validated-form-controls/index.ts @@ -1,5 +1,6 @@ export { ControlWithError } from './control-with-error'; export { ValidatedCheckboxControl } from './checkbox-control'; +export { ValidatedComboboxControl } from './combobox-control'; export { ValidatedNumberControl } from './number-control'; export { ValidatedRadioControl } from './radio-control'; export { ValidatedSelectControl } from './select-control'; diff --git a/packages/dataviews/src/components/validated-form-controls/style.scss b/packages/dataviews/src/components/validated-form-controls/style.scss index 72f318e152b2c4..35f8e306cb2e13 100644 --- a/packages/dataviews/src/components/validated-form-controls/style.scss +++ b/packages/dataviews/src/components/validated-form-controls/style.scss @@ -8,6 +8,13 @@ --wp-components-color-accent: #{$alert-red}; border-color: $alert-red; } + + // For ComboboxControl + .components-combobox-control__suggestions-container:has( + input:invalid[data-validity-visible] +):not(:has([aria-expanded="true"])) { + --wp-admin-theme-color: #{$alert-red}; + } } .dataviews-validated-control__indicator { diff --git a/packages/components/src/validated-form-controls/test/combobox-control.tsx b/packages/dataviews/src/components/validated-form-controls/test/combobox-control.tsx similarity index 96% rename from packages/components/src/validated-form-controls/test/combobox-control.tsx rename to packages/dataviews/src/components/validated-form-controls/test/combobox-control.tsx index 4d34be44bac6a7..0cb2a716b2ce2d 100644 --- a/packages/components/src/validated-form-controls/test/combobox-control.tsx +++ b/packages/dataviews/src/components/validated-form-controls/test/combobox-control.tsx @@ -1,6 +1,6 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { ValidatedComboboxControl } from '../components'; +import { ValidatedComboboxControl } from '../combobox-control'; // The `help` prop is rendered visually by BaseControl but is not // programmatically associated with the combobox input via aria-describedby.