Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

- `Button`: Hide focus outline on `:active` in High Contrast (forced colors) mode to provide visual click feedback ([#76833](https://github.com/WordPress/gutenberg/pull/76833)).

### Internal

- `Modal`, `Menu`: Use `--wpds-motion-*` design tokens for animation duration and easing ([#76097](https://github.com/WordPress/gutenberg/pull/76097)).

## 32.4.0 (2026-03-18)

### Bug Fixes
Expand Down
8 changes: 2 additions & 6 deletions packages/components/src/modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,7 @@ function UnforwardedModal(
};
}, [ bodyOpenClassName ] );

const { closeModal, frameRef, frameStyle, overlayClassname } =
useModalExitAnimation();
const { closeModal, frameRef, overlayClassname } = useModalExitAnimation();

// Calls the isContentScrollable callback when the Modal children container resizes.
useLayoutEffect( () => {
Expand Down Expand Up @@ -259,10 +258,7 @@ function UnforwardedModal(
sizeClass,
className
) }
style={ {
...frameStyle,
...style,
} }
style={ style }
ref={ useMergeRefs( [
frameRef,
constrainedTabbingRef,
Expand Down
39 changes: 29 additions & 10 deletions packages/components/src/modal/style.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@use "@wordpress/base-styles/animations" as *;
@use "@wordpress/base-styles/colors" as *;
@use "@wordpress/base-styles/mixins" as *;
@use "@wordpress/base-styles/variables" as *;
Expand All @@ -15,14 +14,16 @@
background-color: rgba($black, 0.35);
z-index: z-index(".components-modal__screen-overlay");
display: flex;
// This animates the appearance of the backdrop.
@include animation__fade-in();
@media not (prefers-reduced-motion) {
animation: components-modal__fade-in var(--wpds-motion-duration-sm) var(--wpds-motion-easing-gentle);
animation-fill-mode: forwards;
}

&.is-animating-out {
// Note: it's important that the fade-out animation doesn't end after the
// modal frame's disappear animation, because the component will be removed
// from the DOM when that animation ends.
@include animation__fade-out($delay: 80ms);
@media not (prefers-reduced-motion) {
animation: components-modal__fade-out var(--wpds-motion-duration-sm) var(--wpds-motion-easing-gentle) var(--wpds-motion-duration-sm);
animation-fill-mode: forwards;
}
}
}

Expand All @@ -42,7 +43,7 @@
// Animate the modal frame/contents appearing on the page.
animation-name: components-modal__appear-animation;
animation-fill-mode: forwards;
animation-timing-function: cubic-bezier(0.29, 0, 0, 1);
animation-timing-function: var(--wpds-motion-easing-decelerate-emphasized);

// Ensure all headings use the proper editor text color, overriding wp-admin common.css
h1,
Expand All @@ -52,12 +53,12 @@
}

@media not (prefers-reduced-motion) {
animation-duration: var(--modal-frame-animation-duration);
animation-duration: var(--wpds-motion-duration-md);
}

.components-modal__screen-overlay.is-animating-out & {
animation-name: components-modal__disappear-animation;
animation-timing-function: cubic-bezier(1, 0, 0.2, 1);
animation-timing-function: var(--wpds-motion-easing-decelerate-emphasized);
}

// Show a centered modal on bigger screens.
Expand Down Expand Up @@ -119,6 +120,24 @@
}
}

@keyframes components-modal__fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

@keyframes components-modal__fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}

@keyframes components-modal__appear-animation {
from {
opacity: 0;
Expand Down
9 changes: 2 additions & 7 deletions packages/components/src/modal/use-modal-exit-animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import warning from '@wordpress/warning';
*/
import { CONFIG } from '../utils';

// Animation duration (ms) extracted to JS in order to be used on a setTimeout.
const FRAME_ANIMATION_DURATION = CONFIG.transitionDuration;
const FRAME_ANIMATION_DURATION_NUMBER = Number.parseInt(
const FRAME_ANIMATION_DURATION_MS = Number.parseInt(
CONFIG.transitionDuration
);

Expand Down Expand Up @@ -68,7 +66,7 @@ export function useModalExitAnimation() {
// Allow an extra 20% of the animation duration for the
// animationend event to fire, in case the animation frame is
// slightly delayes by some other events in the event loop.
FRAME_ANIMATION_DURATION_NUMBER * 1.2
FRAME_ANIMATION_DURATION_MS * 1.2
);
} );

Expand All @@ -91,9 +89,6 @@ export function useModalExitAnimation() {
return {
overlayClassname: isAnimatingOut ? 'is-animating-out' : undefined,
frameRef,
frameStyle: {
'--modal-frame-animation-duration': `${ FRAME_ANIMATION_DURATION }`,
},
closeModal,
};
}
6 changes: 5 additions & 1 deletion packages/components/src/utils/dropdown-motion.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Motion configuration for dropdown-like popovers.
// Keep constants in sync with: packages/ui/src/utils/css/dropdown-motion.module.css
// Values should stay in sync with --wpds-motion-* design tokens.

export const DROPDOWN_MOTION = Object.freeze( {
SLIDE_DISTANCE: 4,
Expand All @@ -8,7 +9,7 @@ export const DROPDOWN_MOTION = Object.freeze( {
function: 'cubic-bezier',
args: [ 0, 0, 0, 1 ] as const,
},
FADE_DURATION: 80,
FADE_DURATION: 100,
FADE_EASING: {
function: 'linear',
},
Expand All @@ -24,6 +25,9 @@ const convertEasingToString = ( easing: {
return easing.function;
};

// Note: --wpds-* tokens can't be used here directly because the build-time
// fallback injection is not compatible with Emotion. This file is consumed
// by Menu's Emotion styles.
export const DROPDOWN_MOTION_CSS = Object.freeze( {
SLIDE_DISTANCE: `${ DROPDOWN_MOTION.SLIDE_DISTANCE }px`,
SLIDE_DURATION: `${ DROPDOWN_MOTION.SLIDE_DURATION }ms`,
Expand Down
1 change: 1 addition & 0 deletions packages/theme/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- Added PostCSS, esbuild, and Vite build plugins that inject fallback values for design system tokens (`--wpds-*`). Available as package exports: `@wordpress/theme/postcss-plugins/postcss-ds-token-fallbacks`, `@wordpress/theme/esbuild-plugins/esbuild-ds-token-fallbacks`, `@wordpress/theme/vite-plugins/vite-ds-token-fallbacks` ([#75589](https://github.com/WordPress/gutenberg/pull/75589)).
- Add `--wpds-cursor-control` design token for interactive non-link elements ([#75697](https://github.com/WordPress/gutenberg/pull/75697)).
- Add `--wpds-dimension-surface-width-*` design tokens for component width constraints.
- Add `--wpds-motion-duration-*` and `--wpds-motion-easing-*` design tokens for standardizing animation timing across components.

## 0.7.0 (2026-02-18)

Expand Down
26 changes: 15 additions & 11 deletions packages/theme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The design system follows the [Design Tokens Community Group (DTCG)](https://des
| `typography.json` | Font family stacks, font sizes, and line heights |
| `border.json` | Border radius and width values |
| `elevation.json` | Shadow definitions for creating depth and layering |
| `motion.json` | Animation durations and easing curves |

Each JSON file contains both primitive and semantic token definitions in a hierarchical structure. These files are the source of truth for the design system and are processed during the build step to generate CSS custom properties and other output formats in `/src/prebuilt`.

Expand All @@ -59,20 +60,23 @@ Semantic tokens follow a consistent naming pattern:
| `border` | Border properties like radius and width |
| `elevation` | Shadow definitions for layering and depth |
| `font` | Typography properties like family, size, and line-height |
| `motion` | Animation durations and easing curves |

**Property** is the specific design property being defined.

| Value | Description |
| --------- | ---------------------------------- |
| `bg` | Background color |
| `fg` | Foreground color (text and icons) |
| `stroke` | Border and outline color |
| `padding` | Internal spacing within an element |
| `gap` | Spacing between elements |
| `radius` | Border radius for rounded corners |
| `width` | Border width |
| `size` | Font size |
| `family` | Font family |
| Value | Description |
| ---------- | ---------------------------------- |
| `bg` | Background color |
| `fg` | Foreground color (text and icons) |
| `stroke` | Border and outline color |
| `padding` | Internal spacing within an element |
| `gap` | Spacing between elements |
| `radius` | Border radius for rounded corners |
| `width` | Border width |
| `size` | Font size |
| `family` | Font family |
| `duration` | Animation duration |
| `easing` | Animation easing curve |

**Target** is the component or element type the token applies to.

Expand Down
14 changes: 14 additions & 0 deletions packages/theme/docs/tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ Do not edit directly.
| `--wpds-elevation-md` | For components that offer additional actions. Example: Menus, Command Palette |
| `--wpds-elevation-lg` | For components that confirm decisions or handle necessary interruptions. Example: Modals. |

### Motion

| Variable name | Description |
| -------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `--wpds-motion-duration-xs` | Micro-delays and transition offsets |
| `--wpds-motion-duration-sm` | Micro-interactions like focus rings and state changes |
| `--wpds-motion-duration-md` | Standard transitions like menus and popovers |
| `--wpds-motion-duration-lg` | Deliberate animations like slides and reveals |
| `--wpds-motion-duration-xl` | Extended animations like complex or multi-step transitions |
| `--wpds-motion-easing-gentle` | Subtle easing for hover, color, and background transitions |
| `--wpds-motion-easing-standard` | Balanced easing for on-screen movement like resizing, morphing, and layout shifts |
| `--wpds-motion-easing-decelerate` | Decelerating easing for elements entering or exiting the screen, such as menus and popovers |
| `--wpds-motion-easing-decelerate-emphasized` | Expressive easing for prominent elements entering or exiting, like dialogs and drawers |

### Typography

| Variable name | Description |
Expand Down
9 changes: 9 additions & 0 deletions packages/theme/src/prebuilt/css/design-tokens.css
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@
--wpds-font-size-xs: 11px; /* Extra small font size */
--wpds-font-weight-medium: 499; /* Medium font weight for emphasis and headings */
--wpds-font-weight-regular: 400; /* Regular font weight for body text */
--wpds-motion-duration-lg: 300ms; /* Deliberate animations like slides and reveals */
--wpds-motion-duration-md: 200ms; /* Standard transitions like menus and popovers */
--wpds-motion-duration-sm: 100ms; /* Micro-interactions like focus rings and state changes */
--wpds-motion-duration-xl: 400ms; /* Extended animations like complex or multi-step transitions */
--wpds-motion-duration-xs: 50ms; /* Micro-delays and transition offsets */
--wpds-motion-easing-decelerate: cubic-bezier(0, 0, 0, 1); /* Decelerating easing for elements entering or exiting the screen, such as menus and popovers */
--wpds-motion-easing-decelerate-emphasized: cubic-bezier(0.29, 0, 0, 1); /* Expressive easing for prominent elements entering or exiting, like dialogs and drawers */
--wpds-motion-easing-gentle: cubic-bezier(0.25, 0.1, 0.25, 1); /* Subtle easing for hover, color, and background transitions */
--wpds-motion-easing-standard: cubic-bezier(0.4, 0, 0.2, 1); /* Balanced easing for on-screen movement like resizing, morphing, and layout shifts */
}

[data-wpds-theme-provider-id][data-wpds-density='compact'] {
Expand Down
10 changes: 10 additions & 0 deletions packages/theme/src/prebuilt/js/design-token-fallbacks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,14 @@
'--wpds-font-size-xs': '11px',
'--wpds-font-weight-medium': '499',
'--wpds-font-weight-regular': '400',
'--wpds-motion-duration-lg': '300ms',
'--wpds-motion-duration-md': '200ms',
'--wpds-motion-duration-sm': '100ms',
'--wpds-motion-duration-xl': '400ms',
'--wpds-motion-duration-xs': '50ms',
'--wpds-motion-easing-decelerate': 'cubic-bezier(0, 0, 0, 1)',
'--wpds-motion-easing-decelerate-emphasized':

Check failure on line 169 in packages/theme/src/prebuilt/js/design-token-fallbacks.mjs

View workflow job for this annotation

GitHub Actions / All (Node.js 24 on Linux)

Replace `⏎↹↹` with `·`
'cubic-bezier(0.29, 0, 0, 1)',
'--wpds-motion-easing-gentle': 'cubic-bezier(0.25, 0.1, 0.25, 1)',
'--wpds-motion-easing-standard': 'cubic-bezier(0.4, 0, 0.2, 1)',
};
9 changes: 9 additions & 0 deletions packages/theme/src/prebuilt/js/design-tokens.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ export default [
'--wpds-elevation-sm',
'--wpds-elevation-md',
'--wpds-elevation-lg',
'--wpds-motion-duration-xs',
'--wpds-motion-duration-sm',
'--wpds-motion-duration-md',
'--wpds-motion-duration-lg',
'--wpds-motion-duration-xl',
'--wpds-motion-easing-gentle',
'--wpds-motion-easing-standard',
'--wpds-motion-easing-decelerate',
'--wpds-motion-easing-decelerate-emphasized',
'--wpds-font-family-heading',
'--wpds-font-family-body',
'--wpds-font-family-mono',
Expand Down
14 changes: 14 additions & 0 deletions packages/theme/src/prebuilt/ts/token-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ export type GapSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';
*/
export type SurfaceWidthSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';

/**
* Size scale for duration tokens.
*/
export type DurationSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';

/**
* Easing curve variants.
*/
export type Easing =
| 'gentle'
| 'standard'
| 'decelerate'
| 'decelerate-emphasized';

/**
* Size scale for border radius tokens.
*/
Expand Down
11 changes: 11 additions & 0 deletions packages/theme/terrazzo.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default defineConfig( {
'./tokens/cursor.json',
'./tokens/dimension.json',
'./tokens/elevation.json',
'./tokens/motion.json',
'./tokens/typography.json',
],
outDir: './src/prebuilt',
Expand Down Expand Up @@ -121,6 +122,16 @@ export default defineConfig( {
description: 'Size scale for surface width tokens.',
patterns: [ /^wpds-dimension\.surface-width\.([^.]+)$/ ],
},
{
name: 'DurationSize',
description: 'Size scale for duration tokens.',
patterns: [ /^wpds-motion\.duration\.([^.]+)$/ ],
},
{
name: 'Easing',
description: 'Easing curve variants.',
patterns: [ /^wpds-motion\.easing\.([^.]+)$/ ],
},
{
name: 'BorderRadiusSize',
description: 'Size scale for border radius tokens.',
Expand Down
46 changes: 46 additions & 0 deletions packages/theme/tokens/motion.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"wpds-motion": {
"duration": {
"$type": "duration",
"xs": {
"$value": "50ms",
"$description": "Micro-delays and transition offsets"
},
"sm": {
"$value": "100ms",
"$description": "Micro-interactions like focus rings and state changes"
},
"md": {
"$value": "200ms",
"$description": "Standard transitions like menus and popovers"
},
"lg": {
"$value": "300ms",
"$description": "Deliberate animations like slides and reveals"
},
"xl": {
"$value": "400ms",
"$description": "Extended animations like complex or multi-step transitions"
}
},
"easing": {
"$type": "cubicBezier",
"gentle": {
"$value": [ 0.25, 0.1, 0.25, 1 ],
"$description": "Subtle easing for hover, color, and background transitions"
},
"standard": {
"$value": [ 0.4, 0, 0.2, 1 ],
"$description": "Balanced easing for on-screen movement like resizing, morphing, and layout shifts"
},
"decelerate": {
"$value": [ 0, 0, 0, 1 ],
"$description": "Decelerating easing for elements entering or exiting the screen, such as menus and popovers"
},
"decelerate-emphasized": {
"$value": [ 0.29, 0, 0, 1 ],
"$description": "Expressive easing for prominent elements entering or exiting, like dialogs and drawers"
}
}
}
}
1 change: 1 addition & 0 deletions packages/ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

- Extract `useDeprioritizedInitialFocus` shared hook for reuse across overlay components ([#76910](https://github.com/WordPress/gutenberg/pull/76910)).
- `Tabs`: Add development-mode validation for Tab/Panel count matching ([#75170](https://github.com/WordPress/gutenberg/pull/75170)).
- `Dialog`, dropdown motion utilities: Use `--wpds-motion-*` design tokens for animation duration and easing ([#76097](https://github.com/WordPress/gutenberg/pull/76097)).

### TypeScript

Expand Down
Loading
Loading