diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 6b01d991ffb277..f8233dc3cb3c0d 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -5,6 +5,7 @@
### Breaking Changes
- Components that compose Emotion style fragments with `cx()` should pass source-order-dependent fragments in a single `css()` call. Passing separate fragments can change override order after the following components stopped rendering styles through Emotion:
+ - `SelectControl` ([#84732](https://github.com/WordPress/gutenberg/pull/84732))
- `DatePicker` ([#84724](https://github.com/WordPress/gutenberg/pull/84724))
- `FocalPointPicker` ([#84736](https://github.com/WordPress/gutenberg/pull/84736))
- `Menu` ([#84706](https://github.com/WordPress/gutenberg/pull/84706))
@@ -35,6 +36,7 @@
- `StyleProvider`: Register module styles before children measure layout in iframe documents ([#84736](https://github.com/WordPress/gutenberg/pull/84736)).
- `BorderBoxControl`: Unpack multi-value CSS box shorthand strings (such as `"0 0 0 2px"`) into individual side widths when splitting borders ([#84826](https://github.com/WordPress/gutenberg/pull/84826)).
+- `SelectControl`: Preserve the minimal variant's inline layout in iframe documents ([#84732](https://github.com/WordPress/gutenberg/pull/84732)).
- `DatePicker`: Keep month navigation in a grid in iframe documents ([#84724](https://github.com/WordPress/gutenberg/pull/84724)).
- `PaletteEdit`: Name picker dialogs and add screen-reader-only dismissal controls while preserving live edits ([#84333](https://github.com/WordPress/gutenberg/pull/84333)).
- `Grid`: Fix the `bottomLeft` alignment, which resolved to the top right corner instead of the bottom left one ([#82641](https://github.com/WordPress/gutenberg/pull/82641)).
diff --git a/packages/components/src/select-control/chevron-down.tsx b/packages/components/src/select-control/chevron-down.tsx
index 1c22c59a25e551..40c9580b9b97eb 100644
--- a/packages/components/src/select-control/chevron-down.tsx
+++ b/packages/components/src/select-control/chevron-down.tsx
@@ -1,17 +1,20 @@
+import clsx from 'clsx';
+import { isRTL } from '@wordpress/i18n';
import { chevronDown, Icon } from '@wordpress/icons';
-import {
- chevronIconSize,
- DownArrowWrapper,
- InputControlSuffixWrapperWithClickThrough,
-} from './styles/select-control-styles';
+import InputControlSuffixWrapper from '../input-control/input-suffix-wrapper';
+import styles from './style.module.scss';
const SelectControlChevronDown = () => {
return (
-
-
-
-
-
+
+
+
+
+
);
};
diff --git a/packages/components/src/select-control/index.tsx b/packages/components/src/select-control/index.tsx
index f01d8f02a9b27f..b7458d4bf2b89f 100644
--- a/packages/components/src/select-control/index.tsx
+++ b/packages/components/src/select-control/index.tsx
@@ -1,8 +1,11 @@
import clsx from 'clsx';
import { useInstanceId } from '@wordpress/compose';
import { forwardRef } from '@wordpress/element';
+import { isRTL } from '@wordpress/i18n';
import BaseControl from '../base-control';
-import { Select, StyledInputBase } from './styles/select-control-styles';
+import InputBase from '../input-control/input-base';
+import { PolymorphicElement } from '../utils/polymorphic-element';
+import styles from './style.module.scss';
import type { WordPressComponentProps } from '../context';
import type { SelectControlProps } from './types';
import SelectControlChevronDown from './chevron-down';
@@ -85,7 +88,7 @@ function UnforwardedSelectControl< V extends string >(
return (
- (
__unstableInputWidth={
variant === 'minimal' ? 'auto' : undefined
}
- variant={ variant }
+ className={ clsx( styles.root, {
+ [ styles[ 'is-disabled' ] ]: disabled,
+ [ styles[ 'is-minimal' ] ]: variant === 'minimal',
+ } ) }
>
-
{ children || }
-
-
+
+
);
}
diff --git a/packages/components/src/select-control/style.module.scss b/packages/components/src/select-control/style.module.scss
new file mode 100644
index 00000000000000..c289a28fd3fb97
--- /dev/null
+++ b/packages/components/src/select-control/style.module.scss
@@ -0,0 +1,100 @@
+@use "../utils/theme-variables" as *;
+
+.root {
+ color: $components-color-foreground;
+ /* stylelint-disable-next-line declaration-property-value-disallowed-list -- Preserve the existing pointer cursor during the migration. */
+ cursor: pointer;
+
+ &:where(.is-disabled) {
+ color: var(--wpds-color-foreground-interactive-neutral-disabled);
+ cursor: default;
+ }
+}
+
+.root.root:where(.is-minimal) {
+ // Keep the minimal layout over Flex in either stylesheet order.
+ display: inline-flex;
+}
+
+.input.input.input {
+ // Match the existing specificity over wp-admin's form styles.
+ --_wp-components-select-control-padding: 12px;
+ appearance: none;
+ background: transparent;
+ box-sizing: border-box;
+ border: none;
+ box-shadow: none !important;
+ color: currentColor;
+ cursor: inherit;
+ display: block;
+ font-family: inherit;
+ font-size: 16px;
+ line-height: 1.3;
+ margin: 0;
+ width: 100%;
+ max-width: none;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+
+ @media (min-width: 600px) {
+ font-size: 13px;
+ }
+
+ &:where(.is-small, .is-compact) {
+ --_wp-components-select-control-padding: 8px;
+ }
+
+ &:where(:not(.is-multiple)) {
+ height: 40px;
+ min-height: 40px;
+ padding-block: 0;
+
+ &:where(.is-small) {
+ height: 24px;
+ min-height: 24px;
+ }
+
+ &:where(.is-compact) {
+ height: 32px;
+ min-height: 32px;
+ }
+ }
+
+ &:where(.is-multiple) {
+ // Preserve native height for multiple selection.
+ overflow: auto;
+ padding-block: var(--_wp-components-select-control-padding);
+ }
+
+ /* stylelint-disable logical-css/require-logical-properties -- The native select can override its direction independently of the sibling chevron; reserve space on the same physical side. */
+ padding-left: var(--_wp-components-select-control-padding);
+ padding-right: calc(var(--_wp-components-select-control-padding) + 18px);
+ &:where(.is-rtl) {
+ padding-left: calc(var(--_wp-components-select-control-padding) + 18px);
+ padding-right: var(--_wp-components-select-control-padding);
+ }
+
+ &:where(.is-minimal) {
+ field-sizing: content;
+ }
+}
+/* stylelint-enable logical-css/require-logical-properties */
+
+.down-arrow {
+ margin-inline-end: -4px;
+ line-height: 0;
+}
+
+.suffix {
+ position: absolute;
+ pointer-events: none;
+
+ /* stylelint-disable logical-css/require-logical-properties -- Match the locale-based chevron position. */
+ right: 0;
+ &:where(.is-rtl) {
+ right: auto;
+ left: 0;
+ }
+}
+/* stylelint-enable logical-css/require-logical-properties */
diff --git a/packages/components/src/select-control/styles/select-control-styles.ts b/packages/components/src/select-control/styles/select-control-styles.ts
deleted file mode 100644
index acc8c4f5a32a34..00000000000000
--- a/packages/components/src/select-control/styles/select-control-styles.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import { COLORS, rtl, CONFIG } from '../../utils';
-import { space } from '../../utils/space';
-import type { SelectControlProps } from '../types';
-import InputControlSuffixWrapper from '../../input-control/input-suffix-wrapper';
-import { fontSizeStyles } from '../../input-control/styles/input-control-styles';
-import InputBase from '../../input-control/input-base';
-
-interface SelectProps extends Pick<
- SelectControlProps,
- 'disabled' | 'multiple' | 'variant'
-> {
- // Using `selectSize` instead of `size` to avoid a type conflict with the
- // `size` HTML attribute of the `select` element.
- selectSize?: SelectControlProps[ 'size' ];
-}
-
-const disabledStyles = ( { disabled }: SelectProps ) => {
- if ( ! disabled ) {
- return '';
- }
-
- return css`
- color: ${ COLORS.ui.textDisabled };
- cursor: default;
- `;
-};
-
-const inputBaseVariantStyles = ( { variant }: SelectProps ) => {
- if ( variant === 'minimal' ) {
- return css`
- display: inline-flex;
- `;
- }
-
- return '';
-};
-
-export const StyledInputBase = styled( InputBase )`
- color: ${ COLORS.theme.foreground };
- cursor: pointer;
-
- ${ disabledStyles }
- ${ inputBaseVariantStyles }
-`;
-
-const sizeStyles = ( { multiple, selectSize = 'default' }: SelectProps ) => {
- if ( multiple ) {
- // When `multiple`, just use the native browser styles
- // without setting explicit height.
- return;
- }
-
- const sizes = {
- default: {
- height: 40,
- minHeight: 40,
- paddingTop: 0,
- paddingBottom: 0,
- },
- small: {
- height: 24,
- minHeight: 24,
- paddingTop: 0,
- paddingBottom: 0,
- },
- compact: {
- height: 32,
- minHeight: 32,
- paddingTop: 0,
- paddingBottom: 0,
- },
- };
-
- const style = sizes[ selectSize ] || sizes.default;
-
- return css( style );
-};
-
-export const chevronIconSize = 18;
-
-const sizePaddings = ( { multiple, selectSize = 'default' }: SelectProps ) => {
- const padding = {
- default: CONFIG.controlPaddingX,
- small: CONFIG.controlPaddingXSmall,
- compact: CONFIG.controlPaddingXSmall,
- };
-
- const selectedPadding = padding[ selectSize ] || padding.default;
-
- return rtl( {
- paddingLeft: selectedPadding,
- paddingRight: selectedPadding + chevronIconSize,
- ...( multiple
- ? {
- paddingTop: selectedPadding,
- paddingBottom: selectedPadding,
- }
- : {} ),
- } );
-};
-
-const overflowStyles = ( { multiple }: SelectProps ) => {
- return {
- overflow: multiple ? 'auto' : 'hidden',
- };
-};
-
-const variantStyles = ( { variant }: SelectProps ) => {
- if ( variant === 'minimal' ) {
- return css( {
- fieldSizing: 'content',
- } );
- }
-
- return '';
-};
-
-// TODO: Resolve need to use &&& to increase specificity
-// https://github.com/WordPress/gutenberg/issues/18483
-
-export const Select = styled.select< SelectProps >`
- &&& {
- appearance: none;
- background: transparent;
- box-sizing: border-box;
- border: none;
- box-shadow: none !important;
- color: currentColor; // Overrides hover/focus styles in forms.css
- cursor: inherit;
- display: block;
- font-family: inherit;
- line-height: 1.3; // Override forms.css styles, large enough value to prevent descender clipping without affecting height
- margin: 0;
- width: 100%;
- max-width: none;
- white-space: nowrap;
- text-overflow: ellipsis;
-
- ${ fontSizeStyles };
- ${ sizeStyles };
- ${ sizePaddings };
- ${ overflowStyles }
- ${ variantStyles }
- }
-`;
-
-export const DownArrowWrapper = styled.div`
- margin-inline-end: ${ space( -1 ) }; // optically adjust the icon
- line-height: 0;
-`;
-
-export const InputControlSuffixWrapperWithClickThrough = styled(
- InputControlSuffixWrapper
-)`
- position: absolute;
- pointer-events: none;
-
- ${ rtl( { right: 0 } ) }
-`;
diff --git a/tools/eslint/suppressions.json b/tools/eslint/suppressions.json
index 3c123074110ca3..e8cc34b1752c54 100644
--- a/tools/eslint/suppressions.json
+++ b/tools/eslint/suppressions.json
@@ -4588,11 +4588,6 @@
"count": 4
}
},
- "packages/components/src/select-control/styles/select-control-styles.ts": {
- "no-restricted-imports": {
- "count": 2
- }
- },
"packages/components/src/slot-fill/slot.tsx": {
"react-hooks/refs": {
"count": 1