@adres/mgda-ui 0.0.0-stage → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/brand-knowledge.json +451 -0
- package/knowledge/accordion.md +135 -0
- package/knowledge/activity-rings.md +123 -0
- package/knowledge/alert.md +184 -0
- package/knowledge/answer-actions.md +217 -0
- package/knowledge/aspect-ratio.md +82 -0
- package/knowledge/avatar.md +158 -0
- package/knowledge/badge.md +172 -0
- package/knowledge/bar-graph.md +167 -0
- package/knowledge/bento-grid.md +115 -0
- package/knowledge/blockquote.md +153 -0
- package/knowledge/box-list.md +177 -0
- package/knowledge/bullet-list.md +128 -0
- package/knowledge/button-group.md +179 -0
- package/knowledge/button.md +231 -0
- package/knowledge/calendar.md +168 -0
- package/knowledge/card.md +321 -0
- package/knowledge/cards-nav.md +170 -0
- package/knowledge/chain-of-thought.md +164 -0
- package/knowledge/chat-container.md +135 -0
- package/knowledge/chat-message.md +224 -0
- package/knowledge/checkbox-card.md +172 -0
- package/knowledge/checkbox.md +111 -0
- package/knowledge/citations.md +241 -0
- package/knowledge/combobox.md +265 -0
- package/knowledge/countdown-pill.md +153 -0
- package/knowledge/cta.md +118 -0
- package/knowledge/data-list.md +173 -0
- package/knowledge/data-table.md +220 -0
- package/knowledge/dialog.md +249 -0
- package/knowledge/drawer.md +236 -0
- package/knowledge/dropdown-menu.md +238 -0
- package/knowledge/dropzone.md +153 -0
- package/knowledge/email-chips-input.md +161 -0
- package/knowledge/empty-state.md +106 -0
- package/knowledge/entity-header.md +166 -0
- package/knowledge/feature-grid.md +120 -0
- package/knowledge/feedback-bar.md +127 -0
- package/knowledge/footer.md +116 -0
- package/knowledge/heading.md +189 -0
- package/knowledge/hero.md +361 -0
- package/knowledge/input-button.md +187 -0
- package/knowledge/input-group.md +185 -0
- package/knowledge/input.md +256 -0
- package/knowledge/inset.md +177 -0
- package/knowledge/kpi-card.md +206 -0
- package/knowledge/list-nav.md +181 -0
- package/knowledge/logo-cloud.md +102 -0
- package/knowledge/media-gallery.md +158 -0
- package/knowledge/message-actions.md +175 -0
- package/knowledge/nav-sidebar.md +225 -0
- package/knowledge/number-stepper.md +159 -0
- package/knowledge/page-header.md +109 -0
- package/knowledge/pagination.md +225 -0
- package/knowledge/popover.md +159 -0
- package/knowledge/pricing.md +132 -0
- package/knowledge/progress.md +156 -0
- package/knowledge/prompt-input.md +337 -0
- package/knowledge/prompt-suggestions.md +168 -0
- package/knowledge/quota-bar.md +160 -0
- package/knowledge/quote.md +116 -0
- package/knowledge/radio-card.md +172 -0
- package/knowledge/radio-group.md +135 -0
- package/knowledge/reasoning.md +142 -0
- package/knowledge/search.md +131 -0
- package/knowledge/section-nav.md +162 -0
- package/knowledge/segmented-control.md +181 -0
- package/knowledge/select-button.md +205 -0
- package/knowledge/select.md +210 -0
- package/knowledge/separator.md +75 -0
- package/knowledge/shimmer-text.md +140 -0
- package/knowledge/sidebar.md +227 -0
- package/knowledge/skeleton.md +142 -0
- package/knowledge/slider.md +133 -0
- package/knowledge/slideshow.md +159 -0
- package/knowledge/source.md +156 -0
- package/knowledge/spinner.md +120 -0
- package/knowledge/stat-strip.md +128 -0
- package/knowledge/stats.md +117 -0
- package/knowledge/step-indicator.md +157 -0
- package/knowledge/switch.md +88 -0
- package/knowledge/table.md +190 -0
- package/knowledge/tabs.md +169 -0
- package/knowledge/testimonials.md +115 -0
- package/knowledge/text-link.md +192 -0
- package/knowledge/text.md +194 -0
- package/knowledge/thinking-bar.md +115 -0
- package/knowledge/thinking-steps.md +140 -0
- package/knowledge/toaster.md +127 -0
- package/knowledge/toggle.md +113 -0
- package/knowledge/tool-call-card.md +241 -0
- package/knowledge/tooltip.md +120 -0
- package/knowledge/top-nav.md +138 -0
- package/knowledge.json +19854 -0
- package/package.json +94 -4
- package/src/components/accordion.stories.tsx +46 -0
- package/src/components/accordion.tsx +74 -0
- package/src/components/activity-rings.stories.tsx +73 -0
- package/src/components/activity-rings.tsx +121 -0
- package/src/components/alert.stories.tsx +43 -0
- package/src/components/alert.tsx +132 -0
- package/src/components/answer-actions.stories.tsx +54 -0
- package/src/components/answer-actions.test.tsx +37 -0
- package/src/components/answer-actions.tsx +313 -0
- package/src/components/aspect-ratio.stories.tsx +32 -0
- package/src/components/aspect-ratio.tsx +5 -0
- package/src/components/avatar.stories.tsx +40 -0
- package/src/components/avatar.tsx +154 -0
- package/src/components/badge.stories.tsx +27 -0
- package/src/components/badge.tsx +63 -0
- package/src/components/bar-graph.stories.tsx +28 -0
- package/src/components/bar-graph.tsx +204 -0
- package/src/components/bento-grid.stories.tsx +23 -0
- package/src/components/bento-grid.tsx +67 -0
- package/src/components/blockquote.stories.tsx +28 -0
- package/src/components/blockquote.tsx +88 -0
- package/src/components/box-list.stories.tsx +25 -0
- package/src/components/box-list.tsx +108 -0
- package/src/components/bullet-list.stories.tsx +22 -0
- package/src/components/bullet-list.tsx +101 -0
- package/src/components/button-group.stories.tsx +31 -0
- package/src/components/button-group.tsx +156 -0
- package/src/components/button.stories.tsx +66 -0
- package/src/components/button.test.ts +17 -0
- package/src/components/button.tsx +139 -0
- package/src/components/calendar.stories.tsx +25 -0
- package/src/components/calendar.tsx +367 -0
- package/src/components/card.stories.tsx +44 -0
- package/src/components/card.tsx +392 -0
- package/src/components/cards-nav.stories.tsx +35 -0
- package/src/components/cards-nav.tsx +115 -0
- package/src/components/chain-of-thought.stories.tsx +67 -0
- package/src/components/chain-of-thought.test.tsx +50 -0
- package/src/components/chain-of-thought.tsx +170 -0
- package/src/components/chat-container.stories.tsx +47 -0
- package/src/components/chat-container.test.tsx +49 -0
- package/src/components/chat-container.tsx +222 -0
- package/src/components/chat-message.stories.tsx +52 -0
- package/src/components/chat-message.test.tsx +36 -0
- package/src/components/chat-message.tsx +163 -0
- package/src/components/checkbox-card.stories.tsx +27 -0
- package/src/components/checkbox-card.tsx +200 -0
- package/src/components/checkbox.stories.tsx +26 -0
- package/src/components/checkbox.tsx +61 -0
- package/src/components/citations.stories.tsx +64 -0
- package/src/components/citations.test.tsx +61 -0
- package/src/components/citations.tsx +220 -0
- package/src/components/combobox.stories.tsx +184 -0
- package/src/components/combobox.test.tsx +82 -0
- package/src/components/combobox.tsx +407 -0
- package/src/components/countdown-pill.stories.tsx +24 -0
- package/src/components/countdown-pill.tsx +129 -0
- package/src/components/cta.stories.tsx +29 -0
- package/src/components/cta.tsx +52 -0
- package/src/components/data-list.stories.tsx +50 -0
- package/src/components/data-list.test.tsx +35 -0
- package/src/components/data-list.tsx +181 -0
- package/src/components/data-table.stories.tsx +29 -0
- package/src/components/data-table.tsx +200 -0
- package/src/components/dialog.stories.tsx +42 -0
- package/src/components/dialog.tsx +200 -0
- package/src/components/drawer.stories.tsx +48 -0
- package/src/components/drawer.tsx +385 -0
- package/src/components/dropdown-menu.stories.tsx +41 -0
- package/src/components/dropdown-menu.tsx +252 -0
- package/src/components/dropzone.stories.tsx +19 -0
- package/src/components/dropzone.tsx +250 -0
- package/src/components/email-chips-input.stories.tsx +135 -0
- package/src/components/email-chips-input.tsx +210 -0
- package/src/components/empty-state.stories.tsx +22 -0
- package/src/components/empty-state.tsx +35 -0
- package/src/components/entity-header.stories.tsx +43 -0
- package/src/components/entity-header.test.tsx +35 -0
- package/src/components/entity-header.tsx +92 -0
- package/src/components/feature-grid.stories.tsx +25 -0
- package/src/components/feature-grid.tsx +87 -0
- package/src/components/feedback-bar.stories.tsx +25 -0
- package/src/components/feedback-bar.test.tsx +24 -0
- package/src/components/feedback-bar.tsx +62 -0
- package/src/components/footer.stories.tsx +23 -0
- package/src/components/footer.tsx +78 -0
- package/src/components/heading.stories.tsx +45 -0
- package/src/components/heading.test.tsx +22 -0
- package/src/components/heading.tsx +77 -0
- package/src/components/hero.stories.tsx +38 -0
- package/src/components/hero.tsx +498 -0
- package/src/components/input-button.stories.tsx +19 -0
- package/src/components/input-button.tsx +112 -0
- package/src/components/input-group.stories.tsx +38 -0
- package/src/components/input-group.tsx +157 -0
- package/src/components/input.stories.tsx +31 -0
- package/src/components/input.tsx +284 -0
- package/src/components/inset.stories.tsx +29 -0
- package/src/components/inset.tsx +70 -0
- package/src/components/kpi-card.stories.tsx +29 -0
- package/src/components/kpi-card.tsx +284 -0
- package/src/components/list-nav.stories.tsx +22 -0
- package/src/components/list-nav.tsx +145 -0
- package/src/components/logo-cloud.stories.tsx +23 -0
- package/src/components/logo-cloud.tsx +42 -0
- package/src/components/media-gallery.stories.tsx +25 -0
- package/src/components/media-gallery.tsx +347 -0
- package/src/components/message-actions.stories.tsx +45 -0
- package/src/components/message-actions.test.tsx +32 -0
- package/src/components/message-actions.tsx +119 -0
- package/src/components/nav-sidebar.stories.tsx +58 -0
- package/src/components/nav-sidebar.test.tsx +54 -0
- package/src/components/nav-sidebar.tsx +462 -0
- package/src/components/number-stepper.stories.tsx +19 -0
- package/src/components/number-stepper.tsx +158 -0
- package/src/components/page-header.stories.tsx +25 -0
- package/src/components/page-header.tsx +64 -0
- package/src/components/pagination.stories.tsx +110 -0
- package/src/components/pagination.test.tsx +46 -0
- package/src/components/pagination.tsx +144 -0
- package/src/components/popover.stories.tsx +26 -0
- package/src/components/popover.tsx +62 -0
- package/src/components/pricing.stories.tsx +42 -0
- package/src/components/pricing.tsx +130 -0
- package/src/components/progress.stories.tsx +22 -0
- package/src/components/progress.tsx +189 -0
- package/src/components/prompt-input.stories.tsx +62 -0
- package/src/components/prompt-input.test.tsx +106 -0
- package/src/components/prompt-input.tsx +343 -0
- package/src/components/prompt-suggestions.stories.tsx +53 -0
- package/src/components/prompt-suggestions.test.tsx +37 -0
- package/src/components/prompt-suggestions.tsx +122 -0
- package/src/components/quota-bar.stories.tsx +19 -0
- package/src/components/quota-bar.tsx +191 -0
- package/src/components/quote.stories.tsx +18 -0
- package/src/components/quote.tsx +43 -0
- package/src/components/radio-card.stories.tsx +27 -0
- package/src/components/radio-card.tsx +225 -0
- package/src/components/radio-group.stories.tsx +32 -0
- package/src/components/radio-group.tsx +68 -0
- package/src/components/reasoning.stories.tsx +50 -0
- package/src/components/reasoning.test.tsx +48 -0
- package/src/components/reasoning.tsx +143 -0
- package/src/components/search.stories.tsx +18 -0
- package/src/components/search.tsx +133 -0
- package/src/components/section-nav.stories.tsx +59 -0
- package/src/components/section-nav.test.tsx +36 -0
- package/src/components/section-nav.tsx +146 -0
- package/src/components/segmented-control.stories.tsx +22 -0
- package/src/components/segmented-control.tsx +301 -0
- package/src/components/select-button.stories.tsx +27 -0
- package/src/components/select-button.tsx +174 -0
- package/src/components/select.stories.tsx +27 -0
- package/src/components/select.tsx +198 -0
- package/src/components/separator.stories.tsx +22 -0
- package/src/components/separator.tsx +23 -0
- package/src/components/shimmer-text.stories.tsx +23 -0
- package/src/components/shimmer-text.test.tsx +35 -0
- package/src/components/shimmer-text.tsx +43 -0
- package/src/components/sidebar.stories.tsx +25 -0
- package/src/components/sidebar.tsx +234 -0
- package/src/components/skeleton.stories.tsx +22 -0
- package/src/components/skeleton.tsx +96 -0
- package/src/components/slider.stories.tsx +20 -0
- package/src/components/slider.tsx +176 -0
- package/src/components/slideshow.stories.tsx +30 -0
- package/src/components/slideshow.tsx +291 -0
- package/src/components/source.stories.tsx +32 -0
- package/src/components/source.test.tsx +40 -0
- package/src/components/source.tsx +161 -0
- package/src/components/spinner.stories.tsx +19 -0
- package/src/components/spinner.tsx +76 -0
- package/src/components/stat-strip.stories.tsx +36 -0
- package/src/components/stat-strip.test.tsx +25 -0
- package/src/components/stat-strip.tsx +85 -0
- package/src/components/stats.stories.tsx +24 -0
- package/src/components/stats.tsx +83 -0
- package/src/components/step-indicator.stories.tsx +18 -0
- package/src/components/step-indicator.test.tsx +18 -0
- package/src/components/step-indicator.tsx +286 -0
- package/src/components/switch.stories.tsx +26 -0
- package/src/components/switch.tsx +32 -0
- package/src/components/table.stories.tsx +38 -0
- package/src/components/table.tsx +220 -0
- package/src/components/tabs.stories.tsx +25 -0
- package/src/components/tabs.tsx +276 -0
- package/src/components/testimonials.stories.tsx +22 -0
- package/src/components/testimonials.tsx +109 -0
- package/src/components/text-link.stories.tsx +47 -0
- package/src/components/text-link.test.tsx +18 -0
- package/src/components/text-link.tsx +88 -0
- package/src/components/text.stories.tsx +49 -0
- package/src/components/text.tsx +105 -0
- package/src/components/thinking-bar.stories.tsx +19 -0
- package/src/components/thinking-bar.test.tsx +27 -0
- package/src/components/thinking-bar.tsx +64 -0
- package/src/components/thinking-steps.stories.tsx +44 -0
- package/src/components/thinking-steps.test.tsx +42 -0
- package/src/components/thinking-steps.tsx +92 -0
- package/src/components/toaster.stories.tsx +80 -0
- package/src/components/toaster.tsx +36 -0
- package/src/components/toggle.stories.tsx +21 -0
- package/src/components/toggle.tsx +103 -0
- package/src/components/tool-call-card.stories.tsx +97 -0
- package/src/components/tool-call-card.test.tsx +88 -0
- package/src/components/tool-call-card.tsx +231 -0
- package/src/components/tooltip.stories.tsx +25 -0
- package/src/components/tooltip.tsx +43 -0
- package/src/components/top-nav.stories.tsx +20 -0
- package/src/components/top-nav.tsx +76 -0
- package/src/docs/Colors.stories.tsx +192 -0
- package/src/docs/GettingStarted.mdx +72 -0
- package/src/docs/Mcp.mdx +52 -0
- package/src/docs/Typography.stories.tsx +114 -0
- package/src/hooks/use-in-view.ts +32 -0
- package/src/hooks/use-reduced-motion.ts +26 -0
- package/src/index.ts +343 -0
- package/src/lib/cn.test.ts +67 -0
- package/src/lib/cn.ts +81 -0
- package/src/lib/motion.ts +109 -0
- package/src/lib/prefix-utilities.test.ts +56 -0
- package/src/lib/prefix-utilities.ts +50 -0
- package/src/styles/base.css +489 -0
- package/src/styles/motion.css +69 -0
- package/src/styles/overrides.css +44 -0
- package/src/styles/typography.css +173 -0
- package/src/theme/theme.css +391 -0
- package/src/theme/tokens.ts +29 -0
- package/src/theme/types.ts +26 -0
- package/README.md +0 -3
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
3
|
+
|
|
4
|
+
interface Swatch {
|
|
5
|
+
className: string
|
|
6
|
+
label: string
|
|
7
|
+
token: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function ColorSwatch({ className, label, token }: Swatch) {
|
|
11
|
+
return (
|
|
12
|
+
<div className="ax:flex ax:flex-col ax:gap-1.5">
|
|
13
|
+
<div className={`ax:h-16 ax:rounded-md ax:border ax:border-border ${className}`} />
|
|
14
|
+
<div className="ax:flex ax:flex-col">
|
|
15
|
+
<span className="ax:t-label-sm ax:text-foreground">{label}</span>
|
|
16
|
+
<span className="ax:t-caption ax:text-muted-foreground">{token}</span>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function ColorGroup({ title, swatches }: { title: string; swatches: Swatch[] }) {
|
|
23
|
+
return (
|
|
24
|
+
<section className="ax:flex ax:flex-col ax:gap-3">
|
|
25
|
+
<h2 className="ax:t-h3 ax:text-foreground-strong">{title}</h2>
|
|
26
|
+
<div className="ax:grid ax:grid-cols-2 ax:gap-4 ax:sm:grid-cols-4 ax:lg:grid-cols-7">
|
|
27
|
+
{swatches.map((swatch) => (
|
|
28
|
+
<ColorSwatch key={swatch.token} {...swatch} />
|
|
29
|
+
))}
|
|
30
|
+
</div>
|
|
31
|
+
</section>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const SURFACE_SWATCHES: Swatch[] = [
|
|
36
|
+
{ className: "ax:bg-background", label: "Background", token: "--background" },
|
|
37
|
+
{ className: "ax:bg-foreground", label: "Foreground", token: "--foreground" },
|
|
38
|
+
{ className: "ax:bg-foreground-strong", label: "Foreground strong", token: "--foreground-strong" },
|
|
39
|
+
{ className: "ax:bg-foreground-muted", label: "Foreground muted", token: "--foreground-muted" },
|
|
40
|
+
{ className: "ax:bg-card", label: "Card", token: "--card" },
|
|
41
|
+
{ className: "ax:bg-card-foreground", label: "Card foreground", token: "--card-foreground" },
|
|
42
|
+
{ className: "ax:bg-popover", label: "Popover", token: "--popover" },
|
|
43
|
+
{ className: "ax:bg-popover-foreground", label: "Popover foreground", token: "--popover-foreground" },
|
|
44
|
+
{ className: "ax:bg-muted", label: "Muted", token: "--muted" },
|
|
45
|
+
{ className: "ax:bg-muted-foreground", label: "Muted foreground", token: "--muted-foreground" },
|
|
46
|
+
{ className: "ax:bg-border", label: "Border", token: "--border" },
|
|
47
|
+
{ className: "ax:bg-border-strong", label: "Border strong", token: "--border-strong" },
|
|
48
|
+
{ className: "ax:bg-input", label: "Input", token: "--input" },
|
|
49
|
+
{ className: "ax:bg-ring", label: "Ring", token: "--ring" },
|
|
50
|
+
{ className: "ax:bg-selected", label: "Selected", token: "--selected" },
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
const SURFACE_STACK_SWATCHES: Swatch[] = [
|
|
54
|
+
{ className: "ax:bg-surface-n1", label: "Surface -1", token: "--surface-n1" },
|
|
55
|
+
{ className: "ax:bg-surface-0", label: "Surface 0", token: "--surface-0" },
|
|
56
|
+
{ className: "ax:bg-surface-1", label: "Surface 1", token: "--surface-1" },
|
|
57
|
+
{ className: "ax:bg-surface-2", label: "Surface 2", token: "--surface-2" },
|
|
58
|
+
{ className: "ax:bg-surface-3", label: "Surface 3", token: "--surface-3" },
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
const PRIMARY_SWATCHES: Swatch[] = [
|
|
62
|
+
{ className: "ax:bg-primary-weakest", label: "weakest", token: "--primary-weakest" },
|
|
63
|
+
{ className: "ax:bg-primary-weaker", label: "weaker", token: "--primary-weaker" },
|
|
64
|
+
{ className: "ax:bg-primary-weak", label: "weak", token: "--primary-weak" },
|
|
65
|
+
{ className: "ax:bg-primary", label: "base", token: "--primary" },
|
|
66
|
+
{ className: "ax:bg-primary-strong", label: "strong", token: "--primary-strong" },
|
|
67
|
+
{ className: "ax:bg-primary-stronger", label: "stronger", token: "--primary-stronger" },
|
|
68
|
+
{ className: "ax:bg-primary-strongest", label: "strongest", token: "--primary-strongest" },
|
|
69
|
+
{ className: "ax:bg-primary-foreground", label: "foreground", token: "--primary-foreground" },
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
const SECONDARY_SWATCHES: Swatch[] = [
|
|
73
|
+
{ className: "ax:bg-secondary-weakest", label: "weakest", token: "--secondary-weakest" },
|
|
74
|
+
{ className: "ax:bg-secondary-weaker", label: "weaker", token: "--secondary-weaker" },
|
|
75
|
+
{ className: "ax:bg-secondary-weak", label: "weak", token: "--secondary-weak" },
|
|
76
|
+
{ className: "ax:bg-secondary", label: "base", token: "--secondary" },
|
|
77
|
+
{ className: "ax:bg-secondary-strong", label: "strong", token: "--secondary-strong" },
|
|
78
|
+
{ className: "ax:bg-secondary-stronger", label: "stronger", token: "--secondary-stronger" },
|
|
79
|
+
{ className: "ax:bg-secondary-strongest", label: "strongest", token: "--secondary-strongest" },
|
|
80
|
+
{ className: "ax:bg-secondary-foreground", label: "foreground", token: "--secondary-foreground" },
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
const ACCENT_SWATCHES: Swatch[] = [
|
|
84
|
+
{ className: "ax:bg-accent-weakest", label: "weakest", token: "--accent-weakest" },
|
|
85
|
+
{ className: "ax:bg-accent-weaker", label: "weaker", token: "--accent-weaker" },
|
|
86
|
+
{ className: "ax:bg-accent-weak", label: "weak", token: "--accent-weak" },
|
|
87
|
+
{ className: "ax:bg-accent", label: "base", token: "--accent" },
|
|
88
|
+
{ className: "ax:bg-accent-strong", label: "strong", token: "--accent-strong" },
|
|
89
|
+
{ className: "ax:bg-accent-stronger", label: "stronger", token: "--accent-stronger" },
|
|
90
|
+
{ className: "ax:bg-accent-strongest", label: "strongest", token: "--accent-strongest" },
|
|
91
|
+
{ className: "ax:bg-accent-foreground", label: "foreground", token: "--accent-foreground" },
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
const TERTIARY_SWATCHES: Swatch[] = [
|
|
95
|
+
{ className: "ax:bg-tertiary-weakest", label: "weakest", token: "--tertiary-weakest" },
|
|
96
|
+
{ className: "ax:bg-tertiary-weaker", label: "weaker", token: "--tertiary-weaker" },
|
|
97
|
+
{ className: "ax:bg-tertiary-weak", label: "weak", token: "--tertiary-weak" },
|
|
98
|
+
{ className: "ax:bg-tertiary", label: "base", token: "--tertiary" },
|
|
99
|
+
{ className: "ax:bg-tertiary-strong", label: "strong", token: "--tertiary-strong" },
|
|
100
|
+
{ className: "ax:bg-tertiary-stronger", label: "stronger", token: "--tertiary-stronger" },
|
|
101
|
+
{ className: "ax:bg-tertiary-strongest", label: "strongest", token: "--tertiary-strongest" },
|
|
102
|
+
{ className: "ax:bg-tertiary-foreground", label: "foreground", token: "--tertiary-foreground" },
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
const DESTRUCTIVE_SWATCHES: Swatch[] = [
|
|
106
|
+
{ className: "ax:bg-destructive-weakest", label: "weakest", token: "--destructive-weakest" },
|
|
107
|
+
{ className: "ax:bg-destructive-weaker", label: "weaker", token: "--destructive-weaker" },
|
|
108
|
+
{ className: "ax:bg-destructive-weak", label: "weak", token: "--destructive-weak" },
|
|
109
|
+
{ className: "ax:bg-destructive", label: "base", token: "--destructive" },
|
|
110
|
+
{ className: "ax:bg-destructive-strong", label: "strong", token: "--destructive-strong" },
|
|
111
|
+
{ className: "ax:bg-destructive-stronger", label: "stronger", token: "--destructive-stronger" },
|
|
112
|
+
{ className: "ax:bg-destructive-strongest", label: "strongest", token: "--destructive-strongest" },
|
|
113
|
+
{ className: "ax:bg-destructive-foreground", label: "foreground", token: "--destructive-foreground" },
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
const SUCCESS_SWATCHES: Swatch[] = [
|
|
117
|
+
{ className: "ax:bg-success-weakest", label: "weakest", token: "--success-weakest" },
|
|
118
|
+
{ className: "ax:bg-success-weaker", label: "weaker", token: "--success-weaker" },
|
|
119
|
+
{ className: "ax:bg-success-weak", label: "weak", token: "--success-weak" },
|
|
120
|
+
{ className: "ax:bg-success", label: "base", token: "--success" },
|
|
121
|
+
{ className: "ax:bg-success-strong", label: "strong", token: "--success-strong" },
|
|
122
|
+
{ className: "ax:bg-success-stronger", label: "stronger", token: "--success-stronger" },
|
|
123
|
+
{ className: "ax:bg-success-strongest", label: "strongest", token: "--success-strongest" },
|
|
124
|
+
{ className: "ax:bg-success-foreground", label: "foreground", token: "--success-foreground" },
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
const WARNING_SWATCHES: Swatch[] = [
|
|
128
|
+
{ className: "ax:bg-warning-weakest", label: "weakest", token: "--warning-weakest" },
|
|
129
|
+
{ className: "ax:bg-warning-weaker", label: "weaker", token: "--warning-weaker" },
|
|
130
|
+
{ className: "ax:bg-warning-weak", label: "weak", token: "--warning-weak" },
|
|
131
|
+
{ className: "ax:bg-warning", label: "base", token: "--warning" },
|
|
132
|
+
{ className: "ax:bg-warning-strong", label: "strong", token: "--warning-strong" },
|
|
133
|
+
{ className: "ax:bg-warning-stronger", label: "stronger", token: "--warning-stronger" },
|
|
134
|
+
{ className: "ax:bg-warning-strongest", label: "strongest", token: "--warning-strongest" },
|
|
135
|
+
{ className: "ax:bg-warning-foreground", label: "foreground", token: "--warning-foreground" },
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
const NEUTRAL_SWATCHES: Swatch[] = [
|
|
139
|
+
{ className: "ax:bg-neutral-weakest", label: "weakest", token: "--neutral-weakest" },
|
|
140
|
+
{ className: "ax:bg-neutral-weaker", label: "weaker", token: "--neutral-weaker" },
|
|
141
|
+
{ className: "ax:bg-neutral-weak", label: "weak", token: "--neutral-weak" },
|
|
142
|
+
{ className: "ax:bg-neutral", label: "base", token: "--neutral" },
|
|
143
|
+
{ className: "ax:bg-neutral-strong", label: "strong", token: "--neutral-strong" },
|
|
144
|
+
{ className: "ax:bg-neutral-stronger", label: "stronger", token: "--neutral-stronger" },
|
|
145
|
+
{ className: "ax:bg-neutral-strongest", label: "strongest", token: "--neutral-strongest" },
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
const CHART_SWATCHES: Swatch[] = [
|
|
149
|
+
{ className: "ax:bg-chart-1", label: "Chart 1", token: "--chart-1" },
|
|
150
|
+
{ className: "ax:bg-chart-2", label: "Chart 2", token: "--chart-2" },
|
|
151
|
+
{ className: "ax:bg-chart-3", label: "Chart 3", token: "--chart-3" },
|
|
152
|
+
{ className: "ax:bg-chart-4", label: "Chart 4", token: "--chart-4" },
|
|
153
|
+
{ className: "ax:bg-chart-5", label: "Chart 5", token: "--chart-5" },
|
|
154
|
+
{ className: "ax:bg-chart-6", label: "Chart 6", token: "--chart-6" },
|
|
155
|
+
{ className: "ax:bg-chart-7", label: "Chart 7", token: "--chart-7" },
|
|
156
|
+
{ className: "ax:bg-chart-8", label: "Chart 8", token: "--chart-8" },
|
|
157
|
+
{ className: "ax:bg-chart-9", label: "Chart 9", token: "--chart-9" },
|
|
158
|
+
{ className: "ax:bg-chart-10", label: "Chart 10", token: "--chart-10" },
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
function ColorsPage() {
|
|
162
|
+
return (
|
|
163
|
+
<div className="ax:flex ax:flex-col ax:gap-10">
|
|
164
|
+
<p className="ax:t-body-md ax:text-muted-foreground">
|
|
165
|
+
Every swatch below is a semantic Tailwind utility (e.g. <code className="ax:t-code">ax:bg-primary</code>), never a
|
|
166
|
+
literal brand color. Switch the brand toolbar above to see every value repaint at runtime.
|
|
167
|
+
</p>
|
|
168
|
+
<ColorGroup title="Surfaces & structure" swatches={SURFACE_SWATCHES} />
|
|
169
|
+
<ColorGroup title="Surface stack" swatches={SURFACE_STACK_SWATCHES} />
|
|
170
|
+
<ColorGroup title="Primary" swatches={PRIMARY_SWATCHES} />
|
|
171
|
+
<ColorGroup title="Secondary" swatches={SECONDARY_SWATCHES} />
|
|
172
|
+
<ColorGroup title="Accent" swatches={ACCENT_SWATCHES} />
|
|
173
|
+
<ColorGroup title="Tertiary" swatches={TERTIARY_SWATCHES} />
|
|
174
|
+
<ColorGroup title="Destructive" swatches={DESTRUCTIVE_SWATCHES} />
|
|
175
|
+
<ColorGroup title="Success" swatches={SUCCESS_SWATCHES} />
|
|
176
|
+
<ColorGroup title="Warning" swatches={WARNING_SWATCHES} />
|
|
177
|
+
<ColorGroup title="Neutral" swatches={NEUTRAL_SWATCHES} />
|
|
178
|
+
<ColorGroup title="Chart palette" swatches={CHART_SWATCHES} />
|
|
179
|
+
</div>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const meta: Meta<typeof ColorsPage> = {
|
|
184
|
+
title: "Foundation/Colors",
|
|
185
|
+
component: ColorsPage,
|
|
186
|
+
parameters: { layout: "padded" },
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export default meta
|
|
190
|
+
type Story = StoryObj<typeof ColorsPage>
|
|
191
|
+
|
|
192
|
+
export const Default: Story = {}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Meta, Title, Subtitle } from "@storybook/blocks"
|
|
2
|
+
|
|
3
|
+
<Meta title="Docs/Getting Started" />
|
|
4
|
+
|
|
5
|
+
<Title>Getting Started</Title>
|
|
6
|
+
|
|
7
|
+
<Subtitle>Install and use @adres/mgda-ui from npm</Subtitle>
|
|
8
|
+
|
|
9
|
+
Packages are published publicly on [npmjs.com](https://www.npmjs.com) under the `@adres` scope. No special `.npmrc` is required.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @adres/mgda-ui
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Peer dependencies (install in your app if not already present):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install react@19 react-dom@19 tailwindcss@4
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Wire CSS
|
|
24
|
+
|
|
25
|
+
Import order matters with Tailwind CSS 4 and CSS-variable theming:
|
|
26
|
+
|
|
27
|
+
```css
|
|
28
|
+
@import "tailwindcss" prefix(ax);
|
|
29
|
+
|
|
30
|
+
/* Scan the design-system source so semantic utilities are emitted */
|
|
31
|
+
@source "../node_modules/@adres/mgda-ui/src";
|
|
32
|
+
|
|
33
|
+
@import "@adres/mgda-ui/styles";
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Dark mode
|
|
37
|
+
|
|
38
|
+
The MGDA theme is the default on `:root`. For dark mode: add `class="dark"` (or `data-theme="dark"`) on the same element.
|
|
39
|
+
|
|
40
|
+
## Use components
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { Button, Card, CardHeader, CardTitle, CardContent } from "@adres/mgda-ui"
|
|
44
|
+
|
|
45
|
+
export function Example() {
|
|
46
|
+
return (
|
|
47
|
+
<Card>
|
|
48
|
+
<CardHeader>
|
|
49
|
+
<CardTitle>Hello</CardTitle>
|
|
50
|
+
</CardHeader>
|
|
51
|
+
<CardContent>
|
|
52
|
+
<Button variant="primary">Get started</Button>
|
|
53
|
+
</CardContent>
|
|
54
|
+
</Card>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Requirements
|
|
60
|
+
|
|
61
|
+
- **Bundler:** Your app must transpile TypeScript from `node_modules` (Next.js, Vite, etc.). Package exports point at `src/`. There is no separate `dist` build yet.
|
|
62
|
+
- **Tailwind 4:** Add `@source` for `@adres/mgda-ui/src` in your global CSS so component utility classes are scanned.
|
|
63
|
+
- **Tokens only:** Do not hardcode colours: use semantic utilities (`ax:bg-primary`, `ax:text-foreground`, etc.).
|
|
64
|
+
|
|
65
|
+
## Component stories
|
|
66
|
+
|
|
67
|
+
Every component under `src/components/` has a story in Storybook under **Components**.
|
|
68
|
+
|
|
69
|
+
## Links
|
|
70
|
+
|
|
71
|
+
- [npm: @adres/mgda-ui](https://www.npmjs.com/package/@adres/mgda-ui)
|
|
72
|
+
- Repo README: publishing and theme validation (`npm run validate:brands`)
|
package/src/docs/Mcp.mdx
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Meta, Title, Subtitle } from "@storybook/blocks"
|
|
2
|
+
|
|
3
|
+
<Meta title="Docs/MCP" />
|
|
4
|
+
|
|
5
|
+
<Title>DLS MCP</Title>
|
|
6
|
+
|
|
7
|
+
<Subtitle>Connect @adres/dls-mcp so an AI client can use the design system</Subtitle>
|
|
8
|
+
|
|
9
|
+
`@adres/dls-mcp` is the MCP server for this design system. It is a separate npm package from `@adres/mgda-ui`. Paste one config below into the client MCP settings. The key `adresx-dls` is the label the client shows.
|
|
10
|
+
|
|
11
|
+
The [dls-mcp README](https://github.com/adres-dls/dls-mcp#connecting-a-client) is the source of truth if the URL or auth shape changes.
|
|
12
|
+
|
|
13
|
+
## Local (stdio)
|
|
14
|
+
|
|
15
|
+
Node 20 or newer. `npx` downloads the published package. No clone and no token.
|
|
16
|
+
|
|
17
|
+
Cursor reads this from `.cursor/mcp.json`. Claude Code reads the same JSON from `.mcp.json`.
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"adresx-dls": {
|
|
23
|
+
"command": "npx",
|
|
24
|
+
"args": ["-y", "@adres/dls-mcp"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Hosted (HTTP)
|
|
31
|
+
|
|
32
|
+
The deployed server is [https://dls-mcp.vercel.app/mcp](https://dls-mcp.vercel.app/mcp). Every request needs a bearer token. Ask a maintainer for the current value, and keep it out of the repo.
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"adresx-dls": {
|
|
38
|
+
"url": "https://dls-mcp.vercel.app/mcp",
|
|
39
|
+
"headers": {
|
|
40
|
+
"Authorization": "Bearer <token>"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The endpoint is streamable HTTP on `POST /mcp`. When a client asks for a transport, choose `http`.
|
|
48
|
+
|
|
49
|
+
## Links
|
|
50
|
+
|
|
51
|
+
- [npm: @adres/dls-mcp](https://www.npmjs.com/package/@adres/dls-mcp)
|
|
52
|
+
- [GitHub: adres-dls/dls-mcp](https://github.com/adres-dls/dls-mcp)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
3
|
+
|
|
4
|
+
interface Specimen {
|
|
5
|
+
className: string
|
|
6
|
+
label: string
|
|
7
|
+
sample?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const SAMPLE_TEXT = "The quick brown fox jumps over the lazy dog"
|
|
11
|
+
|
|
12
|
+
function TypeSpecimen({ className, label, sample = SAMPLE_TEXT }: Specimen) {
|
|
13
|
+
return (
|
|
14
|
+
<div className="ax:flex ax:flex-col ax:gap-1 ax:border-b ax:border-border ax:pb-4">
|
|
15
|
+
<div className={className}>{sample}</div>
|
|
16
|
+
<span className="ax:t-caption ax:text-muted-foreground">
|
|
17
|
+
{label} - <code className="ax:t-code">{className}</code>
|
|
18
|
+
</span>
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function TypeSection({ title, specimens }: { title: string; specimens: Specimen[] }) {
|
|
24
|
+
return (
|
|
25
|
+
<section className="ax:flex ax:flex-col ax:gap-4">
|
|
26
|
+
<h2 className="ax:t-h3 ax:text-foreground-strong">{title}</h2>
|
|
27
|
+
<div className="ax:flex ax:flex-col ax:gap-4">
|
|
28
|
+
{specimens.map((specimen) => (
|
|
29
|
+
<TypeSpecimen key={specimen.className} {...specimen} />
|
|
30
|
+
))}
|
|
31
|
+
</div>
|
|
32
|
+
</section>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const DISPLAY_SPECIMENS: Specimen[] = [
|
|
37
|
+
{ className: "ax:t-display-3xl", label: "Display 3XL" },
|
|
38
|
+
{ className: "ax:t-display-2xl", label: "Display 2XL" },
|
|
39
|
+
{ className: "ax:t-display-xl", label: "Display XL" },
|
|
40
|
+
{ className: "ax:t-display-lg", label: "Display LG" },
|
|
41
|
+
{ className: "ax:t-display-md", label: "Display MD" },
|
|
42
|
+
{ className: "ax:t-display-sm", label: "Display SM" },
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
const HEADING_SPECIMENS: Specimen[] = [
|
|
46
|
+
{ className: "ax:t-h1", label: "Heading 1" },
|
|
47
|
+
{ className: "ax:t-h2", label: "Heading 2" },
|
|
48
|
+
{ className: "ax:t-h3", label: "Heading 3" },
|
|
49
|
+
{ className: "ax:t-h4", label: "Heading 4" },
|
|
50
|
+
{ className: "ax:t-h5", label: "Heading 5" },
|
|
51
|
+
{ className: "ax:t-h6", label: "Heading 6" },
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
const BODY_SPECIMENS: Specimen[] = [
|
|
55
|
+
{ className: "ax:t-body-xl", label: "Body XL" },
|
|
56
|
+
{ className: "ax:t-body-lg", label: "Body LG" },
|
|
57
|
+
{ className: "ax:t-body-md", label: "Body MD" },
|
|
58
|
+
{ className: "ax:t-body-sm", label: "Body SM" },
|
|
59
|
+
{ className: "ax:t-body-xs", label: "Body XS" },
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
const LABEL_SPECIMENS: Specimen[] = [
|
|
63
|
+
{ className: "ax:t-label-lg", label: "Label LG" },
|
|
64
|
+
{ className: "ax:t-label-md", label: "Label MD" },
|
|
65
|
+
{ className: "ax:t-label-sm", label: "Label SM" },
|
|
66
|
+
{ className: "ax:t-label-xs", label: "Label XS" },
|
|
67
|
+
{ className: "ax:t-label-2xs", label: "Label 2XS" },
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
const MISC_SPECIMENS: Specimen[] = [
|
|
71
|
+
{ className: "ax:t-caption", label: "Caption" },
|
|
72
|
+
{ className: "ax:t-overline", label: "Overline" },
|
|
73
|
+
{ className: "ax:t-code", label: "Code", sample: "const brand = \"adres\"" },
|
|
74
|
+
{ className: "ax:t-micro", label: "Micro" },
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
function TypographyPage() {
|
|
78
|
+
return (
|
|
79
|
+
<div className="ax:flex ax:flex-col ax:gap-10">
|
|
80
|
+
<p className="ax:t-body-md ax:text-muted-foreground">
|
|
81
|
+
Every specimen below is a single semantic utility class (font-size, weight, line-height, and
|
|
82
|
+
letter-spacing bundled together). Switch the brand toolbar above to see the active brand's
|
|
83
|
+
font families take effect.
|
|
84
|
+
</p>
|
|
85
|
+
<section className="ax:flex ax:flex-col ax:gap-4">
|
|
86
|
+
<h2 className="ax:t-h3 ax:text-foreground-strong">Font families</h2>
|
|
87
|
+
<div className="ax:flex ax:flex-col ax:gap-4">
|
|
88
|
+
<div className="ax:flex ax:flex-col ax:gap-1 ax:border-b ax:border-border ax:pb-4">
|
|
89
|
+
<p className="ax:font-sans ax:text-lg">{SAMPLE_TEXT}</p>
|
|
90
|
+
<span className="ax:t-caption ax:text-muted-foreground">
|
|
91
|
+
Sans - <code className="ax:t-code">font-sans</code>
|
|
92
|
+
</span>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</section>
|
|
96
|
+
<TypeSection title="Display" specimens={DISPLAY_SPECIMENS} />
|
|
97
|
+
<TypeSection title="Heading" specimens={HEADING_SPECIMENS} />
|
|
98
|
+
<TypeSection title="Body" specimens={BODY_SPECIMENS} />
|
|
99
|
+
<TypeSection title="Label" specimens={LABEL_SPECIMENS} />
|
|
100
|
+
<TypeSection title="Caption, overline, code & micro" specimens={MISC_SPECIMENS} />
|
|
101
|
+
</div>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const meta: Meta<typeof TypographyPage> = {
|
|
106
|
+
title: "Foundation/Typography",
|
|
107
|
+
component: TypographyPage,
|
|
108
|
+
parameters: { layout: "padded" },
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export default meta
|
|
112
|
+
type Story = StoryObj<typeof TypographyPage>
|
|
113
|
+
|
|
114
|
+
export const Default: Story = {}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState } from "react"
|
|
4
|
+
|
|
5
|
+
// Returns [ref, inView] where inView flips true once the element scrolls into view.
|
|
6
|
+
// Disconnects the observer after first intersection, same semantics as whileInView once:true.
|
|
7
|
+
export function useInView<T extends Element = HTMLElement>(
|
|
8
|
+
rootMargin = "-60px 0px"
|
|
9
|
+
): [React.MutableRefObject<T | null>, boolean] {
|
|
10
|
+
const ref = useRef<T | null>(null)
|
|
11
|
+
const [inView, setInView] = useState(false)
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const el = ref.current
|
|
15
|
+
if (!el || typeof IntersectionObserver === "undefined") return
|
|
16
|
+
|
|
17
|
+
const observer = new IntersectionObserver(
|
|
18
|
+
([entry]) => {
|
|
19
|
+
if (entry?.isIntersecting) {
|
|
20
|
+
setInView(true)
|
|
21
|
+
observer.disconnect()
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{ threshold: 0.1, rootMargin }
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
observer.observe(el)
|
|
28
|
+
return () => observer.disconnect()
|
|
29
|
+
}, [rootMargin])
|
|
30
|
+
|
|
31
|
+
return [ref, inView]
|
|
32
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from "react"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns `true` when the user has requested reduced motion via the OS.
|
|
7
|
+
* Animations should fall back to instant transitions when this returns true.
|
|
8
|
+
*
|
|
9
|
+
* SSR-safe: returns `false` on the server, then re-evaluates on mount.
|
|
10
|
+
*/
|
|
11
|
+
export function useReducedMotion(): boolean {
|
|
12
|
+
const [prefers, setPrefers] = useState(false)
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (typeof window === "undefined" || !window.matchMedia) return
|
|
16
|
+
|
|
17
|
+
const query = window.matchMedia("(prefers-reduced-motion: reduce)")
|
|
18
|
+
setPrefers(query.matches)
|
|
19
|
+
|
|
20
|
+
const handler = (event: MediaQueryListEvent) => setPrefers(event.matches)
|
|
21
|
+
query.addEventListener("change", handler)
|
|
22
|
+
return () => query.removeEventListener("change", handler)
|
|
23
|
+
}, [])
|
|
24
|
+
|
|
25
|
+
return prefers
|
|
26
|
+
}
|