@wordpress/components 27.1.0 → 27.3.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 +53 -3
- package/README.md +13 -0
- package/build/button/index.js +3 -4
- package/build/button/index.js.map +1 -1
- package/build/button/types.js.map +1 -1
- package/build/color-picker/component.js +2 -12
- package/build/color-picker/component.js.map +1 -1
- package/build/color-picker/picker.js +18 -77
- package/build/color-picker/picker.js.map +1 -1
- package/build/color-picker/types.js.map +1 -1
- package/build/custom-select-control-v2/default-component/index.js +4 -2
- package/build/custom-select-control-v2/default-component/index.js.map +1 -1
- package/build/custom-select-control-v2/index.js +1 -8
- package/build/custom-select-control-v2/index.js.map +1 -1
- package/build/custom-select-control-v2/{custom-select-item.js → item.js} +2 -1
- package/build/custom-select-control-v2/{custom-select-item.js.map → item.js.map} +1 -1
- package/build/custom-select-control-v2/legacy-component/index.js +5 -5
- package/build/custom-select-control-v2/legacy-component/index.js.map +1 -1
- package/build/date-time/date/styles.js +7 -7
- package/build/date-time/date/styles.js.map +1 -1
- package/build/form-token-field/index.js +1 -1
- package/build/form-token-field/index.js.map +1 -1
- package/build/input-control/index.js +1 -1
- package/build/input-control/index.js.map +1 -1
- package/build/input-control/input-field.js +2 -1
- package/build/input-control/input-field.js.map +1 -1
- package/build/mobile/color-settings/palette.screen.native.js +1 -0
- package/build/mobile/color-settings/palette.screen.native.js.map +1 -1
- package/build/navigable-container/container.js.map +1 -1
- package/build/navigator/navigator-provider/component.js +162 -120
- package/build/navigator/navigator-provider/component.js.map +1 -1
- package/build/navigator/navigator-screen/component.js +2 -2
- package/build/navigator/navigator-screen/component.js.map +1 -1
- package/build/palette-edit/index.js +18 -12
- package/build/palette-edit/index.js.map +1 -1
- package/build/popover/index.js +7 -34
- package/build/popover/index.js.map +1 -1
- package/build/range-control/styles/range-control-styles.js +29 -29
- package/build/range-control/styles/range-control-styles.js.map +1 -1
- package/build/text-control/types.js.map +1 -1
- package/build/toggle-group-control/toggle-group-control-option-base/component.js +5 -2
- package/build/toggle-group-control/toggle-group-control-option-base/component.js.map +1 -1
- package/build/tools-panel/tools-panel-header/component.js +1 -1
- package/build/tools-panel/tools-panel-header/component.js.map +1 -1
- package/build/utils/config-values.js +1 -1
- package/build/utils/config-values.js.map +1 -1
- package/build/utils/input/base.js +2 -2
- package/build/utils/input/base.js.map +1 -1
- package/build-module/button/index.js +3 -4
- package/build-module/button/index.js.map +1 -1
- package/build-module/button/types.js.map +1 -1
- package/build-module/color-picker/component.js +3 -13
- package/build-module/color-picker/component.js.map +1 -1
- package/build-module/color-picker/picker.js +19 -78
- package/build-module/color-picker/picker.js.map +1 -1
- package/build-module/color-picker/types.js.map +1 -1
- package/build-module/custom-select-control-v2/default-component/index.js +4 -2
- package/build-module/custom-select-control-v2/default-component/index.js.map +1 -1
- package/build-module/custom-select-control-v2/index.js +1 -2
- package/build-module/custom-select-control-v2/index.js.map +1 -1
- package/build-module/custom-select-control-v2/{custom-select-item.js → item.js} +2 -1
- package/build-module/custom-select-control-v2/{custom-select-item.js.map → item.js.map} +1 -1
- package/build-module/custom-select-control-v2/legacy-component/index.js +4 -4
- package/build-module/custom-select-control-v2/legacy-component/index.js.map +1 -1
- package/build-module/date-time/date/styles.js +7 -7
- package/build-module/date-time/date/styles.js.map +1 -1
- package/build-module/form-token-field/index.js +1 -1
- package/build-module/form-token-field/index.js.map +1 -1
- package/build-module/input-control/index.js +1 -1
- package/build-module/input-control/index.js.map +1 -1
- package/build-module/input-control/input-field.js +2 -1
- package/build-module/input-control/input-field.js.map +1 -1
- package/build-module/mobile/color-settings/palette.screen.native.js +1 -0
- package/build-module/mobile/color-settings/palette.screen.native.js.map +1 -1
- package/build-module/navigable-container/container.js.map +1 -1
- package/build-module/navigator/navigator-provider/component.js +163 -121
- package/build-module/navigator/navigator-provider/component.js.map +1 -1
- package/build-module/navigator/navigator-screen/component.js +2 -2
- package/build-module/navigator/navigator-screen/component.js.map +1 -1
- package/build-module/palette-edit/index.js +17 -11
- package/build-module/palette-edit/index.js.map +1 -1
- package/build-module/popover/index.js +9 -36
- package/build-module/popover/index.js.map +1 -1
- package/build-module/range-control/styles/range-control-styles.js +29 -29
- package/build-module/range-control/styles/range-control-styles.js.map +1 -1
- package/build-module/text-control/types.js.map +1 -1
- package/build-module/toggle-group-control/toggle-group-control-option-base/component.js +6 -3
- package/build-module/toggle-group-control/toggle-group-control-option-base/component.js.map +1 -1
- package/build-module/tools-panel/tools-panel-header/component.js +1 -1
- package/build-module/tools-panel/tools-panel-header/component.js.map +1 -1
- package/build-module/utils/config-values.js +1 -1
- package/build-module/utils/config-values.js.map +1 -1
- package/build-module/utils/input/base.js +2 -2
- package/build-module/utils/input/base.js.map +1 -1
- package/build-style/style-rtl.css +26 -29
- package/build-style/style.css +26 -29
- package/build-types/box-control/styles/box-control-styles.d.ts +1 -1
- package/build-types/button/deprecated.d.ts +4 -10
- package/build-types/button/deprecated.d.ts.map +1 -1
- package/build-types/button/index.d.ts +3 -3
- package/build-types/button/index.d.ts.map +1 -1
- package/build-types/button/stories/e2e/index.story.d.ts +1 -1
- package/build-types/button/stories/e2e/index.story.d.ts.map +1 -1
- package/build-types/button/stories/index.story.d.ts +7 -7
- package/build-types/button/stories/index.story.d.ts.map +1 -1
- package/build-types/button/types.d.ts +37 -8
- package/build-types/button/types.d.ts.map +1 -1
- package/build-types/color-picker/component.d.ts.map +1 -1
- package/build-types/color-picker/picker.d.ts +1 -1
- package/build-types/color-picker/picker.d.ts.map +1 -1
- package/build-types/color-picker/styles.d.ts +1 -1
- package/build-types/color-picker/types.d.ts +0 -3
- package/build-types/color-picker/types.d.ts.map +1 -1
- package/build-types/custom-select-control/stories/index.story.d.ts +35 -0
- package/build-types/custom-select-control/stories/index.story.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/default-component/index.d.ts +5 -2
- package/build-types/custom-select-control-v2/default-component/index.d.ts.map +1 -1
- package/build-types/custom-select-control-v2/index.d.ts +1 -2
- package/build-types/custom-select-control-v2/index.d.ts.map +1 -1
- package/build-types/custom-select-control-v2/{custom-select-item.d.ts → item.d.ts} +4 -1
- package/build-types/custom-select-control-v2/item.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/legacy-component/index.d.ts +2 -2
- package/build-types/custom-select-control-v2/legacy-component/index.d.ts.map +1 -1
- package/build-types/custom-select-control-v2/stories/default.story.d.ts +2 -2
- package/build-types/custom-select-control-v2/stories/default.story.d.ts.map +1 -1
- package/build-types/custom-select-control-v2/stories/legacy.story.d.ts +4 -2
- package/build-types/custom-select-control-v2/stories/legacy.story.d.ts.map +1 -1
- package/build-types/date-time/date/styles.d.ts +1 -1
- package/build-types/dropdown/stories/index.story.d.ts +1 -0
- package/build-types/dropdown/stories/index.story.d.ts.map +1 -1
- package/build-types/font-size-picker/styles.d.ts +1 -1
- package/build-types/form-token-field/index.d.ts +1 -1
- package/build-types/input-control/index.d.ts +1 -1
- package/build-types/input-control/input-field.d.ts.map +1 -1
- package/build-types/input-control/stories/index.story.d.ts.map +1 -1
- package/build-types/navigation/styles/navigation-styles.d.ts +1 -1
- package/build-types/navigator/navigator-back-button/component.d.ts +0 -1
- package/build-types/navigator/navigator-back-button/component.d.ts.map +1 -1
- package/build-types/navigator/navigator-back-button/hook.d.ts +1 -2
- package/build-types/navigator/navigator-back-button/hook.d.ts.map +1 -1
- package/build-types/navigator/navigator-button/component.d.ts +0 -1
- package/build-types/navigator/navigator-button/component.d.ts.map +1 -1
- package/build-types/navigator/navigator-button/hook.d.ts +1 -2
- package/build-types/navigator/navigator-button/hook.d.ts.map +1 -1
- package/build-types/navigator/navigator-provider/component.d.ts.map +1 -1
- package/build-types/navigator/navigator-screen/component.d.ts.map +1 -1
- package/build-types/navigator/navigator-to-parent-button/component.d.ts +0 -1
- package/build-types/navigator/navigator-to-parent-button/component.d.ts.map +1 -1
- package/build-types/number-control/styles/number-control-styles.d.ts +1 -1
- package/build-types/palette-edit/index.d.ts +6 -3
- package/build-types/palette-edit/index.d.ts.map +1 -1
- package/build-types/palette-edit/styles.d.ts +2 -2
- package/build-types/popover/index.d.ts.map +1 -1
- package/build-types/text-control/index.d.ts +1 -1
- package/build-types/text-control/types.d.ts +1 -1
- package/build-types/text-control/types.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/toolbar/toolbar-button/index.d.ts +4 -10
- package/build-types/toolbar/toolbar-button/index.d.ts.map +1 -1
- package/package.json +21 -21
- package/src/button/index.tsx +3 -4
- package/src/button/test/index.tsx +6 -6
- package/src/button/types.ts +37 -9
- package/src/color-picker/component.tsx +3 -25
- package/src/color-picker/picker.tsx +12 -96
- package/src/color-picker/types.ts +0 -3
- package/src/confirm-dialog/README.md +7 -0
- package/src/custom-select-control/stories/{index.story.js → index.story.tsx} +8 -3
- package/src/custom-select-control/test/index.js +24 -0
- package/src/custom-select-control-v2/README.md +27 -27
- package/src/custom-select-control-v2/default-component/index.tsx +5 -2
- package/src/custom-select-control-v2/index.tsx +1 -2
- package/src/custom-select-control-v2/{custom-select-item.tsx → item.tsx} +2 -0
- package/src/custom-select-control-v2/legacy-component/index.tsx +4 -6
- package/src/custom-select-control-v2/legacy-component/test/index.tsx +13 -10
- package/src/custom-select-control-v2/stories/default.story.tsx +16 -17
- package/src/custom-select-control-v2/stories/legacy.story.tsx +20 -35
- package/src/custom-select-control-v2/test/index.tsx +26 -16
- package/src/date-time/date/styles.ts +2 -2
- package/src/dimension-control/test/__snapshots__/index.test.js.snap +4 -4
- package/src/dropdown/stories/index.story.tsx +19 -0
- package/src/dropdown/style.scss +26 -0
- package/src/dropdown-menu/style.scss +0 -25
- package/src/flex/flex/README.md +2 -2
- package/src/form-token-field/README.md +1 -1
- package/src/form-token-field/index.tsx +1 -1
- package/src/grid/README.md +11 -11
- package/src/h-stack/README.md +6 -6
- package/src/heading/README.md +1 -1
- package/src/heading/test/__snapshots__/index.tsx.snap +3 -3
- package/src/input-control/README.md +1 -1
- package/src/input-control/index.tsx +1 -1
- package/src/input-control/input-field.tsx +2 -1
- package/src/input-control/stories/index.story.tsx +1 -0
- package/src/item-group/test/__snapshots__/index.js.snap +11 -11
- package/src/mobile/bottom-sheet-select-control/README.md +1 -1
- package/src/mobile/color-settings/palette.screen.native.js +5 -1
- package/src/navigable-container/container.tsx +1 -1
- package/src/navigator/navigator-provider/component.tsx +187 -188
- package/src/navigator/navigator-screen/component.tsx +2 -4
- package/src/palette-edit/index.tsx +21 -21
- package/src/palette-edit/test/index.tsx +21 -17
- package/src/placeholder/style.scss +5 -1
- package/src/popover/index.tsx +59 -99
- package/src/popover/style.scss +0 -9
- package/src/progress-bar/README.md +1 -1
- package/src/radio-control/README.md +3 -3
- package/src/range-control/styles/range-control-styles.ts +1 -1
- package/src/resizable-box/resize-tooltip/README.md +2 -2
- package/src/text/test/__snapshots__/index.tsx.snap +3 -3
- package/src/text-control/style.scss +2 -0
- package/src/text-control/types.ts +12 -1
- package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +14 -10
- package/src/toggle-group-control/toggle-group-control-option-base/component.tsx +14 -12
- package/src/toolbar/toolbar/style.scss +1 -1
- package/src/tools-panel/tools-panel-header/component.tsx +1 -1
- package/src/truncate/README.md +5 -5
- package/src/utils/config-values.js +1 -1
- package/src/utils/input/base.js +1 -1
- package/src/v-stack/README.md +6 -6
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/build-types/custom-select-control-v2/custom-select-item.d.ts.map +0 -1
|
@@ -7,118 +7,34 @@ import { colord } from 'colord';
|
|
|
7
7
|
/**
|
|
8
8
|
* WordPress dependencies
|
|
9
9
|
*/
|
|
10
|
-
import { useMemo
|
|
10
|
+
import { useMemo } from '@wordpress/element';
|
|
11
11
|
/**
|
|
12
12
|
* Internal dependencies
|
|
13
13
|
*/
|
|
14
14
|
import type { PickerProps } from './types';
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
* Track the start and the end of drag pointer events related to controlling
|
|
18
|
-
* the picker's saturation / hue / alpha, and fire the corresponding callbacks.
|
|
19
|
-
* This is particularly useful to implement synergies like the one with the
|
|
20
|
-
* `Popover` component, where a pointer events "trap" is rendered while
|
|
21
|
-
* the user is dragging the pointer to avoid potential interference with iframe
|
|
22
|
-
* elements.
|
|
23
|
-
*
|
|
24
|
-
* @param props
|
|
25
|
-
* @param props.containerEl
|
|
26
|
-
* @param props.onDragStart
|
|
27
|
-
* @param props.onDragEnd
|
|
28
|
-
*/
|
|
29
|
-
const useOnPickerDrag = ( {
|
|
30
|
-
containerEl,
|
|
31
|
-
onDragStart,
|
|
32
|
-
onDragEnd,
|
|
33
|
-
}: Pick< PickerProps, 'containerEl' | 'onDragStart' | 'onDragEnd' > ) => {
|
|
34
|
-
const isDragging = useRef( false );
|
|
35
|
-
const leftWhileDragging = useRef( false );
|
|
36
|
-
useEffect( () => {
|
|
37
|
-
if ( ! containerEl || ( ! onDragStart && ! onDragEnd ) ) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const interactiveElements = [
|
|
41
|
-
containerEl.querySelector( '.react-colorful__saturation' ),
|
|
42
|
-
containerEl.querySelector( '.react-colorful__hue' ),
|
|
43
|
-
containerEl.querySelector( '.react-colorful__alpha' ),
|
|
44
|
-
].filter( ( el ) => !! el ) as Element[];
|
|
45
|
-
|
|
46
|
-
if ( interactiveElements.length === 0 ) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const doc = containerEl.ownerDocument;
|
|
51
|
-
|
|
52
|
-
const onPointerUp: EventListener = ( event ) => {
|
|
53
|
-
isDragging.current = false;
|
|
54
|
-
leftWhileDragging.current = false;
|
|
55
|
-
onDragEnd?.( event as MouseEvent );
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const onPointerDown: EventListener = ( event ) => {
|
|
59
|
-
isDragging.current = true;
|
|
60
|
-
onDragStart?.( event as MouseEvent );
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const onPointerLeave: EventListener = () => {
|
|
64
|
-
leftWhileDragging.current = isDragging.current;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// Try to detect if the user released the pointer while away from the
|
|
68
|
-
// current window. If the check is successfull, the dragEnd callback will
|
|
69
|
-
// called as soon as the pointer re-enters the window (better late than never)
|
|
70
|
-
const onPointerEnter: EventListener = ( event ) => {
|
|
71
|
-
const noPointerButtonsArePressed =
|
|
72
|
-
( event as PointerEvent ).buttons === 0;
|
|
73
|
-
|
|
74
|
-
if ( leftWhileDragging.current && noPointerButtonsArePressed ) {
|
|
75
|
-
onPointerUp( event );
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// The pointerdown event is added on the interactive elements,
|
|
80
|
-
// while the remaining events are added on the document object since
|
|
81
|
-
// the pointer wouldn't necessarily be hovering the initial interactive
|
|
82
|
-
// element at that point.
|
|
83
|
-
interactiveElements.forEach( ( el ) =>
|
|
84
|
-
el.addEventListener( 'pointerdown', onPointerDown )
|
|
85
|
-
);
|
|
86
|
-
doc.addEventListener( 'pointerup', onPointerUp );
|
|
87
|
-
doc.addEventListener( 'pointerenter', onPointerEnter );
|
|
88
|
-
doc.addEventListener( 'pointerleave', onPointerLeave );
|
|
89
|
-
|
|
90
|
-
return () => {
|
|
91
|
-
interactiveElements.forEach( ( el ) =>
|
|
92
|
-
el.removeEventListener( 'pointerdown', onPointerDown )
|
|
93
|
-
);
|
|
94
|
-
doc.removeEventListener( 'pointerup', onPointerUp );
|
|
95
|
-
doc.removeEventListener( 'pointerenter', onPointerEnter );
|
|
96
|
-
doc.removeEventListener( 'pointerleave', onPointerUp );
|
|
97
|
-
};
|
|
98
|
-
}, [ onDragStart, onDragEnd, containerEl ] );
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
export const Picker = ( {
|
|
102
|
-
color,
|
|
103
|
-
enableAlpha,
|
|
104
|
-
onChange,
|
|
105
|
-
onDragStart,
|
|
106
|
-
onDragEnd,
|
|
107
|
-
containerEl,
|
|
108
|
-
}: PickerProps ) => {
|
|
16
|
+
export const Picker = ( { color, enableAlpha, onChange }: PickerProps ) => {
|
|
109
17
|
const Component = enableAlpha
|
|
110
18
|
? RgbaStringColorPicker
|
|
111
19
|
: RgbStringColorPicker;
|
|
112
20
|
const rgbColor = useMemo( () => color.toRgbString(), [ color ] );
|
|
113
21
|
|
|
114
|
-
useOnPickerDrag( { containerEl, onDragStart, onDragEnd } );
|
|
115
|
-
|
|
116
22
|
return (
|
|
117
23
|
<Component
|
|
118
24
|
color={ rgbColor }
|
|
119
25
|
onChange={ ( nextColor ) => {
|
|
120
26
|
onChange( colord( nextColor ) );
|
|
121
27
|
} }
|
|
28
|
+
// Pointer capture fortifies drag gestures so that they continue to
|
|
29
|
+
// work while dragging outside the component over objects like
|
|
30
|
+
// iframes. If a newer version of react-colorful begins to employ
|
|
31
|
+
// pointer capture this will be redundant and should be removed.
|
|
32
|
+
onPointerDown={ ( { currentTarget, pointerId } ) => {
|
|
33
|
+
currentTarget.setPointerCapture( pointerId );
|
|
34
|
+
} }
|
|
35
|
+
onPointerUp={ ( { currentTarget, pointerId } ) => {
|
|
36
|
+
currentTarget.releasePointerCapture( pointerId );
|
|
37
|
+
} }
|
|
122
38
|
/>
|
|
123
39
|
);
|
|
124
40
|
};
|
|
@@ -59,9 +59,6 @@ export interface PickerProps {
|
|
|
59
59
|
color: Colord;
|
|
60
60
|
enableAlpha: boolean;
|
|
61
61
|
onChange: ( nextColor: Colord ) => void;
|
|
62
|
-
containerEl: HTMLElement | null;
|
|
63
|
-
onDragStart?: ( event: MouseEvent ) => void;
|
|
64
|
-
onDragEnd?: ( event: MouseEvent ) => void;
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
export interface ColorInputProps {
|
|
@@ -138,3 +138,10 @@ The optional custom text to display as the confirmation button's label
|
|
|
138
138
|
- Default: "Cancel"
|
|
139
139
|
|
|
140
140
|
The optional custom text to display as the cancellation button's label
|
|
141
|
+
|
|
142
|
+
## Best practices
|
|
143
|
+
|
|
144
|
+
The ConfirmDialog component should:
|
|
145
|
+
|
|
146
|
+
- Be used only for short confirmation messages where a cancel and confirm actions are provided.
|
|
147
|
+
- Use a descriptive text for the _confirm_ button. Default is "OK".
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import type { StoryFn } from '@storybook/react';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* Internal dependencies
|
|
3
8
|
*/
|
|
@@ -18,7 +23,7 @@ export default {
|
|
|
18
23
|
},
|
|
19
24
|
};
|
|
20
25
|
|
|
21
|
-
export const Default = CustomSelectControl.bind( {} );
|
|
26
|
+
export const Default: StoryFn = CustomSelectControl.bind( {} );
|
|
22
27
|
Default.args = {
|
|
23
28
|
label: 'Label',
|
|
24
29
|
options: [
|
|
@@ -46,7 +51,7 @@ Default.args = {
|
|
|
46
51
|
],
|
|
47
52
|
};
|
|
48
53
|
|
|
49
|
-
export const WithLongLabels = CustomSelectControl.bind( {} );
|
|
54
|
+
export const WithLongLabels: StoryFn = CustomSelectControl.bind( {} );
|
|
50
55
|
WithLongLabels.args = {
|
|
51
56
|
...Default.args,
|
|
52
57
|
options: [
|
|
@@ -65,7 +70,7 @@ WithLongLabels.args = {
|
|
|
65
70
|
],
|
|
66
71
|
};
|
|
67
72
|
|
|
68
|
-
export const WithHints = CustomSelectControl.bind( {} );
|
|
73
|
+
export const WithHints: StoryFn = CustomSelectControl.bind( {} );
|
|
69
74
|
WithHints.args = {
|
|
70
75
|
...Default.args,
|
|
71
76
|
options: [
|
|
@@ -238,6 +238,30 @@ describe.each( [
|
|
|
238
238
|
).toHaveTextContent( 'Hint' );
|
|
239
239
|
} );
|
|
240
240
|
|
|
241
|
+
it( 'shows selected hint in list of options when added, regardless of __experimentalShowSelectedHint prop', async () => {
|
|
242
|
+
const user = userEvent.setup();
|
|
243
|
+
|
|
244
|
+
render(
|
|
245
|
+
<Component
|
|
246
|
+
{ ...props }
|
|
247
|
+
label="Custom select"
|
|
248
|
+
options={ [
|
|
249
|
+
{
|
|
250
|
+
key: 'one',
|
|
251
|
+
name: 'One',
|
|
252
|
+
__experimentalHint: 'Hint',
|
|
253
|
+
},
|
|
254
|
+
] }
|
|
255
|
+
/>
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
await user.click(
|
|
259
|
+
screen.getByRole( 'button', { name: 'Custom select' } )
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
expect( screen.getByRole( 'option', { name: /hint/i } ) ).toBeVisible();
|
|
263
|
+
} );
|
|
264
|
+
|
|
241
265
|
describe( 'Keyboard behavior and accessibility', () => {
|
|
242
266
|
it( 'Captures the keypress event and does not let it propagate', async () => {
|
|
243
267
|
const user = userEvent.setup();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CustomSelectControlV2
|
|
2
2
|
|
|
3
3
|
<div class="callout callout-alert">
|
|
4
4
|
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
|
|
@@ -12,31 +12,31 @@ Used to render a customizable select control component.
|
|
|
12
12
|
|
|
13
13
|
#### Uncontrolled Mode
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
`CustomSelectControlV2` can be used in an uncontrolled mode, where the component manages its own state. In this mode, the `defaultValue` prop can be used to set the initial selected value. If this prop is not set, the first value from the children will be selected by default.
|
|
16
16
|
|
|
17
17
|
```jsx
|
|
18
|
-
const
|
|
19
|
-
<
|
|
20
|
-
<
|
|
18
|
+
const UncontrolledCustomSelectControlV2 = () => (
|
|
19
|
+
<CustomSelectControlV2 label="Colors">
|
|
20
|
+
<CustomSelectControlV2.Item value="Blue">
|
|
21
21
|
{ /* The `defaultValue` since it wasn't defined */ }
|
|
22
22
|
<span style={ { color: 'blue' } }>Blue</span>
|
|
23
|
-
</
|
|
24
|
-
<
|
|
23
|
+
</CustomSelectControlV2.Item>
|
|
24
|
+
<CustomSelectControlV2.Item value="Purple">
|
|
25
25
|
<span style={ { color: 'purple' } }>Purple</span>
|
|
26
|
-
</
|
|
27
|
-
<
|
|
26
|
+
</CustomSelectControlV2.Item>
|
|
27
|
+
<CustomSelectControlV2.Item value="Pink">
|
|
28
28
|
<span style={ { color: 'deeppink' } }>Pink</span>
|
|
29
|
-
</
|
|
30
|
-
</
|
|
29
|
+
</CustomSelectControlV2.Item>
|
|
30
|
+
</CustomSelectControlV2>
|
|
31
31
|
);
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
#### Controlled Mode
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
`CustomSelectControlV2` can also be used in a controlled mode, where the parent component specifies the `value` and the `onChange` props to control selection.
|
|
37
37
|
|
|
38
38
|
```jsx
|
|
39
|
-
const
|
|
39
|
+
const ControlledCustomSelectControlV2 = () => {
|
|
40
40
|
const [ value, setValue ] = useState< string | string[] >();
|
|
41
41
|
|
|
42
42
|
const renderControlledValue = ( renderValue: string | string[] ) => (
|
|
@@ -46,7 +46,7 @@ const ControlledCustomSelect = () => {
|
|
|
46
46
|
);
|
|
47
47
|
|
|
48
48
|
return (
|
|
49
|
-
<
|
|
49
|
+
<CustomSelectControlV2
|
|
50
50
|
{ ...props }
|
|
51
51
|
onChange={ ( nextValue ) => {
|
|
52
52
|
setValue( nextValue );
|
|
@@ -55,11 +55,11 @@ const ControlledCustomSelect = () => {
|
|
|
55
55
|
value={ value }
|
|
56
56
|
>
|
|
57
57
|
{ [ 'blue', 'purple', 'pink' ].map( ( option ) => (
|
|
58
|
-
<
|
|
58
|
+
<CustomSelectControlV2.Item key={ option } value={ option }>
|
|
59
59
|
{ renderControlledValue( option ) }
|
|
60
|
-
</
|
|
60
|
+
</CustomSelectControlV2.Item>
|
|
61
61
|
) ) }
|
|
62
|
-
</
|
|
62
|
+
</CustomSelectControlV2>
|
|
63
63
|
);
|
|
64
64
|
};
|
|
65
65
|
```
|
|
@@ -70,23 +70,23 @@ Multiple selection can be enabled by using an array for the `value` and
|
|
|
70
70
|
`defaultValue` props. The argument of the `onChange` function will also change accordingly.
|
|
71
71
|
|
|
72
72
|
```jsx
|
|
73
|
-
const
|
|
74
|
-
<
|
|
73
|
+
const MultiSelectCustomSelectControlV2 = () => (
|
|
74
|
+
<CustomSelectControlV2 defaultValue={ [ 'blue', 'pink' ] } label="Colors">
|
|
75
75
|
{ [ 'blue', 'purple', 'pink' ].map( ( item ) => (
|
|
76
|
-
<
|
|
76
|
+
<CustomSelectControlV2.Item key={ item } value={ item }>
|
|
77
77
|
{ item }
|
|
78
|
-
</
|
|
78
|
+
</CustomSelectControlV2.Item>
|
|
79
79
|
) ) }
|
|
80
|
-
</
|
|
80
|
+
</CustomSelectControlV2>
|
|
81
81
|
);
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
### Components and Sub-components
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
`CustomSelectControlV2` is comprised of two individual components:
|
|
87
87
|
|
|
88
|
-
- `
|
|
89
|
-
- `
|
|
88
|
+
- `CustomSelectControlV2`: a wrapper component and context provider. It is responsible for managing the state of the `CustomSelectControlV2.Item` children.
|
|
89
|
+
- `CustomSelectControlV2.Item`: renders a single select item. The first `CustomSelectControlV2.Item` child will be used as the `defaultValue` when `defaultValue` is undefined.
|
|
90
90
|
|
|
91
91
|
#### Props
|
|
92
92
|
|
|
@@ -94,7 +94,7 @@ The component accepts the following props:
|
|
|
94
94
|
|
|
95
95
|
##### `children`: `React.ReactNode`
|
|
96
96
|
|
|
97
|
-
The child elements. This should be composed of
|
|
97
|
+
The child elements. This should be composed of `CustomSelectControlV2.Item` components.
|
|
98
98
|
|
|
99
99
|
- Required: yes
|
|
100
100
|
|
|
@@ -142,7 +142,7 @@ Can be used to externally control the value of the control.
|
|
|
142
142
|
|
|
143
143
|
- Required: no
|
|
144
144
|
|
|
145
|
-
### `
|
|
145
|
+
### `CustomSelectControlV2.Item`
|
|
146
146
|
|
|
147
147
|
Used to render a select item.
|
|
148
148
|
|
|
@@ -9,8 +9,9 @@ import * as Ariakit from '@ariakit/react';
|
|
|
9
9
|
import _CustomSelect from '../custom-select';
|
|
10
10
|
import type { CustomSelectProps } from '../types';
|
|
11
11
|
import type { WordPressComponentProps } from '../../context';
|
|
12
|
+
import Item from '../item';
|
|
12
13
|
|
|
13
|
-
function
|
|
14
|
+
function CustomSelectControlV2(
|
|
14
15
|
props: WordPressComponentProps< CustomSelectProps, 'button', false >
|
|
15
16
|
) {
|
|
16
17
|
const { defaultValue, onChange, value, ...restProps } = props;
|
|
@@ -24,4 +25,6 @@ function CustomSelect(
|
|
|
24
25
|
return <_CustomSelect { ...restProps } store={ store } />;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
CustomSelectControlV2.Item = Item;
|
|
29
|
+
|
|
30
|
+
export default CustomSelectControlV2;
|
|
@@ -11,12 +11,12 @@ import { useMemo } from '@wordpress/element';
|
|
|
11
11
|
* Internal dependencies
|
|
12
12
|
*/
|
|
13
13
|
import _CustomSelect from '../custom-select';
|
|
14
|
+
import CustomSelectItem from '../item';
|
|
14
15
|
import type { LegacyCustomSelectProps } from '../types';
|
|
15
|
-
import { CustomSelectItem } from '..';
|
|
16
16
|
import * as Styled from '../styles';
|
|
17
17
|
import { ContextSystemProvider } from '../../context';
|
|
18
18
|
|
|
19
|
-
function
|
|
19
|
+
function CustomSelectControl( props: LegacyCustomSelectProps ) {
|
|
20
20
|
const {
|
|
21
21
|
__experimentalShowSelectedHint,
|
|
22
22
|
__next40pxDefaultSize = false,
|
|
@@ -68,9 +68,7 @@ function CustomSelect( props: LegacyCustomSelectProps ) {
|
|
|
68
68
|
<CustomSelectItem
|
|
69
69
|
key={ key }
|
|
70
70
|
value={ name }
|
|
71
|
-
children={
|
|
72
|
-
__experimentalShowSelectedHint ? withHint : name
|
|
73
|
-
}
|
|
71
|
+
children={ __experimentalHint ? withHint : name }
|
|
74
72
|
{ ...rest }
|
|
75
73
|
/>
|
|
76
74
|
);
|
|
@@ -130,4 +128,4 @@ function CustomSelect( props: LegacyCustomSelectProps ) {
|
|
|
130
128
|
);
|
|
131
129
|
}
|
|
132
130
|
|
|
133
|
-
export default
|
|
131
|
+
export default CustomSelectControl;
|
|
@@ -12,7 +12,7 @@ import { useState } from '@wordpress/element';
|
|
|
12
12
|
/**
|
|
13
13
|
* Internal dependencies
|
|
14
14
|
*/
|
|
15
|
-
import
|
|
15
|
+
import UncontrolledCustomSelectControl from '..';
|
|
16
16
|
|
|
17
17
|
const customClass = 'amber-skies';
|
|
18
18
|
|
|
@@ -48,14 +48,14 @@ const legacyProps = {
|
|
|
48
48
|
],
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
const
|
|
51
|
+
const ControlledCustomSelectControl = ( {
|
|
52
52
|
options,
|
|
53
53
|
onChange,
|
|
54
54
|
...restProps
|
|
55
|
-
}: React.ComponentProps< typeof
|
|
55
|
+
}: React.ComponentProps< typeof UncontrolledCustomSelectControl > ) => {
|
|
56
56
|
const [ value, setValue ] = useState( options[ 0 ] );
|
|
57
57
|
return (
|
|
58
|
-
<
|
|
58
|
+
<UncontrolledCustomSelectControl
|
|
59
59
|
{ ...restProps }
|
|
60
60
|
options={ options }
|
|
61
61
|
onChange={ ( args: any ) => {
|
|
@@ -70,8 +70,8 @@ const LegacyControlledCustomSelect = ( {
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
describe.each( [
|
|
73
|
-
[ 'Uncontrolled',
|
|
74
|
-
[ 'Controlled',
|
|
73
|
+
[ 'Uncontrolled', UncontrolledCustomSelectControl ],
|
|
74
|
+
[ 'Controlled', ControlledCustomSelectControl ],
|
|
75
75
|
] )( 'CustomSelectControl (%s)', ( ...modeAndComponent ) => {
|
|
76
76
|
const [ , Component ] = modeAndComponent;
|
|
77
77
|
|
|
@@ -248,7 +248,7 @@ describe.each( [
|
|
|
248
248
|
);
|
|
249
249
|
} );
|
|
250
250
|
|
|
251
|
-
it( 'shows selected hint in list of options when added', async () => {
|
|
251
|
+
it( 'shows selected hint in list of options when added, regardless of __experimentalShowSelectedHint prop', async () => {
|
|
252
252
|
render(
|
|
253
253
|
<Component
|
|
254
254
|
{ ...legacyProps }
|
|
@@ -260,7 +260,6 @@ describe.each( [
|
|
|
260
260
|
__experimentalHint: 'Hint',
|
|
261
261
|
},
|
|
262
262
|
] }
|
|
263
|
-
__experimentalShowSelectedHint
|
|
264
263
|
/>
|
|
265
264
|
);
|
|
266
265
|
|
|
@@ -388,8 +387,10 @@ describe.each( [
|
|
|
388
387
|
await sleep();
|
|
389
388
|
await press.Tab();
|
|
390
389
|
expect( currentSelectedItem ).toHaveFocus();
|
|
390
|
+
expect( currentSelectedItem ).toHaveTextContent( 'violets' );
|
|
391
391
|
|
|
392
|
-
|
|
392
|
+
// Ideally we would test a multi-character typeahead, but anything more than a single character is flaky
|
|
393
|
+
await type( 'a' );
|
|
393
394
|
|
|
394
395
|
expect(
|
|
395
396
|
screen.queryByRole( 'listbox', {
|
|
@@ -398,8 +399,10 @@ describe.each( [
|
|
|
398
399
|
} )
|
|
399
400
|
).not.toBeInTheDocument();
|
|
400
401
|
|
|
402
|
+
// This Enter is a workaround for flakiness, and shouldn't be necessary in an actual browser
|
|
401
403
|
await press.Enter();
|
|
402
|
-
|
|
404
|
+
|
|
405
|
+
expect( currentSelectedItem ).toHaveTextContent( 'amber' );
|
|
403
406
|
} );
|
|
404
407
|
|
|
405
408
|
it( 'Should have correct aria-selected value for selections', async () => {
|
|
@@ -11,15 +11,14 @@ import { useState } from '@wordpress/element';
|
|
|
11
11
|
/**
|
|
12
12
|
* Internal dependencies
|
|
13
13
|
*/
|
|
14
|
-
import
|
|
15
|
-
import { CustomSelectItem } from '..';
|
|
14
|
+
import CustomSelectControlV2 from '..';
|
|
16
15
|
|
|
17
|
-
const meta: Meta< typeof
|
|
16
|
+
const meta: Meta< typeof CustomSelectControlV2 > = {
|
|
18
17
|
title: 'Components (Experimental)/CustomSelectControl v2/Default',
|
|
19
|
-
component:
|
|
18
|
+
component: CustomSelectControlV2,
|
|
20
19
|
subcomponents: {
|
|
21
20
|
// @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170
|
|
22
|
-
|
|
21
|
+
'CustomSelectControlV2.Item': CustomSelectControlV2.Item,
|
|
23
22
|
},
|
|
24
23
|
argTypes: {
|
|
25
24
|
children: { control: { type: null } },
|
|
@@ -48,10 +47,10 @@ const meta: Meta< typeof CustomSelect > = {
|
|
|
48
47
|
};
|
|
49
48
|
export default meta;
|
|
50
49
|
|
|
51
|
-
const Template: StoryFn< typeof
|
|
50
|
+
const Template: StoryFn< typeof CustomSelectControlV2 > = ( props ) => {
|
|
52
51
|
const [ value, setValue ] = useState< string | string[] >();
|
|
53
52
|
return (
|
|
54
|
-
<
|
|
53
|
+
<CustomSelectControlV2
|
|
55
54
|
{ ...props }
|
|
56
55
|
onChange={ ( nextValue: string | string[] ) => {
|
|
57
56
|
setValue( nextValue );
|
|
@@ -68,15 +67,15 @@ Default.args = {
|
|
|
68
67
|
defaultValue: 'Select a color...',
|
|
69
68
|
children: (
|
|
70
69
|
<>
|
|
71
|
-
<
|
|
70
|
+
<CustomSelectControlV2.Item value="Blue">
|
|
72
71
|
<span style={ { color: 'blue' } }>Blue</span>
|
|
73
|
-
</
|
|
74
|
-
<
|
|
72
|
+
</CustomSelectControlV2.Item>
|
|
73
|
+
<CustomSelectControlV2.Item value="Purple">
|
|
75
74
|
<span style={ { color: 'purple' } }>Purple</span>
|
|
76
|
-
</
|
|
77
|
-
<
|
|
75
|
+
</CustomSelectControlV2.Item>
|
|
76
|
+
<CustomSelectControlV2.Item value="Pink">
|
|
78
77
|
<span style={ { color: 'deeppink' } }>Pink</span>
|
|
79
|
-
</
|
|
78
|
+
</CustomSelectControlV2.Item>
|
|
80
79
|
</>
|
|
81
80
|
),
|
|
82
81
|
};
|
|
@@ -100,9 +99,9 @@ MultipleSelection.args = {
|
|
|
100
99
|
'maroon',
|
|
101
100
|
'tangerine',
|
|
102
101
|
].map( ( item ) => (
|
|
103
|
-
<
|
|
102
|
+
<CustomSelectControlV2.Item key={ item } value={ item }>
|
|
104
103
|
{ item }
|
|
105
|
-
</
|
|
104
|
+
</CustomSelectControlV2.Item>
|
|
106
105
|
) ) }
|
|
107
106
|
</>
|
|
108
107
|
),
|
|
@@ -134,9 +133,9 @@ CustomSelectedValue.args = {
|
|
|
134
133
|
<>
|
|
135
134
|
{ [ 'mystery-person', 'identicon', 'wavatar', 'retro' ].map(
|
|
136
135
|
( option ) => (
|
|
137
|
-
<
|
|
136
|
+
<CustomSelectControlV2.Item key={ option } value={ option }>
|
|
138
137
|
{ renderItem( option ) }
|
|
139
|
-
</
|
|
138
|
+
</CustomSelectControlV2.Item>
|
|
140
139
|
)
|
|
141
140
|
) }
|
|
142
141
|
</>
|
|
@@ -11,11 +11,12 @@ import { useState } from '@wordpress/element';
|
|
|
11
11
|
/**
|
|
12
12
|
* Internal dependencies
|
|
13
13
|
*/
|
|
14
|
-
import
|
|
14
|
+
import CustomSelectControl from '../legacy-component';
|
|
15
|
+
import * as V1Story from '../../custom-select-control/stories/index.story';
|
|
15
16
|
|
|
16
|
-
const meta: Meta< typeof
|
|
17
|
+
const meta: Meta< typeof CustomSelectControl > = {
|
|
17
18
|
title: 'Components (Experimental)/CustomSelectControl v2/Legacy',
|
|
18
|
-
component:
|
|
19
|
+
component: CustomSelectControl,
|
|
19
20
|
argTypes: {
|
|
20
21
|
onChange: { control: { type: null } },
|
|
21
22
|
value: { control: { type: null } },
|
|
@@ -42,46 +43,30 @@ const meta: Meta< typeof CustomSelect > = {
|
|
|
42
43
|
};
|
|
43
44
|
export default meta;
|
|
44
45
|
|
|
45
|
-
const Template: StoryFn< typeof
|
|
46
|
-
const [
|
|
46
|
+
const Template: StoryFn< typeof CustomSelectControl > = ( props ) => {
|
|
47
|
+
const [ value, setValue ] = useState( props.options[ 0 ] );
|
|
47
48
|
|
|
48
49
|
const onChange: React.ComponentProps<
|
|
49
|
-
typeof
|
|
50
|
+
typeof CustomSelectControl
|
|
50
51
|
>[ 'onChange' ] = ( changeObject ) => {
|
|
51
|
-
|
|
52
|
+
setValue( changeObject.selectedItem );
|
|
52
53
|
props.onChange?.( changeObject );
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
return (
|
|
56
|
-
<
|
|
57
|
+
<CustomSelectControl
|
|
58
|
+
{ ...props }
|
|
59
|
+
onChange={ onChange }
|
|
60
|
+
value={ value }
|
|
61
|
+
/>
|
|
57
62
|
);
|
|
58
63
|
};
|
|
59
64
|
|
|
60
65
|
export const Default = Template.bind( {} );
|
|
61
|
-
Default.args =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
__experimentalHint: '50%',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
key: 'normal',
|
|
72
|
-
name: 'Normal',
|
|
73
|
-
style: { fontSize: '100%' },
|
|
74
|
-
className: 'can-apply-custom-class-to-option',
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
key: 'large',
|
|
78
|
-
name: 'Large',
|
|
79
|
-
style: { fontSize: '200%' },
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
key: 'huge',
|
|
83
|
-
name: 'Huge',
|
|
84
|
-
style: { fontSize: '300%' },
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
};
|
|
66
|
+
Default.args = V1Story.Default.args;
|
|
67
|
+
|
|
68
|
+
export const WithLongLabels = Template.bind( {} );
|
|
69
|
+
WithLongLabels.args = V1Story.WithLongLabels.args;
|
|
70
|
+
|
|
71
|
+
export const WithHints = Template.bind( {} );
|
|
72
|
+
WithHints.args = V1Story.WithHints.args;
|