@wordpress/components 23.3.1 → 23.3.3
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 +22 -2
- package/build/color-palette/index.js +7 -4
- package/build/color-palette/index.js.map +1 -1
- package/build/color-palette/utils.js +12 -4
- package/build/color-palette/utils.js.map +1 -1
- package/build/custom-select-control/index.js +7 -0
- package/build/custom-select-control/index.js.map +1 -1
- package/build/index.js +16 -10
- package/build/index.js.map +1 -1
- package/build/navigator/context.js +5 -1
- package/build/navigator/context.js.map +1 -1
- package/build/navigator/index.js +8 -0
- package/build/navigator/index.js.map +1 -1
- package/build/navigator/navigator-back-button/hook.js +11 -3
- package/build/navigator/navigator-back-button/hook.js.map +1 -1
- package/build/navigator/navigator-provider/component.js +119 -11
- package/build/navigator/navigator-provider/component.js.map +1 -1
- package/build/navigator/navigator-screen/component.js +18 -7
- package/build/navigator/navigator-screen/component.js.map +1 -1
- package/build/navigator/navigator-to-parent-button/component.js +75 -0
- package/build/navigator/navigator-to-parent-button/component.js.map +1 -0
- package/build/navigator/navigator-to-parent-button/index.js +16 -0
- package/build/navigator/navigator-to-parent-button/index.js.map +1 -0
- package/build/navigator/use-navigator.js +6 -2
- package/build/navigator/use-navigator.js.map +1 -1
- package/build/navigator/utils/router.js +57 -0
- package/build/navigator/utils/router.js.map +1 -0
- package/build/private-apis.js +35 -0
- package/build/private-apis.js.map +1 -0
- package/build/select-control/index.js +1 -1
- package/build/select-control/index.js.map +1 -1
- package/build/select-control/styles/select-control-styles.js +38 -25
- package/build/select-control/styles/select-control-styles.js.map +1 -1
- package/build/tools-panel/tools-panel/hook.js +4 -4
- package/build/tools-panel/tools-panel/hook.js.map +1 -1
- package/build/tools-panel/tools-panel-item/hook.js +20 -11
- package/build/tools-panel/tools-panel-item/hook.js.map +1 -1
- package/build-module/color-palette/index.js +8 -5
- package/build-module/color-palette/index.js.map +1 -1
- package/build-module/color-palette/utils.js +12 -4
- package/build-module/color-palette/utils.js.map +1 -1
- package/build-module/custom-select-control/index.js +5 -0
- package/build-module/custom-select-control/index.js.map +1 -1
- package/build-module/index.js +5 -4
- package/build-module/index.js.map +1 -1
- package/build-module/navigator/context.js +5 -1
- package/build-module/navigator/context.js.map +1 -1
- package/build-module/navigator/index.js +1 -0
- package/build-module/navigator/index.js.map +1 -1
- package/build-module/navigator/navigator-back-button/hook.js +11 -3
- package/build-module/navigator/navigator-back-button/hook.js.map +1 -1
- package/build-module/navigator/navigator-provider/component.js +117 -12
- package/build-module/navigator/navigator-provider/component.js.map +1 -1
- package/build-module/navigator/navigator-screen/component.js +20 -9
- package/build-module/navigator/navigator-screen/component.js.map +1 -1
- package/build-module/navigator/navigator-to-parent-button/component.js +61 -0
- package/build-module/navigator/navigator-to-parent-button/component.js.map +1 -0
- package/build-module/navigator/navigator-to-parent-button/index.js +2 -0
- package/build-module/navigator/navigator-to-parent-button/index.js.map +1 -0
- package/build-module/navigator/use-navigator.js +6 -2
- package/build-module/navigator/use-navigator.js.map +1 -1
- package/build-module/navigator/utils/router.js +51 -0
- package/build-module/navigator/utils/router.js.map +1 -0
- package/build-module/private-apis.js +20 -0
- package/build-module/private-apis.js.map +1 -0
- package/build-module/select-control/index.js +1 -1
- package/build-module/select-control/index.js.map +1 -1
- package/build-module/select-control/styles/select-control-styles.js +38 -25
- package/build-module/select-control/styles/select-control-styles.js.map +1 -1
- package/build-module/tools-panel/tools-panel/hook.js +4 -4
- package/build-module/tools-panel/tools-panel/hook.js.map +1 -1
- package/build-module/tools-panel/tools-panel-item/hook.js +20 -11
- package/build-module/tools-panel/tools-panel-item/hook.js.map +1 -1
- package/build-style/style-rtl.css +0 -11
- package/build-style/style.css +0 -11
- package/build-types/base-control/hooks.d.ts +1 -1
- package/build-types/base-field/hook.d.ts +2 -2
- package/build-types/border-box-control/border-box-control/hook.d.ts +2 -2
- package/build-types/border-box-control/border-box-control-linked-button/hook.d.ts +2 -2
- package/build-types/border-box-control/border-box-control-split-controls/hook.d.ts +2 -2
- package/build-types/border-box-control/border-box-control-visualizer/hook.d.ts +2 -2
- package/build-types/border-control/border-control/hook.d.ts +2 -2
- package/build-types/border-control/border-control-dropdown/hook.d.ts +2 -2
- package/build-types/border-control/border-control-style-picker/hook.d.ts +2 -2
- package/build-types/button/deprecated.d.ts +2 -2
- package/build-types/button/types.d.ts +3 -1
- package/build-types/button/types.d.ts.map +1 -1
- package/build-types/card/card/hook.d.ts +2 -2
- package/build-types/card/card-body/hook.d.ts +2 -2
- package/build-types/card/card-divider/hook.d.ts +2 -2
- package/build-types/card/card-footer/hook.d.ts +2 -2
- package/build-types/card/card-header/hook.d.ts +2 -2
- package/build-types/card/card-media/hook.d.ts +2 -2
- package/build-types/color-palette/index.d.ts.map +1 -1
- package/build-types/color-palette/styles.d.ts +1 -1
- package/build-types/color-palette/utils.d.ts +8 -5
- package/build-types/color-palette/utils.d.ts.map +1 -1
- package/build-types/color-picker/styles.d.ts +7 -7
- package/build-types/custom-select-control/index.d.ts +1 -0
- package/build-types/custom-select-control/index.d.ts.map +1 -1
- package/build-types/date-time/date/styles.d.ts +3 -3
- package/build-types/date-time/date-time/styles.d.ts +3 -3
- package/build-types/date-time/time/styles.d.ts +8 -8
- package/build-types/elevation/hook.d.ts +2 -2
- package/build-types/external-link/styles/external-link-styles.d.ts +1 -1
- package/build-types/flex/flex/hook.d.ts +2 -2
- package/build-types/flex/flex-block/hook.d.ts +2 -2
- package/build-types/flex/flex-item/hook.d.ts +2 -2
- package/build-types/focal-point-picker/styles/focal-point-picker-style.d.ts +2 -2
- package/build-types/form-token-field/styles.d.ts +1 -1
- package/build-types/grid/hook.d.ts +2 -2
- package/build-types/h-stack/component.d.ts +1 -1
- package/build-types/h-stack/hook.d.ts +2 -2
- package/build-types/heading/hook.d.ts +2 -2
- package/build-types/input-control/styles/input-control-styles.d.ts +2 -2
- package/build-types/item-group/item/hook.d.ts +2 -2
- package/build-types/item-group/item-group/hook.d.ts +2 -2
- package/build-types/navigator/context.d.ts.map +1 -1
- package/build-types/navigator/index.d.ts +1 -0
- package/build-types/navigator/index.d.ts.map +1 -1
- package/build-types/navigator/navigator-back-button/component.d.ts +22 -3
- package/build-types/navigator/navigator-back-button/component.d.ts.map +1 -1
- package/build-types/navigator/navigator-back-button/hook.d.ts +24 -6
- package/build-types/navigator/navigator-back-button/hook.d.ts.map +1 -1
- package/build-types/navigator/navigator-button/component.d.ts +22 -3
- package/build-types/navigator/navigator-button/component.d.ts.map +1 -1
- package/build-types/navigator/navigator-button/hook.d.ts +22 -4
- 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 +27 -0
- package/build-types/navigator/navigator-to-parent-button/component.d.ts.map +1 -0
- package/build-types/navigator/navigator-to-parent-button/index.d.ts +2 -0
- package/build-types/navigator/navigator-to-parent-button/index.d.ts.map +1 -0
- package/build-types/navigator/stories/index.d.ts +1 -0
- package/build-types/navigator/stories/index.d.ts.map +1 -1
- package/build-types/navigator/test/router.d.ts +2 -0
- package/build-types/navigator/test/router.d.ts.map +1 -0
- package/build-types/navigator/types.d.ts +25 -9
- package/build-types/navigator/types.d.ts.map +1 -1
- package/build-types/navigator/use-navigator.d.ts.map +1 -1
- package/build-types/navigator/utils/router.d.ts +10 -0
- package/build-types/navigator/utils/router.d.ts.map +1 -0
- package/build-types/number-control/index.d.ts +2 -2
- package/build-types/number-control/stories/index.d.ts +2 -2
- package/build-types/popover/index.d.ts +1 -1
- package/build-types/popover/stories/e2e/index.d.ts +1 -1
- package/build-types/private-apis.d.ts +4 -0
- package/build-types/private-apis.d.ts.map +1 -0
- package/build-types/range-control/index.d.ts +2 -2
- package/build-types/range-control/styles/range-control-styles.d.ts +2 -2
- package/build-types/resizable-box/index.d.ts +1 -1
- package/build-types/resizable-box/resize-tooltip/index.d.ts +1 -1
- package/build-types/resizable-box/stories/index.d.ts +2 -2
- package/build-types/scrollable/hook.d.ts +2 -2
- package/build-types/search-control/index.d.ts +1 -1
- package/build-types/search-control/stories/index.d.ts +2 -2
- package/build-types/select-control/index.d.ts.map +1 -1
- package/build-types/select-control/styles/select-control-styles.d.ts +1 -1
- package/build-types/select-control/styles/select-control-styles.d.ts.map +1 -1
- package/build-types/select-control/types.d.ts +3 -1
- package/build-types/select-control/types.d.ts.map +1 -1
- package/build-types/spacer/hook.d.ts +2 -2
- package/build-types/spinner/index.d.ts +1 -1
- package/build-types/surface/hook.d.ts +2 -2
- package/build-types/text/hook.d.ts +2 -2
- package/build-types/text-control/index.d.ts +3 -3
- package/build-types/tools-panel/tools-panel/hook.d.ts +2 -2
- package/build-types/tools-panel/tools-panel/hook.d.ts.map +1 -1
- package/build-types/tools-panel/tools-panel-header/hook.d.ts +2 -2
- package/build-types/tools-panel/tools-panel-item/hook.d.ts +2 -2
- package/build-types/tools-panel/tools-panel-item/hook.d.ts.map +1 -1
- package/build-types/truncate/hook.d.ts +2 -2
- package/build-types/ui/control-group/hook.d.ts +2 -2
- package/build-types/ui/control-label/hook.d.ts +2 -2
- package/build-types/ui/form-group/form-group.d.ts +2 -2
- package/build-types/ui/form-group/use-form-group.d.ts +2 -2
- package/build-types/unit-control/index.d.ts +1 -1
- package/build-types/unit-control/styles/unit-control-styles.d.ts +2 -2
- package/build-types/v-stack/component.d.ts +2 -2
- package/build-types/v-stack/hook.d.ts +2 -2
- package/build-types/v-stack/stories/index.d.ts +2 -2
- package/package.json +9 -7
- package/src/button/types.ts +5 -2
- package/src/color-palette/index.tsx +13 -5
- package/src/color-palette/test/utils.ts +17 -1
- package/src/color-palette/utils.ts +12 -7
- package/src/custom-select-control/index.js +9 -0
- package/src/custom-select-control/stories/index.js +1 -1
- package/src/custom-select-control/test/index.js +2 -2
- package/src/dimension-control/test/__snapshots__/index.test.js.snap +4 -4
- package/src/index.js +5 -2
- package/src/navigator/context.ts +4 -0
- package/src/navigator/index.ts +1 -0
- package/src/navigator/navigator-back-button/README.md +1 -17
- package/src/navigator/navigator-back-button/hook.ts +10 -5
- package/src/navigator/navigator-button/README.md +1 -1
- package/src/navigator/navigator-provider/README.md +25 -4
- package/src/navigator/navigator-provider/component.tsx +170 -14
- package/src/navigator/navigator-screen/component.tsx +22 -11
- package/src/navigator/navigator-to-parent-button/README.md +15 -0
- package/src/navigator/navigator-to-parent-button/component.tsx +65 -0
- package/src/navigator/navigator-to-parent-button/index.ts +1 -0
- package/src/navigator/stories/index.tsx +93 -3
- package/src/navigator/test/index.tsx +267 -23
- package/src/navigator/test/router.ts +122 -0
- package/src/navigator/types.ts +31 -12
- package/src/navigator/use-navigator.ts +4 -1
- package/src/navigator/utils/router.ts +49 -0
- package/src/private-apis.js +22 -0
- package/src/select-control/README.md +3 -1
- package/src/select-control/index.tsx +3 -1
- package/src/select-control/style.scss +0 -10
- package/src/select-control/styles/select-control-styles.ts +36 -22
- package/src/select-control/types.ts +3 -1
- package/src/tools-panel/test/index.js +65 -0
- package/src/tools-panel/tools-panel/hook.ts +4 -5
- package/src/tools-panel/tools-panel-item/hook.ts +24 -14
- package/tsconfig.json +5 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
import { render, fireEvent, screen } from '@testing-library/react';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Internal dependencies
|
|
8
8
|
*/
|
|
9
|
-
import
|
|
9
|
+
import CustomSelectControl from '..';
|
|
10
10
|
|
|
11
11
|
describe( 'CustomSelectControl', () => {
|
|
12
12
|
it( 'Captures the keypress event and does not let it propagate', () => {
|
|
@@ -116,7 +116,6 @@ exports[`DimensionControl rendering renders with custom sizes 1`] = `
|
|
|
116
116
|
width: 100%;
|
|
117
117
|
max-width: none;
|
|
118
118
|
cursor: pointer;
|
|
119
|
-
overflow: hidden;
|
|
120
119
|
white-space: nowrap;
|
|
121
120
|
text-overflow: ellipsis;
|
|
122
121
|
font-size: 16px;
|
|
@@ -126,6 +125,7 @@ exports[`DimensionControl rendering renders with custom sizes 1`] = `
|
|
|
126
125
|
padding-bottom: 0;
|
|
127
126
|
padding-left: 8px;
|
|
128
127
|
padding-right: 26px;
|
|
128
|
+
overflow: hidden;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
@media ( min-width: 600px ) {
|
|
@@ -387,7 +387,6 @@ exports[`DimensionControl rendering renders with defaults 1`] = `
|
|
|
387
387
|
width: 100%;
|
|
388
388
|
max-width: none;
|
|
389
389
|
cursor: pointer;
|
|
390
|
-
overflow: hidden;
|
|
391
390
|
white-space: nowrap;
|
|
392
391
|
text-overflow: ellipsis;
|
|
393
392
|
font-size: 16px;
|
|
@@ -397,6 +396,7 @@ exports[`DimensionControl rendering renders with defaults 1`] = `
|
|
|
397
396
|
padding-bottom: 0;
|
|
398
397
|
padding-left: 8px;
|
|
399
398
|
padding-right: 26px;
|
|
399
|
+
overflow: hidden;
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
@media ( min-width: 600px ) {
|
|
@@ -668,7 +668,6 @@ exports[`DimensionControl rendering renders with icon and custom icon label 1`]
|
|
|
668
668
|
width: 100%;
|
|
669
669
|
max-width: none;
|
|
670
670
|
cursor: pointer;
|
|
671
|
-
overflow: hidden;
|
|
672
671
|
white-space: nowrap;
|
|
673
672
|
text-overflow: ellipsis;
|
|
674
673
|
font-size: 16px;
|
|
@@ -678,6 +677,7 @@ exports[`DimensionControl rendering renders with icon and custom icon label 1`]
|
|
|
678
677
|
padding-bottom: 0;
|
|
679
678
|
padding-left: 8px;
|
|
680
679
|
padding-right: 26px;
|
|
680
|
+
overflow: hidden;
|
|
681
681
|
}
|
|
682
682
|
|
|
683
683
|
@media ( min-width: 600px ) {
|
|
@@ -961,7 +961,6 @@ exports[`DimensionControl rendering renders with icon and default icon label 1`]
|
|
|
961
961
|
width: 100%;
|
|
962
962
|
max-width: none;
|
|
963
963
|
cursor: pointer;
|
|
964
|
-
overflow: hidden;
|
|
965
964
|
white-space: nowrap;
|
|
966
965
|
text-overflow: ellipsis;
|
|
967
966
|
font-size: 16px;
|
|
@@ -971,6 +970,7 @@ exports[`DimensionControl rendering renders with icon and default icon label 1`]
|
|
|
971
970
|
padding-bottom: 0;
|
|
972
971
|
padding-left: 8px;
|
|
973
972
|
padding-right: 26px;
|
|
973
|
+
overflow: hidden;
|
|
974
974
|
}
|
|
975
975
|
|
|
976
976
|
@media ( min-width: 600px ) {
|
package/src/index.js
CHANGED
|
@@ -59,7 +59,7 @@ export {
|
|
|
59
59
|
useCompositeState as __unstableUseCompositeState,
|
|
60
60
|
} from './composite';
|
|
61
61
|
export { ConfirmDialog as __experimentalConfirmDialog } from './confirm-dialog';
|
|
62
|
-
export {
|
|
62
|
+
export { StableCustomSelectControl as CustomSelectControl } from './custom-select-control';
|
|
63
63
|
export { default as Dashicon } from './dashicon';
|
|
64
64
|
export { default as DateTimePicker, DatePicker, TimePicker } from './date-time';
|
|
65
65
|
export { default as __experimentalDimensionControl } from './dimension-control';
|
|
@@ -115,6 +115,7 @@ export {
|
|
|
115
115
|
NavigatorScreen as __experimentalNavigatorScreen,
|
|
116
116
|
NavigatorButton as __experimentalNavigatorButton,
|
|
117
117
|
NavigatorBackButton as __experimentalNavigatorBackButton,
|
|
118
|
+
NavigatorToParentButton as __experimentalNavigatorToParentButton,
|
|
118
119
|
useNavigator as __experimentalUseNavigator,
|
|
119
120
|
} from './navigator';
|
|
120
121
|
export { default as Notice } from './notice';
|
|
@@ -126,7 +127,6 @@ export { default as PanelHeader } from './panel/header';
|
|
|
126
127
|
export { default as PanelRow } from './panel/row';
|
|
127
128
|
export { default as Placeholder } from './placeholder';
|
|
128
129
|
export { default as Popover } from './popover';
|
|
129
|
-
export { positionToPlacement as __experimentalPopoverPositionToPlacement } from './popover/utils';
|
|
130
130
|
export { default as QueryControls } from './query-controls';
|
|
131
131
|
export { default as __experimentalRadio } from './radio-group/radio';
|
|
132
132
|
export { default as __experimentalRadioGroup } from './radio-group';
|
|
@@ -212,3 +212,6 @@ export {
|
|
|
212
212
|
} from './higher-order/with-focus-return';
|
|
213
213
|
export { default as withNotices } from './higher-order/with-notices';
|
|
214
214
|
export { default as withSpokenMessages } from './higher-order/with-spoken-messages';
|
|
215
|
+
|
|
216
|
+
// Private APIs.
|
|
217
|
+
export { privateApis } from './private-apis';
|
package/src/navigator/context.ts
CHANGED
|
@@ -12,5 +12,9 @@ const initialContextValue: NavigatorContextType = {
|
|
|
12
12
|
location: {},
|
|
13
13
|
goTo: () => {},
|
|
14
14
|
goBack: () => {},
|
|
15
|
+
goToParent: () => {},
|
|
16
|
+
addScreen: () => {},
|
|
17
|
+
removeScreen: () => {},
|
|
18
|
+
params: {},
|
|
15
19
|
};
|
|
16
20
|
export const NavigatorContext = createContext( initialContextValue );
|
package/src/navigator/index.ts
CHANGED
|
@@ -2,4 +2,5 @@ export { NavigatorProvider } from './navigator-provider';
|
|
|
2
2
|
export { NavigatorScreen } from './navigator-screen';
|
|
3
3
|
export { NavigatorButton } from './navigator-button';
|
|
4
4
|
export { NavigatorBackButton } from './navigator-back-button';
|
|
5
|
+
export { NavigatorToParentButton } from './navigator-to-parent-button';
|
|
5
6
|
export { default as useNavigator } from './use-navigator';
|
|
@@ -10,22 +10,6 @@ The `NavigatorBackButton` component can be used to navigate to a screen and shou
|
|
|
10
10
|
|
|
11
11
|
Refer to [the `NavigatorProvider` component](/packages/components/src/navigator/navigator-provider/README.md#usage) for a usage example.
|
|
12
12
|
|
|
13
|
-
## Props
|
|
14
|
-
|
|
15
|
-
The component accepts the following props:
|
|
16
|
-
|
|
17
|
-
### `onClick`: `React.MouseEventHandler< HTMLElement >`
|
|
18
|
-
|
|
19
|
-
The callback called in response to a `click` event.
|
|
20
|
-
|
|
21
|
-
- Required: No
|
|
22
|
-
|
|
23
|
-
### `path`: `string`
|
|
24
|
-
|
|
25
|
-
The path of the screen to navigate to.
|
|
26
|
-
|
|
27
|
-
- Required: Yes
|
|
28
|
-
|
|
29
13
|
### Inherited props
|
|
30
14
|
|
|
31
|
-
`NavigatorBackButton` also inherits all of the [`Button` props](/packages/components/src/button/README.md#props), except for `href`.
|
|
15
|
+
`NavigatorBackButton` also inherits all of the [`Button` props](/packages/components/src/button/README.md#props), except for `href` and `target`.
|
|
@@ -9,26 +9,31 @@ import { useCallback } from '@wordpress/element';
|
|
|
9
9
|
import { useContextSystem, WordPressComponentProps } from '../../ui/context';
|
|
10
10
|
import Button from '../../button';
|
|
11
11
|
import useNavigator from '../use-navigator';
|
|
12
|
-
import type {
|
|
12
|
+
import type { NavigatorBackButtonHookProps } from '../types';
|
|
13
13
|
|
|
14
14
|
export function useNavigatorBackButton(
|
|
15
|
-
props: WordPressComponentProps<
|
|
15
|
+
props: WordPressComponentProps< NavigatorBackButtonHookProps, 'button' >
|
|
16
16
|
) {
|
|
17
17
|
const {
|
|
18
18
|
onClick,
|
|
19
19
|
as = Button,
|
|
20
|
+
goToParent: goToParentProp = false,
|
|
20
21
|
...otherProps
|
|
21
22
|
} = useContextSystem( props, 'NavigatorBackButton' );
|
|
22
23
|
|
|
23
|
-
const { goBack } = useNavigator();
|
|
24
|
+
const { goBack, goToParent } = useNavigator();
|
|
24
25
|
const handleClick: React.MouseEventHandler< HTMLButtonElement > =
|
|
25
26
|
useCallback(
|
|
26
27
|
( e ) => {
|
|
27
28
|
e.preventDefault();
|
|
28
|
-
|
|
29
|
+
if ( goToParentProp ) {
|
|
30
|
+
goToParent();
|
|
31
|
+
} else {
|
|
32
|
+
goBack();
|
|
33
|
+
}
|
|
29
34
|
onClick?.( e );
|
|
30
35
|
},
|
|
31
|
-
[ goBack, onClick ]
|
|
36
|
+
[ goToParentProp, goToParent, goBack, onClick ]
|
|
32
37
|
);
|
|
33
38
|
|
|
34
39
|
return {
|
|
@@ -35,4 +35,4 @@ The path of the screen to navigate to. The value of this prop needs to be [a val
|
|
|
35
35
|
|
|
36
36
|
### Inherited props
|
|
37
37
|
|
|
38
|
-
`NavigatorButton` also inherits all of the [`Button` props](/packages/components/src/button/README.md#props), except for `href`.
|
|
38
|
+
`NavigatorButton` also inherits all of the [`Button` props](/packages/components/src/button/README.md#props), except for `href` and `target`.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
|
-
The `NavigatorProvider` component allows rendering nested views/panels/menus (via the [`NavigatorScreen` component](/packages/components/src/navigator/navigator-screen/README.md)) and navigate between these different states (via the [`NavigatorButton`](/packages/components/src/navigator/navigator-button/README.md) and [`NavigatorBackButton`](/packages/components/src/navigator/navigator-back-button/README.md) components or the `useNavigator` hook). The Global Styles sidebar is an example of this.
|
|
7
|
+
The `NavigatorProvider` component allows rendering nested views/panels/menus (via the [`NavigatorScreen` component](/packages/components/src/navigator/navigator-screen/README.md)) and navigate between these different states (via the [`NavigatorButton`](/packages/components/src/navigator/navigator-button/README.md), [`NavigatorToParentButton`](/packages/components/src/navigator/navigator-to-parent-button/README.md) and [`NavigatorBackButton`](/packages/components/src/navigator/navigator-back-button/README.md) components or the `useNavigator` hook). The Global Styles sidebar is an example of this.
|
|
8
8
|
|
|
9
9
|
## Usage
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
__experimentalNavigatorProvider as NavigatorProvider,
|
|
14
14
|
__experimentalNavigatorScreen as NavigatorScreen,
|
|
15
15
|
__experimentalNavigatorButton as NavigatorButton,
|
|
16
|
-
|
|
16
|
+
__experimentalNavigatorToParentButton as NavigatorToParentButton,
|
|
17
17
|
} from '@wordpress/components';
|
|
18
18
|
|
|
19
19
|
const MyNavigation = () => (
|
|
@@ -27,13 +27,21 @@ const MyNavigation = () => (
|
|
|
27
27
|
|
|
28
28
|
<NavigatorScreen path="/child">
|
|
29
29
|
<p>This is the child screen.</p>
|
|
30
|
-
<
|
|
30
|
+
<NavigatorToParentButton>
|
|
31
31
|
Go back
|
|
32
|
-
</
|
|
32
|
+
</NavigatorToParentButton>
|
|
33
33
|
</NavigatorScreen>
|
|
34
34
|
</NavigatorProvider>
|
|
35
35
|
);
|
|
36
36
|
```
|
|
37
|
+
**Important note**
|
|
38
|
+
|
|
39
|
+
Parent/child navigation only works if the path you define are hierarchical, following a URL-like scheme where each path segment is separated by the `/` character.
|
|
40
|
+
For example:
|
|
41
|
+
- `/` is the root of all paths. There should always be a screen with `path="/"`.
|
|
42
|
+
- `/parent/child` is a child of `/parent`.
|
|
43
|
+
- `/parent/child/grand-child` is a child of `/parent/child`.
|
|
44
|
+
- `/parent/:param` is a child of `/parent` as well.
|
|
37
45
|
|
|
38
46
|
## Props
|
|
39
47
|
|
|
@@ -58,6 +66,15 @@ The `goTo` function allows navigating to a given path. The second argument can a
|
|
|
58
66
|
The available options are:
|
|
59
67
|
|
|
60
68
|
- `focusTargetSelector`: `string`. An optional property used to specify the CSS selector used to restore focus on the matching element when navigating back.
|
|
69
|
+
- `isBack`: `boolean`. An optional property used to specify whether the navigation should be considered as backwards (thus enabling focus restoration when possible, and causing the animation to be backwards too)
|
|
70
|
+
|
|
71
|
+
### `goToParent`: `() => void;`
|
|
72
|
+
|
|
73
|
+
The `goToParent` function allows navigating to the parent screen.
|
|
74
|
+
|
|
75
|
+
Parent/child navigation only works if the path you define are hierarchical (see note above).
|
|
76
|
+
|
|
77
|
+
When a match is not found, the function will try to recursively navigate the path hierarchy until a matching screen (or the root `/`) are found.
|
|
61
78
|
|
|
62
79
|
### `goBack`: `() => void`
|
|
63
80
|
|
|
@@ -70,3 +87,7 @@ The `location` object represent the current location, and has a few properties:
|
|
|
70
87
|
- `path`: `string`. The path associated to the location.
|
|
71
88
|
- `isBack`: `boolean`. A flag that is `true` when the current location was reached by navigating backwards in the location stack.
|
|
72
89
|
- `isInitial`: `boolean`. A flag that is `true` only for the first (root) location in the location stack.
|
|
90
|
+
|
|
91
|
+
### `params`: `Record< string, string | string[] >`
|
|
92
|
+
|
|
93
|
+
The parsed record of parameters from the current location. For example if the current screen path is `/product/:productId` and the location is `/product/123`, then `params` will be `{ productId: '123' }`.
|
|
@@ -7,7 +7,15 @@ import { css } from '@emotion/react';
|
|
|
7
7
|
/**
|
|
8
8
|
* WordPress dependencies
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
useMemo,
|
|
12
|
+
useState,
|
|
13
|
+
useCallback,
|
|
14
|
+
useReducer,
|
|
15
|
+
useRef,
|
|
16
|
+
useEffect,
|
|
17
|
+
} from '@wordpress/element';
|
|
18
|
+
import isShallowEqual from '@wordpress/is-shallow-equal';
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* Internal dependencies
|
|
@@ -24,7 +32,28 @@ import type {
|
|
|
24
32
|
NavigatorProviderProps,
|
|
25
33
|
NavigatorLocation,
|
|
26
34
|
NavigatorContext as NavigatorContextType,
|
|
35
|
+
Screen,
|
|
27
36
|
} from '../types';
|
|
37
|
+
import { patternMatch, findParent } from '../utils/router';
|
|
38
|
+
|
|
39
|
+
type MatchedPath = ReturnType< typeof patternMatch >;
|
|
40
|
+
type ScreenAction = { type: string; screen: Screen };
|
|
41
|
+
|
|
42
|
+
const MAX_HISTORY_LENGTH = 50;
|
|
43
|
+
|
|
44
|
+
function screensReducer(
|
|
45
|
+
state: Screen[] = [],
|
|
46
|
+
action: ScreenAction
|
|
47
|
+
): Screen[] {
|
|
48
|
+
switch ( action.type ) {
|
|
49
|
+
case 'add':
|
|
50
|
+
return [ ...state, action.screen ];
|
|
51
|
+
case 'remove':
|
|
52
|
+
return state.filter( ( s: Screen ) => s.id !== action.screen.id );
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return state;
|
|
56
|
+
}
|
|
28
57
|
|
|
29
58
|
function UnconnectedNavigatorProvider(
|
|
30
59
|
props: WordPressComponentProps< NavigatorProviderProps, 'div' >,
|
|
@@ -40,19 +69,60 @@ function UnconnectedNavigatorProvider(
|
|
|
40
69
|
path: initialPath,
|
|
41
70
|
},
|
|
42
71
|
] );
|
|
72
|
+
const currentLocationHistory = useRef< NavigatorLocation[] >( [] );
|
|
73
|
+
const [ screens, dispatch ] = useReducer( screensReducer, [] );
|
|
74
|
+
const currentScreens = useRef< Screen[] >( [] );
|
|
75
|
+
useEffect( () => {
|
|
76
|
+
currentScreens.current = screens;
|
|
77
|
+
}, [ screens ] );
|
|
78
|
+
useEffect( () => {
|
|
79
|
+
currentLocationHistory.current = locationHistory;
|
|
80
|
+
}, [ locationHistory ] );
|
|
81
|
+
const currentMatch = useRef< MatchedPath >();
|
|
82
|
+
const matchedPath = useMemo( () => {
|
|
83
|
+
let currentPath: string | undefined;
|
|
84
|
+
if (
|
|
85
|
+
locationHistory.length === 0 ||
|
|
86
|
+
( currentPath =
|
|
87
|
+
locationHistory[ locationHistory.length - 1 ].path ) ===
|
|
88
|
+
undefined
|
|
89
|
+
) {
|
|
90
|
+
currentMatch.current = undefined;
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
43
93
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
94
|
+
const resolvePath = ( path: string ) => {
|
|
95
|
+
const newMatch = patternMatch( path, screens );
|
|
96
|
+
|
|
97
|
+
// If the new match is the same as the current match,
|
|
98
|
+
// return the previous one for performance reasons.
|
|
99
|
+
if (
|
|
100
|
+
currentMatch.current &&
|
|
101
|
+
newMatch &&
|
|
102
|
+
isShallowEqual(
|
|
103
|
+
newMatch.params,
|
|
104
|
+
currentMatch.current.params
|
|
105
|
+
) &&
|
|
106
|
+
newMatch.id === currentMatch.current.id
|
|
107
|
+
) {
|
|
108
|
+
return currentMatch.current;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return newMatch;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const newMatch = resolvePath( currentPath );
|
|
115
|
+
currentMatch.current = newMatch;
|
|
116
|
+
return newMatch;
|
|
117
|
+
}, [ screens, locationHistory ] );
|
|
118
|
+
|
|
119
|
+
const addScreen = useCallback(
|
|
120
|
+
( screen: Screen ) => dispatch( { type: 'add', screen } ),
|
|
121
|
+
[]
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const removeScreen = useCallback(
|
|
125
|
+
( screen: Screen ) => dispatch( { type: 'remove', screen } ),
|
|
56
126
|
[]
|
|
57
127
|
);
|
|
58
128
|
|
|
@@ -72,16 +142,102 @@ function UnconnectedNavigatorProvider(
|
|
|
72
142
|
} );
|
|
73
143
|
}, [] );
|
|
74
144
|
|
|
145
|
+
const goTo: NavigatorContextType[ 'goTo' ] = useCallback(
|
|
146
|
+
( path, options = {} ) => {
|
|
147
|
+
const {
|
|
148
|
+
focusTargetSelector,
|
|
149
|
+
isBack = false,
|
|
150
|
+
...restOptions
|
|
151
|
+
} = options;
|
|
152
|
+
|
|
153
|
+
const isNavigatingToPreviousPath =
|
|
154
|
+
isBack &&
|
|
155
|
+
currentLocationHistory.current.length > 1 &&
|
|
156
|
+
currentLocationHistory.current[
|
|
157
|
+
currentLocationHistory.current.length - 2
|
|
158
|
+
].path === path;
|
|
159
|
+
|
|
160
|
+
if ( isNavigatingToPreviousPath ) {
|
|
161
|
+
goBack();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
setLocationHistory( ( prevLocationHistory ) => {
|
|
166
|
+
const newLocation = {
|
|
167
|
+
...restOptions,
|
|
168
|
+
path,
|
|
169
|
+
isBack,
|
|
170
|
+
hasRestoredFocus: false,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
if ( prevLocationHistory.length < 1 ) {
|
|
174
|
+
return [ newLocation ];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return [
|
|
178
|
+
...prevLocationHistory.slice(
|
|
179
|
+
prevLocationHistory.length > MAX_HISTORY_LENGTH - 1
|
|
180
|
+
? 1
|
|
181
|
+
: 0,
|
|
182
|
+
-1
|
|
183
|
+
),
|
|
184
|
+
// Assign `focusTargetSelector` to the previous location in history
|
|
185
|
+
// (the one we just navigated from).
|
|
186
|
+
{
|
|
187
|
+
...prevLocationHistory[
|
|
188
|
+
prevLocationHistory.length - 1
|
|
189
|
+
],
|
|
190
|
+
focusTargetSelector,
|
|
191
|
+
},
|
|
192
|
+
newLocation,
|
|
193
|
+
];
|
|
194
|
+
} );
|
|
195
|
+
},
|
|
196
|
+
[ goBack ]
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const goToParent: NavigatorContextType[ 'goToParent' ] =
|
|
200
|
+
useCallback( () => {
|
|
201
|
+
const currentPath =
|
|
202
|
+
currentLocationHistory.current[
|
|
203
|
+
currentLocationHistory.current.length - 1
|
|
204
|
+
].path;
|
|
205
|
+
if ( currentPath === undefined ) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const parentPath = findParent(
|
|
209
|
+
currentPath,
|
|
210
|
+
currentScreens.current
|
|
211
|
+
);
|
|
212
|
+
if ( parentPath === undefined ) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
goTo( parentPath, { isBack: true } );
|
|
216
|
+
}, [ goTo ] );
|
|
217
|
+
|
|
75
218
|
const navigatorContextValue: NavigatorContextType = useMemo(
|
|
76
219
|
() => ( {
|
|
77
220
|
location: {
|
|
78
221
|
...locationHistory[ locationHistory.length - 1 ],
|
|
79
222
|
isInitial: locationHistory.length === 1,
|
|
80
223
|
},
|
|
224
|
+
params: matchedPath ? matchedPath.params : {},
|
|
225
|
+
match: matchedPath ? matchedPath.id : undefined,
|
|
81
226
|
goTo,
|
|
82
227
|
goBack,
|
|
228
|
+
goToParent,
|
|
229
|
+
addScreen,
|
|
230
|
+
removeScreen,
|
|
83
231
|
} ),
|
|
84
|
-
[
|
|
232
|
+
[
|
|
233
|
+
locationHistory,
|
|
234
|
+
matchedPath,
|
|
235
|
+
goTo,
|
|
236
|
+
goBack,
|
|
237
|
+
goToParent,
|
|
238
|
+
addScreen,
|
|
239
|
+
removeScreen,
|
|
240
|
+
]
|
|
85
241
|
);
|
|
86
242
|
|
|
87
243
|
const cx = useCx();
|
|
@@ -10,12 +10,14 @@ import { css } from '@emotion/react';
|
|
|
10
10
|
* WordPress dependencies
|
|
11
11
|
*/
|
|
12
12
|
import { focus } from '@wordpress/dom';
|
|
13
|
-
import { useContext, useEffect, useMemo, useRef } from '@wordpress/element';
|
|
14
13
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
useContext,
|
|
15
|
+
useEffect,
|
|
16
|
+
useMemo,
|
|
17
|
+
useRef,
|
|
18
|
+
useId,
|
|
19
|
+
} from '@wordpress/element';
|
|
20
|
+
import { useReducedMotion, useMergeRefs } from '@wordpress/compose';
|
|
19
21
|
import { isRTL } from '@wordpress/i18n';
|
|
20
22
|
import { escapeAttribute } from '@wordpress/escape-html';
|
|
21
23
|
|
|
@@ -48,17 +50,26 @@ function UnconnectedNavigatorScreen(
|
|
|
48
50
|
props: Props,
|
|
49
51
|
forwardedRef: ForwardedRef< any >
|
|
50
52
|
) {
|
|
53
|
+
const screenId = useId();
|
|
51
54
|
const { children, className, path, ...otherProps } = useContextSystem(
|
|
52
55
|
props,
|
|
53
56
|
'NavigatorScreen'
|
|
54
57
|
);
|
|
55
58
|
|
|
56
59
|
const prefersReducedMotion = useReducedMotion();
|
|
57
|
-
const { location
|
|
58
|
-
|
|
60
|
+
const { location, match, addScreen, removeScreen } =
|
|
61
|
+
useContext( NavigatorContext );
|
|
62
|
+
const isMatch = match === screenId;
|
|
59
63
|
const wrapperRef = useRef< HTMLDivElement >( null );
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
useEffect( () => {
|
|
66
|
+
const screen = {
|
|
67
|
+
id: screenId,
|
|
68
|
+
path: escapeAttribute( path ),
|
|
69
|
+
};
|
|
70
|
+
addScreen( screen );
|
|
71
|
+
return () => removeScreen( screen );
|
|
72
|
+
}, [ screenId, path, addScreen, removeScreen ] );
|
|
62
73
|
|
|
63
74
|
const cx = useCx();
|
|
64
75
|
const classes = useMemo(
|
|
@@ -110,9 +121,9 @@ function UnconnectedNavigatorScreen(
|
|
|
110
121
|
|
|
111
122
|
// When navigating back, if a selector is provided, use it to look for the
|
|
112
123
|
// target element (assumed to be a node inside the current NavigatorScreen)
|
|
113
|
-
if ( location.isBack &&
|
|
124
|
+
if ( location.isBack && location?.focusTargetSelector ) {
|
|
114
125
|
elementToFocus = wrapperRef.current.querySelector(
|
|
115
|
-
|
|
126
|
+
location.focusTargetSelector
|
|
116
127
|
);
|
|
117
128
|
}
|
|
118
129
|
|
|
@@ -131,7 +142,7 @@ function UnconnectedNavigatorScreen(
|
|
|
131
142
|
isInitialLocation,
|
|
132
143
|
isMatch,
|
|
133
144
|
location.isBack,
|
|
134
|
-
|
|
145
|
+
location.focusTargetSelector,
|
|
135
146
|
] );
|
|
136
147
|
|
|
137
148
|
const mergedWrapperRef = useMergeRefs( [ forwardedRef, wrapperRef ] );
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# `NavigatorToParentButton`
|
|
2
|
+
|
|
3
|
+
<div class="callout callout-alert">
|
|
4
|
+
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
The `NavigatorToParentButton` component can be used to navigate to a screen and should be used in combination with the [`NavigatorProvider`](/packages/components/src/navigator/navigator-provider/README.md), the [`NavigatorScreen`](/packages/components/src/navigator/navigator-screen/README.md) and the [`NavigatorButton`](/packages/components/src/navigator/navigator-button/README.md) components (or the `useNavigator` hook).
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
Refer to [the `NavigatorProvider` component](/packages/components/src/navigator/navigator-provider/README.md#usage) for a usage example.
|
|
12
|
+
|
|
13
|
+
### Inherited props
|
|
14
|
+
|
|
15
|
+
`NavigatorToParentButton` also inherits all of the [`Button` props](/packages/components/src/button/README.md#props), except for `href` and `target`.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import type { ForwardedRef } from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { contextConnect, WordPressComponentProps } from '../../ui/context';
|
|
10
|
+
import { View } from '../../view';
|
|
11
|
+
import { useNavigatorBackButton } from '../navigator-back-button/hook';
|
|
12
|
+
import type { NavigatorToParentButtonProps } from '../types';
|
|
13
|
+
|
|
14
|
+
function UnconnectedNavigatorToParentButton(
|
|
15
|
+
props: WordPressComponentProps< NavigatorToParentButtonProps, 'button' >,
|
|
16
|
+
forwardedRef: ForwardedRef< any >
|
|
17
|
+
) {
|
|
18
|
+
const navigatorToParentButtonProps = useNavigatorBackButton( {
|
|
19
|
+
...props,
|
|
20
|
+
goToParent: true,
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
return <View ref={ forwardedRef } { ...navigatorToParentButtonProps } />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* The `NavigatorToParentButton` component can be used to navigate to a screen and
|
|
28
|
+
* should be used in combination with the `NavigatorProvider`, the
|
|
29
|
+
* `NavigatorScreen` and the `NavigatorButton` components (or the `useNavigator`
|
|
30
|
+
* hook).
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```jsx
|
|
34
|
+
* import {
|
|
35
|
+
* __experimentalNavigatorProvider as NavigatorProvider,
|
|
36
|
+
* __experimentalNavigatorScreen as NavigatorScreen,
|
|
37
|
+
* __experimentalNavigatorButton as NavigatorButton,
|
|
38
|
+
* __experimentalNavigatorToParentButton as NavigatorToParentButton,
|
|
39
|
+
* } from '@wordpress/components';
|
|
40
|
+
*
|
|
41
|
+
* const MyNavigation = () => (
|
|
42
|
+
* <NavigatorProvider initialPath="/">
|
|
43
|
+
* <NavigatorScreen path="/">
|
|
44
|
+
* <p>This is the home screen.</p>
|
|
45
|
+
* <NavigatorButton path="/child">
|
|
46
|
+
* Navigate to child screen.
|
|
47
|
+
* </NavigatorButton>
|
|
48
|
+
* </NavigatorScreen>
|
|
49
|
+
*
|
|
50
|
+
* <NavigatorScreen path="/child">
|
|
51
|
+
* <p>This is the child screen.</p>
|
|
52
|
+
* <NavigatorToParentButton>
|
|
53
|
+
* Go to parent
|
|
54
|
+
* </NavigatorToParentButton>
|
|
55
|
+
* </NavigatorScreen>
|
|
56
|
+
* </NavigatorProvider>
|
|
57
|
+
* );
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export const NavigatorToParentButton = contextConnect(
|
|
61
|
+
UnconnectedNavigatorToParentButton,
|
|
62
|
+
'NavigatorToParentButton'
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
export default NavigatorToParentButton;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as NavigatorToParentButton } from './component';
|