refactor(motion): simplify to default and reduced
This commit is contained in:
@@ -18,50 +18,21 @@ export const themeDetails = {
|
||||
}
|
||||
} as const satisfies Record<ThemeName, { label: string; note: string }>;
|
||||
|
||||
export const motionPackNames = ["calm", "snappy", "spring"] as const;
|
||||
export type MotionPackName = (typeof motionPackNames)[number];
|
||||
export const motionModeNames = ["default", "reduced"] as const;
|
||||
export type MotionModeName = (typeof motionModeNames)[number];
|
||||
|
||||
export const defaultMotionPack: MotionPackName = "calm";
|
||||
export const defaultMotionMode: MotionModeName = "default";
|
||||
|
||||
export const motionPackDetails = {
|
||||
calm: {
|
||||
label: "Calm",
|
||||
note: "Editorial default with restrained lift and steady transitions"
|
||||
},
|
||||
snappy: {
|
||||
label: "Snappy",
|
||||
note: "Shorter durations, tighter distances, and more direct response"
|
||||
},
|
||||
spring: {
|
||||
label: "Spring",
|
||||
note: "More elastic easing, wider movement, and livelier feedback"
|
||||
}
|
||||
} as const satisfies Record<MotionPackName, { label: string; note: string }>;
|
||||
|
||||
export const motionAccessibilityNames = ["system", "full", "reduced"] as const;
|
||||
export type MotionAccessibilityName = (typeof motionAccessibilityNames)[number];
|
||||
|
||||
export const defaultMotionAccessibility: MotionAccessibilityName = "system";
|
||||
|
||||
export const motionAccessibilityDetails = {
|
||||
system: {
|
||||
label: "System",
|
||||
note: "Follow the operating system reduced-motion preference"
|
||||
},
|
||||
full: {
|
||||
label: "Full",
|
||||
note: "Always show the selected motion pack, even if the OS prefers reduced motion"
|
||||
export const motionModeDetails = {
|
||||
default: {
|
||||
label: "Default",
|
||||
note: "Standard Cadence UI motion for hover, press, overlays, and hierarchy"
|
||||
},
|
||||
reduced: {
|
||||
label: "Reduced",
|
||||
note: "Always collapse durations, distances, and animated feedback"
|
||||
note: "Collapse durations, distances, and animated feedback"
|
||||
}
|
||||
} as const satisfies Record<MotionAccessibilityName, { label: string; note: string }>;
|
||||
|
||||
export const motionModeNames = motionAccessibilityNames;
|
||||
export type MotionModeName = MotionAccessibilityName;
|
||||
|
||||
export const defaultMotionMode: MotionModeName = defaultMotionAccessibility;
|
||||
} as const satisfies Record<MotionModeName, { label: string; note: string }>;
|
||||
|
||||
export const motionScale = {
|
||||
instant: "var(--dur-instant)",
|
||||
@@ -190,16 +161,6 @@ function getTargetElement(root?: HTMLElement) {
|
||||
return document.documentElement;
|
||||
}
|
||||
|
||||
export function setMotionPack(pack: MotionPackName, root?: HTMLElement) {
|
||||
const target = getTargetElement(root);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
target.dataset.motionPack = pack;
|
||||
}
|
||||
|
||||
export function setTheme(theme: ThemeName, root?: HTMLElement) {
|
||||
const target = getTargetElement(root);
|
||||
|
||||
@@ -210,24 +171,12 @@ export function setTheme(theme: ThemeName, root?: HTMLElement) {
|
||||
target.dataset.theme = theme;
|
||||
}
|
||||
|
||||
export function setMotionAccessibility(
|
||||
mode: MotionAccessibilityName,
|
||||
root?: HTMLElement
|
||||
) {
|
||||
export function setMotionMode(mode: MotionModeName, root?: HTMLElement) {
|
||||
const target = getTargetElement(root);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode === "system") {
|
||||
delete target.dataset.motion;
|
||||
return;
|
||||
}
|
||||
|
||||
target.dataset.motion = mode;
|
||||
}
|
||||
|
||||
export function setMotionMode(mode: MotionModeName, root?: HTMLElement) {
|
||||
setMotionAccessibility(mode, root);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
:root,
|
||||
[data-motion-pack="calm"] {
|
||||
:root[data-motion="default"],
|
||||
[data-motion="default"] {
|
||||
--dur-instant: 1ms;
|
||||
--dur-fast: 120ms;
|
||||
--dur-base: 200ms;
|
||||
@@ -20,50 +21,6 @@
|
||||
--scale-pop: 1.02;
|
||||
}
|
||||
|
||||
:root[data-motion-pack="snappy"],
|
||||
[data-motion-pack="snappy"] {
|
||||
--dur-instant: 1ms;
|
||||
--dur-fast: 90ms;
|
||||
--dur-base: 150ms;
|
||||
--dur-slow: 220ms;
|
||||
--dur-deliberate: 300ms;
|
||||
|
||||
--ease-standard: cubic-bezier(0.18, 1, 0.32, 1);
|
||||
--ease-emphasized: cubic-bezier(0.2, 1.08, 0.28, 1);
|
||||
--ease-exit: cubic-bezier(0.4, 0, 1, 1);
|
||||
|
||||
--distance-xs: 2px;
|
||||
--distance-sm: 4px;
|
||||
--distance-md: 10px;
|
||||
--distance-lg: 16px;
|
||||
|
||||
--scale-press: 0.985;
|
||||
--scale-hover: 1.006;
|
||||
--scale-pop: 1.012;
|
||||
}
|
||||
|
||||
:root[data-motion-pack="spring"],
|
||||
[data-motion-pack="spring"] {
|
||||
--dur-instant: 1ms;
|
||||
--dur-fast: 140ms;
|
||||
--dur-base: 220ms;
|
||||
--dur-slow: 360ms;
|
||||
--dur-deliberate: 520ms;
|
||||
|
||||
--ease-standard: cubic-bezier(0.2, 1.08, 0.28, 1);
|
||||
--ease-emphasized: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
--ease-exit: cubic-bezier(0.42, 0, 1, 1);
|
||||
|
||||
--distance-xs: 6px;
|
||||
--distance-sm: 12px;
|
||||
--distance-md: 20px;
|
||||
--distance-lg: 32px;
|
||||
|
||||
--scale-press: 0.96;
|
||||
--scale-hover: 1.018;
|
||||
--scale-pop: 1.035;
|
||||
}
|
||||
|
||||
:root[data-motion="reduced"],
|
||||
[data-motion="reduced"] {
|
||||
--dur-instant: 1ms;
|
||||
@@ -93,35 +50,6 @@
|
||||
transition-duration: 1ms !important;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
:root:not([data-motion="full"]) {
|
||||
--dur-instant: 1ms;
|
||||
--dur-fast: 1ms;
|
||||
--dur-base: 1ms;
|
||||
--dur-slow: 1ms;
|
||||
--dur-deliberate: 1ms;
|
||||
--distance-xs: 0px;
|
||||
--distance-sm: 0px;
|
||||
--distance-md: 0px;
|
||||
--distance-lg: 0px;
|
||||
--scale-press: 1;
|
||||
--scale-hover: 1;
|
||||
--scale-pop: 1;
|
||||
}
|
||||
|
||||
:root {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
|
||||
:root:not([data-motion="full"]) *,
|
||||
:root:not([data-motion="full"]) *::before,
|
||||
:root:not([data-motion="full"]) *::after {
|
||||
animation-duration: 1ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
scroll-behavior: auto !important;
|
||||
transition-duration: 1ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes aiui-fade-in {
|
||||
from {
|
||||
|
||||
@@ -1,52 +1,35 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
defaultMotionAccessibility,
|
||||
defaultMotionMode,
|
||||
defaultMotionPack,
|
||||
motionAccessibilityDetails,
|
||||
motionAccessibilityNames,
|
||||
motionModeNames,
|
||||
motionPackDetails,
|
||||
motionPackNames,
|
||||
setMotionAccessibility,
|
||||
setMotionMode,
|
||||
setMotionPack
|
||||
motionModeDetails,
|
||||
setMotionMode
|
||||
} from "@ai-ui/tokens";
|
||||
|
||||
describe("motion contract", () => {
|
||||
it("exposes default values that exist in the public name sets", () => {
|
||||
expect(motionPackNames).toContain(defaultMotionPack);
|
||||
expect(motionAccessibilityNames).toContain(defaultMotionAccessibility);
|
||||
expect(motionModeNames).toContain(defaultMotionMode);
|
||||
expect(motionPackDetails[defaultMotionPack].label).toBeTruthy();
|
||||
expect(motionAccessibilityDetails[defaultMotionAccessibility].label).toBeTruthy();
|
||||
expect(motionModeDetails[defaultMotionMode].label).toBeTruthy();
|
||||
});
|
||||
|
||||
it("sets the active motion pack on the document root", () => {
|
||||
setMotionPack("spring");
|
||||
it("sets default motion mode on the document root", () => {
|
||||
setMotionMode("default");
|
||||
|
||||
expect(document.documentElement.dataset.motionPack).toBe("spring");
|
||||
expect(document.documentElement.dataset.motion).toBe("default");
|
||||
});
|
||||
|
||||
it("sets reduced motion accessibility on the document root", () => {
|
||||
setMotionAccessibility("reduced");
|
||||
it("sets reduced motion mode on the document root", () => {
|
||||
setMotionMode("reduced");
|
||||
|
||||
expect(document.documentElement.dataset.motion).toBe("reduced");
|
||||
});
|
||||
|
||||
it("removes the accessibility override when system mode is restored", () => {
|
||||
setMotionAccessibility("reduced");
|
||||
setMotionMode("system");
|
||||
|
||||
expect(document.documentElement.dataset.motion).toBeUndefined();
|
||||
});
|
||||
|
||||
it("supports explicit full motion override on custom roots", () => {
|
||||
it("supports explicit reduced mode on custom roots", () => {
|
||||
const target = document.createElement("div");
|
||||
|
||||
setMotionAccessibility("full", target);
|
||||
setMotionMode("reduced", target);
|
||||
|
||||
expect(target.dataset.motion).toBe("full");
|
||||
expect(target.dataset.motion).toBe("reduced");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user