refactor(motion): simplify to default and reduced
This commit is contained in:
@@ -11,18 +11,15 @@ import {
|
||||
type SkinName
|
||||
} from "@ai-ui/ui";
|
||||
import {
|
||||
defaultMotionAccessibility,
|
||||
defaultMotionPack,
|
||||
defaultMotionMode,
|
||||
defaultTheme,
|
||||
type MotionAccessibilityName,
|
||||
type MotionPackName,
|
||||
type MotionModeName,
|
||||
type ThemeName
|
||||
} from "@ai-ui/tokens";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
type StyleContractShowcaseProps = {
|
||||
motionAccessibility: MotionAccessibilityName;
|
||||
motionPack: MotionPackName;
|
||||
motionMode: MotionModeName;
|
||||
skin: SkinName;
|
||||
theme: ThemeName;
|
||||
};
|
||||
@@ -147,8 +144,7 @@ function SkinPanel({
|
||||
}
|
||||
|
||||
function StyleContractShowcase({
|
||||
motionAccessibility,
|
||||
motionPack,
|
||||
motionMode,
|
||||
skin,
|
||||
theme
|
||||
}: StyleContractShowcaseProps) {
|
||||
@@ -180,8 +176,7 @@ function StyleContractShowcase({
|
||||
<section className="flex flex-wrap gap-3">
|
||||
<RuntimeBadge label="theme" value={theme} />
|
||||
<RuntimeBadge label="skin" value={skin} />
|
||||
<RuntimeBadge label="motion pack" value={motionPack} />
|
||||
<RuntimeBadge label="accessibility" value={motionAccessibility} />
|
||||
<RuntimeBadge label="motion" value={motionMode} />
|
||||
</section>
|
||||
|
||||
<section className="grid gap-4 lg:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)]">
|
||||
@@ -192,7 +187,7 @@ function StyleContractShowcase({
|
||||
"A new runtime attribute: `data-skin`",
|
||||
"Public helpers from `@ai-ui/ui` for skin names, defaults, and root updates",
|
||||
"A dedicated `@ai-ui/ui/skins.css` entrypoint imported by the docs app",
|
||||
"Storybook globals that apply theme, skin, motion pack, and accessibility override together"
|
||||
"Storybook globals that apply theme, skin, and motion mode together"
|
||||
].map((item) => (
|
||||
<div
|
||||
key={item}
|
||||
@@ -242,8 +237,7 @@ const meta = {
|
||||
title: "Foundation/Style Contract",
|
||||
component: StyleContractShowcase,
|
||||
args: {
|
||||
motionAccessibility: defaultMotionAccessibility,
|
||||
motionPack: defaultMotionPack,
|
||||
motionMode: defaultMotionMode,
|
||||
skin: defaultSkin,
|
||||
theme: defaultTheme
|
||||
},
|
||||
@@ -251,18 +245,14 @@ const meta = {
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Phase 1 adds the runtime style contract. Use the Storybook toolbar to switch the active `theme`, `skin`, `motion pack`, and accessibility override globally, or inspect the side-by-side nested `data-skin` panels below."
|
||||
"Phase 1 adds the runtime style contract. Use the Storybook toolbar to switch the active `theme`, `skin`, and `motion` mode globally, or inspect the side-by-side nested `data-skin` panels below."
|
||||
}
|
||||
}
|
||||
},
|
||||
render: (_args, context) => (
|
||||
<StyleContractShowcase
|
||||
motionAccessibility={
|
||||
(context.globals.motionAccessibility as MotionAccessibilityName | undefined) ??
|
||||
defaultMotionAccessibility
|
||||
}
|
||||
motionPack={
|
||||
(context.globals.motionPack as MotionPackName | undefined) ?? defaultMotionPack
|
||||
motionMode={
|
||||
(context.globals.motionMode as MotionModeName | undefined) ?? defaultMotionMode
|
||||
}
|
||||
skin={(context.globals.skin as SkinName | undefined) ?? defaultSkin}
|
||||
theme={(context.globals.theme as ThemeName | undefined) ?? defaultTheme}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
motionPackDetails,
|
||||
motionPackNames,
|
||||
type MotionPackName
|
||||
motionModeDetails,
|
||||
motionModeNames,
|
||||
type MotionModeName
|
||||
} from "@ai-ui/tokens";
|
||||
import {
|
||||
Button,
|
||||
@@ -26,19 +26,6 @@ import {
|
||||
} from "@ai-ui/ui";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
const motionAccessibilityModes = [
|
||||
{
|
||||
label: "System accessibility",
|
||||
value: "system"
|
||||
},
|
||||
{
|
||||
label: "Reduced accessibility",
|
||||
value: "reduced"
|
||||
}
|
||||
] as const;
|
||||
|
||||
type MotionAccessibilityMode = (typeof motionAccessibilityModes)[number]["value"];
|
||||
|
||||
function ClosePreviewIcon() {
|
||||
return (
|
||||
<svg aria-hidden="true" className="size-4" fill="none" viewBox="0 0 16 16">
|
||||
@@ -97,25 +84,21 @@ function PanelPreview() {
|
||||
}
|
||||
|
||||
function ComparisonCell({
|
||||
motionAccessibility,
|
||||
motionPack,
|
||||
motionMode,
|
||||
skin
|
||||
}: {
|
||||
motionAccessibility: MotionAccessibilityMode;
|
||||
motionPack: MotionPackName;
|
||||
motionMode: MotionModeName;
|
||||
skin: SkinName;
|
||||
}) {
|
||||
return (
|
||||
<section
|
||||
className="grid gap-4 rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-4 shadow-[var(--shadow-sm)]"
|
||||
data-motion={motionAccessibility === "reduced" ? "reduced" : undefined}
|
||||
data-motion-pack={motionPack}
|
||||
data-motion={motionMode}
|
||||
data-skin={skin}
|
||||
>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<RuntimePill>{motionPackDetails[motionPack].label}</RuntimePill>
|
||||
<RuntimePill>{motionModeDetails[motionMode].label}</RuntimePill>
|
||||
<RuntimePill>{skinDetails[skin].label}</RuntimePill>
|
||||
<RuntimePill>{motionAccessibility}</RuntimePill>
|
||||
</div>
|
||||
|
||||
<Card interactive tone="default">
|
||||
@@ -127,7 +110,7 @@ function ComparisonCell({
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-3">
|
||||
<Input
|
||||
aria-label={`${motionPack} ${skin} release note status`}
|
||||
aria-label={`${motionMode} ${skin} release note status`}
|
||||
defaultValue="Launch notes approved"
|
||||
readOnly
|
||||
/>
|
||||
@@ -136,7 +119,7 @@ function ComparisonCell({
|
||||
Quiet notifications
|
||||
</span>
|
||||
<Switch
|
||||
aria-label={`${motionPack} ${skin} quiet notifications`}
|
||||
aria-label={`${motionMode} ${skin} quiet notifications`}
|
||||
checked
|
||||
/>
|
||||
</div>
|
||||
@@ -196,52 +179,30 @@ function StyleMatrixShowcase() {
|
||||
</h1>
|
||||
<p className="max-w-3xl text-[var(--text-lg)] leading-[var(--leading-loose)] text-[var(--color-muted-foreground)]">
|
||||
This page is the screenshot-friendly regression target for the pilot skin work.
|
||||
The grid uses nested `data-skin`, `data-motion-pack`, and
|
||||
`data-motion="reduced"` scopes so the same building blocks can be
|
||||
The grid uses nested `data-skin` and `data-motion` scopes so the same
|
||||
building blocks can be
|
||||
reviewed side by side.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<section className="grid gap-4">
|
||||
{motionPackNames.map((motionPack) => (
|
||||
<div key={motionPack} className="grid gap-4">
|
||||
{motionModeNames.map((motionMode) => (
|
||||
<div key={motionMode} className="grid gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold">{motionPackDetails[motionPack].label}</h2>
|
||||
<h2 className="text-2xl font-semibold">{motionModeDetails[motionMode].label}</h2>
|
||||
<p className="mt-1 max-w-3xl text-sm leading-6 text-[var(--color-muted-foreground)]">
|
||||
{motionPackDetails[motionPack].note}
|
||||
{motionModeDetails[motionMode].note}
|
||||
</p>
|
||||
</div>
|
||||
{motionAccessibilityModes.map((motionAccessibilityMode) => (
|
||||
<div key={`${motionPack}-${motionAccessibilityMode.value}`} className="grid gap-3">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold">
|
||||
{motionAccessibilityMode.label}
|
||||
</h3>
|
||||
<p className="mt-1 text-sm text-[var(--color-muted-foreground)]">
|
||||
{motionAccessibilityMode.value === "reduced"
|
||||
? '`data-motion="reduced"`'
|
||||
: "System preference"}
|
||||
{" "}with{" "}
|
||||
<code className="text-[var(--color-foreground)]">
|
||||
{`data-motion-pack="${motionPack}"`}
|
||||
</code>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-4 xl:grid-cols-3">
|
||||
{skinNames.map((skin) => (
|
||||
<ComparisonCell
|
||||
key={`${motionPack}-${motionAccessibilityMode.value}-${skin}`}
|
||||
motionAccessibility={motionAccessibilityMode.value}
|
||||
motionPack={motionPack}
|
||||
skin={skin}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="grid gap-4 xl:grid-cols-3">
|
||||
{skinNames.map((skin) => (
|
||||
<ComparisonCell
|
||||
key={`${motionMode}-${skin}`}
|
||||
motionMode={motionMode}
|
||||
skin={skin}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
@@ -252,7 +213,7 @@ function StyleMatrixShowcase() {
|
||||
<p className="mt-2 max-w-3xl text-sm leading-6 text-[var(--color-muted-foreground)]">
|
||||
Dialog still portals to the document root, so compare its real overlay and
|
||||
panel treatment with the Storybook toolbar. The matrix above covers scoped
|
||||
inline regression across packs and reduced-motion overlay. The control below
|
||||
inline regression across default and reduced motion modes. The control below
|
||||
covers the live overlay behavior.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
import {
|
||||
colorTokens,
|
||||
defaultTheme,
|
||||
defaultMotionAccessibility,
|
||||
defaultMotionPack,
|
||||
defaultMotionMode,
|
||||
motionTokens,
|
||||
motionAccessibilityDetails,
|
||||
motionPackDetails,
|
||||
motionModeDetails,
|
||||
radiusTokens,
|
||||
shadowTokens,
|
||||
themeDetails,
|
||||
themeNames,
|
||||
typographyTokens,
|
||||
type MotionAccessibilityName,
|
||||
type MotionPackName,
|
||||
type MotionModeName,
|
||||
type ThemeName
|
||||
} from "@ai-ui/tokens";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
type TokensOverviewProps = {
|
||||
motionAccessibility: MotionAccessibilityName;
|
||||
motionPack: MotionPackName;
|
||||
motionMode: MotionModeName;
|
||||
theme: ThemeName;
|
||||
};
|
||||
|
||||
@@ -127,8 +123,7 @@ function ThemeCard({ themeName }: { themeName: ThemeName }) {
|
||||
}
|
||||
|
||||
function TokensOverview({
|
||||
motionAccessibility,
|
||||
motionPack,
|
||||
motionMode,
|
||||
theme
|
||||
}: TokensOverviewProps) {
|
||||
return (
|
||||
@@ -168,18 +163,10 @@ function TokensOverview({
|
||||
</div>
|
||||
<div className="rounded-[var(--radius-md)] border border-[var(--color-border)] bg-[var(--color-card)] px-4 py-3 shadow-[var(--shadow-xs)]">
|
||||
<p className="text-xs uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]">
|
||||
Motion Pack
|
||||
Motion
|
||||
</p>
|
||||
<p className="mt-2 text-sm font-medium text-[var(--color-foreground)]">
|
||||
{motionPackDetails[motionPack].label}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-[var(--radius-md)] border border-[var(--color-border)] bg-[var(--color-card)] px-4 py-3 shadow-[var(--shadow-xs)]">
|
||||
<p className="text-xs uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]">
|
||||
Accessibility Override
|
||||
</p>
|
||||
<p className="mt-2 text-sm font-medium text-[var(--color-foreground)]">
|
||||
{motionAccessibilityDetails[motionAccessibility].label}
|
||||
{motionModeDetails[motionMode].label}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -301,8 +288,8 @@ function TokensOverview({
|
||||
<h2 className="text-2xl font-semibold">Motion tokens</h2>
|
||||
<p className="mt-1 text-sm text-[var(--color-muted-foreground)]">
|
||||
Timing and motion scale now live in variables that components can consume
|
||||
directly. The toolbar now separates the active motion pack from the
|
||||
accessibility override.
|
||||
directly. The toolbar now switches between the default interaction layer
|
||||
and the reduced-motion fallback.
|
||||
</p>
|
||||
<div className="mt-6 grid gap-4 md:grid-cols-2">
|
||||
<div className="space-y-3">
|
||||
@@ -390,18 +377,13 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Overview: Story = {
|
||||
args: {
|
||||
motionAccessibility: defaultMotionAccessibility,
|
||||
motionPack: defaultMotionPack,
|
||||
motionMode: defaultMotionMode,
|
||||
theme: defaultTheme
|
||||
},
|
||||
render: (_args, context) => (
|
||||
<TokensOverview
|
||||
motionAccessibility={
|
||||
(context.globals.motionAccessibility as MotionAccessibilityName | undefined) ??
|
||||
defaultMotionAccessibility
|
||||
}
|
||||
motionPack={
|
||||
(context.globals.motionPack as MotionPackName | undefined) ?? defaultMotionPack
|
||||
motionMode={
|
||||
(context.globals.motionMode as MotionModeName | undefined) ?? defaultMotionMode
|
||||
}
|
||||
theme={context.globals.theme as ThemeName}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user