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

ToolTip: refactor using ariakit #48440

Merged
merged 57 commits into from
Sep 7, 2023
Merged

ToolTip: refactor using ariakit #48440

merged 57 commits into from
Sep 7, 2023

Conversation

brookewp
Copy link
Contributor

@brookewp brookewp commented Feb 25, 2023

What?

Closes #48222
Fixes #43129

The goal for this PR is to refactor our current tooltip using Ariakit's tooltip without changing the existing API.

Why?

After multiple issues arose, we assessed our current 'legacy' Tooltip and decided it would be better to replace it with a new version, using Ariakit. The legacy tooltip has a complex way of handling events and has not been migrated to Typescript. The changes in this PR uses Ariakit's Tooltip with modifications, to create a typed component with simplified implementation details and improved accessibility.

More details can be found in the tracking issue: #48222

How?

By using Ariakit's tooltip and modifications to match the API and behaviors of our legacy tooltip. In the testing instructions below, details on each of the changes are outlined with testing steps.

Testing Instructions

npm run test:unit packages/components/src/tooltip/test/index.tsx

Unit tests should match legacy and test for the same behaviors (+ one new test for Esc feature which is mentioned later in the testing steps).

Six other tests failed after replacing tooltip. Two were resolved outside of this PR (#53703 and #53704). The remaining four had to be resolved within this PR, as the failures are tied to the changes. These started to fail mainly because tests were checking not.toBeInTheDocument, but this version of tooltip remains in the DOM when it is hidden. This is in the case of these tests:

npm run test:unit packages/components/src/button/test/index.tsx
npm run test:unit packages/components/src/tab-panel/test/index.tsx

The tests for ToggleControlGroup called a helper function which references a wrapper's CSS class that no longer wraps tooltip. Also, there is a custom tooltip component WithTooltip added with its own types, which needed to be updated as well.

npm run test:unit packages/components/src/toggle-group-control/test/index.tsx

In PostSavedState, the test query wasn't specific enough, so multiple elements were being found when only one was expected:

npm run test:unit packages/editor/src/components/post-saved-state/test/index.js

Existing behavior:

The following behaviors are default in both versions of tooltip:

Only accepts one child component

This is an expected existing behavior, but there is a bug when the only child is an Icon component. The new tooltip fixes this issue and prevent the workarounds from breaking upon replacement. An example of this workaround can be found in packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js which can be tested in the editor:

  1. Navigate to the site editor (Appearance > Editor)
  2. Click on 'Patterns'
  3. Hover lock icon to see tooltip

We can also test to make sure the workaround isn't needed by removing the span wrapper. With the legacy tooltip, the anchor won't render and there will be a warning that looks like this in the console:

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Check the render method of Tooltip. 

In the new version, it will still warn, but the lock icon will render and the tooltip will behave as expected.

If the tooltip overflows, the position should be flipped.

Screenshot 2023-08-11 at 8 41 31 PM
  1. In the editor sidebar, hover over the close icon 'X' to see tooltip 'Close Settings ⇧⌘,'.
  2. Although it's position is set to be centered, the position will be adjusted to not overflow the document

Workarounds

A few behaviors differ between the tooltip components. Therefore, modifications have been made to match the legacy.

Leaving the document hides the tooltip



The intended default behavior in ariakit (context on why here) is to keep the tooltip visible when focus leaves the anchor to the document, but not in our legacy. To amend this, an `onBlur` has been added to the anchor. This scenario is covered in our unit tests but it can be manually tested:

  1. It is quickest to test this by viewing a story in isolation (example)
  2. Then tab between the anchor and the document
  3. The tooltip should disappear when the focus leaves the anchor

Clicking on the anchor should hide the tooltip

  1. Focus or hover the anchor to make tooltip visible
  2. Click on the anchor
  3. Tooltip should disappear upon mouse click

New features

The only 'new' feature is the tooltip can now be closed by using the 'Esc' key, which is in ARIA guidelines for Tooltip. It can be disabled, but I think it is okay to add it in this first iteration as long as it doesn't break any existing features that use the Escape key. For example, Modal works the same as before, with Escape closing the modal rather than tooltip. I've also added a test for this case, but if there are other cases where this would be a problem, please share!

Tooltip should close on Esc keydown

  1. Focus or hover the anchor to make tooltip visible
  2. Use 'Esc' key to close the tooltip

As mentioned, there is a unit test for modal, but this can be tested manually as well:

  1. Navigate to the Modal component in Storybook
  2. Click button 'Open Modal'
  3. Hover over the close button 'X' to show the tooltip
  4. Use 'Esc' while tooltip is showing
  5. Modal should close

Testing Instructions for Keyboard

Most of the above steps include keyboard testing but these are the main things to look for when using a keyboard:

  1. npm run storybook:dev
  2. Navigate to Tooltip
  3. Click tab key to focus the anchor element (Button) and see a tooltip appear
  4. Click Esc key to close the tooltip

✍️ Dev note

The Tooltip and the TabPanel components have been completely rewritten to leverage third-party, headless libraries (specifically ariakit) as the first tasks of a new experimental effort within the package.

Both migrations were intentionally designed to avoid changes to the API or developer experience, while also bringing several benefits:

  • better compliance with semantics, accessibility requirements, and related WAI-ARIA patterns;
  • better user experience thanks to using a widely used, well-tested underlying implementation;
  • better types and improved unit tests;
  • less maintenance required in the long term.

Specifically to the Tooltip component, the refactor also fixed a long-standing issue and presented the opportunity to align with other components already using a new placement prop in lieu of the legacy, now deprecated position prop.

For TabPanel, the only noteworthy change is that tabpanel elements now get a tabstop. This means that when focused on a tab, pressing the [Tab] key will apply focus to the tabpanel itself, rather than jumping directly to the next focusable element within the tabpanel element.

@brookewp brookewp self-assigned this Feb 25, 2023
@brookewp brookewp added [Type] Enhancement A suggestion for improvement. [Package] Components /packages/components labels Mar 1, 2023
package-lock.json Outdated Show resolved Hide resolved
@github-actions
Copy link

github-actions bot commented Mar 22, 2023

Size Change: +7.55 kB (0%)

Total Size: 1.52 MB

Filename Size Change
build/components/index.min.js 255 kB +7.68 kB (+3%)
build/components/style-rtl.css 11.7 kB -69 B (-1%)
build/components/style.css 11.7 kB -68 B (-1%)
ℹ️ 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.28 kB
build/autop/index.min.js 2.1 kB
build/blob/index.min.js 451 B
build/block-directory/index.min.js 7.01 kB
build/block-directory/style-rtl.css 1.02 kB
build/block-directory/style.css 1.02 kB
build/block-editor/content-rtl.css 4.25 kB
build/block-editor/content.css 4.24 kB
build/block-editor/default-editor-styles-rtl.css 381 B
build/block-editor/default-editor-styles.css 381 B
build/block-editor/index.min.js 215 kB
build/block-editor/style-rtl.css 15.1 kB
build/block-editor/style.css 15.1 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 584 B
build/block-library/blocks/button/editor.css 582 B
build/block-library/blocks/button/style-rtl.css 629 B
build/block-library/blocks/button/style.css 628 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.63 kB
build/block-library/blocks/cover/style.css 1.62 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 293 B
build/block-library/blocks/embed/editor.css 293 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-interactivity.min.js 317 B
build/block-library/blocks/file/view.min.js 375 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 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.53 kB
build/block-library/blocks/gallery/style.css 1.53 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 76 B
build/block-library/blocks/heading/style.css 76 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 834 B
build/block-library/blocks/image/editor.css 833 B
build/block-library/blocks/image/style-rtl.css 1.42 kB
build/block-library/blocks/image/style.css 1.41 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-interactivity.min.js 1.83 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 712 B
build/block-library/blocks/navigation-link/editor.css 711 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 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.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.23 kB
build/block-library/blocks/navigation/style.css 2.22 kB
build/block-library/blocks/navigation/view-interactivity.min.js 988 B
build/block-library/blocks/navigation/view-modal.min.js 2.85 kB
build/block-library/blocks/navigation/view.min.js 469 B
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 401 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-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 588 B
build/block-library/blocks/post-featured-image/editor.css 586 B
build/block-library/blocks/post-featured-image/style-rtl.css 319 B
build/block-library/blocks/post-featured-image/style.css 319 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 314 B
build/block-library/blocks/post-template/style.css 314 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 335 B
build/block-library/blocks/pullquote/style.css 335 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 302 B
build/block-library/blocks/query-pagination/style.css 299 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 450 B
build/block-library/blocks/query/editor.css 449 B
build/block-library/blocks/query/style-rtl.css 370 B
build/block-library/blocks/query/style.css 368 B
build/block-library/blocks/query/view.min.js 559 B
build/block-library/blocks/quote/style-rtl.css 222 B
build/block-library/blocks/quote/style.css 222 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 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 178 B
build/block-library/blocks/search/editor.css 178 B
build/block-library/blocks/search/style-rtl.css 607 B
build/block-library/blocks/search/style.css 607 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 631 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 234 B
build/block-library/blocks/separator/style.css 234 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.44 kB
build/block-library/blocks/social-links/style.css 1.43 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 432 B
build/block-library/blocks/table/editor.css 432 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.2 kB
build/block-library/editor.css 12.1 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 204 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 13.8 kB
build/block-library/style.css 13.8 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.4 kB
build/commands/index.min.js 15.5 kB
build/commands/style-rtl.css 932 B
build/commands/style.css 929 B
build/compose/index.min.js 12.1 kB
build/core-commands/index.min.js 2.6 kB
build/core-data/index.min.js 16.8 kB
build/customize-widgets/index.min.js 12 kB
build/customize-widgets/style-rtl.css 1.46 kB
build/customize-widgets/style.css 1.45 kB
build/data-controls/index.min.js 640 B
build/data/index.min.js 8.84 kB
build/date/index.min.js 17.8 kB
build/deprecated/index.min.js 451 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.64 kB
build/edit-post/classic-rtl.css 544 B
build/edit-post/classic.css 545 B
build/edit-post/index.min.js 35.3 kB
build/edit-post/style-rtl.css 7.6 kB
build/edit-post/style.css 7.59 kB
build/edit-site/index.min.js 90.9 kB
build/edit-site/style-rtl.css 13.2 kB
build/edit-site/style.css 13.2 kB
build/edit-widgets/index.min.js 16.9 kB
build/edit-widgets/style-rtl.css 4.52 kB
build/edit-widgets/style.css 4.52 kB
build/editor/index.min.js 45.5 kB
build/editor/style-rtl.css 3.53 kB
build/editor/style.css 3.52 kB
build/element/index.min.js 4.82 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 7.71 kB
build/format-library/style-rtl.css 554 B
build/format-library/style.css 553 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/index.min.js 11.3 kB
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.72 kB
build/keycodes/index.min.js 1.87 kB
build/list-reusable-blocks/index.min.js 2.2 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/notices/index.min.js 948 B
build/nux/index.min.js 1.99 kB
build/nux/style-rtl.css 735 B
build/nux/style.css 732 B
build/patterns/index.min.js 2.71 kB
build/patterns/style-rtl.css 240 B
build/patterns/style.css 240 B
build/plugins/index.min.js 1.79 kB
build/preferences-persistence/index.min.js 1.84 kB
build/preferences/index.min.js 1.24 kB
build/primitives/index.min.js 943 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 958 B
build/react-i18n/index.min.js 615 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.7 kB
build/reusable-blocks/style-rtl.css 243 B
build/reusable-blocks/style.css 243 B
build/rich-text/index.min.js 11 kB
build/router/index.min.js 1.78 kB
build/server-side-render/index.min.js 1.94 kB
build/shortcode/index.min.js 1.39 kB
build/style-engine/index.min.js 1.85 kB
build/sync/index.min.js 53.8 kB
build/token-list/index.min.js 582 B
build/url/index.min.js 3.73 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 958 B
build/warning/index.min.js 249 B
build/widgets/index.min.js 7.16 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

const button = screen.getByRole( 'button', { name: /Button/i } );

expect( button ).toBeVisible();
//expect( button ).toBeDisabled();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the legacy tooltip, the tooltip will show if an element is disabled. From what I've seen, it shouldn't show unless aria-disabled is added instead. In order to be backwards compatible, we may need to add a temporary solution to be deprecated 🤔

@afercia afercia mentioned this pull request Mar 24, 2023
25 tasks

return (
<>
<TooltipAnchor described state={ tooltipState }>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

After seeing this comment, I just wanted to add a note to clarify what the described prop is. In ariakit, aria-labelledby is the default but aria-describedby can be added by adding the described prop:
https://github.com/ariakit/ariakit/blob/5d8a1f047fcadcf117073c70359663a3946b73bf/packages/ariakit/src/tooltip/tooltip-anchor.ts#L122-L136

According to ARIA guidelines, aria-describedby is required for tooltip so I'm not sure why it isn't the default option. @ciampo pointed out it might be worth asking the author about this choice.

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.

Great job so far! I haven't had the time to take a very detailed look, but I still left some feedback in case you'll have time to work on this today

shortcut,
text,
} = props;


const DEFAULT_PLACEMENT = 'bottom';
Copy link
Contributor

Choose a reason for hiding this comment

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

Interestingly, the legacy tooltip has a default position of bottom middle in code, while the README states that the default is top center.

Personally, I think that it makes more sense for a tooltip's default position to be on top of its anchor, but it makes sense to keep bottom as the default placement, since it corresponds to the current legacy tooltip behaviour

packages/components/src/ui/ariakit-tooltip/index.tsx Outdated Show resolved Hide resolved
packages/components/src/ui/ariakit-tooltip/index.tsx Outdated Show resolved Hide resolved
packages/components/src/ui/ariakit-tooltip/types.ts Outdated Show resolved Hide resolved
packages/components/src/ui/ariakit-tooltip/test/index.tsx Outdated Show resolved Hide resolved
packages/components/src/ui/ariakit-tooltip/types.ts Outdated Show resolved Hide resolved
packages/components/src/ui/ariakit-tooltip/types.ts Outdated Show resolved Hide resolved
packages/components/src/ui/ariakit-tooltip/types.ts Outdated Show resolved Hide resolved

return (
<>
<TooltipAnchor as={ Slot } described state={ tooltipState }>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to use a solution like Slot from Radix to merge props to the immediate child.

This solution was one of the options proposed by ariakit author: ariakit/ariakit#1245 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

That's not needed anymore. See https://ariakit.org/examples/dialog-radix for an example of how to implement an API similar to Radix UI.

This should be as easy as:

<TooltipAnchor render={children} />

@github-actions
Copy link

github-actions bot commented Jul 8, 2023

Flaky tests detected in ef7d837.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/5898187692
📝 Reported issues:

@brookewp brookewp requested a review from tyxla July 26, 2023 22:41
@brookewp
Copy link
Contributor Author

Hey @tyxla! I requested a review from you because of some strange changes in the unit tests since I returned to this PR. The significant change was updating the branch to the updated @ariakit/react instead of ariakit. Since then, unit tests that were passing are now failing. 

I found that only one test failed on its own and I've added an inline comment here on what I found so far.

For the remaining three failing tests, they all pass on their own. They also pass when the previous test is skipped. So it seems to be a weird side effect. I thought maybe it was an issue with async/await, mutation, or timers/mocks not being reset, but I didn't find any solutions from going down those paths.

The only solution I found was if I moved the tests to before the first failing test. This is the test they needed to be moved before:

it( 'should render the tooltip when the tooltip anchor is hovered', async () => {

And three tests were moved, beginning here:

it( 'should not show tooltip on focus as result of mouse click', async () => {

So technically, all unit tests pass now but it's a bit confusing. If you have any insights, I'd appreciate it!

@tyxla
Copy link
Member

tyxla commented Jul 27, 2023

From what I've seen in my initial look, it appears that the first failing test expects that after tabbing, the tooltip will be hidden. However, in my testing with the Storybook instance, it appears that it doesn't. So the test is actually accurately failing, because we don't seem to properly be processing the blur event. So I'd start from investigating what changed between ariakit and @ariakit/react in terms of tabbing away from the tooltip anchor and the disappearance of the tooltip in that case. Haven't checked it myself, but wanted to point that out as a first step towards addressing this.

@tyxla
Copy link
Member

tyxla commented Jul 27, 2023

For the protocol, when testing the ariakit Tooltip here: https://ariakit.org/components/tooltip#api, it correctly hides the tooltip upon tabbing. So it would be a safe bet to say we're likely not utilizing the component API properly somehow. Let me know what you think.

@ciampo
Copy link
Contributor

ciampo commented Sep 7, 2023

The problem seems a side-effect caused by #52620:

  • In that PR, a Button is added to LinkControl
  • For some reason, it looks like that Button shows a tooltip
  • The tooltip is also wrapped in a div with role="presentation", which is always rendered in the page (even when the tooltip is hidden)
  • The failing unit tests are asserting the presence of the spinner by looking for the presentation role, but now that a tooltip is rendered, the test mistakingly gets the tooltip instead of the spinner, which causes the remaining assumptions in the test (ie. a search query is performed) to fail

To confirm my assumption, I've added temporarily a data-testid attribute to the Spinner component, so that we can query byTestId and make sure that we're targeting the spinner (see 5761d79)

A better fix would be to somehow differentiate the spinner from the tooltip wrapper without using test-id (@diegohaz @jsnajdr @tyxla do you have any ideas?)

@jsnajdr
Copy link
Member

jsnajdr commented Sep 7, 2023

One easy fix would be to look for the spinner not globally (screen.findByRole( 'presentation' )) but scope the search to some element related to the search input.

Another idea is to give the spinner a more specific role. There is a StackOverflow question that offers many sensible alternatives -- role="status", role="progressbar", aria-busy="true", ...

Copy link
Member

@tyxla tyxla left a comment

Choose a reason for hiding this comment

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

A better fix would be to somehow differentiate the spinner from the tooltip wrapper without using test-id (@diegohaz @jsnajdr @tyxla do you have any ideas?)

Alternatively to what @jsnajdr suggested, we could use a container.getElementsByClassName() query, with an ESLint ignore rule. This also isn't ideal, but at least it won't clutter the production component with an extra attribute that's only useful for testing. I personally prefer cluttering the test rather than the production code. Plus, with the test ID, we're already at our last resort, so it should be fine that we're aiming to test for an implementation detail.

I'm personally fine with the test ID too, but have a slight preference for the getElementsByClassName in this particular case, to keep the production code clean from unnecessary attributes.

In any case, it's worth trying out the role="progressbar" if we can. Happy to see it in a follow-up PR!

Copy link
Member

@tyxla tyxla left a comment

Choose a reason for hiding this comment

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

Brilliant work @brookewp and team, love to see this at the finish line! ❤️ 🚀

@ciampo
Copy link
Contributor

ciampo commented Sep 7, 2023

Thank you @tyxla and @jsnajdr for your ideas!

Happy to see it in a follow-up PR!

I also personally agree with merging this PR and working on improving the fix in a separate follow-up (another one to add to the list, Brooke!)

Once again, well done @brookewp for taking this one to the finish line 🎉

@ciampo ciampo merged commit 938e747 into trunk Sep 7, 2023
51 checks passed
@ciampo ciampo deleted the add/ariakit-tooltip branch September 7, 2023 12:19
@github-actions github-actions bot added this to the Gutenberg 16.7 milestone Sep 7, 2023
@ciampo
Copy link
Contributor

ciampo commented Sep 7, 2023

To recap, "final final" list of follow-ups:

@youknowriad
Copy link
Contributor

Looks like this PR had a somewhat important (not in a good sense) impact on some performance metrics (block selection, inserter opening). Would be cool if we could investigate the reasons and address them.

@ciampo
Copy link
Contributor

ciampo commented Sep 8, 2023

Looks like this PR had a somewhat important (not in a good sense) impact on some performance metrics (block selection, inserter opening). Would be cool if we could investigate the reasons and address them.

Absolutely, I was about to reach out to you to ask for some help in how to investigate the regressions, since I've never had to do it before.

Was the Performance CI check supposed to flag this before merging?

@tyxla
Copy link
Member

tyxla commented Sep 8, 2023

Haven't dug deeply into this theory, but is it possible that the Ariakit version just deals differently with various timeouts (show timeout, skip timeout, hide timeout), and playing with those timeouts, like reducing them a bit, could have a big positive impact? For example, the default Ariakit timeout is 500 while we set it to 700.

@ciampo
Copy link
Contributor

ciampo commented Sep 8, 2023

I believe that the delay was 700ms also in the previous version of Tooltip.

It is weird that inserting a block got slower with a new tooltip, since tooltips shouldn't be involved in those user actions.

As noticed previously, it seems that ariakit renders the tooltip in the DOM at all times, and only toggles its visibility when needed. Maybe this could be affecting metrics?

@youknowriad
Copy link
Contributor

Was the Performance CI check supposed to flag this before merging?

The performance test run before merging but at the moment doesn't notify about the impact, you have to manually open the job and check the results.

As noticed #48440 (comment), it seems that ariakit renders the tooltip in the DOM at all times, and only toggles its visibility when needed. Maybe this could be affecting metrics?

That seems like a good hint to me. Especially if these components react to changes...

@ciampo
Copy link
Contributor

ciampo commented Sep 8, 2023

Also pinging @diegohaz to see if he can help us to look into this

@diegohaz
Copy link
Member

diegohaz commented Sep 8, 2023

Yeah, if the tooltip was dynamically rendered before, and it's always rendered now, this could have an impact.

The Ariakit Tooltip can be dynamically rendered too:

	const tooltipStore = Ariakit.useTooltipStore( {
		placement: positionToPlacement( position ),
		timeout: delay,
	} );

+	const isTooltipOpen = tooltipStore.useState( 'open' );

	return (
		<>
			<Ariakit.TooltipAnchor
				onBlur={ tooltipStore.hide }
				onClick={ tooltipStore.hide }
				store={ tooltipStore }
				render={ isOnlyChild ? children : undefined }
			>
				{ isOnlyChild ? undefined : children }
			</Ariakit.TooltipAnchor>
-			{ isOnlyChild && ( text || shortcut ) &&
+			{ isOnlyChild && ( text || shortcut ) && isTooltipOpen && (
				<Ariakit.Tooltip

@ciampo
Copy link
Contributor

ciampo commented Sep 8, 2023

Thank you for the suggestion @diegohaz , trying this out in #54312

@ciampo ciampo added the has dev note when dev note is done (for upcoming WordPress release) label Oct 12, 2023
@ciampo
Copy link
Contributor

ciampo commented Oct 12, 2023

Added a dev note in the PR description

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has dev note when dev note is done (for upcoming WordPress release) [Package] Components /packages/components [Type] Enhancement A suggestion for improvement.
Projects
Status: Done 🎉
Development

Successfully merging this pull request may close these issues.

Tooltip: refactor using ariakit [Components] Tooltip throws error when child is a component
8 participants