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

Components: Tabs: Improve Controlled Mode Focus Handling #57696

Merged
merged 14 commits into from Feb 1, 2024

Conversation

chad1008
Copy link
Contributor

@chad1008 chad1008 commented Jan 9, 2024

This PR is meant to initially serve as a proof of concept and place for discussion. I've included a possible path forward but I'm primarily interested in feedback on what the best path forward is. I put the changes together because I wanted to test their viability for own purposes, and figured I may as well include them in case a working example was helpful.

What?

Limit controlled-mode Tabs component focus updates related to selection changes to cases when the tab selected at the time of the change had focus.

Remove the automatic focus syncing behavior while adding a new check to ensure arrow key navigation is preserved.

Why?

Currently, the Tabs component is set to make sure that in controlled mode, if a tab has browser focus and the selected tab changes, the newly selected tab gets focus. This was first discussed when introducing the new Tabs component into the editor settings, and introduced in #56658. In that initial PR, we intentionally skip the focus updates when selectOnMove is false, to avoid moving focus on a user who is actively navigating across the available tabs.

In a separate but similar PR, we came to the conclusion that manual selection was a better option for the tabs in question. This means the update mentioned above will no longer apply, (selectOnMove will be false) and the selected tab can easily become out of sync with the currently focused tab.

I had two thoughts on how to address this:

  • Completely remove the condition that selectOnMove be true for keeping focus and selection in sync
  • Remove the selectOnMove condition, but limit the actual focus update to cases where the tab that was selected at that time of the change actually had focus.

This PR experiments with the second option as a bit of a compromise. @andrewhayward's advice in the discussion linked above was to err on the side of not manipulating focus more than necessary. With the approach on this PR, if you've placed focus on the currently selected tab and the selection changes, focus will update you'll ultimately end up with focus still in alignment with the displayed content. On the other hand, if you've explicitly moved focus away from the selected tab the focus will not be changed. This way if you're actively navigating across tabs when a change happens, you're much less likely to find your focus bouncing around unexpectedly.

Adjusting based on feedback (see comments below), this PR removes the previously introduced focus management. This means that if the currently selected tab is focused and that selection is changed by the controlling component, focus will not be moved to the newly selected tab.

Note: This also means that in the editor settings sidebars (both post and site editors) tabbing through the available blocks into the sidebar can cause the Block tab to be focused while the Document tab is actually selected. If necessary, we can look into adding a helper to the editor itself to avoid this situation. That way we address that use case without making the component itself overly opinionated.

How?

When deciding whether or not to update focus, we check the id of the previously selected tab. If that's the same tab that has focus (we haven't shifted focus yet, so it's still going to be wherever the user last placed it) we know the selected tab was focused before the change was made. In that case we shift the focus to the new tab.

Regardless of any other factors, we no longer change browser focus.

We do, however, have to manage the component's internal focus. Ariakit tracks and manages focus internally via an activeId value. When the selected tab is changed, that activeId also changes to match the selection.

If DOM focus is on a different tab when this happens, the arrow keys will base their actions off of the new activeId, not the current DOM focus. This can lead to awkward navigation. To avoid that, when the selected tab is changed and focus was not already on the focused tab, we update the activeId to once again match the currently select tab in the DOM. This ensures that arrow key behavior remains consistent.

Testing Instructions

In the editor:

Apply the following testing diff

This adds focusOnMove={false} to this implementation, which I'll most likely be doing for real in a separate PR, but it's the most convenient place to test these changes.

diff --git a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js
index 0cd69cb115..eac816b87c 100644
--- a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js
+++ b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js
@@ -157,6 +157,7 @@ const SettingsSidebar = () => {
 			// the selected tab to `null` avoids that.
 			selectedTabId={ isSettingsSidebarActive ? sidebarName : null }
 			onSelect={ onTabSelect }
+			selectOnMove={ false }
 		>
 			<SidebarContent
 				sidebarName={ sidebarName }
  1. Create a new post and make sure the settings sidebar is open
  2. Add a title and a paragraph block or two
  3. Click below the blocks you've added on the empty area of the canvas
  4. Press Tab to focus the title
  5. Press Tab to focus the first block, repeat until focus reaches the last block. While a block is focused, the settings sidebar should automatically select the Block tab
  6. Press Tab to move focus to the sidebar. This removes focus from a block, auto-selecting the Post tab
  7. Confirm that when the Post tab is selected, browser focus does not automatically move to that tab.
  8. Use the arrow keys to move between tabs, confirming they are not automatically selected.
  9. Confirm that when you press an arrow key, focus moves as you'd expect it to on the first keystroke.

In Storybook

Apply the following test diff

This adds selectOnMove={false} and a delay to the Controlled Mode story, so you can move focus to test the the effect of the tab changing on you.

diff --git a/packages/components/src/tabs/stories/index.story.tsx b/packages/components/src/tabs/stories/index.story.tsx
index 0e7ab725e3..5b8a966a35 100644
--- a/packages/components/src/tabs/stories/index.story.tsx
+++ b/packages/components/src/tabs/stories/index.story.tsx
@@ -273,17 +273,29 @@ const ControlledModeTemplate: StoryFn< typeof Tabs > = ( props ) => {
 					<DropdownMenu
 						controls={ [
 							{
-								onClick: () => setSelectedTabId( 'tab1' ),
+								onClick: () =>
+									setTimeout(
+										() => setSelectedTabId( 'tab1' ),
+										3000
+									),
 								title: 'Tab 1',
 								isActive: selectedTabId === 'tab1',
 							},
 							{
-								onClick: () => setSelectedTabId( 'tab2' ),
+								onClick: () =>
+									setTimeout(
+										() => setSelectedTabId( 'tab2' ),
+										3000
+									),
 								title: 'Tab 2',
 								isActive: selectedTabId === 'tab2',
 							},
 							{
-								onClick: () => setSelectedTabId( 'tab3' ),
+								onClick: () =>
+									setTimeout(
+										() => setSelectedTabId( 'tab3' ),
+										3000
+									),
 								title: 'Tab 3',
 								isActive: selectedTabId === 'tab3',
 							},
@@ -299,6 +311,7 @@ const ControlledModeTemplate: StoryFn< typeof Tabs > = ( props ) => {
 export const ControlledMode = ControlledModeTemplate.bind( {} );
 ControlledMode.args = {
 	selectedTabId: 'tab3',
+	selectOnMove: false,
 };
 
 const TabBecomesDisabledTemplate: StoryFn< typeof Tabs > = ( props ) => {
  1. Launch Storybook and open the Controlled Mode story
  2. Using the dropdown menu, select Tab 1
  3. Before the three-second delay elapses, click on the canvas between the Tabs component and the dropdown menu. Then press Tab to focus the currently selected tab (Tab 3)
  4. When the delay runs out the selected tab will change. Confirm that even though the selected tab changed, browser focus did not. You should still be focused on Tab 3 but Tab 1 should be selected and its contents visible.
  5. Test the arrow keys and confirm they behave normally, moving left/right as expected.
  6. Click or use the keyboard to select Tab 1
  7. Use the dropdown again and select Tab 3
  8. Before the delay expires, click on the canvas and press Tab, followed by ArrowRight so that Tab 2 has focus
  9. When the delay expires, confirm that Tab 3 is selected, and its contents are displayed
  10. Confirm that Tab 2 still has browser focus.
  11. Test arrow keys, confirming they move left or right as expected. Specifically, you're making sure they don't act like Tab 3 got focus when it was selected.

@ciampo
Copy link
Contributor

ciampo commented Jan 11, 2024

Before reviewing in details the proposed solution, I actually wonder if adding this quite complex logic to the component is a good idea. When reviewing TabPanel, one of the things we noticed is that the component had a ton of custom behaviour to deal with many edge cases and custom needs of the editor. I'm afraid that we may ending up in the same spot.

A different approach would be to assume that the consumer of the component is in charge of implementing any specific custom behavior themselves, corroborated by Andrew's advice about

to err on the side of not manipulating focus more than necessary.

I'm not sure yet exactly where we should draw the line, but it's definitely something that we should at least consider before moving forward. cc @mirka

@chad1008
Copy link
Contributor Author

chad1008 commented Jan 11, 2024

On the one hand I like the idea of handling this within the component, so the different implementations (I can think of three at the moment) similar to this one don't need to be maintained separately by the editor... but I do see your point about making the component more and more complex.

Thinking about it, I suppose another package could write a reusable helper to handle this logic internally if need be. If we do go that route, it might make sense to remove the previously added focus logic as well. That way the component doesn't manipulate focus at all, and it's entirely in the hands of the consumer.

@ciampo
Copy link
Contributor

ciampo commented Jan 12, 2024

I suppose another package could write a reusable helper to handle this logic internally if need be. If we do go that route, it might make sense to remove the previously added focus logic as well. That way the component doesn't manipulate focus at all, and it's entirely in the hands of the consumer.

Yeah, while we wait to hear Lena's opinion, maybe you could look into exploring this option?

@mirka
Copy link
Member

mirka commented Jan 15, 2024

I'm not sure yet exactly where we should draw the line, but it's definitely something that we should at least consider before moving forward.

Good call.

From what I understood, the proposed changes seem generically useful enough to live inside this component. And the added code complexity doesn't immediately look disproportionate to the value that it adds. Someone could persuade me otherwise on either of these points, but that's my current impression.

Also I'm not sure we can shift this responsibility down to consumers without them coupling their code with Ariakit internals (activeId).

So I'm ok with this logic staying in the component, at least with the information we have now. (Not saying we'll never discover complications in the future though, however low-risk it seems now 😅)

@ciampo
Copy link
Contributor

ciampo commented Jan 16, 2024

That's fair enough. I honestly wanted to take a step back and hear opinions from folks who have been less directly involved in the Tabs work. Happy to continue with this PR, and glad that we had this conversation.

@chad1008 , would you be able to add some unit tests (that would fail on trunk and pass on this PR) ?

@chad1008
Copy link
Contributor Author

Thanks @mirka and @ciampo!

I'll get going on those unit tests.

@chad1008 chad1008 force-pushed the tabs-improve-controlled-focus-sync branch 3 times, most recently from 2832b29 to 8c086f2 Compare January 17, 2024 17:09
packages/components/src/tabs/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/tabs/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/tabs/test/index.tsx Show resolved Hide resolved
packages/components/src/tabs/test/index.tsx Outdated Show resolved Hide resolved
@ciampo ciampo added [Type] Bug An existing feature does not function as intended [Package] Components /packages/components labels Jan 17, 2024
@ciampo ciampo marked this pull request as ready for review January 17, 2024 17:49
Copy link
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

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

Code changes LGTM, unit tests pass, and the changes test well in the editor as per instructions 🚀

From my end, we're good to merge after the pending feedback gets addressed, with the caveat of any accessibility-related feedback that we may receive.

packages/components/src/tabs/index.tsx Show resolved Hide resolved
packages/components/src/tabs/index.tsx Outdated Show resolved Hide resolved
@chad1008 chad1008 added the Needs Accessibility Feedback Need input from accessibility label Jan 17, 2024
@chad1008 chad1008 force-pushed the tabs-improve-controlled-focus-sync branch from 3e0f078 to 1c3a994 Compare January 17, 2024 22:13
packages/components/src/tabs/index.tsx Outdated Show resolved Hide resolved
@chad1008 chad1008 enabled auto-merge (squash) January 18, 2024 17:11
@chad1008 chad1008 force-pushed the tabs-improve-controlled-focus-sync branch from 260eae5 to 908f0f7 Compare January 18, 2024 17:17
@chad1008
Copy link
Contributor Author

feeling ready to merge this one, but in the interest of thoroughness on the a11y front, ccing @andrewhayward or @alexstine in case y'all have any thoughts 😄

@andrewhayward
Copy link
Contributor

...in the interest of thoroughness on the a11y front...

Apologies, I missed this PR.

With the approach on this PR, if you've placed focus on the currently selected tab and the selection changes, focus will update you'll ultimately end up with focus still in alignment with the displayed content. On the other hand, if you've explicitly moved focus away from the selected tab the focus will not be changed. This way if you're actively navigating across tabs when a change happens, you're much less likely to find your focus bouncing around unexpectedly.

I'm happy to defer to @alexstine on this one, who has a lot more real world experience with these things, but as a general rule, we should avoid moving focus unless the user takes an action that might require it. So while I can see where you're coming from with this, it doesn't quite feel right.

Personally I'd recommend the following:

  • If current focus is not on any of the tabs, then the focusable tab should track the active tab
  • If current focus is on one of the tabs and the active tab changes, focus should remain where it is
  • If the active tab has changed, leaving the focus and active states disconnected, they may be realigned when focus leaves the tab set

Does that make sense?

@chad1008
Copy link
Contributor Author

Does that make sense?

@andrewhayward It does! thank you for organizing into those bullets, that was very helpful.

Reading through that, I start to wonder if the best path forward for this PR might actually be:

  • keep the new change that make sure the arrow key behavior remains based off of the focused element
  • remove the previous change that actually changed the focus to keep it in sync

so we don't mess with focus, but we minimize any additional confusion.

@chad1008
Copy link
Contributor Author

@alexstine / @andrewhayward - not an urgent ping, but wondering if either of you had any final insights on approach here.

The more I consider Andrew's feedback above, the more I think moving away from changing focus at all, and just preserving expected arrow key navigation makes the most sense, but I'd definitely prefer to defer to the experts on this one 😄

@ciampo
Copy link
Contributor

ciampo commented Jan 25, 2024

Reading through that, I start to wonder if the best path forward for this PR might actually be:

  • keep the new change that make sure the arrow key behavior remains based off of the focused element
  • remove the previous change that actually changed the focus to keep it in sync

so we don't mess with focus, but we minimize any additional confusion.

This could be a good compromise, although I'm curious to hear other folks' opinions too.

@chad1008 chad1008 force-pushed the tabs-improve-controlled-focus-sync branch from 5df31aa to 32d0066 Compare January 26, 2024 22:50
@chad1008
Copy link
Contributor Author

Thanks @ciampo. In the interest of expediency, i've updated the PR to no longer manipulate focus and instead only manage the arrow key navigation, and requested some fresh reviews.

This change will cause some unit tests to fail, I'll get them updated once we've finalized our path forward.

@chad1008
Copy link
Contributor Author

chad1008 commented Jan 31, 2024

After some additional brainstorming with @ciampo and @mirka we're going to move forward with this PR's approach.

Ultimately, this makes the component less invasive/opinionated by reversing the previous decisions to manipulate focus. It also addresses the bug with arrow key navigation in controlled mode. These both feel like wins!

For future context, if the decision is ever made to restore the focus management, one of the commits on this PR will serve as a good record of what was briefly in place.

I've updated the impacted unit and e2e tests. On the unit tests, I've done away with the previously added describe.each block for selectOnMove, because that prop no longer influences focus or arrow key behavior. There's now just one test that confirms that arrow keys move focus to the correct tab after a selection change by the controlling component.

@ciampo / @mirka, would you mind taking a one last look at the test changes before I push this through? Thanks!!

Copy link

github-actions bot commented Jan 31, 2024

Size Change: +318 B (0%)

Total Size: 1.7 MB

Filename Size Change
build/block-editor/content-rtl.css 4.35 kB -30 B (-1%)
build/block-editor/content.css 4.35 kB -31 B (-1%)
build/block-editor/index.min.js 250 kB +257 B (0%)
build/components/index.min.js 235 kB +60 B (0%)
build/edit-site/index.min.js 195 kB +51 B (0%)
build/edit-site/style-rtl.css 15.3 kB +19 B (0%)
build/edit-site/style.css 15.3 kB +18 B (0%)
build/edit-widgets/index.min.js 17.3 kB +9 B (0%)
build/editor/index.min.js 61.6 kB -16 B (0%)
build/rich-text/index.min.js 10.4 kB -19 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 955 B
build/annotations/index.min.js 2.69 kB
build/api-fetch/index.min.js 2.32 kB
build/autop/index.min.js 2.1 kB
build/blob/index.min.js 578 B
build/block-directory/index.min.js 7.22 kB
build/block-directory/style-rtl.css 1.02 kB
build/block-directory/style.css 1.02 kB
build/block-editor/default-editor-styles-rtl.css 381 B
build/block-editor/default-editor-styles.css 381 B
build/block-editor/style-rtl.css 15.5 kB
build/block-editor/style.css 15.5 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 90 B
build/block-library/blocks/archives/style.css 90 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 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 126 B
build/block-library/blocks/audio/theme.css 126 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 415 B
build/block-library/blocks/button/editor.css 414 B
build/block-library/blocks/button/style-rtl.css 627 B
build/block-library/blocks/button/style.css 626 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 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 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 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-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.69 kB
build/block-library/blocks/cover/style.css 1.68 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 98 B
build/block-library/blocks/details/style.css 98 B
build/block-library/blocks/embed/editor-rtl.css 322 B
build/block-library/blocks/embed/editor.css 322 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 126 B
build/block-library/blocks/embed/theme.css 126 B
build/block-library/blocks/file/editor-rtl.css 316 B
build/block-library/blocks/file/editor.css 316 B
build/block-library/blocks/file/style-rtl.css 280 B
build/block-library/blocks/file/style.css 281 B
build/block-library/blocks/file/view.min.js 316 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 227 B
build/block-library/blocks/form-input/editor.css 227 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 340 B
build/block-library/blocks/form-submission-notification/editor.css 340 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 471 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 947 B
build/block-library/blocks/gallery/editor.css 952 B
build/block-library/blocks/gallery/style-rtl.css 1.72 kB
build/block-library/blocks/gallery/style.css 1.72 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 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 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 336 B
build/block-library/blocks/html/editor.css 337 B
build/block-library/blocks/image/editor-rtl.css 863 B
build/block-library/blocks/image/editor.css 862 B
build/block-library/blocks/image/style-rtl.css 1.6 kB
build/block-library/blocks/image/style.css 1.59 kB
build/block-library/blocks/image/theme-rtl.css 126 B
build/block-library/blocks/image/theme.css 126 B
build/block-library/blocks/image/view.min.js 2.01 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 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 505 B
build/block-library/blocks/media-text/style.css 503 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 668 B
build/block-library/blocks/navigation-link/editor.css 669 B
build/block-library/blocks/navigation-link/style-rtl.css 103 B
build/block-library/blocks/navigation-link/style.css 103 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation/editor-rtl.css 2.25 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.24 kB
build/block-library/blocks/navigation/style.css 2.23 kB
build/block-library/blocks/navigation/view.min.js 1.1 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 377 B
build/block-library/blocks/page-list/editor.css 377 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 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 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/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-content/editor-rtl.css 74 B
build/block-library/blocks/post-content/editor.css 74 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 666 B
build/block-library/blocks/post-featured-image/editor.css 662 B
build/block-library/blocks/post-featured-image/style-rtl.css 342 B
build/block-library/blocks/post-featured-image/style.css 342 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 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 409 B
build/block-library/blocks/post-template/style.css 408 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 354 B
build/block-library/blocks/pullquote/style.css 354 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 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 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/style-rtl.css 312 B
build/block-library/blocks/query/style.css 308 B
build/block-library/blocks/query/view.min.js 1.1 kB
build/block-library/blocks/quote/style-rtl.css 237 B
build/block-library/blocks/quote/style.css 237 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 140 B
build/block-library/blocks/read-more/style.css 140 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 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 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 614 B
build/block-library/blocks/search/style.css 614 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 471 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 229 B
build/block-library/blocks/separator/style.css 229 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 323 B
build/block-library/blocks/shortcode/editor.css 323 B
build/block-library/blocks/site-logo/editor-rtl.css 754 B
build/block-library/blocks/site-logo/editor.css 754 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 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 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.49 kB
build/block-library/blocks/social-links/style.css 1.48 kB
build/block-library/blocks/spacer/editor-rtl.css 348 B
build/block-library/blocks/spacer/editor.css 348 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 395 B
build/block-library/blocks/table/editor.css 395 B
build/block-library/blocks/table/style-rtl.css 639 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 146 B
build/block-library/blocks/table/theme.css 146 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 403 B
build/block-library/blocks/template-part/editor.css 403 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/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 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 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 185 B
build/block-library/blocks/video/style.css 185 B
build/block-library/blocks/video/theme-rtl.css 126 B
build/block-library/blocks/video/theme.css 126 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.1 kB
build/block-library/common.css 1.1 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 12.3 kB
build/block-library/editor.css 12.3 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 215 kB
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 14.7 kB
build/block-library/style.css 14.7 kB
build/block-library/theme-rtl.css 688 B
build/block-library/theme.css 693 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.6 kB
build/commands/index.min.js 15.5 kB
build/commands/style-rtl.css 921 B
build/commands/style.css 918 B
build/components/style-rtl.css 12 kB
build/components/style.css 12 kB
build/compose/index.min.js 12.6 kB
build/core-commands/index.min.js 2.71 kB
build/core-data/index.min.js 72.7 kB
build/customize-widgets/index.min.js 12.1 kB
build/customize-widgets/style-rtl.css 1.34 kB
build/customize-widgets/style.css 1.33 kB
build/data-controls/index.min.js 640 B
build/data/index.min.js 8.92 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 451 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.65 kB
build/edit-post/classic-rtl.css 544 B
build/edit-post/classic.css 545 B
build/edit-post/index.min.js 25 kB
build/edit-post/style-rtl.css 5.67 kB
build/edit-post/style.css 5.66 kB
build/edit-widgets/style-rtl.css 4.48 kB
build/edit-widgets/style.css 4.48 kB
build/editor/style-rtl.css 5.43 kB
build/editor/style.css 5.43 kB
build/element/index.min.js 4.83 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 7.85 kB
build/format-library/style-rtl.css 478 B
build/format-library/style.css 477 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.58 kB
build/interactivity/file.min.js 440 B
build/interactivity/image.min.js 2.15 kB
build/interactivity/index.min.js 12.8 kB
build/interactivity/navigation.min.js 1.23 kB
build/interactivity/query.min.js 884 B
build/interactivity/router.min.js 971 B
build/interactivity/search.min.js 610 B
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.74 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.11 kB
build/list-reusable-blocks/style-rtl.css 836 B
build/list-reusable-blocks/style.css 836 B
build/media-utils/index.min.js 2.9 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 948 B
build/nux/index.min.js 2 kB
build/nux/style-rtl.css 735 B
build/nux/style.css 732 B
build/patterns/index.min.js 5.44 kB
build/patterns/style-rtl.css 540 B
build/patterns/style.css 539 B
build/plugins/index.min.js 1.8 kB
build/preferences-persistence/index.min.js 2.07 kB
build/preferences/index.min.js 2.81 kB
build/preferences/style-rtl.css 698 B
build/preferences/style.css 700 B
build/primitives/index.min.js 975 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1 kB
build/react-i18n/index.min.js 623 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.72 kB
build/reusable-blocks/style-rtl.css 243 B
build/reusable-blocks/style.css 243 B
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.95 kB
build/shortcode/index.min.js 1.39 kB
build/style-engine/index.min.js 2.07 kB
build/token-list/index.min.js 582 B
build/url/index.min.js 3.72 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 957 B
build/warning/index.min.js 249 B
build/widgets/index.min.js 7.21 kB
build/widgets/style-rtl.css 1.15 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.02 kB

compressed-size-action

@andrewhayward
Copy link
Contributor

Thanks for your continued work on this, @chad1008! Maybe I'm misunderstanding the intent of the final implementation, but what I'm seeing seems to go against the testing instructions above.

current.tab.behaviour.mov

When focus is not on the active tab, focus is not moved when the active tab changes. But when focus is on the active tab when it changes, the focus moves with it. This is counter to points 4 and 10 in your Storybook instructions.

@ciampo
Copy link
Contributor

ciampo commented Feb 1, 2024

@andrewhayward , from your screencast it seems like you're testing a stale version of this PR?


@chad1008 and I paired a bit on this PR, and we came up with an updated version of the hook which seems a lot more solid, since it reads the activeId form the ariakit store instead of trying to derive it from DOM attributes, which in return fixes some potential flakiness caused by ariakit's asynchronous updates to the active tab.

I pushed a few commits:

  • the first one updates the hook, as just described;
  • the second one fixes a side effect of this hook, by making sure that the focused tab is the selected tab when tabbing back into a tablist
  • the third commit adds a few unit tests
  • a fourth commit cleans up one of the effect dependencies

@ciampo
Copy link
Contributor

ciampo commented Feb 1, 2024

I'm going to call myself out of this final round of review, as I'm the co-author of these changes. @andrewhayward / @mirka / @chad1008 , if would be great if we could have one final round of review and smoke testing, so that we can unblock the remaining tabs PRs

@andrewhayward
Copy link
Contributor

@andrewhayward , from your screencast it seems like you're testing a stale version of this PR?

Huh... weird, I'm sure I was up to date. Anyway, verified that I have the latest changes, and it is now working as intended/expected.

Copy link
Contributor

@andrewhayward andrewhayward left a comment

Choose a reason for hiding this comment

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

Works as expected, and looks good to me 🚀

@chad1008
Copy link
Contributor Author

chad1008 commented Feb 1, 2024

Thanks so much everyone!

@chad1008 chad1008 merged commit 8443592 into trunk Feb 1, 2024
57 checks passed
@chad1008 chad1008 deleted the tabs-improve-controlled-focus-sync branch February 1, 2024 18:43
@github-actions github-actions bot added this to the Gutenberg 17.7 milestone Feb 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Accessibility Feedback Need input from accessibility [Package] Components /packages/components [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants