@wordpress/components 23.3.1 → 23.3.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 +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 +8 -6
- 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
|
@@ -8,13 +8,15 @@ import type { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
|
8
8
|
*/
|
|
9
9
|
import Button from '../../button';
|
|
10
10
|
import { Card, CardBody, CardFooter, CardHeader } from '../../card';
|
|
11
|
-
import {
|
|
11
|
+
import { VStack } from '../../v-stack';
|
|
12
12
|
import Dropdown from '../../dropdown';
|
|
13
13
|
import {
|
|
14
14
|
NavigatorProvider,
|
|
15
15
|
NavigatorScreen,
|
|
16
16
|
NavigatorButton,
|
|
17
17
|
NavigatorBackButton,
|
|
18
|
+
NavigatorToParentButton,
|
|
19
|
+
useNavigator,
|
|
18
20
|
} from '..';
|
|
19
21
|
|
|
20
22
|
const meta: ComponentMeta< typeof NavigatorProvider > = {
|
|
@@ -46,7 +48,7 @@ const Template: ComponentStory< typeof NavigatorProvider > = ( {
|
|
|
46
48
|
<CardBody>
|
|
47
49
|
<p>This is the home screen.</p>
|
|
48
50
|
|
|
49
|
-
<
|
|
51
|
+
<VStack alignment="left">
|
|
50
52
|
<NavigatorButton variant="secondary" path="/child">
|
|
51
53
|
Navigate to child screen.
|
|
52
54
|
</NavigatorButton>
|
|
@@ -62,6 +64,10 @@ const Template: ComponentStory< typeof NavigatorProvider > = ( {
|
|
|
62
64
|
Navigate to screen with sticky content.
|
|
63
65
|
</NavigatorButton>
|
|
64
66
|
|
|
67
|
+
<NavigatorButton variant="secondary" path="/product/1">
|
|
68
|
+
Navigate to product screen with id 1.
|
|
69
|
+
</NavigatorButton>
|
|
70
|
+
|
|
65
71
|
<Dropdown
|
|
66
72
|
renderToggle={ ( {
|
|
67
73
|
isOpen,
|
|
@@ -86,7 +92,7 @@ const Template: ComponentStory< typeof NavigatorProvider > = ( {
|
|
|
86
92
|
</Card>
|
|
87
93
|
) }
|
|
88
94
|
/>
|
|
89
|
-
</
|
|
95
|
+
</VStack>
|
|
90
96
|
</CardBody>
|
|
91
97
|
</Card>
|
|
92
98
|
</NavigatorScreen>
|
|
@@ -166,6 +172,10 @@ const Template: ComponentStory< typeof NavigatorProvider > = ( {
|
|
|
166
172
|
</CardFooter>
|
|
167
173
|
</Card>
|
|
168
174
|
</NavigatorScreen>
|
|
175
|
+
|
|
176
|
+
<NavigatorScreen path="/product/:id">
|
|
177
|
+
<ProductDetails />
|
|
178
|
+
</NavigatorScreen>
|
|
169
179
|
</NavigatorProvider>
|
|
170
180
|
);
|
|
171
181
|
|
|
@@ -208,3 +218,83 @@ function MetaphorIpsum( { quantity }: { quantity: number } ) {
|
|
|
208
218
|
</>
|
|
209
219
|
);
|
|
210
220
|
}
|
|
221
|
+
|
|
222
|
+
function ProductDetails() {
|
|
223
|
+
const { params } = useNavigator();
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<Card>
|
|
227
|
+
<CardBody>
|
|
228
|
+
<NavigatorBackButton variant="secondary">
|
|
229
|
+
Go back
|
|
230
|
+
</NavigatorBackButton>
|
|
231
|
+
<p>This is the screen for the product with id: { params.id }</p>
|
|
232
|
+
</CardBody>
|
|
233
|
+
</Card>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const NestedNavigatorTemplate: ComponentStory< typeof NavigatorProvider > = ( {
|
|
238
|
+
style,
|
|
239
|
+
...props
|
|
240
|
+
} ) => (
|
|
241
|
+
<NavigatorProvider
|
|
242
|
+
style={ { ...style, height: '100vh', maxHeight: '450px' } }
|
|
243
|
+
{ ...props }
|
|
244
|
+
>
|
|
245
|
+
<NavigatorScreen path="/">
|
|
246
|
+
<Card>
|
|
247
|
+
<CardBody>
|
|
248
|
+
<NavigatorButton variant="secondary" path="/child1">
|
|
249
|
+
Go to first child.
|
|
250
|
+
</NavigatorButton>
|
|
251
|
+
<NavigatorButton variant="secondary" path="/child2">
|
|
252
|
+
Go to second child.
|
|
253
|
+
</NavigatorButton>
|
|
254
|
+
</CardBody>
|
|
255
|
+
</Card>
|
|
256
|
+
</NavigatorScreen>
|
|
257
|
+
<NavigatorScreen path="/child1">
|
|
258
|
+
<Card>
|
|
259
|
+
<CardBody>
|
|
260
|
+
This is the first child
|
|
261
|
+
<NavigatorToParentButton variant="secondary">
|
|
262
|
+
Go back to parent
|
|
263
|
+
</NavigatorToParentButton>
|
|
264
|
+
</CardBody>
|
|
265
|
+
</Card>
|
|
266
|
+
</NavigatorScreen>
|
|
267
|
+
<NavigatorScreen path="/child2">
|
|
268
|
+
<Card>
|
|
269
|
+
<CardBody>
|
|
270
|
+
This is the second child
|
|
271
|
+
<NavigatorToParentButton variant="secondary">
|
|
272
|
+
Go back to parent
|
|
273
|
+
</NavigatorToParentButton>
|
|
274
|
+
<NavigatorButton
|
|
275
|
+
variant="secondary"
|
|
276
|
+
path="/child2/grandchild"
|
|
277
|
+
>
|
|
278
|
+
Go to grand child.
|
|
279
|
+
</NavigatorButton>
|
|
280
|
+
</CardBody>
|
|
281
|
+
</Card>
|
|
282
|
+
</NavigatorScreen>
|
|
283
|
+
<NavigatorScreen path="/child2/grandchild">
|
|
284
|
+
<Card>
|
|
285
|
+
<CardBody>
|
|
286
|
+
This is the grand child
|
|
287
|
+
<NavigatorToParentButton variant="secondary">
|
|
288
|
+
Go back to parent
|
|
289
|
+
</NavigatorToParentButton>
|
|
290
|
+
</CardBody>
|
|
291
|
+
</Card>
|
|
292
|
+
</NavigatorScreen>
|
|
293
|
+
</NavigatorProvider>
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
export const NestedNavigator: ComponentStory< typeof NavigatorProvider > =
|
|
297
|
+
NestedNavigatorTemplate.bind( {} );
|
|
298
|
+
NestedNavigator.args = {
|
|
299
|
+
initialPath: '/child2/grandchild',
|
|
300
|
+
};
|
|
@@ -13,11 +13,14 @@ import { useState } from '@wordpress/element';
|
|
|
13
13
|
/**
|
|
14
14
|
* Internal dependencies
|
|
15
15
|
*/
|
|
16
|
+
import Button from '../../button';
|
|
16
17
|
import {
|
|
17
18
|
NavigatorProvider,
|
|
18
19
|
NavigatorScreen,
|
|
19
20
|
NavigatorButton,
|
|
20
21
|
NavigatorBackButton,
|
|
22
|
+
NavigatorToParentButton,
|
|
23
|
+
useNavigator,
|
|
21
24
|
} from '..';
|
|
22
25
|
|
|
23
26
|
jest.mock( 'framer-motion', () => {
|
|
@@ -50,6 +53,9 @@ const PATHS = {
|
|
|
50
53
|
HOME: '/',
|
|
51
54
|
CHILD: '/child',
|
|
52
55
|
NESTED: '/child/nested',
|
|
56
|
+
PRODUCT_PATTERN: '/product/:productId',
|
|
57
|
+
PRODUCT_1: '/product/1',
|
|
58
|
+
PRODUCT_2: '/product/2',
|
|
53
59
|
INVALID_HTML_ATTRIBUTE: INVALID_HTML_ATTRIBUTE.raw,
|
|
54
60
|
NOT_FOUND: '/not-found',
|
|
55
61
|
};
|
|
@@ -58,6 +64,7 @@ const SCREEN_TEXT = {
|
|
|
58
64
|
home: 'This is the home screen.',
|
|
59
65
|
child: 'This is the child screen.',
|
|
60
66
|
nested: 'This is the nested screen.',
|
|
67
|
+
product: 'This is the product screen.',
|
|
61
68
|
invalidHtmlPath: 'This is the screen with an invalid HTML value as a path.',
|
|
62
69
|
};
|
|
63
70
|
|
|
@@ -65,9 +72,12 @@ const BUTTON_TEXT = {
|
|
|
65
72
|
toNonExistingScreen: 'Navigate to non-existing screen.',
|
|
66
73
|
toChildScreen: 'Navigate to child screen.',
|
|
67
74
|
toNestedScreen: 'Navigate to nested screen.',
|
|
75
|
+
toProductScreen1: 'Navigate to product 1 screen.',
|
|
76
|
+
toProductScreen2: 'Navigate to product 2 screen.',
|
|
68
77
|
toInvalidHtmlPathScreen:
|
|
69
78
|
'Navigate to screen with an invalid HTML value as a path.',
|
|
70
79
|
back: 'Go back',
|
|
80
|
+
backUsingGoTo: 'Go back using goTo',
|
|
71
81
|
};
|
|
72
82
|
|
|
73
83
|
type CustomTestOnClickHandler = (
|
|
@@ -77,6 +87,7 @@ type CustomTestOnClickHandler = (
|
|
|
77
87
|
path: string;
|
|
78
88
|
}
|
|
79
89
|
| { type: 'goBack' }
|
|
90
|
+
| { type: 'goToParent' }
|
|
80
91
|
) => void;
|
|
81
92
|
|
|
82
93
|
function CustomNavigatorButton( {
|
|
@@ -98,20 +109,21 @@ function CustomNavigatorButton( {
|
|
|
98
109
|
);
|
|
99
110
|
}
|
|
100
111
|
|
|
101
|
-
function
|
|
112
|
+
function CustomNavigatorGoToBackButton( {
|
|
102
113
|
path,
|
|
103
114
|
onClick,
|
|
104
115
|
...props
|
|
105
116
|
}: Omit< ComponentPropsWithoutRef< typeof NavigatorButton >, 'onClick' > & {
|
|
106
117
|
onClick?: CustomTestOnClickHandler;
|
|
107
118
|
} ) {
|
|
119
|
+
const { goTo } = useNavigator();
|
|
108
120
|
return (
|
|
109
|
-
<
|
|
121
|
+
<Button
|
|
110
122
|
onClick={ () => {
|
|
123
|
+
goTo( path, { isBack: true } );
|
|
111
124
|
// Used to spy on the values passed to `navigator.goTo`.
|
|
112
125
|
onClick?.( { type: 'goTo', path } );
|
|
113
126
|
} }
|
|
114
|
-
path={ path }
|
|
115
127
|
{ ...props }
|
|
116
128
|
/>
|
|
117
129
|
);
|
|
@@ -134,6 +146,41 @@ function CustomNavigatorBackButton( {
|
|
|
134
146
|
);
|
|
135
147
|
}
|
|
136
148
|
|
|
149
|
+
function CustomNavigatorToParentButton( {
|
|
150
|
+
onClick,
|
|
151
|
+
...props
|
|
152
|
+
}: Omit< ComponentPropsWithoutRef< typeof NavigatorBackButton >, 'onClick' > & {
|
|
153
|
+
onClick?: CustomTestOnClickHandler;
|
|
154
|
+
} ) {
|
|
155
|
+
return (
|
|
156
|
+
<NavigatorToParentButton
|
|
157
|
+
onClick={ () => {
|
|
158
|
+
// Used to spy on the values passed to `navigator.goBack`.
|
|
159
|
+
onClick?.( { type: 'goToParent' } );
|
|
160
|
+
} }
|
|
161
|
+
{ ...props }
|
|
162
|
+
/>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const ProductScreen = ( {
|
|
167
|
+
onBackButtonClick,
|
|
168
|
+
}: {
|
|
169
|
+
onBackButtonClick?: CustomTestOnClickHandler;
|
|
170
|
+
} ) => {
|
|
171
|
+
const { params } = useNavigator();
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<NavigatorScreen path={ PATHS.PRODUCT_PATTERN }>
|
|
175
|
+
<p>{ SCREEN_TEXT.product }</p>
|
|
176
|
+
<p>Product ID is { params.productId }</p>
|
|
177
|
+
<CustomNavigatorBackButton onClick={ onBackButtonClick }>
|
|
178
|
+
{ BUTTON_TEXT.back }
|
|
179
|
+
</CustomNavigatorBackButton>
|
|
180
|
+
</NavigatorScreen>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
137
184
|
const MyNavigation = ( {
|
|
138
185
|
initialPath = PATHS.HOME,
|
|
139
186
|
onNavigatorButtonClick,
|
|
@@ -148,6 +195,12 @@ const MyNavigation = ( {
|
|
|
148
195
|
<NavigatorProvider initialPath={ initialPath }>
|
|
149
196
|
<NavigatorScreen path={ PATHS.HOME }>
|
|
150
197
|
<p>{ SCREEN_TEXT.home }</p>
|
|
198
|
+
{ /*
|
|
199
|
+
* A button useful to test focus restoration. This button is the first
|
|
200
|
+
* tabbable item in the screen, but should not receive focus when
|
|
201
|
+
* navigating to screen as a result of a backwards navigation.
|
|
202
|
+
*/ }
|
|
203
|
+
<button>First tabbable home screen button</button>
|
|
151
204
|
<CustomNavigatorButton
|
|
152
205
|
path={ PATHS.NOT_FOUND }
|
|
153
206
|
onClick={ onNavigatorButtonClick }
|
|
@@ -160,6 +213,18 @@ const MyNavigation = ( {
|
|
|
160
213
|
>
|
|
161
214
|
{ BUTTON_TEXT.toChildScreen }
|
|
162
215
|
</CustomNavigatorButton>
|
|
216
|
+
<CustomNavigatorButton
|
|
217
|
+
path={ PATHS.PRODUCT_1 }
|
|
218
|
+
onClick={ onNavigatorButtonClick }
|
|
219
|
+
>
|
|
220
|
+
{ BUTTON_TEXT.toProductScreen1 }
|
|
221
|
+
</CustomNavigatorButton>
|
|
222
|
+
<CustomNavigatorButton
|
|
223
|
+
path={ PATHS.PRODUCT_2 }
|
|
224
|
+
onClick={ onNavigatorButtonClick }
|
|
225
|
+
>
|
|
226
|
+
{ BUTTON_TEXT.toProductScreen2 }
|
|
227
|
+
</CustomNavigatorButton>
|
|
163
228
|
<CustomNavigatorButton
|
|
164
229
|
path={ PATHS.INVALID_HTML_ATTRIBUTE }
|
|
165
230
|
onClick={ onNavigatorButtonClick }
|
|
@@ -170,12 +235,18 @@ const MyNavigation = ( {
|
|
|
170
235
|
|
|
171
236
|
<NavigatorScreen path={ PATHS.CHILD }>
|
|
172
237
|
<p>{ SCREEN_TEXT.child }</p>
|
|
173
|
-
|
|
238
|
+
{ /*
|
|
239
|
+
* A button useful to test focus restoration. This button is the first
|
|
240
|
+
* tabbable item in the screen, but should not receive focus when
|
|
241
|
+
* navigating to screen as a result of a backwards navigation.
|
|
242
|
+
*/ }
|
|
243
|
+
<button>First tabbable child screen button</button>
|
|
244
|
+
<CustomNavigatorButton
|
|
174
245
|
path={ PATHS.NESTED }
|
|
175
246
|
onClick={ onNavigatorButtonClick }
|
|
176
247
|
>
|
|
177
248
|
{ BUTTON_TEXT.toNestedScreen }
|
|
178
|
-
</
|
|
249
|
+
</CustomNavigatorButton>
|
|
179
250
|
<CustomNavigatorBackButton
|
|
180
251
|
onClick={ onNavigatorButtonClick }
|
|
181
252
|
>
|
|
@@ -203,6 +274,8 @@ const MyNavigation = ( {
|
|
|
203
274
|
</CustomNavigatorBackButton>
|
|
204
275
|
</NavigatorScreen>
|
|
205
276
|
|
|
277
|
+
<ProductScreen onBackButtonClick={ onNavigatorButtonClick } />
|
|
278
|
+
|
|
206
279
|
<NavigatorScreen path={ PATHS.INVALID_HTML_ATTRIBUTE }>
|
|
207
280
|
<p>{ SCREEN_TEXT.invalidHtmlPath }</p>
|
|
208
281
|
<CustomNavigatorBackButton
|
|
@@ -229,6 +302,72 @@ const MyNavigation = ( {
|
|
|
229
302
|
);
|
|
230
303
|
};
|
|
231
304
|
|
|
305
|
+
const MyHierarchicalNavigation = ( {
|
|
306
|
+
initialPath = PATHS.HOME,
|
|
307
|
+
onNavigatorButtonClick,
|
|
308
|
+
}: {
|
|
309
|
+
initialPath?: string;
|
|
310
|
+
onNavigatorButtonClick?: CustomTestOnClickHandler;
|
|
311
|
+
} ) => {
|
|
312
|
+
return (
|
|
313
|
+
<>
|
|
314
|
+
<NavigatorProvider initialPath={ initialPath }>
|
|
315
|
+
<NavigatorScreen path={ PATHS.HOME }>
|
|
316
|
+
<p>{ SCREEN_TEXT.home }</p>
|
|
317
|
+
{ /*
|
|
318
|
+
* A button useful to test focus restoration. This button is the first
|
|
319
|
+
* tabbable item in the screen, but should not receive focus when
|
|
320
|
+
* navigating to screen as a result of a backwards navigation.
|
|
321
|
+
*/ }
|
|
322
|
+
<button>First tabbable home screen button</button>
|
|
323
|
+
<CustomNavigatorButton
|
|
324
|
+
path={ PATHS.CHILD }
|
|
325
|
+
onClick={ onNavigatorButtonClick }
|
|
326
|
+
>
|
|
327
|
+
{ BUTTON_TEXT.toChildScreen }
|
|
328
|
+
</CustomNavigatorButton>
|
|
329
|
+
</NavigatorScreen>
|
|
330
|
+
|
|
331
|
+
<NavigatorScreen path={ PATHS.CHILD }>
|
|
332
|
+
<p>{ SCREEN_TEXT.child }</p>
|
|
333
|
+
{ /*
|
|
334
|
+
* A button useful to test focus restoration. This button is the first
|
|
335
|
+
* tabbable item in the screen, but should not receive focus when
|
|
336
|
+
* navigating to screen as a result of a backwards navigation.
|
|
337
|
+
*/ }
|
|
338
|
+
<button>First tabbable child screen button</button>
|
|
339
|
+
<CustomNavigatorButton
|
|
340
|
+
path={ PATHS.NESTED }
|
|
341
|
+
onClick={ onNavigatorButtonClick }
|
|
342
|
+
>
|
|
343
|
+
{ BUTTON_TEXT.toNestedScreen }
|
|
344
|
+
</CustomNavigatorButton>
|
|
345
|
+
<CustomNavigatorToParentButton
|
|
346
|
+
onClick={ onNavigatorButtonClick }
|
|
347
|
+
>
|
|
348
|
+
{ BUTTON_TEXT.back }
|
|
349
|
+
</CustomNavigatorToParentButton>
|
|
350
|
+
</NavigatorScreen>
|
|
351
|
+
|
|
352
|
+
<NavigatorScreen path={ PATHS.NESTED }>
|
|
353
|
+
<p>{ SCREEN_TEXT.nested }</p>
|
|
354
|
+
<CustomNavigatorToParentButton
|
|
355
|
+
onClick={ onNavigatorButtonClick }
|
|
356
|
+
>
|
|
357
|
+
{ BUTTON_TEXT.back }
|
|
358
|
+
</CustomNavigatorToParentButton>
|
|
359
|
+
<CustomNavigatorGoToBackButton
|
|
360
|
+
path={ PATHS.CHILD }
|
|
361
|
+
onClick={ onNavigatorButtonClick }
|
|
362
|
+
>
|
|
363
|
+
{ BUTTON_TEXT.backUsingGoTo }
|
|
364
|
+
</CustomNavigatorGoToBackButton>
|
|
365
|
+
</NavigatorScreen>
|
|
366
|
+
</NavigatorProvider>
|
|
367
|
+
</>
|
|
368
|
+
);
|
|
369
|
+
};
|
|
370
|
+
|
|
232
371
|
const getScreen = ( screenKey: keyof typeof SCREEN_TEXT ) =>
|
|
233
372
|
screen.getByText( SCREEN_TEXT[ screenKey ] );
|
|
234
373
|
const queryScreen = ( screenKey: keyof typeof SCREEN_TEXT ) =>
|
|
@@ -369,7 +508,7 @@ describe( 'Navigator', () => {
|
|
|
369
508
|
} );
|
|
370
509
|
} );
|
|
371
510
|
|
|
372
|
-
it( 'should not
|
|
511
|
+
it( 'should not render anything if the path does not match any available screen', async () => {
|
|
373
512
|
const spy = jest.fn();
|
|
374
513
|
|
|
375
514
|
const user = userEvent.setup();
|
|
@@ -396,8 +535,6 @@ describe( 'Navigator', () => {
|
|
|
396
535
|
} );
|
|
397
536
|
|
|
398
537
|
it( 'should escape the value of the `path` prop', async () => {
|
|
399
|
-
const user = userEvent.setup();
|
|
400
|
-
|
|
401
538
|
render( <MyNavigation /> );
|
|
402
539
|
|
|
403
540
|
expect( getScreen( 'home' ) ).toBeInTheDocument();
|
|
@@ -407,24 +544,42 @@ describe( 'Navigator', () => {
|
|
|
407
544
|
|
|
408
545
|
// The following line tests the implementation details, but it's necessary
|
|
409
546
|
// as this would be otherwise transparent to the user.
|
|
547
|
+
// A potential way would be to check if an invalid HTML attribute could
|
|
548
|
+
// be detected in the tests (by JSDom or any other plugin). We could then
|
|
549
|
+
// make sure that an invalid path would not error because it's escaped
|
|
550
|
+
// correctly.
|
|
410
551
|
expect(
|
|
411
552
|
getNavigationButton( 'toInvalidHtmlPathScreen' )
|
|
412
553
|
).toHaveAttribute( 'id', INVALID_HTML_ATTRIBUTE.escaped );
|
|
554
|
+
} );
|
|
413
555
|
|
|
414
|
-
|
|
415
|
-
|
|
556
|
+
it( 'should match correctly paths with named arguments', async () => {
|
|
557
|
+
const user = userEvent.setup();
|
|
416
558
|
|
|
417
|
-
|
|
418
|
-
|
|
559
|
+
render( <MyNavigation /> );
|
|
560
|
+
|
|
561
|
+
expect( getScreen( 'home' ) ).toBeInTheDocument();
|
|
419
562
|
|
|
420
|
-
// Navigate
|
|
421
|
-
|
|
563
|
+
// Navigate to Product 1 screen
|
|
564
|
+
await user.click( getNavigationButton( 'toProductScreen1' ) );
|
|
565
|
+
|
|
566
|
+
expect( getScreen( 'product' ) ).toBeInTheDocument();
|
|
567
|
+
|
|
568
|
+
// Check that named parameter is extracted correctly
|
|
569
|
+
expect( screen.getByText( 'Product ID is 1' ) ).toBeInTheDocument();
|
|
570
|
+
|
|
571
|
+
// Navigate back to home screen
|
|
422
572
|
await user.click( getNavigationButton( 'back' ) );
|
|
423
573
|
|
|
424
574
|
expect( getScreen( 'home' ) ).toBeInTheDocument();
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
575
|
+
|
|
576
|
+
// Navigate to Product 2 screen
|
|
577
|
+
await user.click( getNavigationButton( 'toProductScreen2' ) );
|
|
578
|
+
|
|
579
|
+
expect( getScreen( 'product' ) ).toBeInTheDocument();
|
|
580
|
+
|
|
581
|
+
// Check that named parameter is extracted correctly
|
|
582
|
+
expect( screen.getByText( 'Product ID is 2' ) ).toBeInTheDocument();
|
|
428
583
|
} );
|
|
429
584
|
|
|
430
585
|
describe( 'focus management', () => {
|
|
@@ -437,7 +592,11 @@ describe( 'Navigator', () => {
|
|
|
437
592
|
await user.click( getNavigationButton( 'toChildScreen' ) );
|
|
438
593
|
|
|
439
594
|
// The first tabbable element receives focus.
|
|
440
|
-
expect(
|
|
595
|
+
expect(
|
|
596
|
+
screen.getByRole( 'button', {
|
|
597
|
+
name: 'First tabbable child screen button',
|
|
598
|
+
} )
|
|
599
|
+
).toHaveFocus();
|
|
441
600
|
|
|
442
601
|
// Navigate to nested screen.
|
|
443
602
|
await user.click( getNavigationButton( 'toNestedScreen' ) );
|
|
@@ -448,14 +607,29 @@ describe( 'Navigator', () => {
|
|
|
448
607
|
// Navigate back to child screen.
|
|
449
608
|
await user.click( getNavigationButton( 'back' ) );
|
|
450
609
|
|
|
451
|
-
//
|
|
610
|
+
// Focus is restored on the last element that had focus when the
|
|
611
|
+
// navigation away from the screen occurred.
|
|
452
612
|
expect( getNavigationButton( 'toNestedScreen' ) ).toHaveFocus();
|
|
453
613
|
|
|
454
|
-
// Navigate back to home screen
|
|
614
|
+
// Navigate back to home screen.
|
|
455
615
|
await user.click( getNavigationButton( 'back' ) );
|
|
456
616
|
|
|
457
|
-
//
|
|
617
|
+
// Focus is restored on the last element that had focus when the
|
|
618
|
+
// navigation away from the screen occurred.
|
|
458
619
|
expect( getNavigationButton( 'toChildScreen' ) ).toHaveFocus();
|
|
620
|
+
|
|
621
|
+
// Navigate to product screen for product 2
|
|
622
|
+
await user.click( getNavigationButton( 'toProductScreen2' ) );
|
|
623
|
+
|
|
624
|
+
// The first tabbable element receives focus.
|
|
625
|
+
expect( getNavigationButton( 'back' ) ).toHaveFocus();
|
|
626
|
+
|
|
627
|
+
// Navigate back to home screen.
|
|
628
|
+
await user.click( getNavigationButton( 'back' ) );
|
|
629
|
+
|
|
630
|
+
// Focus is restored on the last element that had focus when the
|
|
631
|
+
// navigation away from the screen occurred.
|
|
632
|
+
expect( getNavigationButton( 'toProductScreen2' ) ).toHaveFocus();
|
|
459
633
|
} );
|
|
460
634
|
|
|
461
635
|
it( 'should keep focus on an active element inside navigator, while re-rendering', async () => {
|
|
@@ -467,7 +641,11 @@ describe( 'Navigator', () => {
|
|
|
467
641
|
await user.click( getNavigationButton( 'toChildScreen' ) );
|
|
468
642
|
|
|
469
643
|
// The first tabbable element receives focus.
|
|
470
|
-
expect(
|
|
644
|
+
expect(
|
|
645
|
+
screen.getByRole( 'button', {
|
|
646
|
+
name: 'First tabbable child screen button',
|
|
647
|
+
} )
|
|
648
|
+
).toHaveFocus();
|
|
471
649
|
|
|
472
650
|
// Interact with the inner input.
|
|
473
651
|
// The focus should stay on the input element.
|
|
@@ -485,7 +663,11 @@ describe( 'Navigator', () => {
|
|
|
485
663
|
await user.click( getNavigationButton( 'toChildScreen' ) );
|
|
486
664
|
|
|
487
665
|
// The first tabbable element receives focus.
|
|
488
|
-
expect(
|
|
666
|
+
expect(
|
|
667
|
+
screen.getByRole( 'button', {
|
|
668
|
+
name: 'First tabbable child screen button',
|
|
669
|
+
} )
|
|
670
|
+
).toHaveFocus();
|
|
489
671
|
|
|
490
672
|
// Interact with the outer input.
|
|
491
673
|
// The focus should stay on the input element.
|
|
@@ -493,5 +675,67 @@ describe( 'Navigator', () => {
|
|
|
493
675
|
await user.type( outerInput, 'd' );
|
|
494
676
|
expect( outerInput ).toHaveFocus();
|
|
495
677
|
} );
|
|
678
|
+
|
|
679
|
+
it( 'should restore focus correctly even when the `path` needs to be escaped', async () => {
|
|
680
|
+
const user = userEvent.setup();
|
|
681
|
+
|
|
682
|
+
render( <MyNavigation /> );
|
|
683
|
+
|
|
684
|
+
expect( getScreen( 'home' ) ).toBeInTheDocument();
|
|
685
|
+
|
|
686
|
+
// Navigate to screen with an invalid HTML value for its `path`.
|
|
687
|
+
await user.click(
|
|
688
|
+
getNavigationButton( 'toInvalidHtmlPathScreen' )
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
expect( getScreen( 'invalidHtmlPath' ) ).toBeInTheDocument();
|
|
692
|
+
|
|
693
|
+
// Navigate back to home screen, check that the focus restoration selector
|
|
694
|
+
// worked correctly despite the escaping.
|
|
695
|
+
await user.click( getNavigationButton( 'back' ) );
|
|
696
|
+
|
|
697
|
+
expect( getScreen( 'home' ) ).toBeInTheDocument();
|
|
698
|
+
expect(
|
|
699
|
+
getNavigationButton( 'toInvalidHtmlPathScreen' )
|
|
700
|
+
).toHaveFocus();
|
|
701
|
+
} );
|
|
702
|
+
|
|
703
|
+
it( 'should restore focus while using goTo and goToParent', async () => {
|
|
704
|
+
const user = userEvent.setup();
|
|
705
|
+
|
|
706
|
+
render( <MyHierarchicalNavigation /> );
|
|
707
|
+
|
|
708
|
+
expect( getScreen( 'home' ) ).toBeInTheDocument();
|
|
709
|
+
|
|
710
|
+
// Navigate to child screen.
|
|
711
|
+
await user.click( getNavigationButton( 'toChildScreen' ) );
|
|
712
|
+
expect( getScreen( 'child' ) ).toBeInTheDocument();
|
|
713
|
+
|
|
714
|
+
// Navigate to nested screen.
|
|
715
|
+
await user.click( getNavigationButton( 'toNestedScreen' ) );
|
|
716
|
+
expect( getScreen( 'nested' ) ).toBeInTheDocument();
|
|
717
|
+
expect( getNavigationButton( 'back' ) ).toBeInTheDocument();
|
|
718
|
+
|
|
719
|
+
// Navigate back to child screen using the back button.
|
|
720
|
+
await user.click( getNavigationButton( 'back' ) );
|
|
721
|
+
expect( getScreen( 'child' ) ).toBeInTheDocument();
|
|
722
|
+
expect( getNavigationButton( 'toNestedScreen' ) ).toHaveFocus();
|
|
723
|
+
|
|
724
|
+
// Re navigate to nested screen.
|
|
725
|
+
await user.click( getNavigationButton( 'toNestedScreen' ) );
|
|
726
|
+
expect( getScreen( 'nested' ) ).toBeInTheDocument();
|
|
727
|
+
expect(
|
|
728
|
+
getNavigationButton( 'backUsingGoTo' )
|
|
729
|
+
).toBeInTheDocument();
|
|
730
|
+
|
|
731
|
+
// Navigate back to child screen using the go to button.
|
|
732
|
+
await user.click( getNavigationButton( 'backUsingGoTo' ) );
|
|
733
|
+
expect( getScreen( 'child' ) ).toBeInTheDocument();
|
|
734
|
+
expect( getNavigationButton( 'toNestedScreen' ) ).toHaveFocus();
|
|
735
|
+
|
|
736
|
+
// Navigate back to home screen.
|
|
737
|
+
await user.click( getNavigationButton( 'back' ) );
|
|
738
|
+
expect( getNavigationButton( 'toChildScreen' ) ).toHaveFocus();
|
|
739
|
+
} );
|
|
496
740
|
} );
|
|
497
741
|
} );
|