@wordpress/components 40.0.0 → 40.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/CONTRIBUTING.md +2 -0
- package/build/border-box-control/border-box-control/component.cjs +37 -5
- package/build/border-box-control/border-box-control/component.cjs.map +3 -3
- package/build/border-box-control/border-box-control/hook.cjs +24 -3
- package/build/border-box-control/border-box-control/hook.cjs.map +3 -3
- package/build/border-box-control/border-box-control-linked-button/hook.cjs +2 -2
- package/build/border-box-control/border-box-control-linked-button/hook.cjs.map +2 -2
- package/build/border-box-control/border-box-control-split-controls/hook.cjs +2 -2
- package/build/border-box-control/border-box-control-split-controls/hook.cjs.map +2 -2
- package/build/border-box-control/border-box-control-visualizer/hook.cjs +2 -2
- package/build/border-box-control/border-box-control-visualizer/hook.cjs.map +2 -2
- package/build/color-palette/index.cjs +1 -1
- package/build/color-palette/index.cjs.map +2 -2
- package/build/composite/context.cjs +9 -2
- package/build/composite/context.cjs.map +2 -2
- package/build/composite/group-label.cjs +4 -0
- package/build/composite/group-label.cjs.map +2 -2
- package/build/composite/group.cjs +10 -2
- package/build/composite/group.cjs.map +2 -2
- package/build/composite/item.cjs +4 -0
- package/build/composite/item.cjs.map +3 -3
- package/build/context/context-system-provider.cjs +2 -5
- package/build/context/context-system-provider.cjs.map +3 -3
- package/build/context/use-context-system.cjs +7 -2
- package/build/context/use-context-system.cjs.map +2 -2
- package/build/disabled/index.cjs +1 -1
- package/build/disabled/index.cjs.map +2 -2
- package/build/draggable/index.cjs.map +1 -1
- package/build/form-token-field/index.cjs +1 -1
- package/build/form-token-field/index.cjs.map +2 -2
- package/build/icon/index.cjs +30 -12
- package/build/icon/index.cjs.map +2 -2
- package/build/input-control/styles/input-control-styles.cjs +42 -27
- package/build/input-control/styles/input-control-styles.cjs.map +2 -2
- package/build/item-group/context.cjs +1 -0
- package/build/item-group/context.cjs.map +2 -2
- package/build/item-group/item/component.cjs +12 -0
- package/build/item-group/item/component.cjs.map +3 -3
- package/build/item-group/item/hook.cjs +7 -6
- package/build/item-group/item/hook.cjs.map +2 -2
- package/build/item-group/item-group/component.cjs +1 -0
- package/build/item-group/item-group/component.cjs.map +2 -2
- package/build/item-group/item-group/hook.cjs +1 -1
- package/build/item-group/item-group/hook.cjs.map +2 -2
- package/build/progress-bar/index.cjs +1 -1
- package/build/progress-bar/index.cjs.map +2 -2
- package/build/resizable-box/index.cjs.map +1 -1
- package/build/snackbar/index.cjs +8 -5
- package/build/snackbar/index.cjs.map +2 -2
- package/build/textarea-control/index.cjs +1 -1
- package/build/textarea-control/index.cjs.map +2 -2
- package/build/toggle-group-control/context.cjs +8 -2
- package/build/toggle-group-control/context.cjs.map +2 -2
- package/build/toggle-group-control/toggle-group-control/as-button-group.cjs +5 -2
- package/build/toggle-group-control/toggle-group-control/as-button-group.cjs.map +2 -2
- package/build/toggle-group-control/toggle-group-control/as-radio-group.cjs +5 -2
- package/build/toggle-group-control/toggle-group-control/as-radio-group.cjs.map +2 -2
- package/build/toggle-group-control/toggle-group-control/component.cjs +3 -1
- package/build/toggle-group-control/toggle-group-control/component.cjs.map +2 -2
- package/build/toggle-group-control/toggle-group-control-option/component.cjs +2 -0
- package/build/toggle-group-control/toggle-group-control-option/component.cjs.map +2 -2
- package/build/toggle-group-control/toggle-group-control-option-base/component.cjs +2 -1
- package/build/toggle-group-control/toggle-group-control-option-base/component.cjs.map +2 -2
- package/build/toggle-group-control/toggle-group-control-option-icon/component.cjs +2 -0
- package/build/toggle-group-control/toggle-group-control-option-icon/component.cjs.map +2 -2
- package/build/tools-panel/tools-panel/hook.cjs +102 -106
- package/build/tools-panel/tools-panel/hook.cjs.map +2 -2
- package/build/tools-panel/tools-panel-item/hook.cjs +33 -33
- package/build/tools-panel/tools-panel-item/hook.cjs.map +2 -2
- package/build/tree-grid/cell.cjs +4 -0
- package/build/tree-grid/cell.cjs.map +2 -2
- package/build/tree-grid/roving-tab-index-item.cjs +5 -1
- package/build/tree-grid/roving-tab-index-item.cjs.map +2 -2
- package/build/tree-grid/row.cjs +6 -1
- package/build/tree-grid/row.cjs.map +2 -2
- package/build/tree-grid/use-validate-tree-grid-structure.cjs +81 -0
- package/build/tree-grid/use-validate-tree-grid-structure.cjs.map +7 -0
- package/build/utils/colors-values.cjs +3 -2
- package/build/utils/colors-values.cjs.map +2 -2
- package/build-module/border-box-control/border-box-control/component.mjs +38 -6
- package/build-module/border-box-control/border-box-control/component.mjs.map +2 -2
- package/build-module/border-box-control/border-box-control/hook.mjs +14 -3
- package/build-module/border-box-control/border-box-control/hook.mjs.map +2 -2
- package/build-module/border-box-control/border-box-control-linked-button/hook.mjs +2 -2
- package/build-module/border-box-control/border-box-control-linked-button/hook.mjs.map +2 -2
- package/build-module/border-box-control/border-box-control-split-controls/hook.mjs +2 -2
- package/build-module/border-box-control/border-box-control-split-controls/hook.mjs.map +2 -2
- package/build-module/border-box-control/border-box-control-visualizer/hook.mjs +2 -2
- package/build-module/border-box-control/border-box-control-visualizer/hook.mjs.map +2 -2
- package/build-module/color-palette/index.mjs +1 -1
- package/build-module/color-palette/index.mjs.map +2 -2
- package/build-module/composite/context.mjs +6 -1
- package/build-module/composite/context.mjs.map +2 -2
- package/build-module/composite/group-label.mjs +5 -1
- package/build-module/composite/group-label.mjs.map +2 -2
- package/build-module/composite/group.mjs +11 -3
- package/build-module/composite/group.mjs.map +2 -2
- package/build-module/composite/item.mjs +4 -0
- package/build-module/composite/item.mjs.map +2 -2
- package/build-module/context/context-system-provider.mjs +2 -5
- package/build-module/context/context-system-provider.mjs.map +3 -3
- package/build-module/context/use-context-system.mjs +7 -2
- package/build-module/context/use-context-system.mjs.map +2 -2
- package/build-module/disabled/index.mjs +1 -1
- package/build-module/disabled/index.mjs.map +2 -2
- package/build-module/draggable/index.mjs.map +1 -1
- package/build-module/form-token-field/index.mjs +1 -1
- package/build-module/form-token-field/index.mjs.map +2 -2
- package/build-module/icon/index.mjs +30 -12
- package/build-module/icon/index.mjs.map +2 -2
- package/build-module/input-control/styles/input-control-styles.mjs +42 -27
- package/build-module/input-control/styles/input-control-styles.mjs.map +2 -2
- package/build-module/item-group/context.mjs +1 -0
- package/build-module/item-group/context.mjs.map +2 -2
- package/build-module/item-group/item/component.mjs +12 -0
- package/build-module/item-group/item/component.mjs.map +2 -2
- package/build-module/item-group/item/hook.mjs +7 -6
- package/build-module/item-group/item/hook.mjs.map +2 -2
- package/build-module/item-group/item-group/component.mjs +1 -0
- package/build-module/item-group/item-group/component.mjs.map +2 -2
- package/build-module/item-group/item-group/hook.mjs +1 -1
- package/build-module/item-group/item-group/hook.mjs.map +2 -2
- package/build-module/progress-bar/index.mjs +1 -1
- package/build-module/progress-bar/index.mjs.map +2 -2
- package/build-module/resizable-box/index.mjs.map +1 -1
- package/build-module/snackbar/index.mjs +8 -5
- package/build-module/snackbar/index.mjs.map +2 -2
- package/build-module/textarea-control/index.mjs +1 -1
- package/build-module/textarea-control/index.mjs.map +2 -2
- package/build-module/toggle-group-control/context.mjs +8 -2
- package/build-module/toggle-group-control/context.mjs.map +2 -2
- package/build-module/toggle-group-control/toggle-group-control/as-button-group.mjs +5 -2
- package/build-module/toggle-group-control/toggle-group-control/as-button-group.mjs.map +2 -2
- package/build-module/toggle-group-control/toggle-group-control/as-radio-group.mjs +5 -2
- package/build-module/toggle-group-control/toggle-group-control/as-radio-group.mjs.map +2 -2
- package/build-module/toggle-group-control/toggle-group-control/component.mjs +3 -1
- package/build-module/toggle-group-control/toggle-group-control/component.mjs.map +2 -2
- package/build-module/toggle-group-control/toggle-group-control-option/component.mjs +2 -0
- package/build-module/toggle-group-control/toggle-group-control-option/component.mjs.map +2 -2
- package/build-module/toggle-group-control/toggle-group-control-option-base/component.mjs +2 -1
- package/build-module/toggle-group-control/toggle-group-control-option-base/component.mjs.map +2 -2
- package/build-module/toggle-group-control/toggle-group-control-option-icon/component.mjs +2 -0
- package/build-module/toggle-group-control/toggle-group-control-option-icon/component.mjs.map +2 -2
- package/build-module/tools-panel/tools-panel/hook.mjs +103 -107
- package/build-module/tools-panel/tools-panel/hook.mjs.map +2 -2
- package/build-module/tools-panel/tools-panel-item/hook.mjs +35 -35
- package/build-module/tools-panel/tools-panel-item/hook.mjs.map +2 -2
- package/build-module/tree-grid/cell.mjs +5 -1
- package/build-module/tree-grid/cell.mjs.map +2 -2
- package/build-module/tree-grid/roving-tab-index-item.mjs +5 -1
- package/build-module/tree-grid/roving-tab-index-item.mjs.map +2 -2
- package/build-module/tree-grid/row.mjs +7 -2
- package/build-module/tree-grid/row.mjs.map +2 -2
- package/build-module/tree-grid/use-validate-tree-grid-structure.mjs +56 -0
- package/build-module/tree-grid/use-validate-tree-grid-structure.mjs.map +7 -0
- package/build-module/utils/colors-values.mjs +3 -2
- package/build-module/utils/colors-values.mjs.map +2 -2
- package/build-style/style-rtl.css +27 -85
- package/build-style/style.css +27 -85
- package/build-types/border-box-control/border-box-control/component.d.ts +4 -0
- package/build-types/border-box-control/border-box-control/component.d.ts.map +1 -1
- package/build-types/border-box-control/border-box-control/hook.d.ts +4 -2
- package/build-types/border-box-control/border-box-control/hook.d.ts.map +1 -1
- package/build-types/border-box-control/types.d.ts +6 -2
- package/build-types/border-box-control/types.d.ts.map +1 -1
- package/build-types/composite/context.d.ts +2 -0
- package/build-types/composite/context.d.ts.map +1 -1
- package/build-types/composite/group-label.d.ts.map +1 -1
- package/build-types/composite/group.d.ts.map +1 -1
- package/build-types/composite/item.d.ts.map +1 -1
- package/build-types/composite/types.d.ts +1 -1
- package/build-types/context/context-system-provider.d.ts +8 -6
- package/build-types/context/context-system-provider.d.ts.map +1 -1
- package/build-types/context/use-context-system.d.ts.map +1 -1
- package/build-types/icon/index.d.ts.map +1 -1
- package/build-types/input-control/styles/input-control-styles.d.ts.map +1 -1
- package/build-types/item-group/context.d.ts.map +1 -1
- package/build-types/item-group/item/component.d.ts.map +1 -1
- package/build-types/item-group/item/hook.d.ts +1 -1
- package/build-types/item-group/item/hook.d.ts.map +1 -1
- package/build-types/item-group/item-group/component.d.ts.map +1 -1
- package/build-types/item-group/types.d.ts +4 -0
- package/build-types/item-group/types.d.ts.map +1 -1
- package/build-types/popover/types.d.ts +6 -2
- package/build-types/popover/types.d.ts.map +1 -1
- package/build-types/snackbar/index.d.ts.map +1 -1
- package/build-types/toggle-group-control/context.d.ts +2 -2
- package/build-types/toggle-group-control/context.d.ts.map +1 -1
- package/build-types/toggle-group-control/toggle-group-control/as-button-group.d.ts +1 -1
- package/build-types/toggle-group-control/toggle-group-control/as-button-group.d.ts.map +1 -1
- package/build-types/toggle-group-control/toggle-group-control/as-radio-group.d.ts +1 -1
- package/build-types/toggle-group-control/toggle-group-control/as-radio-group.d.ts.map +1 -1
- package/build-types/toggle-group-control/toggle-group-control/component.d.ts.map +1 -1
- package/build-types/toggle-group-control/toggle-group-control-option/component.d.ts +2 -2
- package/build-types/toggle-group-control/toggle-group-control-option/component.d.ts.map +1 -1
- package/build-types/toggle-group-control/toggle-group-control-option-base/component.d.ts.map +1 -1
- package/build-types/toggle-group-control/toggle-group-control-option-icon/component.d.ts +2 -2
- package/build-types/toggle-group-control/toggle-group-control-option-icon/component.d.ts.map +1 -1
- package/build-types/toggle-group-control/types.d.ts +12 -3
- package/build-types/toggle-group-control/types.d.ts.map +1 -1
- package/build-types/tools-panel/tools-panel/hook.d.ts +4 -4
- package/build-types/tools-panel/tools-panel/hook.d.ts.map +1 -1
- package/build-types/tools-panel/tools-panel-item/hook.d.ts.map +1 -1
- package/build-types/tools-panel/types.d.ts +52 -9
- package/build-types/tools-panel/types.d.ts.map +1 -1
- package/build-types/tree-grid/cell.d.ts.map +1 -1
- package/build-types/tree-grid/roving-tab-index-item.d.ts.map +1 -1
- package/build-types/tree-grid/row.d.ts.map +1 -1
- package/build-types/tree-grid/use-validate-tree-grid-structure.d.ts +2 -0
- package/build-types/tree-grid/use-validate-tree-grid-structure.d.ts.map +1 -0
- package/build-types/utils/colors-values.d.ts.map +1 -1
- package/emotion-to-scss-modules.md +149 -0
- package/package.json +28 -27
- package/src/alignment-matrix-control/test/{index.tsx → index.jsdom.test.tsx} +5 -4
- package/src/angle-picker-control/style.module.scss +1 -1
- package/src/autocomplete/test/get-autocomplete-match.ts +2 -1
- package/src/autocomplete/test/{index.tsx → index.jsdom.test.tsx} +2 -1
- package/src/badge/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/base-control/stories/index.story.tsx +2 -2
- package/src/base-control/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/border-box-control/border-box-control/README.md +5 -3
- package/src/border-box-control/border-box-control/component.tsx +83 -15
- package/src/border-box-control/border-box-control/hook.ts +19 -1
- package/src/border-box-control/stories/index.story.tsx +10 -0
- package/src/border-box-control/style.module.scss +34 -3
- package/src/border-box-control/test/{index.tsx → index.jsdom.test.tsx} +138 -2
- package/src/border-box-control/test/utils.ts +11 -0
- package/src/border-box-control/types.ts +6 -2
- package/src/border-control/test/{index.js → index.jsdom.test.tsx} +44 -24
- package/src/box-control/test/{index.tsx → index.jsdom.test.tsx} +6 -3
- package/src/button/style.scss +0 -6
- package/src/button/test/{index.tsx → index.jsdom.test.tsx} +6 -2
- package/src/checkbox-control/stories/index.story.tsx +1 -1
- package/src/checkbox-control/style.scss +2 -2
- package/src/checkbox-control/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +10 -7
- package/src/checkbox-control/test/{index.tsx → index.jsdom.test.tsx} +4 -1
- package/src/circular-option-picker/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/color-indicator/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +2 -2
- package/src/color-indicator/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/color-palette/index.tsx +1 -1
- package/src/color-palette/test/{index.tsx → index.jsdom.test.tsx} +25 -22
- package/src/color-palette/test/{utils.ts → utils.jsdom.test.ts} +1 -0
- package/src/combobox-control/test/{index.tsx → index.jsdom.test.tsx} +12 -7
- package/src/composite/README.md +1 -1
- package/src/composite/context.tsx +6 -0
- package/src/composite/group-label.tsx +8 -1
- package/src/composite/group.tsx +9 -2
- package/src/composite/item.tsx +6 -0
- package/src/composite/legacy/test/{index.tsx → index.jsdom.test.tsx} +6 -13
- package/src/composite/test/{index.tsx → index.jsdom.test.tsx} +60 -17
- package/src/composite/types.ts +1 -1
- package/src/confirm-dialog/test/{index.tsx → index.jsdom.test.tsx} +16 -14
- package/src/content-editable-control/test/{index.tsx → index.jsdom.test.tsx} +4 -3
- package/src/context/{context-system-provider.js → context-system-provider.tsx} +19 -5
- package/src/context/stories/{ComponentsProvider.stories.jsx → ComponentsProvider.stories.tsx} +2 -2
- package/src/context/test/context-connect.tsx +1 -2
- package/src/context/test/{context-system-provider.js → context-system-provider.jsdom.test.tsx} +93 -51
- package/src/context/test/wordpress-component.tsx +1 -2
- package/src/context/use-context-system.js +13 -4
- package/src/custom-gradient-picker/gradient-bar/test/{utils.ts → utils.jsdom.test.ts} +6 -5
- package/src/custom-gradient-picker/test/serializer.ts +1 -0
- package/src/custom-select-control-v2/test/{index.tsx → index.jsdom.test.tsx} +4 -1
- package/src/date-time/date-picker/test/{index.tsx → index.jsdom.test.tsx} +6 -3
- package/src/date-time/date-picker/test/{use-lilius.ts → use-lilius.jsdom.test.ts} +1 -0
- package/src/date-time/date-time/test/{index.tsx → index.jsdom.test.tsx} +20 -11
- package/src/date-time/test/utils.test.ts +9 -0
- package/src/date-time/time-picker/test/{index.tsx → index.jsdom.test.tsx} +37 -27
- package/src/date-time/time-picker/time-input/test/{index.tsx → index.jsdom.test.tsx} +8 -3
- package/src/disabled/index.tsx +7 -7
- package/src/disabled/test/{index.tsx → index.jsdom.test.tsx} +26 -0
- package/src/draggable/index.tsx +1 -1
- package/src/draggable/style.module.scss +1 -1
- package/src/dropdown/style.module.scss +2 -2
- package/src/dropdown/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/dropdown-menu/test/{index.tsx → index.jsdom.test.tsx} +5 -4
- package/src/duotone-picker/test/{custom-duotone-bar.tsx → custom-duotone-bar.jsdom.test.tsx} +11 -8
- package/src/duotone-picker/test/{index.tsx → index.jsdom.test.tsx} +11 -10
- package/src/external-link/test/{index.tsx → index.jsdom.test.tsx} +5 -4
- package/src/focal-point-picker/test/{index.tsx → index.jsdom.test.tsx} +12 -9
- package/src/focal-point-picker/test/{media.tsx → media.jsdom.test.tsx} +1 -0
- package/src/font-size-picker/test/{font-size-picker-select.tsx → font-size-picker-select.jsdom.test.tsx} +19 -16
- package/src/font-size-picker/test/{font-size-picker-toggle-group.tsx → font-size-picker-toggle-group.jsdom.test.tsx} +13 -11
- package/src/font-size-picker/test/{index.tsx → index.jsdom.test.tsx} +19 -14
- package/src/font-size-picker/test/utils.ts +1 -0
- package/src/form-toggle/style.scss +1 -1
- package/src/form-toggle/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +4 -4
- package/src/form-toggle/test/{index.tsx → index.jsdom.test.tsx} +2 -1
- package/src/form-token-field/index.tsx +1 -1
- package/src/form-token-field/test/{index.tsx → index.jsdom.test.tsx} +86 -44
- package/src/gradient-picker/test/{index.tsx → index.jsdom.test.tsx} +12 -9
- package/src/guide/test/{index.tsx → index.jsdom.test.tsx} +4 -2
- package/src/h-stack/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +4 -4
- package/src/h-stack/test/{index.tsx → index.jsdom.test.tsx} +3 -0
- package/src/higher-order/with-fallback-styles/test/{index.tsx → index.jsdom.test.tsx} +3 -2
- package/src/higher-order/with-filters/test/__snapshots__/index.jsdom.test.tsx.snap +87 -0
- package/src/higher-order/with-filters/test/{index.tsx → index.jsdom.test.tsx} +6 -5
- package/src/higher-order/with-focus-outside/test/{index.tsx → index.jsdom.test.tsx} +2 -1
- package/src/higher-order/with-focus-return/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/higher-order/with-notices/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/higher-order/with-spoken-messages/test/{index.tsx → index.jsdom.test.tsx} +3 -2
- package/src/icon/index.tsx +28 -12
- package/src/icon/test/{index.tsx → index.jsdom.test.tsx} +66 -0
- package/src/input-control/styles/input-control-styles.tsx +38 -7
- package/src/input-control/test/{index.js → index.jsdom.test.tsx} +16 -10
- package/src/isolated-event-container/test/{index.tsx → index.jsdom.test.tsx} +4 -3
- package/src/item-group/context.ts +1 -0
- package/src/item-group/item/component.tsx +19 -1
- package/src/item-group/item/hook.ts +2 -3
- package/src/item-group/item-group/component.tsx +1 -0
- package/src/item-group/style.module.scss +1 -2
- package/src/item-group/test/__snapshots__/{index.js.snap → index.jsdom.test.tsx.snap} +9 -9
- package/src/item-group/test/{index.js → index.jsdom.test.tsx} +99 -2
- package/src/item-group/types.ts +4 -0
- package/src/keyboard-shortcuts/test/{index.tsx → index.jsdom.test.tsx} +5 -4
- package/src/menu/test/{index.tsx → index.jsdom.test.tsx} +67 -23
- package/src/menu-group/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/menu-item/test/__snapshots__/{index.js.snap → index.jsdom.test.tsx.snap} +5 -5
- package/src/menu-item/test/{index.js → index.jsdom.test.tsx} +1 -0
- package/src/modal/test/{aria-helper.ts → aria-helper.jsdom.test.ts} +1 -0
- package/src/modal/test/{index.tsx → index.jsdom.test.tsx} +9 -5
- package/src/navigable-container/test/{navigable-menu.tsx → navigable-menu.jsdom.test.tsx} +7 -5
- package/src/navigable-container/test/{tababble-container.tsx → tababble-container.jsdom.test.tsx} +5 -3
- package/src/navigator/test/{index.tsx → index.jsdom.test.tsx} +5 -2
- package/src/navigator/test/router.ts +1 -0
- package/src/notice/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +7 -4
- package/src/notice/test/{index.tsx → index.jsdom.test.tsx} +8 -4
- package/src/notice/test/{list.tsx → list.jsdom.test.tsx} +1 -0
- package/src/number-control/test/{index.tsx → index.jsdom.test.tsx} +9 -6
- package/src/palette-edit/test/{index.tsx → index.jsdom.test.tsx} +16 -13
- package/src/panel/test/__snapshots__/body.jsdom.test.tsx.snap +9 -0
- package/src/panel/test/__snapshots__/header.jsdom.test.tsx.snap +9 -0
- package/src/panel/test/__snapshots__/index.jsdom.test.tsx.snap +17 -0
- package/src/panel/test/__snapshots__/row.jsdom.test.tsx.snap +17 -0
- package/src/panel/test/{body.tsx → body.jsdom.test.tsx} +2 -1
- package/src/panel/test/{header.tsx → header.jsdom.test.tsx} +1 -0
- package/src/panel/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/panel/test/{row.tsx → row.jsdom.test.tsx} +1 -0
- package/src/placeholder/style.scss +0 -5
- package/src/placeholder/test/{index.tsx → index.jsdom.test.tsx} +19 -14
- package/src/popover/README.md +2 -2
- package/src/popover/test/{index.tsx → index.jsdom.test.tsx} +23 -0
- package/src/popover/types.ts +9 -3
- package/src/progress-bar/style.module.scss +9 -1
- package/src/query-controls/test/terms.ts +1 -0
- package/src/radio-control/test/{index.tsx → index.jsdom.test.tsx} +14 -11
- package/src/range-control/test/{index.tsx → index.jsdom.test.tsx} +10 -7
- package/src/resizable-box/index.tsx +1 -1
- package/src/sandbox/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/scroll-lock/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/shortcut/test/__snapshots__/index.jsdom.test.tsx.snap +15 -0
- package/src/shortcut/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/slot-fill/test/{index.js → index.jsdom.test.tsx} +4 -3
- package/src/slot-fill/test/{slot.js → slot.jsdom.test.tsx} +17 -9
- package/src/snackbar/index.tsx +10 -6
- package/src/snackbar/test/{index.tsx → index.jsdom.test.tsx} +41 -11
- package/src/snackbar/test/list.jsdom.test.tsx +100 -0
- package/src/style-provider/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/surface/style.module.scss +2 -2
- package/src/surface/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/tab-panel/style.scss +4 -23
- package/src/tab-panel/test/{index.tsx → index.jsdom.test.tsx} +22 -21
- package/src/tabs/test/{index.tsx → index.jsdom.test.tsx} +21 -19
- package/src/text-control/test/{text-control.tsx → text-control.jsdom.test.tsx} +1 -0
- package/src/text-highlight/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/textarea-control/style.module.scss +9 -4
- package/src/tip/style.scss +1 -1
- package/src/toggle-control/test/{index.tsx → index.jsdom.test.tsx} +4 -1
- package/src/toggle-group-control/context.ts +14 -5
- package/src/toggle-group-control/stories/index.story.tsx +15 -2
- package/src/toggle-group-control/test/{index.tsx → index.jsdom.test.tsx} +283 -9
- package/src/toggle-group-control/toggle-group-control/README.md +8 -5
- package/src/toggle-group-control/toggle-group-control/as-button-group.tsx +4 -0
- package/src/toggle-group-control/toggle-group-control/as-radio-group.tsx +4 -0
- package/src/toggle-group-control/toggle-group-control/component.tsx +2 -0
- package/src/toggle-group-control/toggle-group-control/style.module.scss +8 -2
- package/src/toggle-group-control/toggle-group-control-option/README.md +8 -5
- package/src/toggle-group-control/toggle-group-control-option/component.tsx +2 -0
- package/src/toggle-group-control/toggle-group-control-option-base/component.tsx +4 -1
- package/src/toggle-group-control/toggle-group-control-option-icon/README.md +7 -0
- package/src/toggle-group-control/toggle-group-control-option-icon/component.tsx +2 -0
- package/src/toggle-group-control/types.ts +12 -3
- package/src/toolbar/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/toolbar/test/{toolbar-group.tsx → toolbar-group.jsdom.test.tsx} +2 -1
- package/src/tools-panel/test/{index.tsx → index.jsdom.test.tsx} +595 -47
- package/src/tools-panel/tools-panel/hook.ts +195 -180
- package/src/tools-panel/tools-panel-item/README.md +42 -1
- package/src/tools-panel/tools-panel-item/hook.ts +97 -69
- package/src/tools-panel/types.ts +54 -9
- package/src/tooltip/test/{index.tsx → index.jsdom.test.tsx} +5 -3
- package/src/tree-grid/cell.tsx +6 -2
- package/src/tree-grid/roving-tab-index-item.tsx +7 -3
- package/src/tree-grid/row.tsx +8 -2
- package/src/tree-grid/test/__snapshots__/{cell.tsx.snap → cell.jsdom.test.tsx.snap} +2 -2
- package/src/tree-grid/test/__snapshots__/index.jsdom.test.tsx.snap +3 -0
- package/src/tree-grid/test/__snapshots__/roving-tab-index-item.jsdom.test.tsx.snap +27 -0
- package/src/tree-grid/test/__snapshots__/roving-tab-index.jsdom.test.tsx.snap +9 -0
- package/src/tree-grid/test/__snapshots__/{row.tsx.snap → row.jsdom.test.tsx.snap} +9 -5
- package/src/tree-grid/test/cell.jsdom.test.tsx +149 -0
- package/src/tree-grid/test/{index.tsx → index.jsdom.test.tsx} +9 -7
- package/src/tree-grid/test/{roving-tab-index-item.tsx → roving-tab-index-item.jsdom.test.tsx} +4 -1
- package/src/tree-grid/test/{roving-tab-index.tsx → roving-tab-index.jsdom.test.tsx} +1 -0
- package/src/tree-grid/test/row.jsdom.test.tsx +132 -0
- package/src/tree-grid/use-validate-tree-grid-structure.ts +104 -0
- package/src/truncate/style.module.scss +0 -1
- package/src/truncate/test/{index.tsx → index.jsdom.test.tsx} +1 -0
- package/src/unit-control/test/{index.tsx → index.jsdom.test.tsx} +22 -19
- package/src/unit-control/test/utils.ts +1 -0
- package/src/utils/colors-values.js +5 -4
- package/src/utils/hooks/test/{use-controlled-state.js → use-controlled-state.jsdom.test.tsx} +22 -7
- package/src/utils/hooks/test/{use-controlled-value.js → use-controlled-value.jsdom.test.tsx} +6 -3
- package/src/utils/hooks/test/{use-cx.js → use-cx.jsdom.test.tsx} +8 -5
- package/src/utils/test/colors.js +1 -0
- package/src/utils/test/{get-node-text.js → get-node-text.tsx} +1 -0
- package/src/utils/test/math.js +1 -0
- package/src/utils/test/rtl.js +1 -0
- package/src/utils/test/space.js +1 -0
- package/src/utils/test/strings.js +1 -0
- package/src/utils/test/unit-values.js +1 -0
- package/src/v-stack/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +4 -4
- package/src/v-stack/test/{index.tsx → index.jsdom.test.tsx} +3 -0
- package/src/validated-form-controls/style.scss +11 -15
- package/src/validated-form-controls/test/{content-editable-control.tsx → content-editable-control.jsdom.test.tsx} +1 -1
- package/src/validated-form-controls/test/{custom-select-control.tsx → custom-select-control.jsdom.test.tsx} +3 -0
- package/src/validated-form-controls/test/{input-control.tsx → input-control.jsdom.test.tsx} +3 -0
- package/src/validated-form-controls/test/{range-control.tsx → range-control.jsdom.test.tsx} +3 -0
- package/src/validated-form-controls/test/{textarea-control.tsx → textarea-control.jsdom.test.tsx} +1 -0
- package/src/view/test/__snapshots__/{index.js.snap → index.jsdom.test.tsx.snap} +7 -7
- package/src/view/test/{index.js → index.jsdom.test.tsx} +7 -2
- package/src/context/test/__snapshots__/context-system-provider.js.snap +0 -35
- package/src/higher-order/with-filters/test/__snapshots__/index.tsx.snap +0 -87
- package/src/panel/test/__snapshots__/body.tsx.snap +0 -9
- package/src/panel/test/__snapshots__/header.tsx.snap +0 -9
- package/src/panel/test/__snapshots__/index.tsx.snap +0 -17
- package/src/panel/test/__snapshots__/row.tsx.snap +0 -17
- package/src/shortcut/test/__snapshots__/index.tsx.snap +0 -15
- package/src/snackbar/test/list.tsx +0 -39
- package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +0 -359
- package/src/tree-grid/test/__snapshots__/index.tsx.snap +0 -3
- package/src/tree-grid/test/__snapshots__/roving-tab-index-item.tsx.snap +0 -27
- package/src/tree-grid/test/__snapshots__/roving-tab-index.tsx.snap +0 -9
- package/src/tree-grid/test/cell.tsx +0 -46
- package/src/tree-grid/test/row.tsx +0 -37
- /package/src/card/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
- /package/src/card/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/color-picker/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/custom-gradient-picker/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/custom-select-control/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
- /package/src/custom-select-control/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/divider/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/elevation/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
- /package/src/elevation/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/flex/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
- /package/src/flex/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/form-file-upload/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/grid/test/{grid.tsx → grid.jsdom.test.tsx} +0 -0
- /package/src/heading/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
- /package/src/heading/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/input-control/test/__snapshots__/{index.js.snap → index.jsdom.test.tsx.snap} +0 -0
- /package/src/progress-bar/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/resizable-box/resize-tooltip/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/resizable-box/resize-tooltip/test/{label.tsx → label.jsdom.test.tsx} +0 -0
- /package/src/scrollable/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/search-control/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/select-control/test/__snapshots__/{select-control.tsx.snap → select-control.jsdom.test.tsx.snap} +0 -0
- /package/src/select-control/test/{select-control.tsx → select-control.jsdom.test.tsx} +0 -0
- /package/src/slot-fill/test/__snapshots__/{slot.js.snap → slot.jsdom.test.tsx.snap} +0 -0
- /package/src/spacer/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
- /package/src/spacer/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/text/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
- /package/src/text/test/{index.tsx → index.jsdom.test.tsx} +0 -0
- /package/src/utils/test/{polymorphic-element.tsx → polymorphic-element.jsdom.test.tsx} +0 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Migrating components from Emotion to SCSS Modules
|
|
2
|
+
|
|
3
|
+
An Emotion migration should preserve the component's public API, rendered elements, interactions, and resulting styles. Use the existing SCSS Modules and `@wordpress/style-runtime` pipeline. A component migration does not require a new CSS extraction pipeline.
|
|
4
|
+
|
|
5
|
+
This temporary guide collects the [migration guidelines in #66806](https://github.com/WordPress/gutenberg/issues/66806) and lessons from its merged PRs. The [reference migrations](#reference-migrations) identify useful examples and their limitations. Read the current implementation before copying an older diff. Some merged PRs include explicitly agreed visual or behavior changes that are not part of a mechanical migration.
|
|
6
|
+
|
|
7
|
+
## Establish the component and consumer contract
|
|
8
|
+
|
|
9
|
+
Before editing, read the component's types, README, stories, style hooks, and composed primitives. Search for consumers of its exported wrappers, style fragments, and public classes, including outside `packages/components`. A shared style file can serve several components, as with `ColorPalette` and `GradientPicker`.
|
|
10
|
+
|
|
11
|
+
Record the behavior that needs comparison:
|
|
12
|
+
|
|
13
|
+
- Default rendered element, supported `as` targets, refs, prop forwarding, and intrinsic HTML/SVG prop filtering.
|
|
14
|
+
- Existing public classes and which element adds each one. `useContextSystem` may already supply the root class. Keep legacy spellings, including singular `component-*` names.
|
|
15
|
+
- Consumer `className` and `style` handling, including spread order and conditional forwarding.
|
|
16
|
+
- Defaults, variants, nested instances, focus and disabled states, directional styles, and animation state changes.
|
|
17
|
+
- Selectors that override the component and selectors the component uses to override its children.
|
|
18
|
+
- Portal and iframe paths, including the document that receives styles.
|
|
19
|
+
|
|
20
|
+
Capture a focused baseline in Storybook or the editor for the states and consumers at risk. If a regression motivates the migration, reproduce it before changing the implementation. An unchanged isolated story cannot establish compatibility for a consumer that adds its own styles.
|
|
21
|
+
|
|
22
|
+
### Replace wrappers without changing their role
|
|
23
|
+
|
|
24
|
+
For `styled( ExistingComponent )`, apply the module class to that same component when it already supplies the needed behavior. Do not replace `Flex`, `Heading`, `Text`, or an input control with a native element just because its wrapper only contained CSS.
|
|
25
|
+
|
|
26
|
+
For a wrapper that relied directly on Emotion's `as` support, inspect and reuse [`PolymorphicElement`](/packages/components/src/utils/polymorphic-element.tsx). Preserve the original default tag and the component's existing ref and prop contract. `View` already delegates to this utility. A fixed internal element with no exposed polymorphic path can remain a plain element.
|
|
27
|
+
|
|
28
|
+
Check the current [`WordPressComponent` types](/packages/components/src/context/wordpress-component.ts) instead of introducing another polymorphic type system. [#80705](https://github.com/WordPress/gutenberg/pull/80705) deliberately reduced intrinsic-prop type complexity to control compilation cost. Removing Emotion does not remove the compatibility obligation for `as`.
|
|
29
|
+
|
|
30
|
+
Keep shared wrappers' private module classes separate from public classes added by callers. In [#80001](https://github.com/WordPress/gutenberg/pull/80001), adding BaseControl label/help classes inside shared wrappers made unrelated consumers match BaseControl selectors; adding classes on both sides also produced duplicates. Test a real `as="legend"` consumer when migrating shared labels, including its visible and visually hidden branches.
|
|
31
|
+
|
|
32
|
+
`View`'s legacy `css` prop is an explicit exception established by [#79443](https://github.com/WordPress/gutenberg/pull/79443). It remains accepted as a no-op and is consumed before rendering. Do not restore its styling behavior, forward it to the DOM, or treat that decision as permission to remove other props.
|
|
33
|
+
|
|
34
|
+
## Translate the styles
|
|
35
|
+
|
|
36
|
+
Follow the package's [styling conventions](/packages/components/CONTRIBUTING.md#styling). Put static declarations in a colocated `style.module.scss`, use kebab-case classes, and compose variants with `clsx`. Use existing semantic attributes and pseudo-classes where appropriate; do not add data attributes solely to select styles.
|
|
37
|
+
|
|
38
|
+
Name modifier classes for their state and make their owning element clear. When scoping a modifier under a base class, account for the extra specificity. A standalone `.is-active` and `.root.is-active` do not have equal specificity.
|
|
39
|
+
|
|
40
|
+
Keep fixed values and calculations in Sass when JavaScript does not need them. `ProgressBar` moved its constant indeterminate indicator width into Sass and shared it with the keyframes. CSS Module keyframes can have descriptive local names without component prefixes.
|
|
41
|
+
|
|
42
|
+
### Preserve dynamic values and overrides
|
|
43
|
+
|
|
44
|
+
Prefer inline custom properties for genuinely dynamic values, with the actual property declared in the stylesheet. Emotion adds units to many numeric CSS values; custom properties do not. Preserve the original conversion, such as `space( value )` or an explicit `px` suffix, and keep zero distinct from an absent value.
|
|
45
|
+
|
|
46
|
+
Check these differences before choosing the representation:
|
|
47
|
+
|
|
48
|
+
- **Cascade.** Moving `z-index` from a CSS rule to `style.zIndex` prevents ordinary consumer CSS from overriding it. [ZStack's review](https://github.com/WordPress/gutenberg/pull/80514#discussion_r3845479235) led to passing the number through a custom property and keeping `z-index` in the module rule.
|
|
49
|
+
- **Precedence.** Preserve consumer `style` values and the component's existing override rules. Do not copy a universal spread order from another migration. `Spacer` lets consumer custom properties win; `Flex` supplies its internal variables after the consumer style object. Ordinary inline CSS properties still override stylesheet declarations.
|
|
50
|
+
- **Inheritance.** Internal custom properties inherit unless reset. Reset them on each instance when nested components must not inherit a parent's values, as in `Spacer`. Do not reset intentionally inherited theme variables.
|
|
51
|
+
- **Shorthands.** A later longhand with an absent custom property can undo the shorthand result. Preserve the fallback and precedence of all-sides, axis, and individual-side values. Check shorthand-only, longhand-only, and combined inputs, including supported CSS strings. The `Spacer` review caught missing longhand fallbacks.
|
|
52
|
+
- **Accepted CSS values.** CSS-wide keywords apply to a custom property itself. `--style: inherit; border-style: var(--style, solid)` does not mean `border-style: inherit`. In [#80437](https://github.com/WordPress/gutenberg/pull/80437#discussion_r3608442254), the indicator retained direct `borderStyle` and `borderColor` values and the original `color || fallback` behavior. Check empty strings and CSS-wide values when the API accepts arbitrary CSS. Direct inline properties can be appropriate, but assess their effect on consumer overrides explicitly.
|
|
53
|
+
|
|
54
|
+
### Preserve direction, tokens, and state changes
|
|
55
|
+
|
|
56
|
+
Use logical properties where they preserve the intended behavior. Compare LTR and RTL, and relevant writing modes, before changing a physical property. `Surface` exposes physical border props; `TextareaControl` retains `resize: vertical`; `DropdownContentWrapper` offsets the Popover's physical padding. These are reasons for narrow lint suppressions, not a blanket ban on logical properties. `padding: 0` also resets more than `padding-inline: 0`.
|
|
57
|
+
|
|
58
|
+
Preserve necessary browser declarations and pseudo-elements. Examples include Truncate's `-webkit-box-orient: vertical`, SearchControl's WebKit search decorations, and TextareaControl's placeholder selectors and global dark-theme ancestor.
|
|
59
|
+
|
|
60
|
+
Prefer equivalent WPDS tokens and existing Sass variables or mixins. Check what they expand to, including fallback values and validated-control accent overrides. A similarly named token can change the color or geometry. Keep intentional visual changes explicit, as in `Surface` and `ToggleGroupControl`, instead of presenting them as style parity.
|
|
61
|
+
|
|
62
|
+
Compare transitions between states as well as static states. [ProgressBar's review](https://github.com/WordPress/gutenberg/pull/80512#discussion_r3830324726) caught a width transition newly applying when switching to indeterminate mode. Preserve the original animation direction, duration, transition conditions, reduced-motion rules, and forced-colors treatment where present.
|
|
63
|
+
|
|
64
|
+
## Preserve the winning declarations
|
|
65
|
+
|
|
66
|
+
CSS Module scoping prevents class-name collisions. It does not control specificity or stylesheet insertion order. The order of class names passed to `clsx` does not control the cascade either.
|
|
67
|
+
|
|
68
|
+
Compare matched declarations on the component and its consumers:
|
|
69
|
+
|
|
70
|
+
- Keep low-specificity defaults overridable. The Divider migration added attribute-selector specificity and broke `CardDivider` and complementary-area border overrides. [#79534](https://github.com/WordPress/gutenberg/pull/79534) wrapped orientation attributes in `:where()` to remove that extra specificity.
|
|
71
|
+
- Preserve deliberate Emotion `&&` or `&&&` increases. Sass can express these as `.wrapper.wrapper` or `.label.label.label`; raw `&&&` is not valid Dart Sass. ConfirmDialog's doubled selector keeps its overlay above the parent Popover.
|
|
72
|
+
- Protect every declaration that must beat a still-Emotion-based primitive. ColorPalette initially protected `font-size` and margin but missed `line-height`; Heading's later rule won in the root document. ToolsPanel had a similar heading conflict.
|
|
73
|
+
- Keep selector relationships and scope. Nesting `.layered > .child` under `.z-stack` adds specificity. Replacing Emotion component interpolation requires checking which real elements the new selector matches.
|
|
74
|
+
- Mark existing external classes with `:global(...)` inside a CSS Module, for example `:global(.components-panel__row) &`. Do not accidentally hash a legacy class, broaden its matching elements, or add a public class solely to replace an internal selector.
|
|
75
|
+
|
|
76
|
+
Use the smallest selector change that preserves the required winner. Do not put every rule in `:where()`, increase every selector, or add `!important` to hide an unexplained conflict. Record why a deliberate specificity adjustment is needed.
|
|
77
|
+
|
|
78
|
+
### Audit remaining Emotion consumers
|
|
79
|
+
|
|
80
|
+
Removing an Emotion wrapper can expose source-order dependencies in callers that still use `useCx`. Where fragments overlap on a property, shorthand/longhand pair, or nested selector, compose them in one `css()` call before passing them to `cx()`:
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
const classes = cx(
|
|
84
|
+
css( baseStyles, condition && overrideStyles ),
|
|
85
|
+
className
|
|
86
|
+
);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This is an interim compatibility fix for existing Emotion consumers, not a pattern for newly migrated styles. Do not mechanically combine unrelated fragments. Audit callers outside the migrated directory: [#79443](https://github.com/WordPress/gutenberg/pull/79443) updated several consumers but missed the BorderBoxControl gutter regression fixed in [#79967](https://github.com/WordPress/gutenberg/pull/79967).
|
|
90
|
+
|
|
91
|
+
Test mixed Emotion/Module composition in both the root and iframe documents when used there. [Scrollable's review](https://github.com/WordPress/gutenberg/pull/80694#discussion_r3845389532) found that `CardBody isScrollable` kept `height: 100%` in an iframe but resolved to `auto` in the root document because insertion order differed.
|
|
92
|
+
|
|
93
|
+
## Verify CSS delivery and behavior
|
|
94
|
+
|
|
95
|
+
Reuse existing tests and stories first. Add or extend a test only for a concrete migration risk that existing coverage does not protect. Choose the smallest check that observes the behavior and would fail if it regressed. A behavior-preserving migration may need no new tests. When automated tests cannot observe the real styling path, document a focused before/after browser check instead of adding a test that cannot detect the regression.
|
|
96
|
+
|
|
97
|
+
[`StyleProvider`](/packages/components/src/style-provider/index.tsx) both supplies an Emotion cache and registers a document with `@wordpress/style-runtime`. Keep the relevant provider and registration path while either responsibility is needed. Removing a component's Emotion import does not make this infrastructure redundant.
|
|
98
|
+
|
|
99
|
+
For SlotFill or portals, use an attached iframe with a real `contentDocument` and `defaultView`. Assert a computed style in the destination document. A class on the element or a style tag in the parent document does not prove delivery. [#80384](https://github.com/WordPress/gutenberg/pull/80384) pairs a registration test with a Storybook example that renders migrated Spacer styles in an iframe.
|
|
100
|
+
|
|
101
|
+
Match the evidence to the behavior at risk:
|
|
102
|
+
|
|
103
|
+
| What needs proof | Suitable evidence |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| DOM, public classes, refs, props, variants, and interactions | Existing component tests; extend them only for an uncovered integration risk. Assert the actual styled node, including the outer Grid child when an inner wrapper has the same class. |
|
|
106
|
+
| Real SCSS declarations, specificity, custom-property resolution, dimensions, and animation | Storybook or editor comparison using production styles, computed styles, and relevant interactions. Include a consumer override and the affected document/RTL states. |
|
|
107
|
+
| Cross-document registration or a particular mixed-style composition mechanism | Reuse shared registration coverage. Add a component-specific test only for an uncovered registration or composition risk. A small fixture stylesheet can test that mechanism; pair it with a real-style check. |
|
|
108
|
+
|
|
109
|
+
Jest mocks stylesheet imports. Public-class assertions can protect a compatibility contract; private module-class assertions establish wiring only. Neither proves that the real CSS loads or wins. Do not add class assertions or snapshots solely to mirror the implementation. Do not inject the desired production selector into a test and claim it protects that selector: the test would still pass if the SCSS rule were deleted. This distinction led to removing tests in [#81792](https://github.com/WordPress/gutenberg/pull/81792#discussion_r3811746653).
|
|
110
|
+
|
|
111
|
+
Keep new tests focused on the migrated component's integration. A wrapper test can protect its `as`, ref, or prop forwarding even when the shared helper is already tested. Do not copy PolymorphicElement's entire filtering suite into every wrapper, duplicate a full editor setup for a small assertion, or introduce a new Storybook testing convention just for the migration. Check the relevant states and combinations from the contract audit; do not generate every prop combination or supported tag. When a real-style assertion is unavailable, state the gap and give reproducible manual steps.
|
|
112
|
+
|
|
113
|
+
## Complete the migration
|
|
114
|
+
|
|
115
|
+
Remove obsolete Emotion imports, files, lint/type suppressions, and utilities that become unused because of this migration. Search all consumers before deleting shared constants. Preserve useful comments explaining layout calculations or compatibility workarounds. Leave unrelated cleanup and global Emotion dependencies, Babel wiring, serializers, `useCx`, and the `rtl` utility until their remaining users are gone.
|
|
116
|
+
|
|
117
|
+
Follow [worktree setup](/docs/contributors/code/getting-started-with-code-contribution.md#set-up-each-worktree) and read the [testing overview](/docs/contributors/code/testing-overview.md) before adding tests. New tests use Vitest; the [migration manifest](/test/unit/test-migration.json) identifies legacy tests still owned by Jest. From the repository root, use the appropriate focused command below, then run lint and the repository gates:
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
npm run test:unit -- <legacy-jest-test-path> --runInBand
|
|
121
|
+
npm run test:unit:vitest -- <vitest-test-path>
|
|
122
|
+
npm run lint:js -- <changed-js-files>
|
|
123
|
+
npm run lint:css
|
|
124
|
+
npm run typecheck
|
|
125
|
+
npm run build
|
|
126
|
+
npm run test:unit:update
|
|
127
|
+
npm run test:unit:vitest:update
|
|
128
|
+
git diff --check
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The snapshot updates are for the whole repository because downstream consumers can change. Jest and Vitest own separate suites, so neither command covers both. Review every snapshot change for removed or duplicated public classes, changed elements, forwarded props, and consumer output. Do not accept a snapshot solely because Emotion classes disappeared. Rerun the exact failing file or shard before attributing a broad failure to the migration.
|
|
132
|
+
|
|
133
|
+
For generated-file verification, start from a clean committed worktree and run the applicable generators and suppression updates. `npm run other:check-local-changes` runs the documentation and theme generators through its npm prehook, then checks the unstaged diff. It does not run every generator or suppression update; consult the current [static-checks workflow](/.github/workflows/static-checks.yml) for those required by the migration. Inspect generated changes before staging them, since staged changes are invisible to the checker. Commit required updates, then repeat the applicable generation and check commands from the clean worktree.
|
|
134
|
+
|
|
135
|
+
Recheck the final selectors and consumers after the last edit or rebase; a previous visual check does not cover a later specificity change. Preserve newer trunk changes, such as focus-ring updates, when moving declarations out of an old style file.
|
|
136
|
+
|
|
137
|
+
Follow [package changelog guidance](/docs/contributors/code/managing-packages.md). For production migrations, use the current unreleased section and this PR's link. The merged migrations record the `cx()` composition limitation under **Breaking Changes**, even when normal component usage is visually unchanged. Do not copy an early pilot's `Internal` entry as the only release note. Record any separately agreed behavior change and its verification independently, as #80715 did for Reset focus retention.
|
|
138
|
+
|
|
139
|
+
## Reference migrations
|
|
140
|
+
|
|
141
|
+
Choose an example for the risk in the current migration, then check it against current source. The full migration history is maintained in [#66806](https://github.com/WordPress/gutenberg/issues/66806).
|
|
142
|
+
|
|
143
|
+
| Migration risk | Merged example | What to inspect |
|
|
144
|
+
| --- | --- | --- |
|
|
145
|
+
| Polymorphic wrappers | View, [#79443](https://github.com/WordPress/gutenberg/pull/79443) | Shared polymorphic replacement, legacy `css` no-op, and downstream consumers. |
|
|
146
|
+
| Dynamic spacing | Spacer, [#79449](https://github.com/WordPress/gutenberg/pull/79449) | Nested custom-property resets and shorthand/longhand fallback. |
|
|
147
|
+
| Selector specificity | Divider, [#79444](https://github.com/WordPress/gutenberg/pull/79444), and [#79534](https://github.com/WordPress/gutenberg/pull/79534) | Orientation selectors and the correction that restored consumer overrides. |
|
|
148
|
+
| Mixed Emotion composition | Border controls, [#80437](https://github.com/WordPress/gutenberg/pull/80437) | Overrides, CSS-wide values, and the linked-control gutter. |
|
|
149
|
+
| Root and iframe delivery | Scrollable, [#80694](https://github.com/WordPress/gutenberg/pull/80694) | CardBody height and stylesheet insertion order in each document. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/components",
|
|
3
|
-
"version": "40.
|
|
3
|
+
"version": "40.1.0",
|
|
4
4
|
"description": "UI components for WordPress.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -62,27 +62,27 @@
|
|
|
62
62
|
"@types/gradient-parser": "^1.1.0",
|
|
63
63
|
"@types/highlight-words-core": "^1.2.1",
|
|
64
64
|
"@use-gesture/react": "^10.3.1",
|
|
65
|
-
"@wordpress/a11y": "^4.
|
|
66
|
-
"@wordpress/base-styles": "^13.
|
|
67
|
-
"@wordpress/compose": "^8.
|
|
68
|
-
"@wordpress/date": "^5.
|
|
69
|
-
"@wordpress/deprecated": "^4.
|
|
70
|
-
"@wordpress/dom": "^4.
|
|
71
|
-
"@wordpress/element": "^8.
|
|
72
|
-
"@wordpress/escape-html": "^3.
|
|
73
|
-
"@wordpress/hooks": "^4.
|
|
74
|
-
"@wordpress/html-entities": "^4.
|
|
75
|
-
"@wordpress/i18n": "^6.
|
|
76
|
-
"@wordpress/icons": "^
|
|
77
|
-
"@wordpress/is-shallow-equal": "^5.
|
|
78
|
-
"@wordpress/kebab-case": "^1.
|
|
79
|
-
"@wordpress/keycodes": "^4.
|
|
80
|
-
"@wordpress/primitives": "^4.
|
|
81
|
-
"@wordpress/private-apis": "^1.
|
|
82
|
-
"@wordpress/rich-text": "^7.
|
|
83
|
-
"@wordpress/style-runtime": "^0.
|
|
84
|
-
"@wordpress/ui": "^0.
|
|
85
|
-
"@wordpress/warning": "^3.
|
|
65
|
+
"@wordpress/a11y": "^4.55.0",
|
|
66
|
+
"@wordpress/base-styles": "^13.1.0",
|
|
67
|
+
"@wordpress/compose": "^8.8.0",
|
|
68
|
+
"@wordpress/date": "^5.55.0",
|
|
69
|
+
"@wordpress/deprecated": "^4.55.0",
|
|
70
|
+
"@wordpress/dom": "^4.55.0",
|
|
71
|
+
"@wordpress/element": "^8.7.0",
|
|
72
|
+
"@wordpress/escape-html": "^3.55.0",
|
|
73
|
+
"@wordpress/hooks": "^4.55.0",
|
|
74
|
+
"@wordpress/html-entities": "^4.55.0",
|
|
75
|
+
"@wordpress/i18n": "^6.28.0",
|
|
76
|
+
"@wordpress/icons": "^16.0.0",
|
|
77
|
+
"@wordpress/is-shallow-equal": "^5.55.0",
|
|
78
|
+
"@wordpress/kebab-case": "^1.2.0",
|
|
79
|
+
"@wordpress/keycodes": "^4.55.0",
|
|
80
|
+
"@wordpress/primitives": "^4.55.0",
|
|
81
|
+
"@wordpress/private-apis": "^1.55.0",
|
|
82
|
+
"@wordpress/rich-text": "^7.55.0",
|
|
83
|
+
"@wordpress/style-runtime": "^0.11.0",
|
|
84
|
+
"@wordpress/ui": "^0.22.0",
|
|
85
|
+
"@wordpress/warning": "^3.55.0",
|
|
86
86
|
"change-case": "^4.1.2",
|
|
87
87
|
"clsx": "^2.1.1",
|
|
88
88
|
"colord": "^2.9.3",
|
|
@@ -106,16 +106,17 @@
|
|
|
106
106
|
"@storybook/addon-docs": "^10.5.3",
|
|
107
107
|
"@storybook/react-vite": "^10.5.3",
|
|
108
108
|
"@testing-library/dom": "^10.4.1",
|
|
109
|
-
"@testing-library/jest-dom": "^
|
|
110
|
-
"@testing-library/react": "^16.3.
|
|
109
|
+
"@testing-library/jest-dom": "^7.0.1",
|
|
110
|
+
"@testing-library/react": "^16.3.3",
|
|
111
111
|
"@testing-library/user-event": "^14.6.1",
|
|
112
112
|
"@types/jest": "^30.0.0",
|
|
113
113
|
"@types/react-dom": "^18.3.1",
|
|
114
|
-
"@wordpress/jest-console": "^9.
|
|
114
|
+
"@wordpress/jest-console": "^9.3.0",
|
|
115
115
|
"@wordpress/stylelint-tools": "file:../../tools/stylelint",
|
|
116
116
|
"snapshot-diff": "^0.10.0",
|
|
117
117
|
"storybook": "^10.5.3",
|
|
118
|
-
"timezone-mock": "^1.3.6"
|
|
118
|
+
"timezone-mock": "^1.3.6",
|
|
119
|
+
"vitest": "^5.0.0"
|
|
119
120
|
},
|
|
120
121
|
"peerDependencies": {
|
|
121
122
|
"@types/react": "^18 || ^19",
|
|
@@ -130,5 +131,5 @@
|
|
|
130
131
|
"publishConfig": {
|
|
131
132
|
"access": "public"
|
|
132
133
|
},
|
|
133
|
-
"gitHead": "
|
|
134
|
+
"gitHead": "485f42ae8a1c58ceea18371a507fd4acfa86fbd8"
|
|
134
135
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
1
2
|
import { render, screen, waitFor, within } from '@testing-library/react';
|
|
2
3
|
import { press, click } from '@ariakit/test';
|
|
3
4
|
import AlignmentMatrixControl from '..';
|
|
@@ -51,7 +52,7 @@ describe( 'AlignmentMatrixControl', () => {
|
|
|
51
52
|
'bottom center',
|
|
52
53
|
'bottom right',
|
|
53
54
|
] )( '%s', async ( alignment ) => {
|
|
54
|
-
const spy =
|
|
55
|
+
const spy = vi.fn();
|
|
55
56
|
|
|
56
57
|
await renderAndInitCompositeStore(
|
|
57
58
|
<AlignmentMatrixControl
|
|
@@ -69,7 +70,7 @@ describe( 'AlignmentMatrixControl', () => {
|
|
|
69
70
|
} );
|
|
70
71
|
|
|
71
72
|
it( 'unless already focused', async () => {
|
|
72
|
-
const spy =
|
|
73
|
+
const spy = vi.fn();
|
|
73
74
|
|
|
74
75
|
await renderAndInitCompositeStore(
|
|
75
76
|
<AlignmentMatrixControl
|
|
@@ -96,7 +97,7 @@ describe( 'AlignmentMatrixControl', () => {
|
|
|
96
97
|
[ 'ArrowDown', 'bottom center' ],
|
|
97
98
|
[ 'ArrowRight', 'center right' ],
|
|
98
99
|
] as const )( '%s', async ( keyRef, cellRef ) => {
|
|
99
|
-
const spy =
|
|
100
|
+
const spy = vi.fn();
|
|
100
101
|
|
|
101
102
|
await renderAndInitCompositeStore(
|
|
102
103
|
<AlignmentMatrixControl onChange={ spy } />
|
|
@@ -117,7 +118,7 @@ describe( 'AlignmentMatrixControl', () => {
|
|
|
117
118
|
[ 'ArrowDown', 'bottom right' ],
|
|
118
119
|
[ 'ArrowRight', 'bottom right' ],
|
|
119
120
|
] as const )( '%s', async ( keyRef, cellRef ) => {
|
|
120
|
-
const spy =
|
|
121
|
+
const spy = vi.fn();
|
|
121
122
|
|
|
122
123
|
await renderAndInitCompositeStore(
|
|
123
124
|
<AlignmentMatrixControl onChange={ spy } />
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
border-radius: $radius-round;
|
|
32
32
|
box-sizing: border-box;
|
|
33
33
|
display: block;
|
|
34
|
-
/* stylelint-disable-next-line
|
|
34
|
+
/* stylelint-disable-next-line logical-css/require-logical-properties -- Geometric centering */
|
|
35
35
|
left: 50%;
|
|
36
36
|
top: 4px;
|
|
37
37
|
transform: translateX(-50%);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
1
2
|
import { getAutocompleteMatch } from '../get-autocomplete-match';
|
|
2
3
|
import type { WPCompleter } from '../types';
|
|
3
4
|
|
|
@@ -174,7 +175,7 @@ describe( 'getAutocompleteMatch', () => {
|
|
|
174
175
|
} );
|
|
175
176
|
|
|
176
177
|
it( 'should pass correct before/after text to allowContext', () => {
|
|
177
|
-
const allowContext =
|
|
178
|
+
const allowContext = vi.fn().mockReturnValue( true );
|
|
178
179
|
const completers = [
|
|
179
180
|
createCompleter( {
|
|
180
181
|
triggerPrefix: '@',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
1
2
|
import { render, screen, renderHook } from '@testing-library/react';
|
|
2
3
|
import userEvent from '@testing-library/user-event';
|
|
3
4
|
import { useRef } from '@wordpress/element';
|
|
@@ -119,7 +120,7 @@ describe( 'AutocompleterUI', () => {
|
|
|
119
120
|
it( 'should call reset function when a click on another element occurs', async () => {
|
|
120
121
|
const user = userEvent.setup();
|
|
121
122
|
|
|
122
|
-
const resetSpy =
|
|
123
|
+
const resetSpy = vi.fn();
|
|
123
124
|
|
|
124
125
|
const autocompleter = {
|
|
125
126
|
name: 'fruit',
|
|
@@ -19,9 +19,9 @@ const meta: Meta< typeof BaseControl > = {
|
|
|
19
19
|
controls: { expanded: true },
|
|
20
20
|
docs: { canvas: { sourceState: 'shown' } },
|
|
21
21
|
componentStatus: {
|
|
22
|
-
status: 'recommended',
|
|
22
|
+
status: 'not-recommended',
|
|
23
23
|
whereUsed: 'global',
|
|
24
|
-
notes: '`
|
|
24
|
+
notes: 'Use [`Field`](?path=/docs/design-system-components-form-primitives-field--docs) from `@wordpress/ui` instead. For a purely visual label outside `Field.Root`, use `Field.VisualLabel`. For a group legend, use [`Fieldset`](?path=/docs/design-system-components-form-primitives-fieldset--docs) and `Fieldset.Legend`.',
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
27
|
};
|
|
@@ -103,7 +103,9 @@ Provides control over whether the label will only be visible to screen readers.
|
|
|
103
103
|
|
|
104
104
|
### `label`: `string`
|
|
105
105
|
|
|
106
|
-
If provided, a label will be generated using this as the content.
|
|
106
|
+
If provided, a label will be generated using this as the content. A visible
|
|
107
|
+
label is rendered in a row alongside the linked/unlinked toggle; when there is
|
|
108
|
+
no visible label the toggle is rendered beside the border inputs instead.
|
|
107
109
|
|
|
108
110
|
_Whether it is visible only to screen readers is controlled via
|
|
109
111
|
`hideLabelFromVision`._
|
|
@@ -130,9 +132,9 @@ The available base placements are 'top', 'right', 'bottom', 'left'. Each of thes
|
|
|
130
132
|
|
|
131
133
|
- Required: No
|
|
132
134
|
|
|
133
|
-
### `popoverOffset`: `number`
|
|
135
|
+
### `popoverOffset`: `number | { mainAxis?: number; crossAxis?: number }`
|
|
134
136
|
|
|
135
|
-
The space between the popover and the control wrapper.
|
|
137
|
+
The space between the popover and the control wrapper. A number displaces the popover along its main axis; pass an object to also displace it along its cross axis.
|
|
136
138
|
|
|
137
139
|
- Required: No
|
|
138
140
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { __ } from '@wordpress/i18n';
|
|
2
2
|
import { useMemo, useState } from '@wordpress/element';
|
|
3
|
-
import { useMergeRefs } from '@wordpress/compose';
|
|
3
|
+
import { useInstanceId, useMergeRefs } from '@wordpress/compose';
|
|
4
4
|
import BorderBoxControlLinkedButton from '../border-box-control-linked-button';
|
|
5
5
|
import BorderBoxControlSplitControls from '../border-box-control-split-controls';
|
|
6
6
|
import { BorderControl } from '../../border-control';
|
|
7
|
-
import
|
|
7
|
+
import BaseControl from '../../base-control';
|
|
8
|
+
import { Grid } from '../../grid';
|
|
8
9
|
import { View } from '../../view';
|
|
9
10
|
import { VisuallyHidden } from '../../visually-hidden';
|
|
10
11
|
import type { WordPressComponentProps } from '../../context';
|
|
@@ -16,17 +17,22 @@ import type {
|
|
|
16
17
|
BorderControlProps,
|
|
17
18
|
} from '../../border-control/types';
|
|
18
19
|
|
|
19
|
-
const BorderLabel = ( props: LabelProps ) => {
|
|
20
|
-
const { label, hideLabelFromVision } = props;
|
|
20
|
+
const BorderLabel = ( props: LabelProps & { id?: string } ) => {
|
|
21
|
+
const { id, label, hideLabelFromVision } = props;
|
|
21
22
|
|
|
22
23
|
if ( ! label ) {
|
|
23
24
|
return null;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
// The visible label is rendered as `BaseControl.VisualLabel` so it carries
|
|
28
|
+
// the stable `.components-base-control__label` className consumers style
|
|
29
|
+
// against; `StyledLabel` is an emotion component with a generated one.
|
|
26
30
|
return hideLabelFromVision ? (
|
|
27
|
-
<VisuallyHidden as="
|
|
31
|
+
<VisuallyHidden as="span" id={ id }>
|
|
32
|
+
{ label }
|
|
33
|
+
</VisuallyHidden>
|
|
28
34
|
) : (
|
|
29
|
-
<
|
|
35
|
+
<BaseControl.VisualLabel id={ id }>{ label }</BaseControl.VisualLabel>
|
|
30
36
|
);
|
|
31
37
|
};
|
|
32
38
|
|
|
@@ -42,6 +48,8 @@ const UnconnectedBorderBoxControl = (
|
|
|
42
48
|
enableAlpha,
|
|
43
49
|
enableStyle,
|
|
44
50
|
hasMixedBorders,
|
|
51
|
+
hasVisibleLabel,
|
|
52
|
+
headerClassName,
|
|
45
53
|
hideLabelFromVision,
|
|
46
54
|
isLinked,
|
|
47
55
|
label,
|
|
@@ -55,9 +63,27 @@ const UnconnectedBorderBoxControl = (
|
|
|
55
63
|
toggleLinked,
|
|
56
64
|
wrapperClassName,
|
|
57
65
|
__experimentalIsRenderedInSidebar,
|
|
66
|
+
'aria-label': ariaLabel,
|
|
67
|
+
'aria-labelledby': ariaLabelledBy,
|
|
58
68
|
...otherProps
|
|
59
69
|
} = useBorderBoxControl( props );
|
|
60
70
|
|
|
71
|
+
// The label names the group of border controls rather than a single input,
|
|
72
|
+
// so it is associated via `aria-labelledby` instead of `htmlFor`.
|
|
73
|
+
const generatedLabelId = useInstanceId(
|
|
74
|
+
BorderBoxControl,
|
|
75
|
+
'border-box-control-label'
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// A consumer-provided accessible name takes precedence, so the generated
|
|
79
|
+
// relationship is only used as a fallback. Where an external name wins,
|
|
80
|
+
// the unused ID is left off the internal label. Empty values are treated
|
|
81
|
+
// as absent, matching the accessible name computation, which skips an
|
|
82
|
+
// empty `aria-label` or `aria-labelledby` rather than resolving a name
|
|
83
|
+
// from it.
|
|
84
|
+
const labelId =
|
|
85
|
+
label && ! ariaLabel && ! ariaLabelledBy ? generatedLabelId : undefined;
|
|
86
|
+
|
|
61
87
|
// Use internal state instead of a ref to make sure that the component
|
|
62
88
|
// re-renders when the popover's anchor updates.
|
|
63
89
|
const [ popoverAnchor, setPopoverAnchor ] = useState< Element | null >(
|
|
@@ -80,12 +106,46 @@ const UnconnectedBorderBoxControl = (
|
|
|
80
106
|
);
|
|
81
107
|
|
|
82
108
|
const mergedRef = useMergeRefs( [ setPopoverAnchor, forwardedRef ] );
|
|
109
|
+
|
|
83
110
|
return (
|
|
84
|
-
<View
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
111
|
+
<View
|
|
112
|
+
className={ className }
|
|
113
|
+
// Whichever naming source wins, it describes the border controls
|
|
114
|
+
// as a whole, so the wrapper needs a role for that accessible
|
|
115
|
+
// name to attach to. Without a name there is no group to expose.
|
|
116
|
+
role={ label || ariaLabel || ariaLabelledBy ? 'group' : undefined }
|
|
117
|
+
aria-label={ ariaLabel }
|
|
118
|
+
aria-labelledby={ ariaLabelledBy ?? labelId }
|
|
119
|
+
{ ...otherProps }
|
|
120
|
+
ref={ mergedRef }
|
|
121
|
+
>
|
|
122
|
+
{ hasVisibleLabel ? (
|
|
123
|
+
// The toggle shares the label's row so that it lines up with
|
|
124
|
+
// the equivalent toggle on sibling controls, e.g. the border
|
|
125
|
+
// radius one.
|
|
126
|
+
<Grid
|
|
127
|
+
className={ headerClassName }
|
|
128
|
+
columns={ 2 }
|
|
129
|
+
templateColumns="1fr min-content"
|
|
130
|
+
alignment="center"
|
|
131
|
+
>
|
|
132
|
+
<BorderLabel
|
|
133
|
+
id={ labelId }
|
|
134
|
+
label={ label }
|
|
135
|
+
hideLabelFromVision={ hideLabelFromVision }
|
|
136
|
+
/>
|
|
137
|
+
<BorderBoxControlLinkedButton
|
|
138
|
+
onClick={ toggleLinked }
|
|
139
|
+
isLinked={ isLinked }
|
|
140
|
+
/>
|
|
141
|
+
</Grid>
|
|
142
|
+
) : (
|
|
143
|
+
<BorderLabel
|
|
144
|
+
id={ labelId }
|
|
145
|
+
label={ label }
|
|
146
|
+
hideLabelFromVision={ hideLabelFromVision }
|
|
147
|
+
/>
|
|
148
|
+
) }
|
|
89
149
|
<View className={ wrapperClassName }>
|
|
90
150
|
{ isLinked ? (
|
|
91
151
|
<BorderControl
|
|
@@ -123,10 +183,14 @@ const UnconnectedBorderBoxControl = (
|
|
|
123
183
|
}
|
|
124
184
|
/>
|
|
125
185
|
) }
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
186
|
+
{ /* With no label row to join, the toggle sits alongside the
|
|
187
|
+
inputs instead. */ }
|
|
188
|
+
{ ! hasVisibleLabel && (
|
|
189
|
+
<BorderBoxControlLinkedButton
|
|
190
|
+
onClick={ toggleLinked }
|
|
191
|
+
isLinked={ isLinked }
|
|
192
|
+
/>
|
|
193
|
+
) }
|
|
130
194
|
</View>
|
|
131
195
|
</View>
|
|
132
196
|
);
|
|
@@ -136,6 +200,10 @@ const UnconnectedBorderBoxControl = (
|
|
|
136
200
|
* An input control for the color, style, and width of the border of a box. The
|
|
137
201
|
* border can be customized as a whole, or individually for each side of the box.
|
|
138
202
|
*
|
|
203
|
+
* The controls are exposed as a group named by the `label` prop. Passing
|
|
204
|
+
* `aria-labelledby` or `aria-label` names the group instead, taking precedence
|
|
205
|
+
* over `label`; with none of the three, the wrapper is not exposed as a group.
|
|
206
|
+
*
|
|
139
207
|
* ```jsx
|
|
140
208
|
* import { BorderBoxControl } from '@wordpress/components';
|
|
141
209
|
* import { __ } from '@wordpress/i18n';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
1
2
|
import { useState } from '@wordpress/element';
|
|
2
3
|
import styles from '../style.module.scss';
|
|
3
4
|
import {
|
|
@@ -23,6 +24,8 @@ export function useBorderBoxControl(
|
|
|
23
24
|
onChange,
|
|
24
25
|
enableAlpha = false,
|
|
25
26
|
enableStyle = true,
|
|
27
|
+
hideLabelFromVision,
|
|
28
|
+
label,
|
|
26
29
|
value,
|
|
27
30
|
__experimentalIsRenderedInSidebar = false,
|
|
28
31
|
// Deprecated props, no longer used.
|
|
@@ -31,6 +34,11 @@ export function useBorderBoxControl(
|
|
|
31
34
|
...otherProps
|
|
32
35
|
} = useContextSystem( props, 'BorderBoxControl' );
|
|
33
36
|
|
|
37
|
+
// A visible label gives the control a header row to place the linked/
|
|
38
|
+
// unlinked toggle in, alongside that label. Without one the toggle stays
|
|
39
|
+
// inside the input wrapper, positioned absolutely.
|
|
40
|
+
const hasVisibleLabel = !! label && ! hideLabelFromVision;
|
|
41
|
+
|
|
34
42
|
const mixedBorders = hasMixedBorders( value );
|
|
35
43
|
const splitBorders = hasSplitBorders( value );
|
|
36
44
|
|
|
@@ -99,13 +107,23 @@ export function useBorderBoxControl(
|
|
|
99
107
|
}
|
|
100
108
|
};
|
|
101
109
|
|
|
102
|
-
|
|
110
|
+
// The linked control reserves an inline-end gutter for the absolutely
|
|
111
|
+
// positioned toggle. Once the toggle moves up into the header row that
|
|
112
|
+
// gutter only shortens the input, so drop it.
|
|
113
|
+
const linkedControlClassName = clsx( styles[ 'linked-border-control' ], {
|
|
114
|
+
[ styles[ 'linked-border-control-full-width' ] ]: hasVisibleLabel,
|
|
115
|
+
} );
|
|
103
116
|
const wrapperClassName = styles.wrapper;
|
|
117
|
+
const headerClassName = styles.header;
|
|
104
118
|
|
|
105
119
|
return {
|
|
106
120
|
...otherProps,
|
|
107
121
|
className,
|
|
108
122
|
colors,
|
|
123
|
+
hasVisibleLabel,
|
|
124
|
+
headerClassName,
|
|
125
|
+
hideLabelFromVision,
|
|
126
|
+
label,
|
|
109
127
|
disableUnits: mixedBorders && ! hasWidthValue,
|
|
110
128
|
enableAlpha,
|
|
111
129
|
enableStyle,
|
|
@@ -79,3 +79,13 @@ Default.args = {
|
|
|
79
79
|
label: 'Borders',
|
|
80
80
|
enableStyle: true,
|
|
81
81
|
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* With no visible label there is no label row for the linked/unlinked toggle to
|
|
85
|
+
* join, so it is rendered alongside the border inputs instead.
|
|
86
|
+
*/
|
|
87
|
+
export const WithoutLabel = Template.bind( {} );
|
|
88
|
+
WithoutLabel.args = {
|
|
89
|
+
...Default.args,
|
|
90
|
+
label: undefined,
|
|
91
|
+
};
|