diff --git a/apps/docs/src/style-matrix.stories.tsx b/apps/docs/src/style-matrix.stories.tsx new file mode 100644 index 0000000..92ab596 --- /dev/null +++ b/apps/docs/src/style-matrix.stories.tsx @@ -0,0 +1,231 @@ +import { + Button, + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, + Input, + Skeleton, + Switch, + skinDetails, + skinNames, + type SkinName +} from "@ai-ui/ui"; +import type { Meta, StoryObj } from "@storybook/react"; + +const motionModes = [ + { + label: "System motion", + value: "system" + }, + { + label: "Reduced motion", + value: "reduced" + } +] as const; + +type MotionMode = (typeof motionModes)[number]["value"]; + +function RuntimePill({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} + +function PanelPreview() { + return ( +
+
+
+

+ Dialog panel contract +

+

+ Panel vars preview the dialog surface without opening an overlay in every + matrix cell. +

+
+ +
+
+ + +
+
+ ); +} + +function ComparisonCell({ + motion, + skin +}: { + motion: MotionMode; + skin: SkinName; +}) { + return ( +
+
+ {skinDetails[skin].label} + {motion} +
+ + + + Release routing + + The same component tree should now pick up distinct skin treatments. + + + + +
+ + Quiet notifications + + +
+
+ + + +
+
+
+ + +
+ ); +} + +function MatrixDialogSandbox() { + return ( + + + + + + + Dialog validation sandbox + + Use the Storybook toolbar to validate the real overlay under the active theme, + skin, and motion settings. + + + + + + + + + ); +} + +function StyleMatrixShowcase() { + return ( +
+
+
+

+ AI UI / Phase 3 +

+

+ Style matrix compares the same product surface across skin and motion scopes. +

+

+ This page is the screenshot-friendly regression target for the pilot skin work. + The grid uses nested `data-skin` and `data-motion` scopes so the same building + blocks can be reviewed side by side. +

+
+ +
+ {motionModes.map((motionMode) => ( +
+
+
+

{motionMode.label}

+

+ `{motionMode.value === "reduced" ? 'data-motion="reduced"' : "default"}` + {" "} + on the wrapper scope. +

+
+
+
+ {skinNames.map((skin) => ( + + ))} +
+
+ ))} +
+ +
+
+

Live overlay validation

+

+ 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. The control below covers the live overlay behavior. +

+
+
+ +
+
+
+
+ ); +} + +const meta = { + title: "Foundation/Style Matrix", + component: StyleMatrixShowcase, + parameters: { + docs: { + description: { + component: + "Phase 3 adds the regression-oriented comparison surface. Use this page for screenshots and visual review, then use the live dialog sandbox below to validate portal-driven overlays under the active toolbar settings." + } + } + } +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Overview: Story = {}; diff --git a/docs/rfcs/multi-style-architecture.md b/docs/rfcs/multi-style-architecture.md index 5889084..9ccc80c 100644 --- a/docs/rfcs/multi-style-architecture.md +++ b/docs/rfcs/multi-style-architecture.md @@ -511,7 +511,7 @@ Deliverables: Status: -- not started +- completed ### Phase 4: Expand Coverage @@ -605,7 +605,9 @@ As of 2026-03-20, the project is at this point: - docs switching surface added in `Foundation/Style Contract` - pilot recipe extraction completed for `Button`, `Card`, `Input`, `Dialog`, `Switch`, and `Skeleton` +- screenshot-friendly validation surface added in `Foundation/Style Matrix` +- scoped `data-motion="reduced"` now works for nested docs wrappers - broader component-library rollout still pending -The next implementation task should be Phase 3: add a dedicated comparison-oriented docs -validation surface for skins and motion modes. +The next implementation task should be Phase 4: expand the skin-aware pattern across the +broader component library. diff --git a/packages/tokens/src/motion.css b/packages/tokens/src/motion.css index 2a5a718..59af710 100644 --- a/packages/tokens/src/motion.css +++ b/packages/tokens/src/motion.css @@ -19,7 +19,8 @@ --scale-pop: 1.02; } -:root[data-motion="reduced"] { +:root[data-motion="reduced"], +[data-motion="reduced"] { --dur-instant: 1ms; --dur-fast: 1ms; --dur-base: 1ms; @@ -32,6 +33,19 @@ --scale-press: 1; --scale-hover: 1; --scale-pop: 1; + scroll-behavior: auto; +} + +:root[data-motion="reduced"] *, +:root[data-motion="reduced"] *::before, +:root[data-motion="reduced"] *::after, +[data-motion="reduced"] *, +[data-motion="reduced"] *::before, +[data-motion="reduced"] *::after { + animation-duration: 1ms !important; + animation-iteration-count: 1 !important; + scroll-behavior: auto !important; + transition-duration: 1ms !important; } @media (prefers-reduced-motion: reduce) {