@wordpress/commands 0.2.0 → 0.4.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 +4 -0
- package/build/components/command-menu.js +47 -24
- package/build/components/command-menu.js.map +1 -1
- package/build/hooks/use-command.js +2 -1
- package/build/hooks/use-command.js.map +1 -1
- package/build/private-apis.js +4 -1
- package/build/private-apis.js.map +1 -1
- package/build/store/actions.js +33 -4
- package/build/store/actions.js.map +1 -1
- package/build/store/reducer.js +28 -2
- package/build/store/reducer.js.map +1 -1
- package/build/store/selectors.js +5 -0
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/command-menu.js +47 -25
- package/build-module/components/command-menu.js.map +1 -1
- package/build-module/hooks/use-command.js +2 -1
- package/build-module/hooks/use-command.js.map +1 -1
- package/build-module/private-apis.js +3 -1
- package/build-module/private-apis.js.map +1 -1
- package/build-module/store/actions.js +29 -4
- package/build-module/store/actions.js.map +1 -1
- package/build-module/store/reducer.js +28 -2
- package/build-module/store/reducer.js.map +1 -1
- package/build-module/store/selectors.js +3 -0
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +20 -76
- package/build-style/style.css +20 -76
- package/package.json +10 -10
- package/src/components/command-menu.js +72 -44
- package/src/components/style.scss +20 -78
- package/src/hooks/use-command.js +2 -0
- package/src/private-apis.js +2 -0
- package/src/store/actions.js +29 -5
- package/src/store/reducer.js +21 -0
- package/src/store/selectors.js +5 -0
|
@@ -9,11 +9,16 @@ import { Command } from 'cmdk';
|
|
|
9
9
|
import { useSelect, useDispatch } from '@wordpress/data';
|
|
10
10
|
import { useState, useEffect, useRef, useCallback } from '@wordpress/element';
|
|
11
11
|
import { __ } from '@wordpress/i18n';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
Modal,
|
|
14
|
+
TextHighlight,
|
|
15
|
+
__experimentalHStack as HStack,
|
|
16
|
+
} from '@wordpress/components';
|
|
13
17
|
import {
|
|
14
18
|
store as keyboardShortcutsStore,
|
|
15
19
|
useShortcut,
|
|
16
20
|
} from '@wordpress/keyboard-shortcuts';
|
|
21
|
+
import { Icon } from '@wordpress/icons';
|
|
17
22
|
|
|
18
23
|
/**
|
|
19
24
|
* Internal dependencies
|
|
@@ -39,12 +44,18 @@ function CommandMenuLoader( { name, search, hook, setLoader, close } ) {
|
|
|
39
44
|
value={ command.name }
|
|
40
45
|
onSelect={ () => command.callback( { close } ) }
|
|
41
46
|
>
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/>
|
|
47
|
-
|
|
47
|
+
<HStack
|
|
48
|
+
alignment="left"
|
|
49
|
+
className="commands-command-menu__item"
|
|
50
|
+
>
|
|
51
|
+
<Icon icon={ command.icon } />
|
|
52
|
+
<span>
|
|
53
|
+
<TextHighlight
|
|
54
|
+
text={ command.label }
|
|
55
|
+
highlight={ search }
|
|
56
|
+
/>
|
|
57
|
+
</span>
|
|
58
|
+
</HStack>
|
|
48
59
|
</Command.Item>
|
|
49
60
|
) ) }
|
|
50
61
|
</Command.List>
|
|
@@ -91,19 +102,25 @@ export function CommandMenuGroup( { group, search, setLoader, close } ) {
|
|
|
91
102
|
);
|
|
92
103
|
|
|
93
104
|
return (
|
|
94
|
-
<Command.Group
|
|
105
|
+
<Command.Group>
|
|
95
106
|
{ commands.map( ( command ) => (
|
|
96
107
|
<Command.Item
|
|
97
108
|
key={ command.name }
|
|
98
109
|
value={ command.name }
|
|
99
110
|
onSelect={ () => command.callback( { close } ) }
|
|
100
111
|
>
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
/>
|
|
106
|
-
|
|
112
|
+
<HStack
|
|
113
|
+
alignment="left"
|
|
114
|
+
className="commands-command-menu__item"
|
|
115
|
+
>
|
|
116
|
+
<Icon icon={ command.icon } />
|
|
117
|
+
<span>
|
|
118
|
+
<TextHighlight
|
|
119
|
+
text={ command.label }
|
|
120
|
+
highlight={ search }
|
|
121
|
+
/>
|
|
122
|
+
</span>
|
|
123
|
+
</HStack>
|
|
107
124
|
</Command.Item>
|
|
108
125
|
) ) }
|
|
109
126
|
{ loaders.map( ( loader ) => (
|
|
@@ -122,14 +139,16 @@ export function CommandMenuGroup( { group, search, setLoader, close } ) {
|
|
|
122
139
|
export function CommandMenu() {
|
|
123
140
|
const { registerShortcut } = useDispatch( keyboardShortcutsStore );
|
|
124
141
|
const [ search, setSearch ] = useState( '' );
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
const { getGroups } = select( commandsStore );
|
|
142
|
+
const { groups, isOpen } = useSelect( ( select ) => {
|
|
143
|
+
const { getGroups, isOpen: _isOpen } = select( commandsStore );
|
|
128
144
|
return {
|
|
129
145
|
groups: getGroups(),
|
|
146
|
+
isOpen: _isOpen(),
|
|
130
147
|
};
|
|
131
148
|
}, [] );
|
|
149
|
+
const { open, close } = useDispatch( commandsStore );
|
|
132
150
|
const [ loaders, setLoaders ] = useState( {} );
|
|
151
|
+
const commandMenuInput = useRef();
|
|
133
152
|
|
|
134
153
|
useEffect( () => {
|
|
135
154
|
registerShortcut( {
|
|
@@ -147,7 +166,11 @@ export function CommandMenu() {
|
|
|
147
166
|
'core/commands',
|
|
148
167
|
( event ) => {
|
|
149
168
|
event.preventDefault();
|
|
150
|
-
|
|
169
|
+
if ( isOpen ) {
|
|
170
|
+
close();
|
|
171
|
+
} else {
|
|
172
|
+
open();
|
|
173
|
+
}
|
|
151
174
|
},
|
|
152
175
|
{
|
|
153
176
|
bindGlobal: true,
|
|
@@ -162,12 +185,19 @@ export function CommandMenu() {
|
|
|
162
185
|
} ) ),
|
|
163
186
|
[]
|
|
164
187
|
);
|
|
165
|
-
const
|
|
188
|
+
const closeAndReset = () => {
|
|
166
189
|
setSearch( '' );
|
|
167
|
-
|
|
190
|
+
close();
|
|
168
191
|
};
|
|
169
192
|
|
|
170
|
-
|
|
193
|
+
useEffect( () => {
|
|
194
|
+
// Focus the command menu input when mounting the modal.
|
|
195
|
+
if ( isOpen ) {
|
|
196
|
+
commandMenuInput.current.focus();
|
|
197
|
+
}
|
|
198
|
+
}, [ isOpen ] );
|
|
199
|
+
|
|
200
|
+
if ( ! isOpen ) {
|
|
171
201
|
return false;
|
|
172
202
|
}
|
|
173
203
|
const isLoading = Object.values( loaders ).some( Boolean );
|
|
@@ -176,39 +206,37 @@ export function CommandMenu() {
|
|
|
176
206
|
<Modal
|
|
177
207
|
className="commands-command-menu"
|
|
178
208
|
overlayClassName="commands-command-menu__overlay"
|
|
179
|
-
onRequestClose={
|
|
209
|
+
onRequestClose={ closeAndReset }
|
|
180
210
|
__experimentalHideHeader
|
|
181
211
|
>
|
|
182
212
|
<div className="commands-command-menu__container">
|
|
183
213
|
<Command label={ __( 'Global Command Menu' ) }>
|
|
184
214
|
<div className="commands-command-menu__header">
|
|
185
215
|
<Command.Input
|
|
186
|
-
|
|
187
|
-
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
188
|
-
autoFocus
|
|
216
|
+
ref={ commandMenuInput }
|
|
189
217
|
value={ search }
|
|
190
218
|
onValueChange={ setSearch }
|
|
191
|
-
placeholder={ __(
|
|
192
|
-
'Search for content and templates, or try commands like "Add…"'
|
|
193
|
-
) }
|
|
219
|
+
placeholder={ __( 'Type a command or search' ) }
|
|
194
220
|
/>
|
|
195
221
|
</div>
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
222
|
+
{ search && (
|
|
223
|
+
<Command.List>
|
|
224
|
+
{ ! isLoading && (
|
|
225
|
+
<Command.Empty>
|
|
226
|
+
{ __( 'No results found.' ) }
|
|
227
|
+
</Command.Empty>
|
|
228
|
+
) }
|
|
229
|
+
{ groups.map( ( group ) => (
|
|
230
|
+
<CommandMenuGroup
|
|
231
|
+
key={ group }
|
|
232
|
+
group={ group }
|
|
233
|
+
search={ search }
|
|
234
|
+
setLoader={ setLoader }
|
|
235
|
+
close={ closeAndReset }
|
|
236
|
+
/>
|
|
237
|
+
) ) }
|
|
238
|
+
</Command.List>
|
|
239
|
+
) }
|
|
212
240
|
</Command>
|
|
213
241
|
</div>
|
|
214
242
|
</Modal>
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// dirty hack to clean up modal
|
|
2
2
|
.commands-command-menu {
|
|
3
|
-
padding: 0;
|
|
4
3
|
width: 100%;
|
|
5
|
-
max-width:
|
|
4
|
+
max-width: 480px;
|
|
6
5
|
position: relative;
|
|
7
6
|
top: 15%;
|
|
8
7
|
|
|
@@ -20,7 +19,6 @@
|
|
|
20
19
|
.commands-command-menu__header {
|
|
21
20
|
display: flex;
|
|
22
21
|
align-items: center;
|
|
23
|
-
margin: $grid-unit-15 $grid-unit-15 0 $grid-unit-15;
|
|
24
22
|
|
|
25
23
|
.components-button {
|
|
26
24
|
height: $grid-unit-70;
|
|
@@ -38,72 +36,47 @@
|
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
.commands-command-menu__container {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
padding: 0 8px;
|
|
44
|
-
font-size: 12px;
|
|
45
|
-
color: $gray-800;
|
|
46
|
-
background: $gray-300;
|
|
47
|
-
border-radius: 4px;
|
|
48
|
-
width: fit-content;
|
|
49
|
-
display: flex;
|
|
50
|
-
align-items: center;
|
|
51
|
-
margin: $grid-unit-20 $grid-unit-20 0;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
[cmdk-linear-shortcuts] {
|
|
55
|
-
display: flex;
|
|
56
|
-
margin-left: auto;
|
|
57
|
-
gap: $grid-unit-10;
|
|
58
|
-
|
|
59
|
-
kbd {
|
|
60
|
-
color: $gray-800;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
39
|
+
// the style here is a hack to force safari to repaint to avoid a style glitch
|
|
40
|
+
will-change: transform;
|
|
63
41
|
|
|
64
42
|
[cmdk-input] {
|
|
65
|
-
border:
|
|
43
|
+
border: none;
|
|
66
44
|
width: 100%;
|
|
67
|
-
padding: $grid-unit-
|
|
68
|
-
min-height: $grid-unit-70;
|
|
45
|
+
padding: $grid-unit-20;
|
|
69
46
|
outline: none;
|
|
70
47
|
color: $gray-900;
|
|
71
48
|
margin: 0;
|
|
72
|
-
|
|
49
|
+
font-size: 20px;
|
|
50
|
+
line-height: 28px;
|
|
51
|
+
border-bottom: 1px solid $gray-200;
|
|
52
|
+
border-radius: 0;
|
|
73
53
|
|
|
74
54
|
&::placeholder {
|
|
75
55
|
color: $gray-600;
|
|
76
56
|
}
|
|
77
57
|
|
|
78
58
|
&:focus {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
59
|
+
box-shadow: none;
|
|
60
|
+
outline: none;
|
|
61
|
+
border-bottom: 1px solid $gray-200;
|
|
82
62
|
}
|
|
83
63
|
}
|
|
84
64
|
|
|
85
65
|
[cmdk-item] {
|
|
86
|
-
|
|
87
|
-
border-radius: $radius-block-ui;
|
|
66
|
+
border-radius: $grid-unit-05;
|
|
88
67
|
cursor: pointer;
|
|
89
|
-
height: $grid-unit-50;
|
|
90
68
|
display: flex;
|
|
91
69
|
align-items: center;
|
|
92
|
-
|
|
93
|
-
padding: 0 $grid-unit-20;
|
|
70
|
+
padding: $grid-unit;
|
|
94
71
|
color: $gray-900;
|
|
95
|
-
user-select: none;
|
|
96
|
-
will-change: background, color;
|
|
97
|
-
transition: all 150ms ease;
|
|
98
|
-
transition-property: none;
|
|
99
|
-
position: relative;
|
|
100
72
|
|
|
101
|
-
&[aria-selected="true"]
|
|
73
|
+
&[aria-selected="true"],
|
|
74
|
+
&:active {
|
|
102
75
|
background: rgba(var(--wp-admin-theme-color--rgb), 0.04);
|
|
103
76
|
color: var(--wp-admin-theme-color);
|
|
104
77
|
|
|
105
78
|
svg {
|
|
106
|
-
|
|
79
|
+
fill: var(--wp-admin-theme-color);
|
|
107
80
|
}
|
|
108
81
|
}
|
|
109
82
|
|
|
@@ -112,46 +85,15 @@
|
|
|
112
85
|
cursor: not-allowed;
|
|
113
86
|
}
|
|
114
87
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
background: rgba(var(--wp-admin-theme-color--rgb), 0.08);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
& + [cmdk-item] {
|
|
121
|
-
margin-top: $grid-unit-05;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
svg,
|
|
125
|
-
.dashicon {
|
|
126
|
-
width: $grid-unit-20;
|
|
127
|
-
height: $grid-unit-20;
|
|
128
|
-
color: $gray-800;
|
|
88
|
+
svg {
|
|
89
|
+
fill: $gray-600;
|
|
129
90
|
}
|
|
130
91
|
}
|
|
131
92
|
|
|
132
93
|
[cmdk-root] > [cmdk-list] {
|
|
133
|
-
min-height: 300px;
|
|
134
94
|
max-height: 400px;
|
|
135
95
|
overflow: auto;
|
|
136
|
-
|
|
137
|
-
transition: 100ms ease;
|
|
138
|
-
transition-property: height;
|
|
139
|
-
margin: $grid-unit-15;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
[cmdk-group-heading] {
|
|
143
|
-
user-select: none;
|
|
144
|
-
color: $gray-700;
|
|
145
|
-
padding: $grid-unit-30 $grid-unit-20 $grid-unit-20;
|
|
146
|
-
display: flex;
|
|
147
|
-
align-items: center;
|
|
148
|
-
font-size: 11px;
|
|
149
|
-
text-transform: uppercase;
|
|
150
|
-
font-weight: 500;
|
|
151
|
-
position: sticky;
|
|
152
|
-
top: 0;
|
|
153
|
-
background: $white;
|
|
154
|
-
z-index: 1;
|
|
96
|
+
padding: $grid-unit;
|
|
155
97
|
}
|
|
156
98
|
|
|
157
99
|
[cmdk-empty] {
|
package/src/hooks/use-command.js
CHANGED
|
@@ -26,6 +26,7 @@ export default function useCommand( command ) {
|
|
|
26
26
|
name: command.name,
|
|
27
27
|
group: command.group,
|
|
28
28
|
label: command.label,
|
|
29
|
+
icon: command.icon,
|
|
29
30
|
callback: currentCallback.current,
|
|
30
31
|
} );
|
|
31
32
|
return () => {
|
|
@@ -35,6 +36,7 @@ export default function useCommand( command ) {
|
|
|
35
36
|
command.name,
|
|
36
37
|
command.label,
|
|
37
38
|
command.group,
|
|
39
|
+
command.icon,
|
|
38
40
|
registerCommand,
|
|
39
41
|
unregisterCommand,
|
|
40
42
|
] );
|
package/src/private-apis.js
CHANGED
|
@@ -8,6 +8,7 @@ import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/pri
|
|
|
8
8
|
*/
|
|
9
9
|
import { default as useCommand } from './hooks/use-command';
|
|
10
10
|
import { default as useCommandLoader } from './hooks/use-command-loader';
|
|
11
|
+
import { store } from './store';
|
|
11
12
|
|
|
12
13
|
export const { lock, unlock } =
|
|
13
14
|
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
|
|
@@ -19,4 +20,5 @@ export const privateApis = {};
|
|
|
19
20
|
lock( privateApis, {
|
|
20
21
|
useCommand,
|
|
21
22
|
useCommandLoader,
|
|
23
|
+
store,
|
|
22
24
|
} );
|
package/src/store/actions.js
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @typedef {Object} WPCommandConfig
|
|
7
7
|
*
|
|
8
|
-
* @property {string}
|
|
9
|
-
* @property {string}
|
|
10
|
-
* @property {string=}
|
|
11
|
-
* @property {
|
|
8
|
+
* @property {string} name Command name.
|
|
9
|
+
* @property {string} label Command label.
|
|
10
|
+
* @property {string=} group Command group.
|
|
11
|
+
* @property {JSX.Element} icon Command icon.
|
|
12
|
+
* @property {Function} callback Command callback.
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -32,11 +33,12 @@
|
|
|
32
33
|
*
|
|
33
34
|
* @return {Object} action.
|
|
34
35
|
*/
|
|
35
|
-
export function registerCommand( { name, label, callback, group = '' } ) {
|
|
36
|
+
export function registerCommand( { name, label, icon, callback, group = '' } ) {
|
|
36
37
|
return {
|
|
37
38
|
type: 'REGISTER_COMMAND',
|
|
38
39
|
name,
|
|
39
40
|
label,
|
|
41
|
+
icon,
|
|
40
42
|
callback,
|
|
41
43
|
group,
|
|
42
44
|
};
|
|
@@ -89,3 +91,25 @@ export function unregisterCommandLoader( name, group ) {
|
|
|
89
91
|
group,
|
|
90
92
|
};
|
|
91
93
|
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Opens the command center.
|
|
97
|
+
*
|
|
98
|
+
* @return {Object} action.
|
|
99
|
+
*/
|
|
100
|
+
export function open() {
|
|
101
|
+
return {
|
|
102
|
+
type: 'OPEN',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Closes the command center.
|
|
108
|
+
*
|
|
109
|
+
* @return {Object} action.
|
|
110
|
+
*/
|
|
111
|
+
export function close() {
|
|
112
|
+
return {
|
|
113
|
+
type: 'CLOSE',
|
|
114
|
+
};
|
|
115
|
+
}
|
package/src/store/reducer.js
CHANGED
|
@@ -23,6 +23,7 @@ function commands( state = {}, action ) {
|
|
|
23
23
|
label: action.label,
|
|
24
24
|
group: action.group,
|
|
25
25
|
callback: action.callback,
|
|
26
|
+
icon: action.icon,
|
|
26
27
|
},
|
|
27
28
|
},
|
|
28
29
|
};
|
|
@@ -73,9 +74,29 @@ function commandLoaders( state = {}, action ) {
|
|
|
73
74
|
return state;
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Reducer returning the command center open state.
|
|
79
|
+
*
|
|
80
|
+
* @param {Object} state Current state.
|
|
81
|
+
* @param {Object} action Dispatched action.
|
|
82
|
+
*
|
|
83
|
+
* @return {boolean} Updated state.
|
|
84
|
+
*/
|
|
85
|
+
function isOpen( state = false, action ) {
|
|
86
|
+
switch ( action.type ) {
|
|
87
|
+
case 'OPEN':
|
|
88
|
+
return true;
|
|
89
|
+
case 'CLOSE':
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return state;
|
|
94
|
+
}
|
|
95
|
+
|
|
76
96
|
const reducer = combineReducers( {
|
|
77
97
|
commands,
|
|
78
98
|
commandLoaders,
|
|
99
|
+
isOpen,
|
|
79
100
|
} );
|
|
80
101
|
|
|
81
102
|
export default reducer;
|
package/src/store/selectors.js
CHANGED
|
@@ -18,6 +18,7 @@ export const getGroups = createSelector(
|
|
|
18
18
|
),
|
|
19
19
|
( state ) => [ state.commands, state.commandLoaders ]
|
|
20
20
|
);
|
|
21
|
+
|
|
21
22
|
export const getCommands = createSelector(
|
|
22
23
|
( state, group ) => Object.values( state.commands[ group ] ?? {} ),
|
|
23
24
|
( state, group ) => [ state.commands[ group ] ]
|
|
@@ -27,3 +28,7 @@ export const getCommandLoaders = createSelector(
|
|
|
27
28
|
( state, group ) => Object.values( state.commandLoaders[ group ] ?? {} ),
|
|
28
29
|
( state, group ) => [ state.commandLoaders[ group ] ]
|
|
29
30
|
);
|
|
31
|
+
|
|
32
|
+
export function isOpen( state ) {
|
|
33
|
+
return state.isOpen;
|
|
34
|
+
}
|