Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigator: stabilize and export APIs #64613

Merged
merged 38 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
fdd212c
Remove experimental status from Storybook
ciampo Aug 19, 2024
03b69f7
NavigatorProvider => Navigator (internally)
ciampo Aug 19, 2024
b2273a7
Move legacy exports to separate file
ciampo Aug 19, 2024
f2897cc
Export overloaded notation
ciampo Aug 19, 2024
c35b80f
Use overloaded notation in Storybook
ciampo Aug 19, 2024
f659276
Use overloaded notation in unit tests (skipping deprecated component …
ciampo Aug 19, 2024
a489aa7
Update docs manifest.json
ciampo Aug 19, 2024
af0c4d9
Navigator: update docs
ciampo Aug 19, 2024
ca58f31
Navigator.BackButton: update docs
ciampo Aug 19, 2024
adf9678
NavigatorToParentButton: delete README
ciampo Aug 19, 2024
7fc6593
Navigator.Button: update docs
ciampo Aug 19, 2024
37384e6
NavigatorScreen: update docs
ciampo Aug 19, 2024
30dbe5f
Restore `NavigatorToParentButton` test
ciampo Aug 19, 2024
f4da1e6
Use dot notation in context namespaces too
ciampo Aug 19, 2024
d9fe1d8
Use named export for `NavigatorToParentButton` too
ciampo Aug 19, 2024
1d27a89
Fixup docs manifest
ciampo Aug 19, 2024
2617d23
Export stable version from components package
ciampo Aug 19, 2024
24d0bc3
CHANGELOG
ciampo Aug 19, 2024
d21bb27
Change index.ts extension to tsx to allow Storybook to extract JSDocs…
ciampo Aug 21, 2024
c805a37
Remove unnecessary and mispelled display name for top-level `Navigator`
ciampo Aug 26, 2024
aa9b28a
Remove @example tag from top-level export
ciampo Aug 26, 2024
212e29c
Clean up unused imports
ciampo Aug 26, 2024
0cdc3f4
Fix storybook styles
ciampo Sep 26, 2024
a2699e9
Update new section of the docs
ciampo Sep 26, 2024
eb0276d
Update more docs
ciampo Sep 26, 2024
7228e33
Update deprecation warning
ciampo Sep 26, 2024
585faac
Update and align docs
ciampo Sep 26, 2024
c0a754f
Fix tests warning checks
ciampo Sep 26, 2024
521ca86
Typo
ciampo Sep 26, 2024
72cd0bc
Fix useContextSystem names
ciampo Sep 26, 2024
0987fac
Remove mentions of the `useNavigator` hook
ciampo Sep 26, 2024
ca7ac76
useNavigator JSDocs
ciampo Sep 26, 2024
1d29ff1
Move all READMEs under the main README
ciampo Sep 26, 2024
616015a
Move README to component's root folder
ciampo Sep 26, 2024
4639c0b
Update types JSDocs to match README
ciampo Sep 26, 2024
4ea2a09
Update docs manifest
ciampo Sep 26, 2024
999795a
Fix JSDocs typos, grammar, and broken links.
ciampo Sep 27, 2024
578c98a
Update storybook selector
ciampo Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 3 additions & 27 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1098,33 +1098,9 @@
"parent": "components"
},
{
"title": "NavigatorBackButton",
"slug": "navigator-back-button",
"markdown_source": "../packages/components/src/navigator/navigator-back-button/README.md",
"parent": "components"
},
{
"title": "NavigatorButton",
"slug": "navigator-button",
"markdown_source": "../packages/components/src/navigator/navigator-button/README.md",
"parent": "components"
},
{
"title": "NavigatorProvider",
"slug": "navigator-provider",
"markdown_source": "../packages/components/src/navigator/navigator-provider/README.md",
"parent": "components"
},
Comment on lines -1112 to -1117
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, removing things from the manifest is not going to remove it from the Block Editor Handbook 😱 There are some extra steps, see #60003 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I'll follow-up accordingly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a reminder we'll need to take care of this one after merging.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @WordPress/wordpress-org-meta-team , could you help with this? We need to update the Block Editor Handbook, removing the following components:

If possible, we'd also like to set a redirect for those pages being removed. The redirect should point to the Navigator component.

Could you please help with that? Thank you 🙏

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These updates have shipped. I noticed the formatting on the new doc loses consistency around the Navigator.Button point (heading is not bold):

Screenshot 2024-10-01 at 10 42 06 AM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

I noticed the formatting on the new doc loses consistency around the Navigator.Button point (heading is not bold):

Good catch! Opened #65763 to fix it

{
"title": "NavigatorScreen",
"slug": "navigator-screen",
"markdown_source": "../packages/components/src/navigator/navigator-screen/README.md",
"parent": "components"
},
{
"title": "NavigatorToParentButton",
"slug": "navigator-to-parent-button",
"markdown_source": "../packages/components/src/navigator/navigator-to-parent-button/README.md",
"title": "Navigator",
"slug": "navigator",
"markdown_source": "../packages/components/src/navigator/README.md",
"parent": "components"
},
{
Expand Down
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- `Navigator`: add support for exit animation ([#64777](https://github.com/WordPress/gutenberg/pull/64777)).
- `Guide`: Update finish button to use the new default size ([#65680](https://github.com/WordPress/gutenberg/pull/65680)).
- `BorderControl`: Use `__next40pxDefaultSize` prop for Reset button ([#65682](https://github.com/WordPress/gutenberg/pull/65682)).
- `Navigator`: stabilize APIs ([#64613](https://github.com/WordPress/gutenberg/pull/64613)).
ciampo marked this conversation as resolved.
Show resolved Hide resolved

## 28.8.0 (2024-09-19)

Expand Down
1 change: 1 addition & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export {
NavigatorToParentButton as __experimentalNavigatorToParentButton,
useNavigator as __experimentalUseNavigator,
ciampo marked this conversation as resolved.
Show resolved Hide resolved
} from './navigator/legacy';
export { Navigator, useNavigator } from './navigator';
export { default as Notice } from './notice';
export { default as __experimentalNumberControl } from './number-control';
export { default as NoticeList } from './notice/list';
Expand Down
168 changes: 168 additions & 0 deletions packages/components/src/navigator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# `Navigator`

`Navigator` is a collection components that allow rendering nested views/panels/menus (via the `Navigator.Screen` component) and navigate between them (via the `Navigator.Button` and `Navigator.BackButton` components).

## Usage

```jsx
import { Navigator } from '@wordpress/components';

const MyNavigation = () => (
<Navigator initialPath="/">
<Navigator.Screen path="/">
<p>This is the home screen.</p>
<Navigator.Button path="/child">
Navigate to child screen.
</Navigator.Button>
</Navigator.Screen>
<Navigator.Screen path="/child">
<p>This is the child screen.</p>
<Navigator.BackButton>Go back</Navigator.BackButton>
</Navigator.Screen>
</Navigator>
);
```

### Hierarchical `path`s

`Navigator` assumes that screens are organized hierarchically according to their `path`, which should follow a URL-like scheme where each path segment starts with and is separated by the `/` character.

`Navigator` will treat "back" navigations as going to the parent screen — it is, therefore, the responsibility of the consumer of the component to create the correct screen hierarchy.

For example:

- `/` is the root of all paths. There should always be a screen with `path="/"`;
- `/parent/child` is a child of `/parent`;
- `/parent/child/grand-child` is a child of `/parent/child`;
- `/parent/:param` is a child of `/parent` as well;
- if the current screen has a `path="/parent/child/grand-child"`, when going "back" `Navigator` will try to recursively navigate the path hierarchy until a matching screen (or the root `/`) is found.

### Height and animations

Due to how `Navigator.Screen` animations work, it is recommended that the `Navigator` component is assigned a `height` to prevent some potential UI jumps while moving across screens.

### Individual components

`Navigator` is comprised of four individual components:

- `Navigator`: a wrapper component and context provider. It holds the main logic for hiding and showing screens.
- `Navigator.Screen`: represents a single view/screen/panel;
- `Navigator.Button`: renders a button that allows navigating to a different `Navigator.Screen`;
- `Navigator.BackButton`: renders a button that allows navigating to the parent `Navigator.Screen` (see the section above about hierarchical paths).

For advanced usages, consumers can use the `useNavigator` hook.

#### `Navigator`

##### Props

###### `initialPath`: `string`

The initial active path.

- Required: Yes

###### `children`: `string`

The children elements.

- Required: Yes

#### `Navigator.Screen`

###### `path`: `string`

The screen's path, matched against the current path stored in the navigator.

`Navigator` assumes that screens are organized hierarchically according to their `path`, which should follow a URL-like scheme where each path segment starts with and is separated by the `/` character.

`Navigator` will treat "back" navigations as going to the parent screen — it is, therefore, the responsibility of the consumer of the component to create the correct screen hierarchy.

For example:

- `/` is the root of all paths. There should always be a screen with `path="/"`.
- `/parent/child` is a child of `/parent`.
- `/parent/child/grand-child` is a child of `/parent/child`.
- `/parent/:param` is a child of `/parent` as well.
- if the current screen has a `path` with value `/parent/child/grand-child`, when going "back" `Navigator` will try to recursively navigate the path hierarchy until a matching screen (or the root `/`) is found.

- Required: Yes

###### `children`: `string`

The children elements.

- Required: Yes

##### `Navigator.Button`

###### `path`: `string`

The path of the screen to navigate to. The value of this prop needs to be [a valid value for an HTML attribute](https://html.spec.whatwg.org/multipage/syntax.html#attributes-2).

- Required: Yes

###### `attributeName`: `string`

The HTML attribute used to identify the `Navigator.Button`, which is used by `Navigator` to restore focus.

- Required: No
- Default: `id`

###### `children`: `string`

The children elements.

- Required: No

###### Inherited props

`Navigator.Button` also inherits all of the [`Button` props](/packages/components/src/button/README.md#props), except for `href` and `target`.

##### `Navigator.BackButton`

###### `children`: `string`

The children elements.

- Required: No

###### Inherited props

`Navigator.BackButton` also inherits all of the [`Button` props](/packages/components/src/button/README.md#props), except for `href` and `target`.

###### `useNavigator`

You can retrieve a `navigator` instance by using the `useNavigator` hook.

The `navigator` instance has a few properties:

###### `goTo`: `( path: string, options: NavigateOptions ) => void`

The `goTo` function allows navigating to a given path. The second argument can augment the navigation operations with different options.

The available options are:

- `focusTargetSelector`: `string`. An optional property used to specify the CSS selector used to restore focus on the matching element when navigating back;
- `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);
- `skipFocus`: `boolean`. An optional property used to opt out of `Navigator`'s focus management, useful when the consumer of the component wants to manage focus themselves;

###### `goBack`: `( path: string, options: NavigateOptions ) => void`

The `goBack` function allows navigating to the parent screen. Parent/child navigation only works if the paths you define are hierarchical (see note above).

When a match is not found, the function will try to recursively navigate the path hierarchy until a matching screen (or the root `/`) is found.

The available options are the same as for the `goTo` method, except for the `isBack` property, which is not available for the `goBack` method.

###### `location`: `NavigatorLocation`

The `location` object represents the current location, and has a few properties:

- `path`: `string`. The path associated to the location.
- `isBack`: `boolean`. A flag that is `true` when the current location was reached by navigating backwards.
- `isInitial`: `boolean`. A flag that is `true` only for the initial location.

###### `params`: `Record< string, string | string[] >`

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' }`.
131 changes: 131 additions & 0 deletions packages/components/src/navigator/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/**
* Internal dependencies
*/
import { Navigator as TopLevelNavigator } from './navigator/component';
import { NavigatorScreen } from './navigator-screen/component';
import { NavigatorButton } from './navigator-button/component';
import { NavigatorBackButton } from './navigator-back-button/component';
export { useNavigator } from './use-navigator';

/**
* The `Navigator` component allows rendering nested views/panels/menus
* (via the `Navigator.Screen` component) and navigate between them
* (via the `Navigator.Button` and `Navigator.BackButton` components).
*
* ```jsx
* import { Navigator } from '@wordpress/components';
*
* const MyNavigation = () => (
* <Navigator initialPath="/">
* <Navigator.Screen path="/">
* <p>This is the home screen.</p>
* <Navigator.Button path="/child">
* Navigate to child screen.
* </Navigator.Button>
* </Navigator.Screen>
*
* <Navigator.Screen path="/child">
* <p>This is the child screen.</p>
* <Navigator.BackButton>
* Go back
* </Navigator.BackButton>
* </Navigator.Screen>
* </Navigator>
* );
* ```
*/
export const Navigator = Object.assign( TopLevelNavigator, {
/**
* The `Navigator.Screen` component represents a single view/screen/panel and
* should be used in combination with the `Navigator`, the `Navigator.Button`
* and the `Navigator.BackButton` components.
*
* @example
* ```jsx
* import { Navigator } from '@wordpress/components';
*
* const MyNavigation = () => (
* <Navigator initialPath="/">
* <Navigator.Screen path="/">
* <p>This is the home screen.</p>
* <Navigator.Button path="/child">
* Navigate to child screen.
* </Navigator.Button>
* </Navigator.Screen>
*
* <Navigator.Screen path="/child">
* <p>This is the child screen.</p>
* <Navigator.BackButton>
* Go back
* </Navigator.BackButton>
* </Navigator.Screen>
* </Navigator>
* );
* ```
*/
Screen: Object.assign( NavigatorScreen, {
displayName: 'Navigator.Screen',
} ),
ciampo marked this conversation as resolved.
Show resolved Hide resolved
/**
* The `Navigator.Button` component can be used to navigate to a screen and
* should be used in combination with the `Navigator`, the `Navigator.Screen`
* and the `Navigator.BackButton` components.
*
* @example
* ```jsx
* import { Navigator } from '@wordpress/components';
*
* const MyNavigation = () => (
* <Navigator initialPath="/">
* <Navigator.Screen path="/">
* <p>This is the home screen.</p>
* <Navigator.Button path="/child">
* Navigate to child screen.
* </Navigator.Button>
* </Navigator.Screen>
*
* <Navigator.Screen path="/child">
* <p>This is the child screen.</p>
* <Navigator.BackButton>
* Go back
* </Navigator.BackButton>
* </Navigator.Screen>
* </Navigator>
* );
* ```
*/
Button: Object.assign( NavigatorButton, {
displayName: 'Navigator.Button',
} ),
/**
* The `Navigator.BackButton` component can be used to navigate to a screen and
* should be used in combination with the `Navigator`, the `Navigator.Screen`
* and the `Navigator.Button` components.
*
* @example
* ```jsx
* import { Navigator } from '@wordpress/components';
*
* const MyNavigation = () => (
* <Navigator initialPath="/">
* <Navigator.Screen path="/">
* <p>This is the home screen.</p>
* <Navigator.Button path="/child">
* Navigate to child screen.
* </Navigator.Button>
* </Navigator.Screen>
*
* <Navigator.Screen path="/child">
* <p>This is the child screen.</p>
* <Navigator.BackButton>
* Go back
* </Navigator.BackButton>
* </Navigator.Screen>
* </Navigator>
* );
* ```
*/
BackButton: Object.assign( NavigatorBackButton, {
displayName: 'Navigator.BackButton',
} ),
} );
Loading
Loading