AnimationDurations for durations, Interpolators for easing curves, and createTransition for composing a CSS transition value. Literal timing values drift out of step when the system is tuned.import {useMemo} from 'react';
import type {ReactNode} from 'react';
import {
AnimationDurations,
Interpolators,
createTransition,
reducedMotionDuration,
usePrefersReducedMotion,
} from '@wearables-ui-toolkit/mrbd';
export function DetailReveal({
isExpanded,
children,
}: {
isExpanded: boolean;
children: ReactNode;
}) {
const prefersReducedMotion = usePrefersReducedMotion();
const transition = useMemo(
() =>
createTransition(
['opacity', 'transform'],
reducedMotionDuration(
AnimationDurations.TEXT_OPACITY,
prefersReducedMotion,
),
Interpolators.TEXT_OPACITY,
reducedMotionDuration(
AnimationDurations.TEXT_OPACITY_EXPAND_DELAY,
prefersReducedMotion,
),
),
[prefersReducedMotion],
);
return (
<div
className="detail-reveal"
style={{transition, opacity: isExpanded ? 1 : 0}}
>
{children}
</div>
);
}
.detail-reveal {
padding: var(--uit-spacing-medium);
color: var(--uit-color-text-primary);
}
reducedMotionDuration as well as the duration. Otherwise a reduced-motion change still waits before snapping, which reads as a lag rather than as an instant update.@media (prefers-reduced-motion: reduce) instead — see reduced motion.createTransition(properties, duration, interpolator?, delay?)| Parameter | Type | Default | Description |
|---|---|---|---|
properties | string \| string[] | — | One CSS property name, or several. An array produces one comma-separated entry per property, all with the same timing. |
duration | number | — | Duration in milliseconds. The helper appends the unit. |
interpolator | string | Interpolators.CONTAINER_SCALE | A CSS timing function. |
delay | number | 0 | Delay in milliseconds. Emitted only when greater than zero. |
transition property, shaped as "<property> <duration>ms <timing-function>", with " <delay>ms" appended when a delay was given. Compose several groups with different timings by calling it more than once and joining the results with ", ".AnimationDurations| Constant | What it times |
|---|---|
CONTAINER_STATE_CHANGE | The baseline state change between the default and focused appearance. |
CONTAINER_PRESS_IN | Any state into pressed. The shortest state-change duration, so press feedback feels immediate. |
CONTAINER_PRESS_OUT | Pressed back to the previous state. Slightly longer than press-in, so the release reads as a settle rather than a snap. |
CONTAINER_STATE_CHANGE_FAST_FOCUS | A focus change while the user is scrolling quickly. Shorter than the baseline so focus keeps up with the movement. |
CONTAINER_FAST_MOVEMENT_EXPANSION_HESITATION_DELAY | How long a container waits before expanding while focus is moving fast, so items that are merely passed over never expand. |
TEXT_OPACITY | A text opacity fade. |
TEXT_OPACITY_EXPAND_DELAY | The delay before the text fade when content expands, so the text arrives after the surface has started to open. |
TEXT_OPACITY_COLLAPSE_DELAY | The matching delay when content collapses. Collapse adds none, so the fade starts immediately. |
ICON_ROTATION | An icon rotating in place. |
CONTAINER_RUBBERBAND | One segment of the two-stage rubber-band response shown when focus cannot move further. |
Interpolatorstransition shorthand, animation-timing-function, and the easing option of the Web Animations API.| Constant | Curve |
|---|---|
CONTAINER_SCALE | Smooth ease-in-out for state changes. The default used by createTransition. |
CONTAINER_PRESS_IN | Fast start for responsive press feedback. |
CONTAINER_PRESS_OUT | Softer release curve. |
ICON_AVATAR | Icon and avatar transitions, such as a chip exchanging its leading element. |
CONTAINER_RUBBERBAND_STAGE_ONE | The outward segment of the rubber-band response. |
CONTAINER_RUBBERBAND_STAGE_TWO | The return segment of the rubber-band response. |
TEXT_OPACITY | Standard ease for subtle opacity changes. |
LINEAR | No easing — a constant rate. |
| Change | Duration | Interpolator |
|---|---|---|
Default to or from focused | CONTAINER_STATE_CHANGE | CONTAINER_SCALE |
Focus change during fast scrolling | CONTAINER_STATE_CHANGE_FAST_FOCUS | CONTAINER_SCALE |
Into pressed | CONTAINER_PRESS_IN | CONTAINER_PRESS_IN |
Out of pressed | CONTAINER_PRESS_OUT | CONTAINER_PRESS_OUT |
Text fade | TEXT_OPACITY | TEXT_OPACITY |
Rubber-band segment | CONTAINER_RUBBERBAND | CONTAINER_RUBBERBAND_STAGE_ONE, then CONTAINER_RUBBERBAND_STAGE_TWO |
Container: press-in and press-out drive the content scale with a spring, because a press can be released at any point, while every other state change follows these curves. The press durations above still time the material’s visual-state transition for those changes; only the content scale is spring-driven, and it settles on the spring’s own timing.reducedMotionDuration collapses the duration to zero, which makes the property jump to its new value on the next frame while still going through the same code path.AnimationDurations and Interpolators by name and keep the designed pairings so related motion remains synchronized.createTransition so property lists, units, and delays stay consistent.opacity and transform, which the browser can composite.