diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 54f516ed84ba9..34c1a6ca410c3 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -22,7 +22,8 @@
- Remove `reduceMotion` util ([#61963](https://github.com/WordPress/gutenberg/pull/61963)).
- Add type support for CSS Custom Properties ([#61872](https://github.com/WordPress/gutenberg/pull/61872)).
- Remove usage of deprecated spreading of `key` prop in JSX in CustomSelectControl and FormTokenField components ([#61692](https://github.com/WordPress/gutenberg/pull/61692)).
-- Tooltip: Fix Ariakit tooltip store usage ([#61858](https://github.com/WordPress/gutenberg/pull/61858)).
+- `Tooltip`: Fix Ariakit tooltip store usage ([#61858](https://github.com/WordPress/gutenberg/pull/61858)).
+- `CustomSelectControlV2`: Use `InputBase` for styling ([#60261](https://github.com/WordPress/gutenberg/pull/60261)).
## 27.6.0 (2024-05-16)
diff --git a/packages/components/src/custom-select-control-v2/custom-select.tsx b/packages/components/src/custom-select-control-v2/custom-select.tsx
index 2bd1221f1381e..9ae402d37f40d 100644
--- a/packages/components/src/custom-select-control-v2/custom-select.tsx
+++ b/packages/components/src/custom-select-control-v2/custom-select.tsx
@@ -3,7 +3,6 @@
*/
import { createContext, useMemo } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
-import { Icon, chevronDown } from '@wordpress/icons';
/**
* Internal dependencies
@@ -14,13 +13,12 @@ import type {
CustomSelectContext as CustomSelectContextType,
CustomSelectStore,
CustomSelectButtonProps,
+ CustomSelectButtonSize,
_CustomSelectProps,
} from './types';
-import {
- contextConnectWithoutRef,
- useContextSystem,
- type WordPressComponentProps,
-} from '../context';
+import type { WordPressComponentProps } from '../context';
+import InputBase from '../input-control/input-base';
+import SelectControlChevronDown from '../select-control/chevron-down';
export const CustomSelectContext =
createContext< CustomSelectContextType >( undefined );
@@ -46,23 +44,19 @@ function defaultRenderSelectedValue(
return value;
}
-const UnconnectedCustomSelectButton = (
- props: Omit<
- WordPressComponentProps<
- CustomSelectButtonProps & CustomSelectStore,
- 'button',
- false
- >,
- 'onChange'
- >
-) => {
- const {
- renderSelectedValue,
- size = 'default',
- store,
- ...restProps
- } = useContextSystem( props, 'CustomSelectControlButton' );
-
+const CustomSelectButton = ( {
+ renderSelectedValue,
+ size = 'default',
+ store,
+ ...restProps
+}: Omit<
+ WordPressComponentProps<
+ CustomSelectButtonProps & CustomSelectButtonSize & CustomSelectStore,
+ 'button',
+ false
+ >,
+ 'onChange'
+> ) => {
const { value: currentValue } = store.useState();
const computedRenderSelectedValue = useMemo(
@@ -81,21 +75,18 @@ const UnconnectedCustomSelectButton = (
showOnKeyDown={ false }
>
{ computedRenderSelectedValue( currentValue ) }
-
);
};
-const CustomSelectButton = contextConnectWithoutRef(
- UnconnectedCustomSelectButton,
- 'CustomSelectControlButton'
-);
-
-function _CustomSelect( props: _CustomSelectProps & CustomSelectStore ) {
+function _CustomSelect(
+ props: _CustomSelectProps & CustomSelectStore & CustomSelectButtonSize
+) {
const {
children,
hideLabelFromVision = false,
label,
+ size,
store,
...restProps
} = props;
@@ -109,12 +100,22 @@ function _CustomSelect( props: _CustomSelectProps & CustomSelectStore ) {
{ label }
) }
-
-
-
- { children }
-
-
+ }
+ >
+
+
+
+ { children }
+
+
+
>
);
}
diff --git a/packages/components/src/custom-select-control-v2/legacy-component/index.tsx b/packages/components/src/custom-select-control-v2/legacy-component/index.tsx
index 0472d7df327b6..43f102e6ee049 100644
--- a/packages/components/src/custom-select-control-v2/legacy-component/index.tsx
+++ b/packages/components/src/custom-select-control-v2/legacy-component/index.tsx
@@ -3,10 +3,7 @@
*/
// eslint-disable-next-line no-restricted-imports
import * as Ariakit from '@ariakit/react';
-/**
- * WordPress dependencies
- */
-import { useMemo } from '@wordpress/element';
+
/**
* Internal dependencies
*/
@@ -14,12 +11,12 @@ import _CustomSelect from '../custom-select';
import CustomSelectItem from '../item';
import type { LegacyCustomSelectProps } from '../types';
import * as Styled from '../styles';
-import { ContextSystemProvider } from '../../context';
function CustomSelectControl( props: LegacyCustomSelectProps ) {
const {
__experimentalShowSelectedHint,
__next40pxDefaultSize = false,
+ describedBy,
options,
onChange,
size = 'default',
@@ -94,39 +91,33 @@ function CustomSelectControl( props: LegacyCustomSelectProps ) {
);
};
- // translate legacy button sizing
- const contextSystemValue = useMemo( () => {
- let selectedSize;
-
+ const translatedSize = ( () => {
if (
( __next40pxDefaultSize && size === 'default' ) ||
size === '__unstable-large'
) {
- selectedSize = 'default';
- } else if ( ! __next40pxDefaultSize && size === 'default' ) {
- selectedSize = 'compact';
- } else {
- selectedSize = size;
+ return 'default';
}
-
- return {
- CustomSelectControlButton: { _overrides: { size: selectedSize } },
- };
- }, [ __next40pxDefaultSize, size ] );
-
- const translatedProps = {
- 'aria-describedby': props.describedBy,
- children,
- renderSelectedValue: __experimentalShowSelectedHint
- ? renderSelectedValueHint
- : undefined,
- ...restProps,
- };
+ if ( ! __next40pxDefaultSize && size === 'default' ) {
+ return 'compact';
+ }
+ return size;
+ } )();
return (
-
- <_CustomSelect { ...translatedProps } store={ store } />
-
+ <_CustomSelect
+ aria-describedby={ describedBy }
+ renderSelectedValue={
+ __experimentalShowSelectedHint
+ ? renderSelectedValueHint
+ : undefined
+ }
+ size={ translatedSize }
+ store={ store }
+ { ...restProps }
+ >
+ { children }
+
);
}
diff --git a/packages/components/src/custom-select-control-v2/styles.ts b/packages/components/src/custom-select-control-v2/styles.ts
index f268b75b30c5c..676a9c1a1ec59 100644
--- a/packages/components/src/custom-select-control-v2/styles.ts
+++ b/packages/components/src/custom-select-control-v2/styles.ts
@@ -10,7 +10,7 @@ import styled from '@emotion/styled';
*/
import { COLORS, CONFIG } from '../utils';
import { space } from '../utils/space';
-import type { CustomSelectButtonProps } from './types';
+import type { CustomSelectButtonSize } from './types';
const ITEM_PADDING = space( 2 );
@@ -46,7 +46,7 @@ export const Select = styled( Ariakit.Select, {
size,
hasCustomRenderProp,
}: {
- size: NonNullable< CustomSelectButtonProps[ 'size' ] >;
+ size: NonNullable< CustomSelectButtonSize[ 'size' ] >;
hasCustomRenderProp: boolean;
} ) => {
const heightProperty = hasCustomRenderProp ? 'minHeight' : 'height';
@@ -79,17 +79,15 @@ export const Select = styled( Ariakit.Select, {
align-items: center;
justify-content: space-between;
background-color: ${ COLORS.theme.background };
- border: 1px solid ${ COLORS.ui.border };
- border-radius: 2px;
+ border: none;
cursor: pointer;
font-size: ${ CONFIG.fontSize };
width: 100%;
+
&[data-focus-visible] {
- outline-style: solid;
- }
- &[aria-expanded='true'] {
- outline: 1.5px solid ${ COLORS.theme.accent };
+ outline: none; // handled by InputBase component
}
+
${ getSize() }
`;
} );
@@ -98,6 +96,10 @@ export const SelectPopover = styled( Ariakit.SelectPopover )`
border-radius: 2px;
background: ${ COLORS.theme.background };
border: 1px solid ${ COLORS.theme.foreground };
+
+ &[data-focus-visible] {
+ outline: none; // outline will be on the trigger, rather than the popover
+ }
`;
export const SelectItem = styled( Ariakit.SelectItem )`
diff --git a/packages/components/src/custom-select-control-v2/types.ts b/packages/components/src/custom-select-control-v2/types.ts
index 313bc06dd493b..5540a533c09d4 100644
--- a/packages/components/src/custom-select-control-v2/types.ts
+++ b/packages/components/src/custom-select-control-v2/types.ts
@@ -14,6 +14,19 @@ export type CustomSelectStore = {
export type CustomSelectContext = CustomSelectStore | undefined;
+type CustomSelectSize< Size = 'compact' | 'default' > = {
+ /**
+ * The size of the control.
+ *
+ * @default 'default'
+ */
+ size?: Size;
+};
+
+export type CustomSelectButtonSize = CustomSelectSize<
+ 'compact' | 'default' | 'small'
+>;
+
export type CustomSelectButtonProps = {
/**
* An optional default value for the control when used in uncontrolled mode.
@@ -30,19 +43,13 @@ export type CustomSelectButtonProps = {
renderSelectedValue?: (
selectedValue: string | string[]
) => React.ReactNode;
- /**
- * The size of the control.
- *
- * @default 'default'
- */
- size?: 'compact' | 'default' | 'small';
/**
* The value of the control when used in uncontrolled mode.
*/
value?: string | string[];
};
-export type _CustomSelectProps = {
+export type _CustomSelectProps = CustomSelectButtonProps & {
/**
* The child elements. This should be composed of `CustomSelectItem` components.
*/
@@ -60,14 +67,8 @@ export type _CustomSelectProps = {
};
export type CustomSelectProps = _CustomSelectProps &
- Omit< CustomSelectButtonProps, 'size' > & {
- /**
- * The size of the control.
- *
- * @default 'default'
- */
- size?: Exclude< CustomSelectButtonProps[ 'size' ], 'small' >;
- };
+ CustomSelectButtonProps &
+ CustomSelectSize;
/**
* The legacy object structure for the options array.
diff --git a/packages/components/src/input-control/input-base.tsx b/packages/components/src/input-control/input-base.tsx
index 9e34139f3e54b..58396f3ab9859 100644
--- a/packages/components/src/input-control/input-base.tsx
+++ b/packages/components/src/input-control/input-base.tsx
@@ -64,7 +64,7 @@ function getUIFlexProps( labelPosition?: LabelPosition ) {
return props;
}
-export function InputBase(
+function InputBase(
props: WordPressComponentProps< InputBaseProps, 'div' >,
ref: ForwardedRef< HTMLDivElement >
) {
@@ -144,4 +144,8 @@ export function InputBase(
);
}
+/**
+ * `InputBase` is an internal component used to style the standard borders for an input,
+ * as well as handle the layout for prefix/suffix elements.
+ */
export default contextConnect( InputBase, 'InputBase' );