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

ToggleGroupControl: rewrite backdrop animation with framer-motion #40107

Closed
wants to merge 26 commits into from

Conversation

ciampo
Copy link
Contributor

@ciampo ciampo commented Apr 6, 2022

What?

Completely rewrite the ToggleGroupControl 's animated backdrop using framer-motion and a couple of different approaches to reading size and position of DOM elements.

Fixes #37506

Why?

Current implementation is complex, difficult to read, imperative (based off arbitrary timeouts), and buggy

How?

Main changes are:

  • use framer-motion to handle the animation
  • Simplify the backdrop positioning and sizing calculations:
    • use offsetLeft instead of getBoundingClientRect().left in order to get the gap relative to the offset parent (instead of the viewport)
    • calculate all item sizes before hand, so that the animation can run smooth while the user interacts with the component
    • use useLayoutEffect in order to make sure that all DOM updates have taken effect before calculating sizes and offsets

Testing Instructions

Make sure that the backdrop animation works as expected in Storybook and in the editor (in particular testing for the scenario highlighted in #37506)

Screenshots or screencast

toggle-grou-control-animation.mp4
toggle-group-control-animation-editor.mp4

className={ labelViewClasses }
data-active={ isActive }
// Necessary for the ToggleGroupControlBackdrop component to render properly
data-toggle-group-control-option-wrapper="true"
Copy link
Contributor Author

@ciampo ciampo Apr 6, 2022

Choose a reason for hiding this comment

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

The data-toggle-group-control-option-wrapper is used as a way for the backdrop component to always find the correct ToggleGroupControl's "option wrapper", which is used to compute the correct position and size to apply to the backdrop.

@@ -98,7 +104,9 @@ export type ToggleGroupControlProps = Omit<
/**
* React children
*/
children: ReactNode;
children:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change is not necessary, but I thought it could be interesting to enforce only the expected children type via TypeScript

window.cancelAnimationFrame( animationRequestId );
};
}, [ canAnimate, containerRef, containerWidth, state, isAdaptiveWidth ] );
const toggleGroupOptionWrapper = item.ref.current?.closest(
Copy link
Contributor Author

@ciampo ciampo Apr 6, 2022

Choose a reason for hiding this comment

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

Since the markup of ToggleGroupControlOptionBase can change if the tooltip is enabled or not, I decided to add a data attribute to the option's wrapper and use Element.closest() to find it each item's wrapper.

bounce: 0.2,
// Transition durations in the config are expressed as a string in milliseconds,
// while `framer-motion` needs them as integers in seconds.
duration: parseInt( CONFIG.transitionDurationFast, 10 ) / 1000,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This felt a bit hacky but I couldn't come up with another way of reusing our config as it's written today

@github-actions
Copy link

github-actions bot commented Apr 6, 2022

Size Change: -24 B (0%)

Total Size: 1.22 MB

Filename Size Change
build/block-library/index.min.js 175 kB +15 B (0%)
build/components/index.min.js 223 kB -39 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/admin-manifest/index.min.js 1.24 kB
build/annotations/index.min.js 2.77 kB
build/api-fetch/index.min.js 2.27 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 487 B
build/block-directory/index.min.js 6.49 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 149 kB
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 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/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 59 B
build/block-library/blocks/avatar/style.css 59 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 445 B
build/block-library/blocks/button/editor.css 445 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 103 B
build/block-library/blocks/code/style.css 103 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 406 B
build/block-library/blocks/columns/style.css 406 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-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.56 kB
build/block-library/blocks/cover/style.css 1.56 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 353 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 961 B
build/block-library/blocks/gallery/editor.css 964 B
build/block-library/blocks/gallery/style-rtl.css 1.51 kB
build/block-library/blocks/gallery/style.css 1.51 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 333 B
build/block-library/blocks/group/editor.css 333 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 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 731 B
build/block-library/blocks/image/editor.css 730 B
build/block-library/blocks/image/style-rtl.css 529 B
build/block-library/blocks/image/style.css 535 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 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 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 708 B
build/block-library/blocks/navigation-link/editor.css 706 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 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation-submenu/view.min.js 375 B
build/block-library/blocks/navigation/editor-rtl.css 2.03 kB
build/block-library/blocks/navigation/editor.css 2.04 kB
build/block-library/blocks/navigation/style-rtl.css 1.93 kB
build/block-library/blocks/navigation/style.css 1.92 kB
build/block-library/blocks/navigation/view.min.js 2.85 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 363 B
build/block-library/blocks/page-list/editor.css 363 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 260 B
build/block-library/blocks/paragraph/style.css 260 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 370 B
build/block-library/blocks/pullquote/style.css 370 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 369 B
build/block-library/blocks/query/editor.css 369 B
build/block-library/blocks/quote/style-rtl.css 213 B
build/block-library/blocks/quote/style.css 213 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 140 B
build/block-library/blocks/separator/editor.css 140 B
build/block-library/blocks/separator/style-rtl.css 233 B
build/block-library/blocks/separator/style.css 233 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 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 759 B
build/block-library/blocks/site-logo/editor.css 759 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 226 B
build/block-library/blocks/tag-cloud/style.css 227 B
build/block-library/blocks/template-part/editor-rtl.css 149 B
build/block-library/blocks/template-part/editor.css 149 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 934 B
build/block-library/common.css 932 B
build/block-library/editor-rtl.css 10.2 kB
build/block-library/editor.css 10.2 kB
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/style-rtl.css 11.3 kB
build/block-library/style.css 11.3 kB
build/block-library/theme-rtl.css 689 B
build/block-library/theme.css 694 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/blocks/index.min.js 46.9 kB
build/components/style-rtl.css 14.9 kB
build/components/style.css 14.9 kB
build/compose/index.min.js 11.2 kB
build/core-data/index.min.js 14.5 kB
build/customize-widgets/index.min.js 11 kB
build/customize-widgets/style-rtl.css 1.39 kB
build/customize-widgets/style.css 1.39 kB
build/data-controls/index.min.js 663 B
build/data/index.min.js 8.64 kB
build/date/index.min.js 32 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.58 kB
build/edit-navigation/index.min.js 15.8 kB
build/edit-navigation/style-rtl.css 4.04 kB
build/edit-navigation/style.css 4.05 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/index.min.js 30 kB
build/edit-post/style-rtl.css 7.18 kB
build/edit-post/style.css 7.18 kB
build/edit-site/index.min.js 46.9 kB
build/edit-site/style-rtl.css 7.79 kB
build/edit-site/style.css 7.76 kB
build/edit-widgets/index.min.js 16.3 kB
build/edit-widgets/style-rtl.css 4.4 kB
build/edit-widgets/style.css 4.39 kB
build/editor/index.min.js 38.4 kB
build/editor/style-rtl.css 3.71 kB
build/editor/style.css 3.71 kB
build/element/index.min.js 4.29 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 6.62 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.83 kB
build/keycodes/index.min.js 1.41 kB
build/list-reusable-blocks/index.min.js 1.75 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.94 kB
build/notices/index.min.js 957 B
build/nux/index.min.js 2.12 kB
build/nux/style-rtl.css 751 B
build/nux/style.css 749 B
build/plugins/index.min.js 1.98 kB
build/preferences/index.min.js 1.2 kB
build/primitives/index.min.js 949 B
build/priority-queue/index.min.js 611 B
build/react-i18n/index.min.js 704 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.69 kB
build/reusable-blocks/index.min.js 2.24 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11.2 kB
build/server-side-render/index.min.js 1.61 kB
build/shortcode/index.min.js 1.52 kB
build/token-list/index.min.js 668 B
build/url/index.min.js 1.99 kB
build/vendors/react-dom.min.js 38.5 kB
build/vendors/react.min.js 4.34 kB
build/viewport/index.min.js 1.08 kB
build/warning/index.min.js 280 B
build/widgets/index.min.js 7.21 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.07 kB

compressed-size-action

@ciampo ciampo self-assigned this Apr 6, 2022
@@ -33,7 +33,6 @@ const TOGGLE_GROUP_CONTROL_PROPS = {
toggleGroupControlBackdropBackgroundColor:
CONTROL_PROPS.controlSurfaceColor,
toggleGroupControlBackdropBorderColor: COLORS.ui.border,
toggleGroupControlBackdropBoxShadow: 'transparent',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Deleted as it didn't seem like it made any difference

@ciampo ciampo added [Type] Bug An existing feature does not function as intended [Type] Enhancement A suggestion for improvement. [Package] Components /packages/components [Feature] Component System WordPress component system labels Apr 6, 2022
@ciampo ciampo marked this pull request as ready for review April 6, 2022 18:55
@ciampo ciampo requested a review from ajitbohra as a code owner April 6, 2022 18:55
@ciampo ciampo force-pushed the feat/toggle-group-backdrop-animation-rewrite branch from 0ab7c9d to 931d63e Compare April 6, 2022 18:56
@jasmussen
Copy link
Contributor

Very nice! The animation for the backdrop is present in the segmented control in this branch, but presumably without the technical challenges that are present in trunk:

this branch

For comparison, here's the trunk version:
trunk

The trunk version feels a bit slower, just a millisecond or so. That makes it feel a bit more alive — still fast enough that if you use the arrowkeys to set the specific size, it feels instant enough, but still slow enough that you the animation is perceptible. Can we slow this framer version down just a teensy bit to better match what's in trunk?

I realize it's probably hard to discern the speed differential with the reduced framerate of the GIFs above, but nevertheless.

@ciampo
Copy link
Contributor Author

ciampo commented Apr 7, 2022

Can we slow this framer version down just a teensy bit to better match what's in trunk?

I changed it (ffde8ad) from 160ms to 200ms, as that was the slowest transition duration that we currently have in our config.

If that's still too fast, I'm happy to introduce one more variable — maybe 250ms ?

@jasmussen
Copy link
Contributor

I'd love another inspection on this, because it still feels a bit too fast for me. Compare this branch:
currently

with trunk:

trunk

Trunk still feels a bit more harmonious. The curious thing is, looking at the code, it appears the trunk version was set to 100ms 🤔

Is there any elastic bounciness going on? It's a bit hard to tell. If yes, I don't think we should have that — ease in/out should be sufficient. Thanks for keeping at this!

@ciampo
Copy link
Contributor Author

ciampo commented Apr 7, 2022

I agree that it feels different, it must be a difference between how the animation was implemented previously (raw CSS values) and how framer-motion handles it.

Is there any elastic bounciness going on?

There was indeed some bounciness going on — I went ahead and removed it, while increasing the animation duration to 250ms.

Another thing I noticed is that the previous implementation had a 100ms delay that was introduced as a hacky fix to tentatively solve the popover bug.

Given that the animation is now slower, would you still like me to re-introduce that delay? I'd personally be against adding a delay here, because it would make the overall interaction feel less responsive (e.g. RAIL model).

@jasmussen
Copy link
Contributor

The animation actually feels pretty decent now:
now

I noticed another thing. The left side looks good:
Screenshot 2022-04-07 at 14 08 49

1px border, 2px padding inside. But the right side looks off:

Screenshot 2022-04-07 at 14 08 54

@ciampo
Copy link
Contributor Author

ciampo commented Apr 7, 2022

Mhh, I think that could be caused by subpixel rouding/rendering, and can probably vary depending on the device / screen resolution / browser.

For example, on my external screen, the font size control component in the editor looks fine in Chrome but similar to your screenshot Firefox:

Chrome:

Screenshot 2022-04-07 at 14 47 26

Firefox:

Screenshot 2022-04-07 at 14 56 36

At the same time, the Storybook example seems fine on both Chrome and Firefox:

Chrome:

Screenshot 2022-04-07 at 14 59 35

Firefox:

Screenshot 2022-04-07 at 14 57 36


Maybe we can look into it in a separate follow-up, if the rest of this PR looks good?

@jasmussen
Copy link
Contributor

It doesn't appear to be subpixel math on the backdrop itself, I see all whole pixels:

Screenshot 2022-04-07 at 15 18 55

I know it seems like a small detail, but it bugs me 😅 — if we are to address it in a followup as a bugfix, we need to have high confidence that we can fix it. I.e. if we can figure out a solution, it's fine to do separately.

@ciampo
Copy link
Contributor Author

ciampo commented Apr 7, 2022

Alright, I'll take a look at it next week and see what I can do.

bounce: 0,
// Transition durations in the config are expressed as a string in milliseconds,
// while `framer-motion` needs them as integers in seconds.
duration: parseInt( CONFIG.transitionDurationSlow, 10 ) / 1000,
Copy link
Member

Choose a reason for hiding this comment

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

What do you think about just hardcoding the duration value here? I guess because:

  • It's a pretty specialized animation anyway
  • What if the CONFIG values are ever changed from ms to s
  • It seems like overkill to extract a separate TRANSITION_DURATION_MS object (Or maybe not? Will it come up a lot in these JS animations?)

No strong opinion though, just throwing it out there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm happy to hardcode it, although we may want to reconsider having a more clear, better organised shared "transition duration" settings when we start refactoring our shared configs

background: ${ COLORS.gray[ 900 ] };
border-radius: ${ CONFIG.controlBorderRadius };
box-shadow: ${ CONFIG.toggleGroupControlBackdropBoxShadow };
box-shadow: none;
Copy link
Member

Choose a reason for hiding this comment

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

Is this rule necessary?

@stokesman
Copy link
Contributor

Doh! 🤦 I had meant to make a separate branch but missed it and pushed directly to this one. I hope it's no trouble @ciampo and I'm not trying to make a habit of this! I'm going to leave it for now but if you'd like I can drop the commits and force push this back to how you had it.

Before explaining what my changes are about, I want to point out how terribly tricky this seemingly simple animation can be. Marco has done a great job on simplifying it 👏.

So the final issue here was the backdrop (the dark box that slides around to indicate the active item) could end up misaligned from the right side of the toggle control’s border #40107 (comment).

To fix that we need to have the backdrop use sub-pixel size and positions as previously provided by getBoundingClientRect. The problem with using that function is that its measurement is affected by scaling from containing elements and that's what makes for the unexpected results in the popover for colors (its mount animation scales everything). It's possible to work around that by having the effect that sets the measure hold off until scale is 1:1 but it's a bit more complicated and makes for a late appearance of the backdrop in such contexts.

So what I came up with was to avoid measuring and instead calculate the size and position that the backdrop needs to be. It actually ends up allowing for more simplification but I've just realized the biggest downfall—isAdaptiveWidth is not supported!

To support varying sized options, I think measuring will have to be done. Maybe there's a way to apply that strategy only when isAdaptiveWidth={ true } without too much complication. Otherwise, if we can't think of a better way to resolve all this maybe we could consider dropping that prop. It seems to be unused in Gutenberg and the component is experimental.

@stokesman
Copy link
Contributor

I've found a way to support isAdaptiveWidth and keep it pretty simple (and also not have to update snapshots). It's not ready for a push just yet and I've got to call a day for now.

@ciampo
Copy link
Contributor Author

ciampo commented Apr 12, 2022

Thank you for the explanation, @stokesman !

I was also working on a new approach that ideally ditches all calculations altogether by using framer-motion's layout animations — I'll probably open a new branch for this approach anyway

ciampo and others added 23 commits April 12, 2022 20:43
…s only allowed components of ToggleGroupControl
This makes is easy to calculate a width that will be the same as that
of the option elements and avoid having to measure them. A few minor
style adjustments are included.
This reverts commit 2ce5baa.
@stokesman stokesman force-pushed the feat/toggle-group-backdrop-animation-rewrite branch from 2ce5baa to 631d5f9 Compare April 13, 2022 04:03
@stokesman
Copy link
Contributor

stokesman commented Apr 13, 2022

I've rebased this and updated it so it works with isAdaptiveWidth so this should be a viable solution. The key was using getComputedStyle for the width measurement because it provides sub-pixel precision without being affected by parent transforms. It can't provide the x position but it's easy to calculate that.

@ciampo
Copy link
Contributor Author

ciampo commented Apr 13, 2022

Thank you @stokesman for the work here!

I'd say that the preferred approach for the backdrop animation with framer-motion would be the one using shared layout animations (attempted in #40276, and not ready yet to be landed), as it avoids most of the explicit size/position calculations.

With that in mind, I'm going to pause working on/reviewing this PR for the time being, and see if we land #40276 in the next days — in case we can't, we can always get back to this PR.

@ciampo
Copy link
Contributor Author

ciampo commented Aug 8, 2022

Closing in favour of #40276 (which is still currently blocked by framer/motion#1524 )

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] Bug An existing feature does not function as intended [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Color select component backdrop render and animation opportunities
4 participants