@wordpress/components 26.0.1 → 27.0.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/.stylelintrc.js +2 -2
- package/CHANGELOG.md +23 -0
- package/CONTRIBUTING.md +72 -0
- package/build/autocomplete/index.js +3 -8
- package/build/autocomplete/index.js.map +1 -1
- package/build/color-picker/component.js +10 -1
- package/build/color-picker/component.js.map +1 -1
- package/build/color-picker/styles.js +8 -9
- package/build/color-picker/styles.js.map +1 -1
- package/build/combobox-control/index.js +4 -9
- package/build/combobox-control/index.js.map +1 -1
- package/build/custom-select-control/index.js +2 -15
- package/build/custom-select-control/index.js.map +1 -1
- package/build/custom-select-control-v2/custom-select-item.js +32 -0
- package/build/custom-select-control-v2/custom-select-item.js.map +1 -0
- package/build/custom-select-control-v2/custom-select.js +91 -0
- package/build/custom-select-control-v2/custom-select.js.map +1 -0
- package/build/custom-select-control-v2/default-component/index.js +41 -0
- package/build/custom-select-control-v2/default-component/index.js.map +1 -0
- package/build/custom-select-control-v2/index.js +13 -82
- package/build/custom-select-control-v2/index.js.map +1 -1
- package/build/custom-select-control-v2/legacy-adapter.js +29 -0
- package/build/custom-select-control-v2/legacy-adapter.js.map +1 -0
- package/build/custom-select-control-v2/legacy-component/index.js +123 -0
- package/build/custom-select-control-v2/legacy-component/index.js.map +1 -0
- package/build/custom-select-control-v2/styles.js +73 -50
- package/build/custom-select-control-v2/styles.js.map +1 -1
- package/build/custom-select-control-v2/types.js.map +1 -1
- package/build/font-size-picker/font-size-picker-select.js +0 -1
- package/build/font-size-picker/font-size-picker-select.js.map +1 -1
- package/build/form-token-field/index.js +3 -8
- package/build/form-token-field/index.js.map +1 -1
- package/build/form-token-field/suggestions-list.js +5 -12
- package/build/form-token-field/suggestions-list.js.map +1 -1
- package/build/mobile/keyboard-aware-flat-list/use-scroll-to-section.native.js +1 -1
- package/build/mobile/keyboard-aware-flat-list/use-scroll-to-section.native.js.map +1 -1
- package/build/modal/index.js +2 -10
- package/build/modal/index.js.map +1 -1
- package/build/progress-bar/styles.js +5 -5
- package/build/progress-bar/styles.js.map +1 -1
- package/build/utils/with-ignore-ime-events.js +34 -0
- package/build/utils/with-ignore-ime-events.js.map +1 -0
- package/build-module/autocomplete/index.js +3 -8
- package/build-module/autocomplete/index.js.map +1 -1
- package/build-module/color-picker/component.js +11 -2
- package/build-module/color-picker/component.js.map +1 -1
- package/build-module/color-picker/styles.js +8 -9
- package/build-module/color-picker/styles.js.map +1 -1
- package/build-module/combobox-control/index.js +4 -9
- package/build-module/combobox-control/index.js.map +1 -1
- package/build-module/custom-select-control/index.js +2 -15
- package/build-module/custom-select-control/index.js.map +1 -1
- package/build-module/custom-select-control-v2/custom-select-item.js +26 -0
- package/build-module/custom-select-control-v2/custom-select-item.js.map +1 -0
- package/build-module/custom-select-control-v2/custom-select.js +82 -0
- package/build-module/custom-select-control-v2/custom-select.js.map +1 -0
- package/build-module/custom-select-control-v2/default-component/index.js +30 -0
- package/build-module/custom-select-control-v2/default-component/index.js.map +1 -0
- package/build-module/custom-select-control-v2/index.js +2 -74
- package/build-module/custom-select-control-v2/index.js.map +1 -1
- package/build-module/custom-select-control-v2/legacy-adapter.js +21 -0
- package/build-module/custom-select-control-v2/legacy-adapter.js.map +1 -0
- package/build-module/custom-select-control-v2/legacy-component/index.js +111 -0
- package/build-module/custom-select-control-v2/legacy-component/index.js.map +1 -0
- package/build-module/custom-select-control-v2/styles.js +73 -42
- package/build-module/custom-select-control-v2/styles.js.map +1 -1
- package/build-module/custom-select-control-v2/types.js.map +1 -1
- package/build-module/font-size-picker/font-size-picker-select.js +0 -1
- package/build-module/font-size-picker/font-size-picker-select.js.map +1 -1
- package/build-module/form-token-field/index.js +3 -8
- package/build-module/form-token-field/index.js.map +1 -1
- package/build-module/form-token-field/suggestions-list.js +5 -12
- package/build-module/form-token-field/suggestions-list.js.map +1 -1
- package/build-module/mobile/keyboard-aware-flat-list/use-scroll-to-section.native.js +1 -1
- package/build-module/mobile/keyboard-aware-flat-list/use-scroll-to-section.native.js.map +1 -1
- package/build-module/modal/index.js +3 -10
- package/build-module/modal/index.js.map +1 -1
- package/build-module/progress-bar/styles.js +5 -5
- package/build-module/progress-bar/styles.js.map +1 -1
- package/build-module/utils/with-ignore-ime-events.js +28 -0
- package/build-module/utils/with-ignore-ime-events.js.map +1 -0
- package/build-style/style-rtl.css +8 -1
- package/build-style/style.css +8 -1
- package/build-types/alignment-matrix-control/stories/index.story.d.ts +1 -1
- package/build-types/angle-picker-control/stories/index.story.d.ts +1 -1
- package/build-types/animate/stories/index.story.d.ts +7 -7
- package/build-types/autocomplete/index.d.ts.map +1 -1
- package/build-types/base-control/stories/index.story.d.ts +1 -1
- package/build-types/border-box-control/stories/index.story.d.ts +1 -1
- package/build-types/border-control/stories/index.story.d.ts +6 -6
- package/build-types/box-control/stories/index.story.d.ts +6 -6
- package/build-types/button/stories/e2e/index.story.d.ts +1 -1
- package/build-types/button/stories/index.story.d.ts +7 -7
- package/build-types/card/stories/index.story.d.ts +2 -2
- package/build-types/circular-option-picker/stories/index.story.d.ts +5 -5
- package/build-types/color-palette/stories/index.story.d.ts +3 -3
- package/build-types/color-picker/component.d.ts.map +1 -1
- package/build-types/color-picker/stories/index.story.d.ts +1 -1
- package/build-types/color-picker/styles.d.ts.map +1 -1
- package/build-types/combobox-control/index.d.ts.map +1 -1
- package/build-types/combobox-control/stories/index.story.d.ts +2 -2
- package/build-types/confirm-dialog/stories/index.story.d.ts +2 -2
- package/build-types/custom-gradient-picker/stories/index.story.d.ts +1 -1
- package/build-types/custom-select-control/index.d.ts.map +1 -1
- package/build-types/custom-select-control-v2/custom-select-item.d.ts +9 -0
- package/build-types/custom-select-control-v2/custom-select-item.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/custom-select.d.ts +6 -0
- package/build-types/custom-select-control-v2/custom-select.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/default-component/index.d.ts +5 -0
- package/build-types/custom-select-control-v2/default-component/index.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/index.d.ts +5 -6
- package/build-types/custom-select-control-v2/index.d.ts.map +1 -1
- package/build-types/custom-select-control-v2/legacy-adapter.d.ts +6 -0
- package/build-types/custom-select-control-v2/legacy-adapter.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/legacy-component/index.d.ts +5 -0
- package/build-types/custom-select-control-v2/legacy-component/index.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/stories/default.story.d.ts +29 -0
- package/build-types/custom-select-control-v2/stories/default.story.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/stories/legacy.story.d.ts +12 -0
- package/build-types/custom-select-control-v2/stories/legacy.story.d.ts.map +1 -0
- package/build-types/custom-select-control-v2/styles.d.ts +31 -6
- package/build-types/custom-select-control-v2/styles.d.ts.map +1 -1
- package/build-types/custom-select-control-v2/types.d.ts +137 -14
- package/build-types/custom-select-control-v2/types.d.ts.map +1 -1
- package/build-types/dimension-control/stories/index.story.d.ts +2 -2
- package/build-types/drop-zone/stories/index.story.d.ts +1 -1
- package/build-types/dropdown/stories/index.story.d.ts +3 -3
- package/build-types/dropdown-menu/stories/index.story.d.ts +2 -2
- package/build-types/dropdown-menu-v2/stories/index.story.d.ts.map +1 -1
- package/build-types/duotone-picker/stories/duotone-picker.story.d.ts +1 -1
- package/build-types/duotone-picker/stories/duotone-swatch.story.d.ts +3 -3
- package/build-types/focal-point-picker/stories/index.story.d.ts +4 -4
- package/build-types/font-size-picker/font-size-picker-select.d.ts.map +1 -1
- package/build-types/form-file-upload/stories/index.story.d.ts +5 -5
- package/build-types/form-token-field/index.d.ts.map +1 -1
- package/build-types/form-token-field/suggestions-list.d.ts.map +1 -1
- package/build-types/gradient-picker/stories/index.story.d.ts +3 -3
- package/build-types/guide/stories/index.story.d.ts +1 -1
- package/build-types/icon/stories/index.story.d.ts +4 -4
- package/build-types/input-control/stories/index.story.d.ts +6 -6
- package/build-types/keyboard-shortcuts/stories/index.story.d.ts +1 -1
- package/build-types/menu-group/stories/index.story.d.ts +1 -1
- package/build-types/menu-item/stories/index.story.d.ts +4 -4
- package/build-types/modal/index.d.ts.map +1 -1
- package/build-types/navigation/stories/index.story.d.ts +6 -6
- package/build-types/notice/stories/index.story.d.ts +4 -4
- package/build-types/number-control/stories/index.story.d.ts +1 -1
- package/build-types/palette-edit/stories/index.story.d.ts +2 -2
- package/build-types/progress-bar/stories/index.story.d.ts.map +1 -1
- package/build-types/query-controls/stories/index.story.d.ts +1 -1
- package/build-types/resizable-box/stories/index.story.d.ts +2 -2
- package/build-types/responsive-wrapper/stories/index.story.d.ts +1 -1
- package/build-types/sandbox/stories/index.story.d.ts +1 -1
- package/build-types/search-control/stories/index.story.d.ts +2 -2
- package/build-types/select-control/stories/index.story.d.ts +2 -2
- package/build-types/shortcut/stories/index.story.d.ts +1 -1
- package/build-types/tab-panel/stories/index.story.d.ts +4 -4
- package/build-types/tabs/stories/index.story.d.ts +9 -9
- package/build-types/tabs/stories/index.story.d.ts.map +1 -1
- package/build-types/text/stories/index.story.d.ts +3 -3
- package/build-types/theme/stories/index.story.d.ts +1 -1
- package/build-types/theme/stories/index.story.d.ts.map +1 -1
- package/build-types/toggle-control/stories/index.story.d.ts +2 -2
- package/build-types/toolbar/stories/index.story.d.ts +3 -3
- package/build-types/tooltip/stories/index.story.d.ts +1 -1
- package/build-types/tree-grid/stories/index.story.d.ts +1 -1
- package/build-types/tree-select/stories/index.story.d.ts +1 -1
- package/build-types/utils/with-ignore-ime-events.d.ts +15 -0
- package/build-types/utils/with-ignore-ime-events.d.ts.map +1 -0
- package/build-types/v-stack/stories/index.story.d.ts +1 -1
- package/package.json +19 -20
- package/src/alignment-matrix-control/test/index.tsx +3 -1
- package/src/autocomplete/index.tsx +3 -10
- package/src/circular-option-picker/test/index.tsx +4 -1
- package/src/color-picker/component.tsx +22 -11
- package/src/color-picker/styles.ts +1 -15
- package/src/combobox-control/index.tsx +33 -41
- package/src/composite/legacy/test/index.tsx +18 -2
- package/src/custom-select-control/README.md +0 -10
- package/src/custom-select-control/index.js +3 -22
- package/src/custom-select-control/stories/index.story.js +0 -1
- package/src/custom-select-control/test/index.js +17 -17
- package/src/custom-select-control-v2/README.md +97 -7
- package/src/custom-select-control-v2/custom-select-item.tsx +29 -0
- package/src/custom-select-control-v2/custom-select.tsx +122 -0
- package/src/custom-select-control-v2/default-component/index.tsx +24 -0
- package/src/custom-select-control-v2/index.tsx +2 -102
- package/src/custom-select-control-v2/legacy-adapter.tsx +25 -0
- package/src/custom-select-control-v2/legacy-component/index.tsx +133 -0
- package/src/custom-select-control-v2/stories/{index.story.tsx → default.story.tsx} +27 -33
- package/src/custom-select-control-v2/stories/legacy.story.tsx +88 -0
- package/src/custom-select-control-v2/styles.ts +82 -38
- package/src/custom-select-control-v2/test/index.tsx +808 -148
- package/src/custom-select-control-v2/types.ts +148 -20
- package/src/dropdown-menu-v2/stories/index.story.tsx +1 -0
- package/src/dropdown-menu-v2/test/index.tsx +4 -1
- package/src/font-size-picker/font-size-picker-select.tsx +0 -1
- package/src/form-token-field/index.tsx +3 -10
- package/src/form-token-field/suggestions-list.tsx +5 -17
- package/src/mobile/keyboard-aware-flat-list/use-scroll-to-section.native.js +1 -1
- package/src/modal/index.tsx +2 -12
- package/src/modal/style.scss +1 -0
- package/src/progress-bar/stories/index.story.tsx +1 -0
- package/src/progress-bar/styles.ts +2 -2
- package/src/tab-panel/test/index.tsx +8 -1
- package/src/tabs/stories/index.story.tsx +1 -0
- package/src/tabs/test/index.tsx +36 -6
- package/src/theme/stories/index.story.tsx +1 -0
- package/src/toggle-group-control/test/index.tsx +4 -0
- package/src/toolbar/toolbar-group/style.scss +1 -0
- package/src/tooltip/test/index.tsx +5 -0
- package/src/utils/with-ignore-ime-events.ts +32 -0
- package/tsconfig.json +0 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/build/custom-select-control/styles.js +0 -27
- package/build/custom-select-control/styles.js.map +0 -1
- package/build-module/custom-select-control/styles.js +0 -18
- package/build-module/custom-select-control/styles.js.map +0 -1
- package/build-types/custom-select-control/styles.d.ts +0 -11
- package/build-types/custom-select-control/styles.d.ts.map +0 -1
- package/build-types/custom-select-control-v2/stories/index.story.d.ts +0 -20
- package/build-types/custom-select-control-v2/stories/index.story.d.ts.map +0 -1
- package/src/custom-select-control/styles.ts +0 -28
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useContext } from '@wordpress/element';
|
|
5
|
+
import { Icon, check } from '@wordpress/icons';
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import type { CustomSelectItemProps } from './types';
|
|
10
|
+
import type { WordPressComponentProps } from '../context';
|
|
11
|
+
import * as Styled from './styles';
|
|
12
|
+
import { CustomSelectContext } from './custom-select';
|
|
13
|
+
|
|
14
|
+
export function CustomSelectItem( {
|
|
15
|
+
children,
|
|
16
|
+
...props
|
|
17
|
+
}: WordPressComponentProps< CustomSelectItemProps, 'div', false > ) {
|
|
18
|
+
const customSelectContext = useContext( CustomSelectContext );
|
|
19
|
+
return (
|
|
20
|
+
<Styled.SelectItem store={ customSelectContext?.store } { ...props }>
|
|
21
|
+
{ children ?? props.value }
|
|
22
|
+
<Styled.SelectedItemCheck>
|
|
23
|
+
<Icon icon={ check } />
|
|
24
|
+
</Styled.SelectedItemCheck>
|
|
25
|
+
</Styled.SelectItem>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default CustomSelectItem;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { createContext, useMemo } from '@wordpress/element';
|
|
5
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
6
|
+
import { Icon, chevronDown } from '@wordpress/icons';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import { VisuallyHidden } from '..';
|
|
12
|
+
import * as Styled from './styles';
|
|
13
|
+
import type {
|
|
14
|
+
CustomSelectContext as CustomSelectContextType,
|
|
15
|
+
CustomSelectStore,
|
|
16
|
+
CustomSelectButtonProps,
|
|
17
|
+
_CustomSelectProps,
|
|
18
|
+
} from './types';
|
|
19
|
+
import {
|
|
20
|
+
contextConnectWithoutRef,
|
|
21
|
+
useContextSystem,
|
|
22
|
+
type WordPressComponentProps,
|
|
23
|
+
} from '../context';
|
|
24
|
+
|
|
25
|
+
export const CustomSelectContext =
|
|
26
|
+
createContext< CustomSelectContextType >( undefined );
|
|
27
|
+
|
|
28
|
+
function defaultRenderSelectedValue(
|
|
29
|
+
value: CustomSelectButtonProps[ 'value' ]
|
|
30
|
+
) {
|
|
31
|
+
const isValueEmpty = Array.isArray( value )
|
|
32
|
+
? value.length === 0
|
|
33
|
+
: value === undefined || value === null;
|
|
34
|
+
|
|
35
|
+
if ( isValueEmpty ) {
|
|
36
|
+
return __( 'Select an item' );
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if ( Array.isArray( value ) ) {
|
|
40
|
+
return value.length === 1
|
|
41
|
+
? value[ 0 ]
|
|
42
|
+
: // translators: %s: number of items selected (it will always be 2 or more items)
|
|
43
|
+
sprintf( __( '%s items selected' ), value.length );
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const UnconnectedCustomSelectButton = (
|
|
50
|
+
props: Omit<
|
|
51
|
+
WordPressComponentProps<
|
|
52
|
+
CustomSelectButtonProps & CustomSelectStore,
|
|
53
|
+
'button',
|
|
54
|
+
false
|
|
55
|
+
>,
|
|
56
|
+
'onChange'
|
|
57
|
+
>
|
|
58
|
+
) => {
|
|
59
|
+
const {
|
|
60
|
+
renderSelectedValue,
|
|
61
|
+
size = 'default',
|
|
62
|
+
store,
|
|
63
|
+
...restProps
|
|
64
|
+
} = useContextSystem( props, 'CustomSelectControlButton' );
|
|
65
|
+
|
|
66
|
+
const { value: currentValue } = store.useState();
|
|
67
|
+
|
|
68
|
+
const computedRenderSelectedValue = useMemo(
|
|
69
|
+
() => renderSelectedValue ?? defaultRenderSelectedValue,
|
|
70
|
+
[ renderSelectedValue ]
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Styled.Select
|
|
75
|
+
{ ...restProps }
|
|
76
|
+
size={ size }
|
|
77
|
+
hasCustomRenderProp={ !! renderSelectedValue }
|
|
78
|
+
store={ store }
|
|
79
|
+
// to match legacy behavior where using arrow keys
|
|
80
|
+
// move selection rather than open the popover
|
|
81
|
+
showOnKeyDown={ false }
|
|
82
|
+
>
|
|
83
|
+
<div>{ computedRenderSelectedValue( currentValue ) }</div>
|
|
84
|
+
<Icon icon={ chevronDown } size={ 18 } />
|
|
85
|
+
</Styled.Select>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const CustomSelectButton = contextConnectWithoutRef(
|
|
90
|
+
UnconnectedCustomSelectButton,
|
|
91
|
+
'CustomSelectControlButton'
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
function _CustomSelect( props: _CustomSelectProps & CustomSelectStore ) {
|
|
95
|
+
const {
|
|
96
|
+
children,
|
|
97
|
+
hideLabelFromVision = false,
|
|
98
|
+
label,
|
|
99
|
+
store,
|
|
100
|
+
...restProps
|
|
101
|
+
} = props;
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<>
|
|
105
|
+
{ hideLabelFromVision ? ( // TODO: Replace with BaseControl
|
|
106
|
+
<VisuallyHidden as="label">{ label }</VisuallyHidden>
|
|
107
|
+
) : (
|
|
108
|
+
<Styled.SelectLabel store={ store }>
|
|
109
|
+
{ label }
|
|
110
|
+
</Styled.SelectLabel>
|
|
111
|
+
) }
|
|
112
|
+
<CustomSelectButton { ...restProps } store={ store } />
|
|
113
|
+
<Styled.SelectPopover gutter={ 12 } store={ store } sameWidth>
|
|
114
|
+
<CustomSelectContext.Provider value={ { store } }>
|
|
115
|
+
{ children }
|
|
116
|
+
</CustomSelectContext.Provider>
|
|
117
|
+
</Styled.SelectPopover>
|
|
118
|
+
</>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export default _CustomSelect;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
// eslint-disable-next-line no-restricted-imports
|
|
5
|
+
import * as Ariakit from '@ariakit/react';
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import _CustomSelect from '../custom-select';
|
|
10
|
+
import type { CustomSelectProps } from '../types';
|
|
11
|
+
|
|
12
|
+
function CustomSelect( props: CustomSelectProps ) {
|
|
13
|
+
const { defaultValue, onChange, value, ...restProps } = props;
|
|
14
|
+
// Forward props + store from v2 implementation
|
|
15
|
+
const store = Ariakit.useSelectStore( {
|
|
16
|
+
setValue: ( nextValue ) => onChange?.( nextValue ),
|
|
17
|
+
defaultValue,
|
|
18
|
+
value,
|
|
19
|
+
} );
|
|
20
|
+
|
|
21
|
+
return <_CustomSelect { ...restProps } store={ store } />;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default CustomSelect;
|
|
@@ -1,105 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
// eslint-disable-next-line no-restricted-imports
|
|
5
|
-
import * as Ariakit from '@ariakit/react';
|
|
6
|
-
/**
|
|
7
|
-
* WordPress dependencies
|
|
8
|
-
*/
|
|
9
|
-
import { createContext, useContext } from '@wordpress/element';
|
|
10
|
-
import { __, sprintf } from '@wordpress/i18n';
|
|
11
|
-
|
|
12
1
|
/**
|
|
13
2
|
* Internal dependencies
|
|
14
3
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
CustomSelectProps,
|
|
18
|
-
CustomSelectItemProps,
|
|
19
|
-
CustomSelectContext as CustomSelectContextType,
|
|
20
|
-
} from './types';
|
|
21
|
-
import type { WordPressComponentProps } from '../context';
|
|
22
|
-
|
|
23
|
-
export const CustomSelectContext =
|
|
24
|
-
createContext< CustomSelectContextType >( undefined );
|
|
25
|
-
|
|
26
|
-
function defaultRenderSelectedValue( value: CustomSelectProps[ 'value' ] ) {
|
|
27
|
-
const isValueEmpty = Array.isArray( value )
|
|
28
|
-
? value.length === 0
|
|
29
|
-
: value === undefined || value === null;
|
|
30
|
-
|
|
31
|
-
if ( isValueEmpty ) {
|
|
32
|
-
return __( 'Select an item' );
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if ( Array.isArray( value ) ) {
|
|
36
|
-
return value.length === 1
|
|
37
|
-
? value[ 0 ]
|
|
38
|
-
: // translators: %s: number of items selected (it will always be 2 or more items)
|
|
39
|
-
sprintf( __( '%s items selected' ), value.length );
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return value;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function CustomSelect( {
|
|
46
|
-
children,
|
|
47
|
-
defaultValue,
|
|
48
|
-
label,
|
|
49
|
-
onChange,
|
|
50
|
-
size = 'default',
|
|
51
|
-
value,
|
|
52
|
-
renderSelectedValue,
|
|
53
|
-
...props
|
|
54
|
-
}: WordPressComponentProps< CustomSelectProps, 'button', false > ) {
|
|
55
|
-
const store = Ariakit.useSelectStore( {
|
|
56
|
-
setValue: ( nextValue ) => onChange?.( nextValue ),
|
|
57
|
-
defaultValue,
|
|
58
|
-
value,
|
|
59
|
-
// fix for Safari bug: https://github.com/WordPress/gutenberg/issues/55023#issuecomment-1834035917
|
|
60
|
-
virtualFocus: false,
|
|
61
|
-
} );
|
|
62
|
-
|
|
63
|
-
const { value: currentValue } = store.useState();
|
|
64
|
-
|
|
65
|
-
const computedRenderSelectedValue =
|
|
66
|
-
renderSelectedValue ?? defaultRenderSelectedValue;
|
|
67
|
-
|
|
68
|
-
return (
|
|
69
|
-
<>
|
|
70
|
-
<Styled.CustomSelectLabel store={ store }>
|
|
71
|
-
{ label }
|
|
72
|
-
</Styled.CustomSelectLabel>
|
|
73
|
-
<Styled.CustomSelectButton
|
|
74
|
-
{ ...props }
|
|
75
|
-
size={ size }
|
|
76
|
-
hasCustomRenderProp={ !! renderSelectedValue }
|
|
77
|
-
store={ store }
|
|
78
|
-
>
|
|
79
|
-
{ computedRenderSelectedValue( currentValue ) }
|
|
80
|
-
<Ariakit.SelectArrow />
|
|
81
|
-
</Styled.CustomSelectButton>
|
|
82
|
-
<Styled.CustomSelectPopover gutter={ 12 } store={ store } sameWidth>
|
|
83
|
-
<CustomSelectContext.Provider value={ { store } }>
|
|
84
|
-
{ children }
|
|
85
|
-
</CustomSelectContext.Provider>
|
|
86
|
-
</Styled.CustomSelectPopover>
|
|
87
|
-
</>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function CustomSelectItem( {
|
|
92
|
-
children,
|
|
93
|
-
...props
|
|
94
|
-
}: WordPressComponentProps< CustomSelectItemProps, 'div', false > ) {
|
|
95
|
-
const customSelectContext = useContext( CustomSelectContext );
|
|
96
|
-
return (
|
|
97
|
-
<Styled.CustomSelectItem
|
|
98
|
-
store={ customSelectContext?.store }
|
|
99
|
-
{ ...props }
|
|
100
|
-
>
|
|
101
|
-
{ children ?? props.value }
|
|
102
|
-
<Ariakit.SelectItemCheck />
|
|
103
|
-
</Styled.CustomSelectItem>
|
|
104
|
-
);
|
|
105
|
-
}
|
|
4
|
+
export { default as CustomSelect } from './legacy-adapter';
|
|
5
|
+
export { default as CustomSelectItem } from './custom-select-item';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import _LegacyCustomSelect from './legacy-component';
|
|
5
|
+
import _NewCustomSelect from './default-component';
|
|
6
|
+
import type { CustomSelectProps, LegacyCustomSelectProps } from './types';
|
|
7
|
+
import type { WordPressComponentProps } from '../context';
|
|
8
|
+
|
|
9
|
+
function isLegacy( props: any ): props is LegacyCustomSelectProps {
|
|
10
|
+
return typeof props.options !== 'undefined';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function CustomSelect(
|
|
14
|
+
props:
|
|
15
|
+
| LegacyCustomSelectProps
|
|
16
|
+
| WordPressComponentProps< CustomSelectProps, 'button', false >
|
|
17
|
+
) {
|
|
18
|
+
if ( isLegacy( props ) ) {
|
|
19
|
+
return <_LegacyCustomSelect { ...props } />;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return <_NewCustomSelect { ...props } />;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default CustomSelect;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
// eslint-disable-next-line no-restricted-imports
|
|
5
|
+
import * as Ariakit from '@ariakit/react';
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { useMemo } from '@wordpress/element';
|
|
10
|
+
/**
|
|
11
|
+
* Internal dependencies
|
|
12
|
+
*/
|
|
13
|
+
import _CustomSelect from '../custom-select';
|
|
14
|
+
import type { LegacyCustomSelectProps } from '../types';
|
|
15
|
+
import { CustomSelectItem } from '..';
|
|
16
|
+
import * as Styled from '../styles';
|
|
17
|
+
import { ContextSystemProvider } from '../../context';
|
|
18
|
+
|
|
19
|
+
function CustomSelect( props: LegacyCustomSelectProps ) {
|
|
20
|
+
const {
|
|
21
|
+
__experimentalShowSelectedHint,
|
|
22
|
+
__next40pxDefaultSize = false,
|
|
23
|
+
options,
|
|
24
|
+
onChange,
|
|
25
|
+
size = 'default',
|
|
26
|
+
value,
|
|
27
|
+
...restProps
|
|
28
|
+
} = props;
|
|
29
|
+
|
|
30
|
+
// Forward props + store from v2 implementation
|
|
31
|
+
const store = Ariakit.useSelectStore( {
|
|
32
|
+
async setValue( nextValue ) {
|
|
33
|
+
if ( ! onChange ) return;
|
|
34
|
+
|
|
35
|
+
// Executes the logic in a microtask after the popup is closed.
|
|
36
|
+
// This is simply to ensure the isOpen state matches that in Downshift.
|
|
37
|
+
await Promise.resolve();
|
|
38
|
+
const state = store.getState();
|
|
39
|
+
|
|
40
|
+
const changeObject = {
|
|
41
|
+
highlightedIndex: state.renderedItems.findIndex(
|
|
42
|
+
( item ) => item.value === nextValue
|
|
43
|
+
),
|
|
44
|
+
inputValue: '',
|
|
45
|
+
isOpen: state.open,
|
|
46
|
+
selectedItem: {
|
|
47
|
+
name: nextValue as string,
|
|
48
|
+
key: nextValue as string,
|
|
49
|
+
},
|
|
50
|
+
type: '',
|
|
51
|
+
};
|
|
52
|
+
onChange( changeObject );
|
|
53
|
+
},
|
|
54
|
+
} );
|
|
55
|
+
|
|
56
|
+
const children = options.map(
|
|
57
|
+
( { name, key, __experimentalHint, ...rest } ) => {
|
|
58
|
+
const withHint = (
|
|
59
|
+
<Styled.WithHintWrapper>
|
|
60
|
+
<span>{ name }</span>
|
|
61
|
+
<Styled.ExperimentalHintItem className="components-custom-select-control__item-hint">
|
|
62
|
+
{ __experimentalHint }
|
|
63
|
+
</Styled.ExperimentalHintItem>
|
|
64
|
+
</Styled.WithHintWrapper>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<CustomSelectItem
|
|
69
|
+
key={ key }
|
|
70
|
+
value={ name }
|
|
71
|
+
children={
|
|
72
|
+
__experimentalShowSelectedHint ? withHint : name
|
|
73
|
+
}
|
|
74
|
+
{ ...rest }
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const renderSelectedValueHint = () => {
|
|
81
|
+
const { value: currentValue } = store.getState();
|
|
82
|
+
|
|
83
|
+
const currentHint = options?.find(
|
|
84
|
+
( { name } ) => currentValue === name
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<>
|
|
89
|
+
{ currentValue }
|
|
90
|
+
<Styled.SelectedExperimentalHintItem className="components-custom-select-control__hint">
|
|
91
|
+
{ currentHint?.__experimentalHint }
|
|
92
|
+
</Styled.SelectedExperimentalHintItem>
|
|
93
|
+
</>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// translate legacy button sizing
|
|
98
|
+
const contextSystemValue = useMemo( () => {
|
|
99
|
+
let selectedSize;
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
( __next40pxDefaultSize && size === 'default' ) ||
|
|
103
|
+
size === '__unstable-large'
|
|
104
|
+
) {
|
|
105
|
+
selectedSize = 'default';
|
|
106
|
+
} else if ( ! __next40pxDefaultSize && size === 'default' ) {
|
|
107
|
+
selectedSize = 'compact';
|
|
108
|
+
} else {
|
|
109
|
+
selectedSize = size;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
CustomSelectControlButton: { _overrides: { size: selectedSize } },
|
|
114
|
+
};
|
|
115
|
+
}, [ __next40pxDefaultSize, size ] );
|
|
116
|
+
|
|
117
|
+
const translatedProps = {
|
|
118
|
+
'aria-describedby': props.describedBy,
|
|
119
|
+
children,
|
|
120
|
+
renderSelectedValue: __experimentalShowSelectedHint
|
|
121
|
+
? renderSelectedValueHint
|
|
122
|
+
: undefined,
|
|
123
|
+
...restProps,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<ContextSystemProvider value={ contextSystemValue }>
|
|
128
|
+
<_CustomSelect { ...translatedProps } store={ store } />
|
|
129
|
+
</ContextSystemProvider>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export default CustomSelect;
|
|
@@ -11,10 +11,11 @@ import { useState } from '@wordpress/element';
|
|
|
11
11
|
/**
|
|
12
12
|
* Internal dependencies
|
|
13
13
|
*/
|
|
14
|
-
import
|
|
14
|
+
import CustomSelect from '../default-component';
|
|
15
|
+
import { CustomSelectItem } from '..';
|
|
15
16
|
|
|
16
17
|
const meta: Meta< typeof CustomSelect > = {
|
|
17
|
-
title: 'Components (Experimental)/CustomSelectControl v2',
|
|
18
|
+
title: 'Components (Experimental)/CustomSelectControl v2/Default',
|
|
18
19
|
component: CustomSelect,
|
|
19
20
|
subcomponents: {
|
|
20
21
|
// @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170
|
|
@@ -22,15 +23,14 @@ const meta: Meta< typeof CustomSelect > = {
|
|
|
22
23
|
},
|
|
23
24
|
argTypes: {
|
|
24
25
|
children: { control: { type: null } },
|
|
25
|
-
renderSelectedValue: { control: { type: null } },
|
|
26
26
|
value: { control: { type: null } },
|
|
27
27
|
},
|
|
28
|
+
tags: [ 'status-wip' ],
|
|
28
29
|
parameters: {
|
|
29
30
|
badges: [ 'wip' ],
|
|
30
31
|
actions: { argTypesRegex: '^on.*' },
|
|
31
32
|
controls: { expanded: true },
|
|
32
33
|
docs: {
|
|
33
|
-
canvas: { sourceState: 'shown' },
|
|
34
34
|
source: { excludeDecorators: true },
|
|
35
35
|
},
|
|
36
36
|
},
|
|
@@ -49,15 +49,11 @@ const meta: Meta< typeof CustomSelect > = {
|
|
|
49
49
|
export default meta;
|
|
50
50
|
|
|
51
51
|
const Template: StoryFn< typeof CustomSelect > = ( props ) => {
|
|
52
|
-
return <CustomSelect { ...props } />;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const ControlledTemplate: StoryFn< typeof CustomSelect > = ( props ) => {
|
|
56
52
|
const [ value, setValue ] = useState< string | string[] >();
|
|
57
53
|
return (
|
|
58
54
|
<CustomSelect
|
|
59
55
|
{ ...props }
|
|
60
|
-
onChange={ ( nextValue ) => {
|
|
56
|
+
onChange={ ( nextValue: string | string[] ) => {
|
|
61
57
|
setValue( nextValue );
|
|
62
58
|
props.onChange?.( nextValue );
|
|
63
59
|
} }
|
|
@@ -68,14 +64,18 @@ const ControlledTemplate: StoryFn< typeof CustomSelect > = ( props ) => {
|
|
|
68
64
|
|
|
69
65
|
export const Default = Template.bind( {} );
|
|
70
66
|
Default.args = {
|
|
71
|
-
label: 'Label',
|
|
67
|
+
label: 'Label text',
|
|
68
|
+
defaultValue: 'Select a color...',
|
|
72
69
|
children: (
|
|
73
70
|
<>
|
|
74
|
-
<CustomSelectItem value="
|
|
75
|
-
<span style={ {
|
|
71
|
+
<CustomSelectItem value="Blue">
|
|
72
|
+
<span style={ { color: 'blue' } }>Blue</span>
|
|
76
73
|
</CustomSelectItem>
|
|
77
|
-
<CustomSelectItem value="
|
|
78
|
-
<span style={ {
|
|
74
|
+
<CustomSelectItem value="Purple">
|
|
75
|
+
<span style={ { color: 'purple' } }>Purple</span>
|
|
76
|
+
</CustomSelectItem>
|
|
77
|
+
<CustomSelectItem value="Pink">
|
|
78
|
+
<span style={ { color: 'deeppink' } }>Pink</span>
|
|
79
79
|
</CustomSelectItem>
|
|
80
80
|
</>
|
|
81
81
|
),
|
|
@@ -83,21 +83,13 @@ Default.args = {
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Multiple selection can be enabled by using an array for the `value` and
|
|
86
|
-
* `defaultValue` props. The argument of the `onChange` function will also
|
|
86
|
+
* `defaultValue` props. The argument type of the `onChange` function will also
|
|
87
87
|
* change accordingly.
|
|
88
88
|
*/
|
|
89
|
-
export const
|
|
90
|
-
|
|
91
|
-
defaultValue: [ 'lavender', 'tangerine' ],
|
|
89
|
+
export const MultipleSelection = Template.bind( {} );
|
|
90
|
+
MultipleSelection.args = {
|
|
92
91
|
label: 'Select Colors',
|
|
93
|
-
|
|
94
|
-
if ( ! Array.isArray( currentValue ) ) {
|
|
95
|
-
return currentValue;
|
|
96
|
-
}
|
|
97
|
-
if ( currentValue.length === 0 ) return 'No colors selected';
|
|
98
|
-
if ( currentValue.length === 1 ) return currentValue[ 0 ];
|
|
99
|
-
return `${ currentValue.length } colors selected`;
|
|
100
|
-
},
|
|
92
|
+
defaultValue: [ 'lavender', 'tangerine' ],
|
|
101
93
|
children: (
|
|
102
94
|
<>
|
|
103
95
|
{ [
|
|
@@ -116,32 +108,34 @@ MultiSelect.args = {
|
|
|
116
108
|
),
|
|
117
109
|
};
|
|
118
110
|
|
|
119
|
-
const
|
|
111
|
+
const renderItem = ( gravatar: string | string[] ) => {
|
|
120
112
|
const avatar = `https://gravatar.com/avatar?d=${ gravatar }`;
|
|
121
113
|
return (
|
|
122
114
|
<div style={ { display: 'flex', alignItems: 'center' } }>
|
|
123
115
|
<img
|
|
124
116
|
style={ { maxHeight: '75px', marginRight: '10px' } }
|
|
125
|
-
key={ avatar }
|
|
126
117
|
src={ avatar }
|
|
127
118
|
alt=""
|
|
128
|
-
aria-hidden="true"
|
|
129
119
|
/>
|
|
130
120
|
<span>{ gravatar }</span>
|
|
131
121
|
</div>
|
|
132
122
|
);
|
|
133
123
|
};
|
|
134
124
|
|
|
135
|
-
|
|
136
|
-
|
|
125
|
+
/**
|
|
126
|
+
* The `renderSelectedValue` prop can be used to customize how the selected value
|
|
127
|
+
* is rendered in the dropdown trigger.
|
|
128
|
+
*/
|
|
129
|
+
export const CustomSelectedValue = Template.bind( {} );
|
|
130
|
+
CustomSelectedValue.args = {
|
|
137
131
|
label: 'Default Gravatars',
|
|
138
|
-
renderSelectedValue:
|
|
132
|
+
renderSelectedValue: renderItem,
|
|
139
133
|
children: (
|
|
140
134
|
<>
|
|
141
135
|
{ [ 'mystery-person', 'identicon', 'wavatar', 'retro' ].map(
|
|
142
136
|
( option ) => (
|
|
143
137
|
<CustomSelectItem key={ option } value={ option }>
|
|
144
|
-
{
|
|
138
|
+
{ renderItem( option ) }
|
|
145
139
|
</CustomSelectItem>
|
|
146
140
|
)
|
|
147
141
|
) }
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import type { Meta, StoryFn } from '@storybook/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { useState } from '@wordpress/element';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import _LegacyCustomSelect from '../legacy-component';
|
|
15
|
+
import { CustomSelect } from '..';
|
|
16
|
+
|
|
17
|
+
const meta: Meta< typeof _LegacyCustomSelect > = {
|
|
18
|
+
title: 'Components (Experimental)/CustomSelectControl v2/Legacy',
|
|
19
|
+
component: _LegacyCustomSelect,
|
|
20
|
+
argTypes: {
|
|
21
|
+
onChange: { control: { type: null } },
|
|
22
|
+
value: { control: { type: null } },
|
|
23
|
+
},
|
|
24
|
+
parameters: {
|
|
25
|
+
badges: [ 'wip' ],
|
|
26
|
+
actions: { argTypesRegex: '^on.*' },
|
|
27
|
+
controls: { expanded: true },
|
|
28
|
+
docs: {
|
|
29
|
+
source: { excludeDecorators: true },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
decorators: [
|
|
33
|
+
( Story ) => (
|
|
34
|
+
<div
|
|
35
|
+
style={ {
|
|
36
|
+
minHeight: '150px',
|
|
37
|
+
} }
|
|
38
|
+
>
|
|
39
|
+
<Story />
|
|
40
|
+
</div>
|
|
41
|
+
),
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
export default meta;
|
|
45
|
+
|
|
46
|
+
const Template: StoryFn< typeof _LegacyCustomSelect > = ( props ) => {
|
|
47
|
+
const [ fontSize, setFontSize ] = useState( props.options[ 0 ] );
|
|
48
|
+
|
|
49
|
+
const onChange: React.ComponentProps<
|
|
50
|
+
typeof _LegacyCustomSelect
|
|
51
|
+
>[ 'onChange' ] = ( changeObject ) => {
|
|
52
|
+
setFontSize( changeObject.selectedItem );
|
|
53
|
+
props.onChange?.( changeObject );
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<CustomSelect { ...props } onChange={ onChange } value={ fontSize } />
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const Default = Template.bind( {} );
|
|
62
|
+
Default.args = {
|
|
63
|
+
label: 'Label text',
|
|
64
|
+
options: [
|
|
65
|
+
{
|
|
66
|
+
key: 'small',
|
|
67
|
+
name: 'Small',
|
|
68
|
+
style: { fontSize: '50%' },
|
|
69
|
+
__experimentalHint: '50%',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
key: 'normal',
|
|
73
|
+
name: 'Normal',
|
|
74
|
+
style: { fontSize: '100%' },
|
|
75
|
+
className: 'can-apply-custom-class-to-option',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: 'large',
|
|
79
|
+
name: 'Large',
|
|
80
|
+
style: { fontSize: '200%' },
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
key: 'huge',
|
|
84
|
+
name: 'Huge',
|
|
85
|
+
style: { fontSize: '300%' },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|