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: add focus restoration #38149

Merged
merged 12 commits into from
Feb 7, 2022
Merged

Conversation

ciampo
Copy link
Contributor

@ciampo ciampo commented Jan 21, 2022

Description

Following the conversation in #37063 and the exploratory work done in #37223, this PR is the first step towards adding support for advanced focus restoration in Navigator. The plan is to have the work split across 3 PRs:


This PR adds focus restoration to the Navigator:

  • added focusTargetSelector to the push function's options
  • added functionality to NavigatorProvider to store the focusTargetSelector with the correct location
  • added focus restoration functionality to NavigatorScreen
  • refactored usages across gutenberg and storybook
  • Updated unit tests
  • Updated docs

How has this been tested?

  • Unit tests pass
  • Check that the Storybook example works as expected (including focus restoration)
  • Check that the Global Styles Sidebar in the site editor works as expected (including focus restoration)
  • Check that the Preferences Modal in the post editor (on mobile viewports) works as expected (including focus restoration)

Types of changes

New feature (technically not breaking, since the component is experimental)

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal).

@ciampo ciampo self-assigned this Jan 21, 2022
@ciampo ciampo added [Feature] Component System WordPress component system [Package] Components /packages/components [Type] Enhancement A suggestion for improvement. labels Jan 21, 2022
elementToFocus.focus();
}, [ isInitialLocation, isMatch ] );

const mergedWrapperRef = useMergeRefs( [ forwardedRef, wrapperRef ] );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Merging the two refs, so that they are correctly assigned to the wrapper element regardless of the value of prefersReducedMotion

Comment on lines +92 to +102
const firstTabbable = ( focus.tabbable.find(
wrapperRef.current
) as HTMLElement[] )[ 0 ];

elementToFocus = firstTabbable ?? wrapperRef.current;
Copy link
Contributor Author

@ciampo ciampo Jan 21, 2022

Choose a reason for hiding this comment

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

This code effectively replicates the same logic as in the useFocusOnMount's logic

@github-actions
Copy link

github-actions bot commented Jan 21, 2022

Size Change: +218 B (0%)

Total Size: 1.14 MB

Filename Size Change
build/components/index.min.js 215 kB +104 B (0%)
build/edit-post/index.min.js 29.7 kB +57 B (0%)
build/edit-site/index.min.js 41.6 kB +57 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 960 B
build/admin-manifest/index.min.js 1.1 kB
build/annotations/index.min.js 2.75 kB
build/api-fetch/index.min.js 2.22 kB
build/autop/index.min.js 2.12 kB
build/blob/index.min.js 459 B
build/block-directory/index.min.js 6.28 kB
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-editor/index.min.js 141 kB
build/block-editor/style-rtl.css 14.6 kB
build/block-editor/style.css 14.6 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 111 B
build/block-library/blocks/audio/style.css 111 B
build/block-library/blocks/audio/theme-rtl.css 125 B
build/block-library/blocks/audio/theme.css 125 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 470 B
build/block-library/blocks/button/editor.css 470 B
build/block-library/blocks/button/style-rtl.css 560 B
build/block-library/blocks/button/style.css 560 B
build/block-library/blocks/buttons/editor-rtl.css 292 B
build/block-library/blocks/buttons/editor.css 292 B
build/block-library/blocks/buttons/style-rtl.css 275 B
build/block-library/blocks/buttons/style.css 275 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 90 B
build/block-library/blocks/code/style.css 90 B
build/block-library/blocks/code/theme-rtl.css 131 B
build/block-library/blocks/code/theme.css 131 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-template/style-rtl.css 127 B
build/block-library/blocks/comment-template/style.css 127 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-query-loop/editor-rtl.css 95 B
build/block-library/blocks/comments-query-loop/editor.css 95 B
build/block-library/blocks/cover/editor-rtl.css 546 B
build/block-library/blocks/cover/editor.css 547 B
build/block-library/blocks/cover/style-rtl.css 1.4 kB
build/block-library/blocks/cover/style.css 1.4 kB
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 417 B
build/block-library/blocks/embed/style.css 417 B
build/block-library/blocks/embed/theme-rtl.css 124 B
build/block-library/blocks/embed/theme.css 124 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 255 B
build/block-library/blocks/file/style.css 255 B
build/block-library/blocks/file/view.min.js 322 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 965 B
build/block-library/blocks/gallery/editor.css 967 B
build/block-library/blocks/gallery/style-rtl.css 1.61 kB
build/block-library/blocks/gallery/style.css 1.61 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 159 B
build/block-library/blocks/group/editor.css 159 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 114 B
build/block-library/blocks/heading/style.css 114 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 810 B
build/block-library/blocks/image/editor.css 809 B
build/block-library/blocks/image/style-rtl.css 500 B
build/block-library/blocks/image/style.css 503 B
build/block-library/blocks/image/theme-rtl.css 124 B
build/block-library/blocks/image/theme.css 124 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 199 B
build/block-library/blocks/latest-posts/editor.css 198 B
build/block-library/blocks/latest-posts/style-rtl.css 447 B
build/block-library/blocks/latest-posts/style.css 446 B
build/block-library/blocks/list/style-rtl.css 94 B
build/block-library/blocks/list/style.css 94 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 493 B
build/block-library/blocks/media-text/style.css 490 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 649 B
build/block-library/blocks/navigation-link/editor.css 650 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B
build/block-library/blocks/navigation-link/style.css 94 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation-submenu/view.min.js 343 B
build/block-library/blocks/navigation/editor-rtl.css 1.98 kB
build/block-library/blocks/navigation/editor.css 1.99 kB
build/block-library/blocks/navigation/style-rtl.css 1.85 kB
build/block-library/blocks/navigation/style.css 1.84 kB
build/block-library/blocks/navigation/view.min.js 2.81 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 401 B
build/block-library/blocks/page-list/editor.css 402 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 273 B
build/block-library/blocks/paragraph/style.css 273 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/style-rtl.css 446 B
build/block-library/blocks/post-comments-form/style.css 446 B
build/block-library/blocks/post-comments/style-rtl.css 521 B
build/block-library/blocks/post-comments/style.css 521 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 721 B
build/block-library/blocks/post-featured-image/editor.css 721 B
build/block-library/blocks/post-featured-image/style-rtl.css 153 B
build/block-library/blocks/post-featured-image/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 323 B
build/block-library/blocks/post-template/style.css 323 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 80 B
build/block-library/blocks/post-title/style.css 80 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 389 B
build/block-library/blocks/pullquote/style.css 388 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query/editor-rtl.css 131 B
build/block-library/blocks/query/editor.css 132 B
build/block-library/blocks/quote/style-rtl.css 201 B
build/block-library/blocks/quote/style.css 201 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 397 B
build/block-library/blocks/search/style.css 398 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 99 B
build/block-library/blocks/separator/editor.css 99 B
build/block-library/blocks/separator/style-rtl.css 245 B
build/block-library/blocks/separator/style.css 245 B
build/block-library/blocks/separator/theme-rtl.css 172 B
build/block-library/blocks/separator/theme.css 172 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 744 B
build/block-library/blocks/site-logo/editor.css 744 B
build/block-library/blocks/site-logo/style-rtl.css 181 B
build/block-library/blocks/site-logo/style.css 181 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 177 B
build/block-library/blocks/social-link/editor.css 177 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.37 kB
build/block-library/blocks/social-links/style.css 1.36 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 471 B
build/block-library/blocks/table/editor.css 472 B
build/block-library/blocks/table/style-rtl.css 481 B
build/block-library/blocks/table/style.css 481 B
build/block-library/blocks/table/theme-rtl.css 188 B
build/block-library/blocks/table/theme.css 188 B
build/block-library/blocks/tag-cloud/style-rtl.css 214 B
build/block-library/blocks/tag-cloud/style.css 215 B
build/block-library/blocks/template-part/editor-rtl.css 560 B
build/block-library/blocks/template-part/editor.css 559 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 571 B
build/block-library/blocks/video/editor.css 572 B
build/block-library/blocks/video/style-rtl.css 173 B
build/block-library/blocks/video/style.css 173 B
build/block-library/blocks/video/theme-rtl.css 124 B
build/block-library/blocks/video/theme.css 124 B
build/block-library/common-rtl.css 921 B
build/block-library/common.css 919 B
build/block-library/editor-rtl.css 10.1 kB
build/block-library/editor.css 10.1 kB
build/block-library/index.min.js 167 kB
build/block-library/reset-rtl.css 474 B
build/block-library/reset.css 474 B
build/block-library/style-rtl.css 11.1 kB
build/block-library/style.css 11.1 kB
build/block-library/theme-rtl.css 672 B
build/block-library/theme.css 676 B
build/block-serialization-default-parser/index.min.js 1.09 kB
build/block-serialization-spec-parser/index.min.js 2.79 kB
build/blocks/index.min.js 46.4 kB
build/components/style-rtl.css 15.5 kB
build/components/style.css 15.5 kB
build/compose/index.min.js 11.2 kB
build/core-data/index.min.js 13.4 kB
build/customize-widgets/index.min.js 11.4 kB
build/customize-widgets/style-rtl.css 1.5 kB
build/customize-widgets/style.css 1.49 kB
build/data-controls/index.min.js 631 B
build/data/index.min.js 7.44 kB
build/date/index.min.js 31.9 kB
build/deprecated/index.min.js 485 B
build/dom-ready/index.min.js 304 B
build/dom/index.min.js 4.5 kB
build/edit-navigation/index.min.js 16.2 kB
build/edit-navigation/style-rtl.css 3.76 kB
build/edit-navigation/style.css 3.76 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/style-rtl.css 7.15 kB
build/edit-post/style.css 7.14 kB
build/edit-site/style-rtl.css 7.22 kB
build/edit-site/style.css 7.21 kB
build/edit-widgets/index.min.js 16.7 kB
build/edit-widgets/style-rtl.css 4.17 kB
build/edit-widgets/style.css 4.17 kB
build/editor/index.min.js 38.5 kB
build/editor/style-rtl.css 3.71 kB
build/editor/style.css 3.71 kB
build/element/index.min.js 3.29 kB
build/escape-html/index.min.js 517 B
build/format-library/index.min.js 6.58 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.63 kB
build/html-entities/index.min.js 424 B
build/i18n/index.min.js 3.75 kB
build/is-shallow-equal/index.min.js 501 B
build/keyboard-shortcuts/index.min.js 1.8 kB
build/keycodes/index.min.js 1.39 kB
build/list-reusable-blocks/index.min.js 1.72 kB
build/list-reusable-blocks/style-rtl.css 838 B
build/list-reusable-blocks/style.css 838 B
build/media-utils/index.min.js 2.92 kB
build/notices/index.min.js 925 B
build/nux/index.min.js 2.09 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 743 B
build/plugins/index.min.js 1.95 kB
build/primitives/index.min.js 917 B
build/priority-queue/index.min.js 582 B
build/react-i18n/index.min.js 671 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.65 kB
build/reusable-blocks/index.min.js 2.22 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11 kB
build/server-side-render/index.min.js 1.58 kB
build/shortcode/index.min.js 1.49 kB
build/token-list/index.min.js 639 B
build/url/index.min.js 1.9 kB
build/viewport/index.min.js 1.05 kB
build/warning/index.min.js 248 B
build/widgets/index.min.js 7.15 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.04 kB

compressed-size-action

@ciampo ciampo force-pushed the feat/navigator-focus-restoration branch from e0a2250 to 67d68df Compare January 21, 2022 23:04
Copy link
Member

@mirka mirka left a comment

Choose a reason for hiding this comment

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

Tests out very well! 👍 There was a styling issue (#38414), but that was unrelated to this PR.

To be honest, it isn't immediately clear to me why there is a complicated system to manipulate isBack and isInitial flags in the stack. As a person who hasn't worked on this 😄, I would think that we could rely on simple stack mechanics instead of tinkering with these flags in the history array, if the current location were set explicitly in the push/pop functions instead of just peeking the stack.

const [ locationHistory, setLocationHistory ] = useState();
const [ location, setLocation ] = useState();

const push = path => {
  setLocation({path, isBack: false}); // any flags are set here, instead of mucking with them in the history stack
  setLocationHistory([...locationHistory, {path}]);
};

const pop = () => {
  const newLocationHistory = [...locationHistory];
  setLocation({...newLocationHistory.pop(), isBack: true});
  setLocationHistory(newLocationHistory);
};

^ This kind of way better matches my mental model of how a history stack works, but maybe there are other complications to consider. Non-blocking, just a thought!

@ciampo
Copy link
Contributor Author

ciampo commented Feb 2, 2022

Thank you @mirka for the review! I'm glad you took some time to look into the code and post some in-depth feedback with fresh eyes!

Looking at your code, these are the major differences that stand out:

  1. your example features an additional piece of state (location), while the code in the PR that is simply "derived" with the assumption that the current location is always the last item of the stack
  2. your example uses array.pop(), while the code in the PR avoids array mutation (e.g. using slice) (similarly to what you'd need to do in a typical Redux reducers)
  3. the code for the push function in the PR is indeed a bit complicated, but its complexity is mostly there because when pushing a new location, we need to also update the previous location (the most important update being adding a focusTargetSelector)

To summarise, I see points 1 and 2 more about personal preference (explicit vs derived location state, array "surgery" with mutable/immutable methods).

Regarding the complexity of the push function, we could try to "slim it down" a bit and simplify the manipulation of isBack and isInitial, but fundamentally it wouldn't change that much (we'd still need to set at least focusTargetSelector on the "previous" location item, for example)

Here's an example of what code be easily removed
diff --git a/packages/components/src/navigator/navigator-provider/component.tsx b/packages/components/src/navigator/navigator-provider/component.tsx
index c20e7aaa5c..69685e4de0 100644
--- a/packages/components/src/navigator/navigator-provider/component.tsx
+++ b/packages/components/src/navigator/navigator-provider/component.tsx
@@ -42,7 +42,6 @@ function NavigatorProvider(
 	>( [
 		{
 			path: initialPath,
-			isBack: false,
 			isInitial: true,
 		},
 	] );
@@ -51,26 +50,18 @@ function NavigatorProvider(
 		( path, options = {} ) => {
 			const { focusTargetSelector, ...restOptions } = options;
 
-			// Notes:
-			// - the `isBack` flag is set to `false` when navigating forwards on both
-			//   the previous and the new location.
-			// - the `isInitial` flag is set to `false` for the new location, to make
-			//   sure it doesn't get overridden by mistake.
-			// - the `focusTargetSelector` prop is set on the current (soon previous)
-			//   location, as it is used to restore focus in NavigatorScreen. The
-			//   remaining options are instead set on the new location being pushed.
+			// `focusTargetSelector` is set on the current (soon to be previous)
+			// location, as it is used to restore focus in NavigatorScreen. The
+			// remaining options are instead set on the new location being pushed.
 			setLocationHistory( [
 				...locationHistory.slice( 0, -1 ),
 				{
 					...locationHistory[ locationHistory.length - 1 ],
-					isBack: false,
 					focusTargetSelector,
 				},
 				{
 					...restOptions,
 					path,
-					isBack: false,
-					isInitial: false,
 				},
 			] );
 		},

What do you think about the proposed changes? Do you still think we should change the code further?

@mirka
Copy link
Member

mirka commented Feb 2, 2022

Thanks for the thoughtful reply! I trust your gut so I defer to your decision either way 🙂

It's just that in my experience, undo functionality like this was usually implemented with standard stack operation equivalents, without having to alter a previous item in the history stack. I don't really mind whether the "stack operation" is achieved by pop-ing a copy or slice-ing (personal preference, like you say). It's only the history rewrite part (point number 3) that's weird to me.

Could the focusTargetSelector problem be solved by making the previous path (instead of the current path) be the top of the stack?

const push = (path, focusTargetSelector) => {
  setLocationHistory([...locationHistory, {path: location.path, focusTargetSelector}]); // push *current* path to history
  setLocation({path, isBack: false}); // go to *new* path
};

I'm also starting to wonder if API-wise it would be more friendly to name it something like const { goTo, goBack } = useNavigator() instead of push/pop, which is kind of a (half-untrue) implementation detail in either approach.

@ciampo
Copy link
Contributor Author

ciampo commented Feb 4, 2022

It's just that in my experience, undo functionality like this was usually implemented with standard stack operation equivalents, without having to alter a previous item in the history stack

This is a fair point. I though about a way to simplify this, and I came up with a potential solution (committed in 4bfccc7):

  • isInitial is now derived (by simply checking if the location array has only one element left)
  • focusTargetSelector is added to the current location in the push function. In order to used it to restore focus when navigating back, the NavigatorScreen keeps a reference of the previous location (via usePrevious)

What do you think?

I'm also starting to wonder if API-wise it would be more friendly to name it something like const { goTo, goBack } = useNavigator() instead of push/pop, which is kind of a (half-untrue) implementation detail in either approach.

I personally like goTo/goBack! @youknowriad what do you think? If we all agree, I can go ahead and implement this in a separate PR.

@mirka
Copy link
Member

mirka commented Feb 7, 2022

What do you think?

Much simplified, and I like the use of usePrevious here! 👍

@youknowriad
Copy link
Contributor

I personally like goTo/goBack! @youknowriad what do you think?

I don't have a strong preference. I guess the argument of push/pop is to make it closer to the browser history API?

@ciampo ciampo force-pushed the feat/navigator-focus-restoration branch from 4bfccc7 to b3e5ede Compare February 7, 2022 11:30
@ciampo
Copy link
Contributor Author

ciampo commented Feb 7, 2022

Much simplified, and I like the use of usePrevious here! 👍

Awesome! I'll give this PR one final check, rebase on top of trunk and merge once all tests pass.

I don't have a strong preference. I guess the argument of push/pop is to make it closer to the browser history API?

That is also a fair point, although the History API's public functions are pushState replaceState, back, forward and go (onpopstate is an event, but not a function) — so, if we wanted to stick closer to the History APIs, there's also an argument for calling these functions pushState / back.

Personally, I'm not sure it's a good idea to name Navigator's APIs in a similar fashion to the History APIs, because it could create an expectation that Navigator can plug into (and modify) the browser's history. In that sense, I like @mirka's suggestion, as it makes that differentiation more clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Component System WordPress component system [Package] Components /packages/components [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants