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: improve animation #65175

Merged
merged 55 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
f5a833a
Refactor utils and switch Tabs indicator animation to `transform`.
DaniGuardiola Aug 30, 2024
42080a4
docs tweak
DaniGuardiola Aug 30, 2024
7377fc0
Update packages/components/src/tabs/styles.ts
DaniGuardiola Aug 30, 2024
405c258
Add RTL support.
DaniGuardiola Sep 2, 2024
4726e53
Addressed @ciampo's comments.
DaniGuardiola Sep 2, 2024
6835665
Correct for antialiasing rounding.
DaniGuardiola Sep 2, 2024
1e444af
Make antialiasing adjustment optional.
DaniGuardiola Sep 2, 2024
7861921
Use larger base value and revert antialiasing adjustment code.
DaniGuardiola Sep 2, 2024
55dd870
DRY RTL
DaniGuardiola Sep 2, 2024
d03622b
Remove RTL story (redundant since Storybook has a dynamic setting to …
DaniGuardiola Sep 2, 2024
c347fad
Fix bug.
DaniGuardiola Sep 2, 2024
59797e4
Fix bug (for real this time).
DaniGuardiola Sep 2, 2024
f82b413
Add changelog entry.
DaniGuardiola Sep 2, 2024
4db2b35
De-cleverfy code.
DaniGuardiola Sep 2, 2024
e36a506
Sync useResizeObserver with #64943 and make useTrackElementOffsetRect…
DaniGuardiola Sep 8, 2024
b57955b
Merge branch 'trunk' of https://github.com/WordPress/gutenberg into i…
DaniGuardiola Sep 10, 2024
bc62400
Deduplicate utility and clean up.
DaniGuardiola Sep 10, 2024
6745607
Minor Tabs code improvement.
DaniGuardiola Sep 10, 2024
cf98e2d
Replace framer motion animation with faster CSS animation.
DaniGuardiola Sep 10, 2024
3f6a381
DRY antialiasing factor.
DaniGuardiola Sep 11, 2024
522d816
Changelogs.
DaniGuardiola Sep 11, 2024
9753d21
Merge branch 'improve/tabs-indicator-animation-and-utils' of https://…
DaniGuardiola Sep 11, 2024
5403b54
Merge branch 'trunk' of https://github.com/WordPress/gutenberg into i…
DaniGuardiola Sep 12, 2024
fe2b51e
Various improvements, fixes, and feedback addressed.
DaniGuardiola Sep 13, 2024
098a3a5
Simplify.
DaniGuardiola Sep 13, 2024
95337ea
Simplify using derived state.
DaniGuardiola Sep 13, 2024
536de06
Add similar useOnValueUpdate detail to Tabs.
DaniGuardiola Sep 13, 2024
62e591e
Fix skipping animation.
DaniGuardiola Sep 13, 2024
1db1fd7
Add similar detail to Tabs animation.
DaniGuardiola Sep 13, 2024
90b5300
Fix setState depth issue.
DaniGuardiola Sep 13, 2024
cf3fb33
Merge branch 'trunk' of https://github.com/WordPress/gutenberg into i…
DaniGuardiola Sep 23, 2024
ee5059a
Fix unit test error.
DaniGuardiola Sep 23, 2024
02066d7
Add changelog entries
DaniGuardiola Sep 24, 2024
a38dbd1
Fix changelog
DaniGuardiola Sep 24, 2024
069676d
Update test snapshot.
DaniGuardiola Sep 24, 2024
6e27452
Depends less on React.
DaniGuardiola Sep 27, 2024
43851bc
Switch to layout effect for `useOnValueUpdate`
DaniGuardiola Sep 27, 2024
3165838
Switched to transform strategy.
DaniGuardiola Sep 29, 2024
b24a585
Fix resizing bug.
DaniGuardiola Sep 29, 2024
8939f1f
Transition border-radius too.
DaniGuardiola Sep 29, 2024
148eaaa
Undo Tabs changes (no longer relevant).
DaniGuardiola Sep 29, 2024
69a99c8
DRY animation code.
DaniGuardiola Sep 29, 2024
53f868a
Avoid useless re-runs in effect.
DaniGuardiola Sep 29, 2024
5259fca
Rename `activeElement` -> `selectedElement` for clarity.
DaniGuardiola Sep 29, 2024
6c6c575
Rename `--indicator-` -> `--selected-` for accuracy.
DaniGuardiola Sep 29, 2024
bbc688b
Minor tweak.
DaniGuardiola Sep 29, 2024
6a21e66
Add safe defaults to CSS custom properties.
DaniGuardiola Sep 29, 2024
fcbb336
Tweak `useSubelementAnimation`.
DaniGuardiola Sep 29, 2024
bfbe282
Fix parent missing when there's no selected option.
DaniGuardiola Sep 30, 2024
82467e5
Merge branch 'trunk' into improve/toggle-group-control-animation
ciampo Oct 1, 2024
bf635dc
Update snapshots
ciampo Oct 1, 2024
89164d6
Add docs to utility.
DaniGuardiola Oct 1, 2024
153fdeb
Added note about border-radius.
DaniGuardiola Oct 1, 2024
63d994b
Merge branch 'trunk' of https://github.com/WordPress/gutenberg into i…
DaniGuardiola Oct 1, 2024
f34a9e2
Merge branch 'trunk' into improve/toggle-group-control-animation
ciampo Oct 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## Unreleased

### Bug Fixes

- `ToggleGroupControl`: indicator doesn't jump around when the layout around it changes ([#65175](https://github.com/WordPress/gutenberg/pull/65175)).

### Enhancements

- `ToggleGroupControl`: indicator animation is now more lightweight and performant ([#65175](https://github.com/WordPress/gutenberg/pull/65175)).

## 28.8.0 (2024-09-19)

### Bug Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
outline-offset: -2px;
}

@media not ( prefers-reduced-motion ) {
.emotion-8.is-animation-enabled::before {
transition-property: left,width;
transition-duration: 0.2s;
transition-timing-function: ease-out;
}
}

.emotion-8::before {
content: '';
position: absolute;
pointer-events: none;
background: #1e1e1e;
border-radius: 1px;
outline: 2px solid transparent;
outline-offset: -3px;
left: calc(
var( --indicator-left ) * 1px - 1px
);
width: calc( var( --indicator-width ) * 1px );
height: calc( var( --indicator-height ) * 1px );
}

.emotion-10 {
display: -webkit-inline-box;
display: -webkit-inline-flex;
Expand Down Expand Up @@ -150,17 +173,7 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
line-height: 1;
}

.emotion-15 {
background: #1e1e1e;
border-radius: 1px;
position: absolute;
inset: 0;
z-index: 1;
outline: 2px solid transparent;
outline-offset: -3px;
}

.emotion-18 {
.emotion-17 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
Expand Down Expand Up @@ -204,22 +217,22 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
}

@media not ( prefers-reduced-motion ) {
.emotion-18 {
.emotion-17 {
-webkit-transition: background 160ms linear,color 160ms linear,font-weight 60ms linear;
transition: background 160ms linear,color 160ms linear,font-weight 60ms linear;
}
}

.emotion-18::-moz-focus-inner {
.emotion-17::-moz-focus-inner {
border: 0;
}

.emotion-18[disabled] {
.emotion-17[disabled] {
opacity: 0.4;
cursor: default;
}

.emotion-18:active {
.emotion-17:active {
background: #fff;
}

Expand All @@ -246,6 +259,7 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
data-wp-component="ToggleGroupControl"
id="toggle-group-control-as-radio-group-11"
role="radiogroup"
style="--indicator-left: 0; --indicator-width: 0; --indicator-height: 0;"
>
<div
class="emotion-10 emotion-11"
Expand Down Expand Up @@ -280,20 +294,14 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
</svg>
</div>
</button>
<div>
<div
class="emotion-15"
role="presentation"
/>
</div>
</div>
<div
class="emotion-10 emotion-11"
>
<button
aria-checked="false"
aria-label="Lowercase"
class="emotion-18 components-toggle-group-control-option-base"
class="emotion-17 components-toggle-group-control-option-base"
data-value="lowercase"
data-wp-c16t="true"
data-wp-component="ToggleGroupControlOptionBase"
Expand Down Expand Up @@ -392,6 +400,29 @@ exports[`ToggleGroupControl controlled should render correctly with text options
outline-offset: -2px;
}

@media not ( prefers-reduced-motion ) {
.emotion-8.is-animation-enabled::before {
transition-property: left,width;
transition-duration: 0.2s;
transition-timing-function: ease-out;
}
}

.emotion-8::before {
content: '';
position: absolute;
pointer-events: none;
background: #1e1e1e;
border-radius: 1px;
outline: 2px solid transparent;
outline-offset: -3px;
left: calc(
var( --indicator-left ) * 1px - 1px
);
width: calc( var( --indicator-width ) * 1px );
height: calc( var( --indicator-height ) * 1px );
}

.emotion-10 {
display: -webkit-inline-box;
display: -webkit-inline-flex;
Expand Down Expand Up @@ -495,6 +526,7 @@ exports[`ToggleGroupControl controlled should render correctly with text options
data-wp-component="ToggleGroupControl"
id="toggle-group-control-as-radio-group-10"
role="radiogroup"
style="--indicator-left: 0; --indicator-width: 0; --indicator-height: 0;"
>
<div
class="emotion-10 emotion-11"
Expand Down Expand Up @@ -612,6 +644,29 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
outline-offset: -2px;
}

@media not ( prefers-reduced-motion ) {
.emotion-8.is-animation-enabled::before {
transition-property: left,width;
transition-duration: 0.2s;
transition-timing-function: ease-out;
}
}

.emotion-8::before {
content: '';
position: absolute;
pointer-events: none;
background: #1e1e1e;
border-radius: 1px;
outline: 2px solid transparent;
outline-offset: -3px;
left: calc(
var( --indicator-left ) * 1px - 1px
);
width: calc( var( --indicator-width ) * 1px );
height: calc( var( --indicator-height ) * 1px );
}

.emotion-10 {
display: -webkit-inline-box;
display: -webkit-inline-flex;
Expand Down Expand Up @@ -702,17 +757,7 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
line-height: 1;
}

.emotion-15 {
background: #1e1e1e;
border-radius: 1px;
position: absolute;
inset: 0;
z-index: 1;
outline: 2px solid transparent;
outline-offset: -3px;
}

.emotion-18 {
.emotion-17 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
Expand Down Expand Up @@ -756,22 +801,22 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
}

@media not ( prefers-reduced-motion ) {
.emotion-18 {
.emotion-17 {
-webkit-transition: background 160ms linear,color 160ms linear,font-weight 60ms linear;
transition: background 160ms linear,color 160ms linear,font-weight 60ms linear;
}
}

.emotion-18::-moz-focus-inner {
.emotion-17::-moz-focus-inner {
border: 0;
}

.emotion-18[disabled] {
.emotion-17[disabled] {
opacity: 0.4;
cursor: default;
}

.emotion-18:active {
.emotion-17:active {
background: #fff;
}

Expand All @@ -798,6 +843,7 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
data-wp-component="ToggleGroupControl"
id="toggle-group-control-as-radio-group-1"
role="radiogroup"
style="--indicator-left: 0; --indicator-width: 0; --indicator-height: 0;"
>
<div
class="emotion-10 emotion-11"
Expand Down Expand Up @@ -832,20 +878,14 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
</svg>
</div>
</button>
<div>
<div
class="emotion-15"
role="presentation"
/>
</div>
</div>
<div
class="emotion-10 emotion-11"
>
<button
aria-checked="false"
aria-label="Lowercase"
class="emotion-18 components-toggle-group-control-option-base"
class="emotion-17 components-toggle-group-control-option-base"
data-value="lowercase"
data-wp-c16t="true"
data-wp-component="ToggleGroupControlOptionBase"
Expand Down Expand Up @@ -938,6 +978,29 @@ exports[`ToggleGroupControl uncontrolled should render correctly with text optio
outline-offset: -2px;
}

@media not ( prefers-reduced-motion ) {
.emotion-8.is-animation-enabled::before {
transition-property: left,width;
transition-duration: 0.2s;
transition-timing-function: ease-out;
}
}

.emotion-8::before {
content: '';
position: absolute;
pointer-events: none;
background: #1e1e1e;
border-radius: 1px;
outline: 2px solid transparent;
outline-offset: -3px;
left: calc(
var( --indicator-left ) * 1px - 1px
);
width: calc( var( --indicator-width ) * 1px );
height: calc( var( --indicator-height ) * 1px );
}

.emotion-10 {
display: -webkit-inline-box;
display: -webkit-inline-flex;
Expand Down Expand Up @@ -1041,6 +1104,7 @@ exports[`ToggleGroupControl uncontrolled should render correctly with text optio
data-wp-component="ToggleGroupControl"
id="toggle-group-control-as-radio-group-0"
role="radiogroup"
style="--indicator-left: 0; --indicator-width: 0; --indicator-height: 0;"
>
<div
class="emotion-10 emotion-11"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
*/
import type { ForwardedRef } from 'react';
import * as Ariakit from '@ariakit/react';
import { motion } from 'framer-motion';

/**
* WordPress dependencies
*/
import { useReducedMotion, useInstanceId } from '@wordpress/compose';
import { useMemo } from '@wordpress/element';
import { useInstanceId } from '@wordpress/compose';
import { useLayoutEffect, useMemo, useRef } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -27,12 +26,6 @@ import Tooltip from '../../tooltip';

const { ButtonContentView, LabelView } = styles;

const REDUCED_MOTION_TRANSITION_CONFIG = {
duration: 0,
};

const LAYOUT_ID = 'toggle-group-backdrop-shared-layout-id';

const WithToolTip = ( { showTooltip, text, children }: WithToolTipProps ) => {
if ( showTooltip && text ) {
return (
Expand All @@ -58,7 +51,6 @@ function ToggleGroupControlOptionBase(
>,
forwardedRef: ForwardedRef< any >
) {
const shouldReduceMotion = useReducedMotion();
const toggleGroupControlContext = useToggleGroupControlContext();

const id = useInstanceId(
Expand Down Expand Up @@ -107,7 +99,6 @@ function ToggleGroupControlOptionBase(
),
[ cx, isDeselectable, isIcon, isPressed, size, className ]
);
const backdropClasses = useMemo( () => cx( styles.backdropView ), [ cx ] );

const buttonOnClick = () => {
if ( isDeselectable && isPressed ) {
Expand All @@ -124,8 +115,15 @@ function ToggleGroupControlOptionBase(
ref: forwardedRef,
};

const labelRef = useRef< HTMLDivElement | null >( null );
useLayoutEffect( () => {
if ( isPressed && labelRef.current ) {
toggleGroupControlContext.setSelectedElement( labelRef.current );
}
}, [ isPressed, toggleGroupControlContext ] );

return (
<LabelView className={ labelViewClasses }>
<LabelView ref={ labelRef } className={ labelViewClasses }>
<WithToolTip
showTooltip={ showTooltip }
text={ otherButtonProps[ 'aria-label' ] }
Expand Down Expand Up @@ -163,21 +161,6 @@ function ToggleGroupControlOptionBase(
</Ariakit.Radio>
) }
</WithToolTip>
{ /* Animated backdrop using framer motion's shared layout animation */ }
{ isPressed ? (
<motion.div layout layoutRoot>
<motion.div
className={ backdropClasses }
transition={
shouldReduceMotion
? REDUCED_MOTION_TRANSITION_CONFIG
: undefined
}
role="presentation"
layoutId={ LAYOUT_ID }
/>
</motion.div>
) : null }
</LabelView>
);
}
Expand Down
Loading
Loading