@wordpress/interface 4.0.1-next.5df0cd52b7.0 → 4.1.2
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 +6 -0
- package/README.md +66 -1
- package/build/components/index.js +16 -0
- package/build/components/index.js.map +1 -1
- package/build/components/interface-skeleton/index.js +7 -6
- package/build/components/interface-skeleton/index.js.map +1 -1
- package/build/components/more-menu-dropdown/index.js +52 -0
- package/build/components/more-menu-dropdown/index.js.map +1 -0
- package/build/components/more-menu-feature-toggle/index.js +63 -0
- package/build/components/more-menu-feature-toggle/index.js.map +1 -0
- package/build/index.js +2 -2
- package/build/index.js.map +1 -1
- package/build/store/actions.js +57 -0
- package/build/store/actions.js.map +1 -1
- package/build/store/index.js +4 -2
- package/build/store/index.js.map +1 -1
- package/build/store/reducer.js +64 -2
- package/build/store/reducer.js.map +1 -1
- package/build/store/selectors.js +20 -0
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/index.js +2 -0
- package/build-module/components/index.js.map +1 -1
- package/build-module/components/interface-skeleton/index.js +7 -7
- package/build-module/components/interface-skeleton/index.js.map +1 -1
- package/build-module/components/more-menu-dropdown/index.js +39 -0
- package/build-module/components/more-menu-dropdown/index.js.map +1 -0
- package/build-module/components/more-menu-feature-toggle/index.js +50 -0
- package/build-module/components/more-menu-feature-toggle/index.js.map +1 -0
- package/build-module/index.js +1 -1
- package/build-module/index.js.map +1 -1
- package/build-module/store/actions.js +51 -0
- package/build-module/store/actions.js.map +1 -1
- package/build-module/store/index.js +4 -2
- package/build-module/store/index.js.map +1 -1
- package/build-module/store/reducer.js +61 -1
- package/build-module/store/reducer.js.map +1 -1
- package/build-module/store/selectors.js +18 -0
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +47 -2
- package/build-style/style.css +47 -2
- package/package.json +12 -11
- package/src/components/complementary-area/style.scss +10 -2
- package/src/components/complementary-area-header/style.scss +8 -0
- package/src/components/index.js +2 -0
- package/src/components/interface-skeleton/index.js +5 -5
- package/src/components/more-menu-dropdown/README.md +78 -0
- package/src/components/more-menu-dropdown/index.js +46 -0
- package/src/components/more-menu-dropdown/style.scss +35 -0
- package/src/components/more-menu-feature-toggle/README.md +59 -0
- package/src/components/more-menu-feature-toggle/index.js +53 -0
- package/src/index.js +1 -1
- package/src/store/actions.js +48 -0
- package/src/store/index.js +4 -2
- package/src/store/reducer.js +55 -0
- package/src/store/selectors.js +20 -0
- package/src/store/test/selectors.js +107 -0
- package/src/style.scss +1 -0
package/build-style/style.css
CHANGED
|
@@ -122,6 +122,12 @@
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
@media (min-width: 782px) {
|
|
126
|
+
.components-panel__header + .interface-complementary-area-header {
|
|
127
|
+
margin-top: 0;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
125
131
|
.interface-complementary-area {
|
|
126
132
|
background: #fff;
|
|
127
133
|
color: #1e1e1e;
|
|
@@ -157,12 +163,18 @@
|
|
|
157
163
|
.interface-complementary-area p {
|
|
158
164
|
margin-top: 0;
|
|
159
165
|
}
|
|
160
|
-
.interface-complementary-area h2
|
|
161
|
-
.interface-complementary-area h3 {
|
|
166
|
+
.interface-complementary-area h2 {
|
|
162
167
|
font-size: 13px;
|
|
163
168
|
color: #1e1e1e;
|
|
164
169
|
margin-bottom: 1.5em;
|
|
165
170
|
}
|
|
171
|
+
.interface-complementary-area h3 {
|
|
172
|
+
font-size: 11px;
|
|
173
|
+
text-transform: uppercase;
|
|
174
|
+
font-weight: 500;
|
|
175
|
+
color: #1e1e1e;
|
|
176
|
+
margin-bottom: 1.5em;
|
|
177
|
+
}
|
|
166
178
|
.interface-complementary-area hr {
|
|
167
179
|
border-top: none;
|
|
168
180
|
border-bottom: 1px solid #f0f0f0;
|
|
@@ -383,6 +395,39 @@ body.is-fullscreen-mode .interface-interface-skeleton {
|
|
|
383
395
|
bottom: 0;
|
|
384
396
|
}
|
|
385
397
|
|
|
398
|
+
.interface-more-menu-dropdown {
|
|
399
|
+
margin-left: -4px;
|
|
400
|
+
}
|
|
401
|
+
.interface-more-menu-dropdown .components-button {
|
|
402
|
+
width: auto;
|
|
403
|
+
padding: 0 2px;
|
|
404
|
+
}
|
|
405
|
+
@media (min-width: 600px) {
|
|
406
|
+
.interface-more-menu-dropdown {
|
|
407
|
+
margin-left: 0;
|
|
408
|
+
}
|
|
409
|
+
.interface-more-menu-dropdown .components-button {
|
|
410
|
+
padding: 0 4px;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.interface-more-menu-dropdown__content .components-popover__content {
|
|
415
|
+
min-width: 280px;
|
|
416
|
+
}
|
|
417
|
+
@media (min-width: 480px) {
|
|
418
|
+
.interface-more-menu-dropdown__content .components-popover__content {
|
|
419
|
+
width: auto;
|
|
420
|
+
max-width: 480px;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
.interface-more-menu-dropdown__content .components-popover__content .components-dropdown-menu__menu {
|
|
424
|
+
padding: 0;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.components-popover.interface-more-menu-dropdown__content {
|
|
428
|
+
z-index: 99998;
|
|
429
|
+
}
|
|
430
|
+
|
|
386
431
|
.interface-pinned-items {
|
|
387
432
|
display: flex;
|
|
388
433
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/interface",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.2",
|
|
4
4
|
"description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -32,20 +32,21 @@
|
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@babel/runtime": "^7.13.10",
|
|
35
|
-
"@wordpress/
|
|
36
|
-
"@wordpress/
|
|
37
|
-
"@wordpress/
|
|
38
|
-
"@wordpress/
|
|
39
|
-
"@wordpress/
|
|
40
|
-
"@wordpress/
|
|
41
|
-
"@wordpress/
|
|
42
|
-
"@wordpress/
|
|
43
|
-
"@wordpress/
|
|
35
|
+
"@wordpress/a11y": "^3.2.3",
|
|
36
|
+
"@wordpress/components": "^19.0.0",
|
|
37
|
+
"@wordpress/compose": "^5.0.4",
|
|
38
|
+
"@wordpress/data": "^6.1.2",
|
|
39
|
+
"@wordpress/deprecated": "^3.2.2",
|
|
40
|
+
"@wordpress/element": "^4.0.3",
|
|
41
|
+
"@wordpress/i18n": "^4.2.3",
|
|
42
|
+
"@wordpress/icons": "^6.0.1",
|
|
43
|
+
"@wordpress/plugins": "^4.0.4",
|
|
44
|
+
"@wordpress/viewport": "^4.0.4",
|
|
44
45
|
"classnames": "^2.3.1",
|
|
45
46
|
"lodash": "^4.17.21"
|
|
46
47
|
},
|
|
47
48
|
"publishConfig": {
|
|
48
49
|
"access": "public"
|
|
49
50
|
},
|
|
50
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "157f4ae53ab98e574af01f72213ae5a9613159ff"
|
|
51
52
|
}
|
|
@@ -35,13 +35,21 @@
|
|
|
35
35
|
margin-top: 0;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
h2
|
|
39
|
-
h3 {
|
|
38
|
+
h2 {
|
|
40
39
|
font-size: $default-font-size;
|
|
41
40
|
color: $gray-900;
|
|
42
41
|
margin-bottom: 1.5em;
|
|
43
42
|
}
|
|
44
43
|
|
|
44
|
+
// Subheading style.
|
|
45
|
+
h3 {
|
|
46
|
+
font-size: 11px;
|
|
47
|
+
text-transform: uppercase;
|
|
48
|
+
font-weight: 500;
|
|
49
|
+
color: $gray-900;
|
|
50
|
+
margin-bottom: 1.5em;
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
hr {
|
|
46
54
|
border-top: none;
|
|
47
55
|
border-bottom: 1px solid $gray-100;
|
|
@@ -31,3 +31,11 @@
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
// This overrides the negative margins between two consecutives panels.
|
|
36
|
+
// since the first panel is hidden.
|
|
37
|
+
.components-panel__header + .interface-complementary-area-header {
|
|
38
|
+
@include break-medium() {
|
|
39
|
+
margin-top: 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/components/index.js
CHANGED
|
@@ -3,4 +3,6 @@ export { default as ComplementaryAreaMoreMenuItem } from './complementary-area-m
|
|
|
3
3
|
export { default as FullscreenMode } from './fullscreen-mode';
|
|
4
4
|
export { default as InterfaceSkeleton } from './interface-skeleton';
|
|
5
5
|
export { default as PinnedItems } from './pinned-items';
|
|
6
|
+
export { default as MoreMenuDropdown } from './more-menu-dropdown';
|
|
7
|
+
export { default as MoreMenuFeatureToggle } from './more-menu-feature-toggle';
|
|
6
8
|
export { default as ActionItem } from './action-item';
|
|
@@ -9,7 +9,7 @@ import classnames from 'classnames';
|
|
|
9
9
|
/**
|
|
10
10
|
* WordPress dependencies
|
|
11
11
|
*/
|
|
12
|
-
import { forwardRef, useEffect
|
|
12
|
+
import { forwardRef, useEffect } from '@wordpress/element';
|
|
13
13
|
import { __unstableUseNavigateRegions as useNavigateRegions } from '@wordpress/components';
|
|
14
14
|
import { __ } from '@wordpress/i18n';
|
|
15
15
|
import { useMergeRefs } from '@wordpress/compose';
|
|
@@ -44,8 +44,7 @@ function InterfaceSkeleton(
|
|
|
44
44
|
},
|
|
45
45
|
ref
|
|
46
46
|
) {
|
|
47
|
-
const
|
|
48
|
-
const regionsClassName = useNavigateRegions( fallbackRef, shortcuts );
|
|
47
|
+
const navigateRegionsProps = useNavigateRegions( shortcuts );
|
|
49
48
|
|
|
50
49
|
useHTMLClass( 'interface-interface-skeleton__html-container' );
|
|
51
50
|
|
|
@@ -70,11 +69,12 @@ function InterfaceSkeleton(
|
|
|
70
69
|
|
|
71
70
|
return (
|
|
72
71
|
<div
|
|
73
|
-
|
|
72
|
+
{ ...navigateRegionsProps }
|
|
73
|
+
ref={ useMergeRefs( [ ref, navigateRegionsProps.ref ] ) }
|
|
74
74
|
className={ classnames(
|
|
75
75
|
className,
|
|
76
76
|
'interface-interface-skeleton',
|
|
77
|
-
|
|
77
|
+
navigateRegionsProps.className,
|
|
78
78
|
!! footer && 'has-footer'
|
|
79
79
|
) }
|
|
80
80
|
>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# MoreMenuDropdown
|
|
2
|
+
|
|
3
|
+
`MoreMenuDropdown` is a convenient component for rendering an editor 'more' menu. This is typically a menu that provides:
|
|
4
|
+
|
|
5
|
+
- menu items for quick toggling editor preferences.
|
|
6
|
+
- a way to open dialogs for keyboard shortcuts and editor preferences.
|
|
7
|
+
- links to help.
|
|
8
|
+
|
|
9
|
+
This component implements a `DropdownMenu` component from the `@wordpress/components` package.
|
|
10
|
+
|
|
11
|
+
See also the `MoreMenuFeatureToggle` component in the `@wordpress/interface` package, which provides an easy way to implement a feature toggle as a child of this component. Use with the `MenuGroup`, `MenuItem`, `MenuItemsChoice` components from the `@wordpress/components` package to implement more advanced behaviors.
|
|
12
|
+
|
|
13
|
+
Note that just like the `DropdownMenu` component, this component accepts a render callback, which child elements should be returned from.
|
|
14
|
+
|
|
15
|
+
## Example
|
|
16
|
+
|
|
17
|
+
```jsx
|
|
18
|
+
function MyEditorMenu() {
|
|
19
|
+
return (
|
|
20
|
+
<MoreMenuDropdown>
|
|
21
|
+
{ () => (
|
|
22
|
+
<MenuGroup label={ __( 'Features' ) }>
|
|
23
|
+
<MoreMenuFeatureToggle
|
|
24
|
+
scope="namespace/editor-or-plugin-name"
|
|
25
|
+
feature="myFeatureName"
|
|
26
|
+
label={ __( 'My feature' ) }
|
|
27
|
+
info={ __( 'A really awesome feature' ) }
|
|
28
|
+
messageActivated={ __( 'My feature activated' )}
|
|
29
|
+
messageDeactivated={ __( 'My feature deactivated' )}
|
|
30
|
+
/>
|
|
31
|
+
</MenuGroup>
|
|
32
|
+
) }
|
|
33
|
+
</MoreMenuDropdown>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Props
|
|
39
|
+
|
|
40
|
+
### as
|
|
41
|
+
|
|
42
|
+
Provide a component that the dropdown should render as. This may be useful if you need `MoreMenuDropdown` to render a `ToolbarDropdownMenu` instead of a `DropdownMenu`. Defaults to `DropdownMenu`.
|
|
43
|
+
|
|
44
|
+
- Type: `Component`
|
|
45
|
+
- Required: No.
|
|
46
|
+
|
|
47
|
+
### className
|
|
48
|
+
|
|
49
|
+
Provide an additional class name to the dropdown component.
|
|
50
|
+
|
|
51
|
+
- Type: `String`
|
|
52
|
+
- Required: No
|
|
53
|
+
|
|
54
|
+
### label
|
|
55
|
+
|
|
56
|
+
Change the label of the button that opens the dropdown.
|
|
57
|
+
|
|
58
|
+
- Default: 'Options'
|
|
59
|
+
- Type: `String`
|
|
60
|
+
- Required: No
|
|
61
|
+
|
|
62
|
+
### popoverProps
|
|
63
|
+
|
|
64
|
+
Override or extend the dropdown's popover props.
|
|
65
|
+
|
|
66
|
+
See the documentation for the `DropdownMenu` and `Popover` components in the `@wordpress/components` package for more information.
|
|
67
|
+
|
|
68
|
+
- Type: `Object`
|
|
69
|
+
- Required: No
|
|
70
|
+
|
|
71
|
+
### toggleProps
|
|
72
|
+
|
|
73
|
+
Override or extend the dropdown's toggle props.
|
|
74
|
+
|
|
75
|
+
See the documentation for the `DropdownMenu` and `Button` components in the `@wordpress/components` package for more information.
|
|
76
|
+
|
|
77
|
+
- Type: `Object`
|
|
78
|
+
- Required: No
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import classnames from 'classnames';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { DropdownMenu } from '@wordpress/components';
|
|
10
|
+
import { __ } from '@wordpress/i18n';
|
|
11
|
+
import { moreVertical } from '@wordpress/icons';
|
|
12
|
+
|
|
13
|
+
export default function MoreMenuDropdown( {
|
|
14
|
+
as: DropdownComponent = DropdownMenu,
|
|
15
|
+
className,
|
|
16
|
+
/* translators: button label text should, if possible, be under 16 characters. */
|
|
17
|
+
label = __( 'Options' ),
|
|
18
|
+
popoverProps,
|
|
19
|
+
toggleProps,
|
|
20
|
+
children,
|
|
21
|
+
} ) {
|
|
22
|
+
return (
|
|
23
|
+
<DropdownComponent
|
|
24
|
+
className={ classnames(
|
|
25
|
+
'interface-more-menu-dropdown',
|
|
26
|
+
className
|
|
27
|
+
) }
|
|
28
|
+
icon={ moreVertical }
|
|
29
|
+
label={ label }
|
|
30
|
+
popoverProps={ {
|
|
31
|
+
position: 'bottom left',
|
|
32
|
+
...popoverProps,
|
|
33
|
+
className: classnames(
|
|
34
|
+
'interface-more-menu-dropdown__content',
|
|
35
|
+
popoverProps?.className
|
|
36
|
+
),
|
|
37
|
+
} }
|
|
38
|
+
toggleProps={ {
|
|
39
|
+
tooltipPosition: 'bottom',
|
|
40
|
+
...toggleProps,
|
|
41
|
+
} }
|
|
42
|
+
>
|
|
43
|
+
{ ( onClose ) => children( onClose ) }
|
|
44
|
+
</DropdownComponent>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.interface-more-menu-dropdown {
|
|
2
|
+
margin-left: -4px;
|
|
3
|
+
|
|
4
|
+
// the padding and margin of the more menu is intentionally non-standard
|
|
5
|
+
.components-button {
|
|
6
|
+
width: auto;
|
|
7
|
+
padding: 0 2px;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@include break-small() {
|
|
11
|
+
margin-left: 0;
|
|
12
|
+
|
|
13
|
+
.components-button {
|
|
14
|
+
padding: 0 4px;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.interface-more-menu-dropdown__content .components-popover__content {
|
|
20
|
+
min-width: 280px;
|
|
21
|
+
|
|
22
|
+
// Let the menu scale to fit items.
|
|
23
|
+
@include break-mobile() {
|
|
24
|
+
width: auto;
|
|
25
|
+
max-width: $break-mobile;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.components-dropdown-menu__menu {
|
|
29
|
+
padding: 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.components-popover.interface-more-menu-dropdown__content {
|
|
34
|
+
z-index: z-index(".components-popover.edit-widgets-more-menu__content");
|
|
35
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# MoreMenuFeatureToggle
|
|
2
|
+
|
|
3
|
+
`MoreMenuFeatureToggle` renders a menu item that can be used as a child of the `MoreMenuDropdown` component. The component
|
|
4
|
+
is connected to the interface package's store, and will toggle the value of a 'feature' between true and false.
|
|
5
|
+
|
|
6
|
+
This component implements a `MenuItem` component from the `@wordpress/components` package.
|
|
7
|
+
|
|
8
|
+
## Props
|
|
9
|
+
|
|
10
|
+
### scope
|
|
11
|
+
|
|
12
|
+
The 'scope' of the feature. This is usually a namespaced string that represents the name of the editor (e.g. 'core/edit-post'), and often matches the name of the store for the editor.
|
|
13
|
+
|
|
14
|
+
- Type: `String`
|
|
15
|
+
- Required: Yes
|
|
16
|
+
|
|
17
|
+
### feature
|
|
18
|
+
|
|
19
|
+
The name of the feature to toggle (e.g. 'fixedToolbar').
|
|
20
|
+
|
|
21
|
+
- Type: `String`
|
|
22
|
+
- Required: Yes
|
|
23
|
+
|
|
24
|
+
### label
|
|
25
|
+
|
|
26
|
+
A human readable label for the feature.
|
|
27
|
+
|
|
28
|
+
- Type: `String`
|
|
29
|
+
- Required: Yes
|
|
30
|
+
|
|
31
|
+
### info
|
|
32
|
+
|
|
33
|
+
A human readable description of what this toggle does.
|
|
34
|
+
|
|
35
|
+
- Type: `Object`
|
|
36
|
+
- Required: No
|
|
37
|
+
|
|
38
|
+
### messageActivated
|
|
39
|
+
|
|
40
|
+
A message read by a screen reader when the feature is activated. (e.g. 'Fixed toolbar activated')
|
|
41
|
+
|
|
42
|
+
- Type: `String`
|
|
43
|
+
- Required: No
|
|
44
|
+
|
|
45
|
+
### messageDeactivated
|
|
46
|
+
|
|
47
|
+
A message read by a screen reader when the feature is deactivated. (e.g. 'Fixed toolbar deactivated')
|
|
48
|
+
|
|
49
|
+
- Type: `String`
|
|
50
|
+
- Required: No
|
|
51
|
+
|
|
52
|
+
### shortcut
|
|
53
|
+
|
|
54
|
+
A keyboard shortcut for the feature. This is just used for display purposes and the implementation of the shortcut should be handled separately.
|
|
55
|
+
|
|
56
|
+
Consider using the `displayShortcut` helper from the `@wordpress/keycodes` package for this prop.
|
|
57
|
+
|
|
58
|
+
- Type: `Array`
|
|
59
|
+
- Required: No
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
5
|
+
import { MenuItem } from '@wordpress/components';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
import { check } from '@wordpress/icons';
|
|
8
|
+
import { speak } from '@wordpress/a11y';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Internal dependencies
|
|
12
|
+
*/
|
|
13
|
+
import { store as interfaceStore } from '../../store';
|
|
14
|
+
|
|
15
|
+
export default function MoreMenuFeatureToggle( {
|
|
16
|
+
scope,
|
|
17
|
+
label,
|
|
18
|
+
info,
|
|
19
|
+
messageActivated,
|
|
20
|
+
messageDeactivated,
|
|
21
|
+
shortcut,
|
|
22
|
+
feature,
|
|
23
|
+
} ) {
|
|
24
|
+
const isActive = useSelect(
|
|
25
|
+
( select ) =>
|
|
26
|
+
select( interfaceStore ).isFeatureActive( scope, feature ),
|
|
27
|
+
[ feature ]
|
|
28
|
+
);
|
|
29
|
+
const { toggleFeature } = useDispatch( interfaceStore );
|
|
30
|
+
const speakMessage = () => {
|
|
31
|
+
if ( isActive ) {
|
|
32
|
+
speak( messageDeactivated || __( 'Feature deactivated' ) );
|
|
33
|
+
} else {
|
|
34
|
+
speak( messageActivated || __( 'Feature activated' ) );
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<MenuItem
|
|
40
|
+
icon={ isActive && check }
|
|
41
|
+
isSelected={ isActive }
|
|
42
|
+
onClick={ () => {
|
|
43
|
+
toggleFeature( scope, feature );
|
|
44
|
+
speakMessage();
|
|
45
|
+
} }
|
|
46
|
+
role="menuitemcheckbox"
|
|
47
|
+
info={ info }
|
|
48
|
+
shortcut={ shortcut }
|
|
49
|
+
>
|
|
50
|
+
{ label }
|
|
51
|
+
</MenuItem>
|
|
52
|
+
);
|
|
53
|
+
}
|
package/src/index.js
CHANGED
package/src/store/actions.js
CHANGED
|
@@ -82,3 +82,51 @@ export function pinItem( scope, itemId ) {
|
|
|
82
82
|
export function unpinItem( scope, itemId ) {
|
|
83
83
|
return setMultipleEnableItem( 'pinnedItems', scope, itemId, false );
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Returns an action object used in signalling that a feature should be toggled.
|
|
88
|
+
*
|
|
89
|
+
* @param {string} scope The feature scope (e.g. core/edit-post).
|
|
90
|
+
* @param {string} featureName The feature name.
|
|
91
|
+
*/
|
|
92
|
+
export function toggleFeature( scope, featureName ) {
|
|
93
|
+
return function ( { select, dispatch } ) {
|
|
94
|
+
const currentValue = select.isFeatureActive( scope, featureName );
|
|
95
|
+
dispatch.setFeatureValue( scope, featureName, ! currentValue );
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Returns an action object used in signalling that a feature should be set to
|
|
101
|
+
* a true or false value
|
|
102
|
+
*
|
|
103
|
+
* @param {string} scope The feature scope (e.g. core/edit-post).
|
|
104
|
+
* @param {string} featureName The feature name.
|
|
105
|
+
* @param {boolean} value The value to set.
|
|
106
|
+
*
|
|
107
|
+
* @return {Object} Action object.
|
|
108
|
+
*/
|
|
109
|
+
export function setFeatureValue( scope, featureName, value ) {
|
|
110
|
+
return {
|
|
111
|
+
type: 'SET_FEATURE_VALUE',
|
|
112
|
+
scope,
|
|
113
|
+
featureName,
|
|
114
|
+
value: !! value,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns an action object used in signalling that defaults should be set for features.
|
|
120
|
+
*
|
|
121
|
+
* @param {string} scope The feature scope (e.g. core/edit-post).
|
|
122
|
+
* @param {Object<string, boolean>} defaults A key/value map of feature names to values.
|
|
123
|
+
*
|
|
124
|
+
* @return {Object} Action object.
|
|
125
|
+
*/
|
|
126
|
+
export function setFeatureDefaults( scope, defaults ) {
|
|
127
|
+
return {
|
|
128
|
+
type: 'SET_FEATURE_DEFAULTS',
|
|
129
|
+
scope,
|
|
130
|
+
defaults,
|
|
131
|
+
};
|
|
132
|
+
}
|
package/src/store/index.js
CHANGED
|
@@ -22,7 +22,8 @@ export const store = createReduxStore( STORE_NAME, {
|
|
|
22
22
|
reducer,
|
|
23
23
|
actions,
|
|
24
24
|
selectors,
|
|
25
|
-
persist: [ 'enableItems' ],
|
|
25
|
+
persist: [ 'enableItems', 'preferences' ],
|
|
26
|
+
__experimentalUseThunks: true,
|
|
26
27
|
} );
|
|
27
28
|
|
|
28
29
|
// Once we build a more generic persistence plugin that works across types of stores
|
|
@@ -31,5 +32,6 @@ registerStore( STORE_NAME, {
|
|
|
31
32
|
reducer,
|
|
32
33
|
actions,
|
|
33
34
|
selectors,
|
|
34
|
-
persist: [ 'enableItems' ],
|
|
35
|
+
persist: [ 'enableItems', 'preferences' ],
|
|
36
|
+
__experimentalUseThunks: true,
|
|
35
37
|
} );
|
package/src/store/reducer.js
CHANGED
|
@@ -78,6 +78,59 @@ export function multipleEnableItems(
|
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Reducer returning the defaults for user preferences.
|
|
83
|
+
*
|
|
84
|
+
* This is kept intentionally separate from the preferences
|
|
85
|
+
* themselves so that defaults are not persisted.
|
|
86
|
+
*
|
|
87
|
+
* @param {Object} state Current state.
|
|
88
|
+
* @param {Object} action Dispatched action.
|
|
89
|
+
*
|
|
90
|
+
* @return {Object} Updated state.
|
|
91
|
+
*/
|
|
92
|
+
export const preferenceDefaults = combineReducers( {
|
|
93
|
+
features( state = {}, action ) {
|
|
94
|
+
if ( action.type === 'SET_FEATURE_DEFAULTS' ) {
|
|
95
|
+
const { scope, defaults } = action;
|
|
96
|
+
return {
|
|
97
|
+
...state,
|
|
98
|
+
[ scope ]: {
|
|
99
|
+
...state[ scope ],
|
|
100
|
+
...defaults,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return state;
|
|
106
|
+
},
|
|
107
|
+
} );
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Reducer returning the user preferences.
|
|
111
|
+
*
|
|
112
|
+
* @param {Object} state Current state.
|
|
113
|
+
* @param {Object} action Dispatched action.
|
|
114
|
+
*
|
|
115
|
+
* @return {Object} Updated state.
|
|
116
|
+
*/
|
|
117
|
+
export const preferences = combineReducers( {
|
|
118
|
+
features( state = {}, action ) {
|
|
119
|
+
if ( action.type === 'SET_FEATURE_VALUE' ) {
|
|
120
|
+
const { scope, featureName, value } = action;
|
|
121
|
+
return {
|
|
122
|
+
...state,
|
|
123
|
+
[ scope ]: {
|
|
124
|
+
...state[ scope ],
|
|
125
|
+
[ featureName ]: value,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return state;
|
|
131
|
+
},
|
|
132
|
+
} );
|
|
133
|
+
|
|
81
134
|
const enableItems = combineReducers( {
|
|
82
135
|
singleEnableItems,
|
|
83
136
|
multipleEnableItems,
|
|
@@ -85,4 +138,6 @@ const enableItems = combineReducers( {
|
|
|
85
138
|
|
|
86
139
|
export default combineReducers( {
|
|
87
140
|
enableItems,
|
|
141
|
+
preferenceDefaults,
|
|
142
|
+
preferences,
|
|
88
143
|
} );
|
package/src/store/selectors.js
CHANGED
|
@@ -61,3 +61,23 @@ export function isItemPinned( state, scope, item ) {
|
|
|
61
61
|
false
|
|
62
62
|
);
|
|
63
63
|
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Returns a boolean indicating whether a feature is active for a particular
|
|
67
|
+
* scope.
|
|
68
|
+
*
|
|
69
|
+
* @param {Object} state The store state.
|
|
70
|
+
* @param {string} scope The scope of the feature (e.g. core/edit-post).
|
|
71
|
+
* @param {string} featureName The name of the feature.
|
|
72
|
+
*
|
|
73
|
+
* @return {boolean} Is the feature enabled?
|
|
74
|
+
*/
|
|
75
|
+
export function isFeatureActive( state, scope, featureName ) {
|
|
76
|
+
const featureValue = state.preferences.features[ scope ]?.[ featureName ];
|
|
77
|
+
const defaultedFeatureValue =
|
|
78
|
+
featureValue !== undefined
|
|
79
|
+
? featureValue
|
|
80
|
+
: state.preferenceDefaults.features[ scope ]?.[ featureName ];
|
|
81
|
+
|
|
82
|
+
return !! defaultedFeatureValue;
|
|
83
|
+
}
|