@adres/mgda-ui 0.0.0-stage → 0.0.1

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.
Files changed (325) hide show
  1. package/brand-knowledge.json +451 -0
  2. package/knowledge/accordion.md +135 -0
  3. package/knowledge/activity-rings.md +123 -0
  4. package/knowledge/alert.md +184 -0
  5. package/knowledge/answer-actions.md +217 -0
  6. package/knowledge/aspect-ratio.md +82 -0
  7. package/knowledge/avatar.md +158 -0
  8. package/knowledge/badge.md +172 -0
  9. package/knowledge/bar-graph.md +167 -0
  10. package/knowledge/bento-grid.md +115 -0
  11. package/knowledge/blockquote.md +153 -0
  12. package/knowledge/box-list.md +177 -0
  13. package/knowledge/bullet-list.md +128 -0
  14. package/knowledge/button-group.md +179 -0
  15. package/knowledge/button.md +231 -0
  16. package/knowledge/calendar.md +168 -0
  17. package/knowledge/card.md +321 -0
  18. package/knowledge/cards-nav.md +170 -0
  19. package/knowledge/chain-of-thought.md +164 -0
  20. package/knowledge/chat-container.md +135 -0
  21. package/knowledge/chat-message.md +224 -0
  22. package/knowledge/checkbox-card.md +172 -0
  23. package/knowledge/checkbox.md +111 -0
  24. package/knowledge/citations.md +241 -0
  25. package/knowledge/combobox.md +265 -0
  26. package/knowledge/countdown-pill.md +153 -0
  27. package/knowledge/cta.md +118 -0
  28. package/knowledge/data-list.md +173 -0
  29. package/knowledge/data-table.md +220 -0
  30. package/knowledge/dialog.md +249 -0
  31. package/knowledge/drawer.md +236 -0
  32. package/knowledge/dropdown-menu.md +238 -0
  33. package/knowledge/dropzone.md +153 -0
  34. package/knowledge/email-chips-input.md +161 -0
  35. package/knowledge/empty-state.md +106 -0
  36. package/knowledge/entity-header.md +166 -0
  37. package/knowledge/feature-grid.md +120 -0
  38. package/knowledge/feedback-bar.md +127 -0
  39. package/knowledge/footer.md +116 -0
  40. package/knowledge/heading.md +189 -0
  41. package/knowledge/hero.md +361 -0
  42. package/knowledge/input-button.md +187 -0
  43. package/knowledge/input-group.md +185 -0
  44. package/knowledge/input.md +256 -0
  45. package/knowledge/inset.md +177 -0
  46. package/knowledge/kpi-card.md +206 -0
  47. package/knowledge/list-nav.md +181 -0
  48. package/knowledge/logo-cloud.md +102 -0
  49. package/knowledge/media-gallery.md +158 -0
  50. package/knowledge/message-actions.md +175 -0
  51. package/knowledge/nav-sidebar.md +225 -0
  52. package/knowledge/number-stepper.md +159 -0
  53. package/knowledge/page-header.md +109 -0
  54. package/knowledge/pagination.md +225 -0
  55. package/knowledge/popover.md +159 -0
  56. package/knowledge/pricing.md +132 -0
  57. package/knowledge/progress.md +156 -0
  58. package/knowledge/prompt-input.md +337 -0
  59. package/knowledge/prompt-suggestions.md +168 -0
  60. package/knowledge/quota-bar.md +160 -0
  61. package/knowledge/quote.md +116 -0
  62. package/knowledge/radio-card.md +172 -0
  63. package/knowledge/radio-group.md +135 -0
  64. package/knowledge/reasoning.md +142 -0
  65. package/knowledge/search.md +131 -0
  66. package/knowledge/section-nav.md +162 -0
  67. package/knowledge/segmented-control.md +181 -0
  68. package/knowledge/select-button.md +205 -0
  69. package/knowledge/select.md +210 -0
  70. package/knowledge/separator.md +75 -0
  71. package/knowledge/shimmer-text.md +140 -0
  72. package/knowledge/sidebar.md +227 -0
  73. package/knowledge/skeleton.md +142 -0
  74. package/knowledge/slider.md +133 -0
  75. package/knowledge/slideshow.md +159 -0
  76. package/knowledge/source.md +156 -0
  77. package/knowledge/spinner.md +120 -0
  78. package/knowledge/stat-strip.md +128 -0
  79. package/knowledge/stats.md +117 -0
  80. package/knowledge/step-indicator.md +157 -0
  81. package/knowledge/switch.md +88 -0
  82. package/knowledge/table.md +190 -0
  83. package/knowledge/tabs.md +169 -0
  84. package/knowledge/testimonials.md +115 -0
  85. package/knowledge/text-link.md +192 -0
  86. package/knowledge/text.md +194 -0
  87. package/knowledge/thinking-bar.md +115 -0
  88. package/knowledge/thinking-steps.md +140 -0
  89. package/knowledge/toaster.md +127 -0
  90. package/knowledge/toggle.md +113 -0
  91. package/knowledge/tool-call-card.md +241 -0
  92. package/knowledge/tooltip.md +120 -0
  93. package/knowledge/top-nav.md +138 -0
  94. package/knowledge.json +19854 -0
  95. package/package.json +94 -4
  96. package/src/components/accordion.stories.tsx +46 -0
  97. package/src/components/accordion.tsx +74 -0
  98. package/src/components/activity-rings.stories.tsx +73 -0
  99. package/src/components/activity-rings.tsx +121 -0
  100. package/src/components/alert.stories.tsx +43 -0
  101. package/src/components/alert.tsx +132 -0
  102. package/src/components/answer-actions.stories.tsx +54 -0
  103. package/src/components/answer-actions.test.tsx +37 -0
  104. package/src/components/answer-actions.tsx +313 -0
  105. package/src/components/aspect-ratio.stories.tsx +32 -0
  106. package/src/components/aspect-ratio.tsx +5 -0
  107. package/src/components/avatar.stories.tsx +40 -0
  108. package/src/components/avatar.tsx +154 -0
  109. package/src/components/badge.stories.tsx +27 -0
  110. package/src/components/badge.tsx +63 -0
  111. package/src/components/bar-graph.stories.tsx +28 -0
  112. package/src/components/bar-graph.tsx +204 -0
  113. package/src/components/bento-grid.stories.tsx +23 -0
  114. package/src/components/bento-grid.tsx +67 -0
  115. package/src/components/blockquote.stories.tsx +28 -0
  116. package/src/components/blockquote.tsx +88 -0
  117. package/src/components/box-list.stories.tsx +25 -0
  118. package/src/components/box-list.tsx +108 -0
  119. package/src/components/bullet-list.stories.tsx +22 -0
  120. package/src/components/bullet-list.tsx +101 -0
  121. package/src/components/button-group.stories.tsx +31 -0
  122. package/src/components/button-group.tsx +156 -0
  123. package/src/components/button.stories.tsx +66 -0
  124. package/src/components/button.test.ts +17 -0
  125. package/src/components/button.tsx +139 -0
  126. package/src/components/calendar.stories.tsx +25 -0
  127. package/src/components/calendar.tsx +367 -0
  128. package/src/components/card.stories.tsx +44 -0
  129. package/src/components/card.tsx +392 -0
  130. package/src/components/cards-nav.stories.tsx +35 -0
  131. package/src/components/cards-nav.tsx +115 -0
  132. package/src/components/chain-of-thought.stories.tsx +67 -0
  133. package/src/components/chain-of-thought.test.tsx +50 -0
  134. package/src/components/chain-of-thought.tsx +170 -0
  135. package/src/components/chat-container.stories.tsx +47 -0
  136. package/src/components/chat-container.test.tsx +49 -0
  137. package/src/components/chat-container.tsx +222 -0
  138. package/src/components/chat-message.stories.tsx +52 -0
  139. package/src/components/chat-message.test.tsx +36 -0
  140. package/src/components/chat-message.tsx +163 -0
  141. package/src/components/checkbox-card.stories.tsx +27 -0
  142. package/src/components/checkbox-card.tsx +200 -0
  143. package/src/components/checkbox.stories.tsx +26 -0
  144. package/src/components/checkbox.tsx +61 -0
  145. package/src/components/citations.stories.tsx +64 -0
  146. package/src/components/citations.test.tsx +61 -0
  147. package/src/components/citations.tsx +220 -0
  148. package/src/components/combobox.stories.tsx +184 -0
  149. package/src/components/combobox.test.tsx +82 -0
  150. package/src/components/combobox.tsx +407 -0
  151. package/src/components/countdown-pill.stories.tsx +24 -0
  152. package/src/components/countdown-pill.tsx +129 -0
  153. package/src/components/cta.stories.tsx +29 -0
  154. package/src/components/cta.tsx +52 -0
  155. package/src/components/data-list.stories.tsx +50 -0
  156. package/src/components/data-list.test.tsx +35 -0
  157. package/src/components/data-list.tsx +181 -0
  158. package/src/components/data-table.stories.tsx +29 -0
  159. package/src/components/data-table.tsx +200 -0
  160. package/src/components/dialog.stories.tsx +42 -0
  161. package/src/components/dialog.tsx +200 -0
  162. package/src/components/drawer.stories.tsx +48 -0
  163. package/src/components/drawer.tsx +385 -0
  164. package/src/components/dropdown-menu.stories.tsx +41 -0
  165. package/src/components/dropdown-menu.tsx +252 -0
  166. package/src/components/dropzone.stories.tsx +19 -0
  167. package/src/components/dropzone.tsx +250 -0
  168. package/src/components/email-chips-input.stories.tsx +135 -0
  169. package/src/components/email-chips-input.tsx +210 -0
  170. package/src/components/empty-state.stories.tsx +22 -0
  171. package/src/components/empty-state.tsx +35 -0
  172. package/src/components/entity-header.stories.tsx +43 -0
  173. package/src/components/entity-header.test.tsx +35 -0
  174. package/src/components/entity-header.tsx +92 -0
  175. package/src/components/feature-grid.stories.tsx +25 -0
  176. package/src/components/feature-grid.tsx +87 -0
  177. package/src/components/feedback-bar.stories.tsx +25 -0
  178. package/src/components/feedback-bar.test.tsx +24 -0
  179. package/src/components/feedback-bar.tsx +62 -0
  180. package/src/components/footer.stories.tsx +23 -0
  181. package/src/components/footer.tsx +78 -0
  182. package/src/components/heading.stories.tsx +45 -0
  183. package/src/components/heading.test.tsx +22 -0
  184. package/src/components/heading.tsx +77 -0
  185. package/src/components/hero.stories.tsx +38 -0
  186. package/src/components/hero.tsx +498 -0
  187. package/src/components/input-button.stories.tsx +19 -0
  188. package/src/components/input-button.tsx +112 -0
  189. package/src/components/input-group.stories.tsx +38 -0
  190. package/src/components/input-group.tsx +157 -0
  191. package/src/components/input.stories.tsx +31 -0
  192. package/src/components/input.tsx +284 -0
  193. package/src/components/inset.stories.tsx +29 -0
  194. package/src/components/inset.tsx +70 -0
  195. package/src/components/kpi-card.stories.tsx +29 -0
  196. package/src/components/kpi-card.tsx +284 -0
  197. package/src/components/list-nav.stories.tsx +22 -0
  198. package/src/components/list-nav.tsx +145 -0
  199. package/src/components/logo-cloud.stories.tsx +23 -0
  200. package/src/components/logo-cloud.tsx +42 -0
  201. package/src/components/media-gallery.stories.tsx +25 -0
  202. package/src/components/media-gallery.tsx +347 -0
  203. package/src/components/message-actions.stories.tsx +45 -0
  204. package/src/components/message-actions.test.tsx +32 -0
  205. package/src/components/message-actions.tsx +119 -0
  206. package/src/components/nav-sidebar.stories.tsx +58 -0
  207. package/src/components/nav-sidebar.test.tsx +54 -0
  208. package/src/components/nav-sidebar.tsx +462 -0
  209. package/src/components/number-stepper.stories.tsx +19 -0
  210. package/src/components/number-stepper.tsx +158 -0
  211. package/src/components/page-header.stories.tsx +25 -0
  212. package/src/components/page-header.tsx +64 -0
  213. package/src/components/pagination.stories.tsx +110 -0
  214. package/src/components/pagination.test.tsx +46 -0
  215. package/src/components/pagination.tsx +144 -0
  216. package/src/components/popover.stories.tsx +26 -0
  217. package/src/components/popover.tsx +62 -0
  218. package/src/components/pricing.stories.tsx +42 -0
  219. package/src/components/pricing.tsx +130 -0
  220. package/src/components/progress.stories.tsx +22 -0
  221. package/src/components/progress.tsx +189 -0
  222. package/src/components/prompt-input.stories.tsx +62 -0
  223. package/src/components/prompt-input.test.tsx +106 -0
  224. package/src/components/prompt-input.tsx +343 -0
  225. package/src/components/prompt-suggestions.stories.tsx +53 -0
  226. package/src/components/prompt-suggestions.test.tsx +37 -0
  227. package/src/components/prompt-suggestions.tsx +122 -0
  228. package/src/components/quota-bar.stories.tsx +19 -0
  229. package/src/components/quota-bar.tsx +191 -0
  230. package/src/components/quote.stories.tsx +18 -0
  231. package/src/components/quote.tsx +43 -0
  232. package/src/components/radio-card.stories.tsx +27 -0
  233. package/src/components/radio-card.tsx +225 -0
  234. package/src/components/radio-group.stories.tsx +32 -0
  235. package/src/components/radio-group.tsx +68 -0
  236. package/src/components/reasoning.stories.tsx +50 -0
  237. package/src/components/reasoning.test.tsx +48 -0
  238. package/src/components/reasoning.tsx +143 -0
  239. package/src/components/search.stories.tsx +18 -0
  240. package/src/components/search.tsx +133 -0
  241. package/src/components/section-nav.stories.tsx +59 -0
  242. package/src/components/section-nav.test.tsx +36 -0
  243. package/src/components/section-nav.tsx +146 -0
  244. package/src/components/segmented-control.stories.tsx +22 -0
  245. package/src/components/segmented-control.tsx +301 -0
  246. package/src/components/select-button.stories.tsx +27 -0
  247. package/src/components/select-button.tsx +174 -0
  248. package/src/components/select.stories.tsx +27 -0
  249. package/src/components/select.tsx +198 -0
  250. package/src/components/separator.stories.tsx +22 -0
  251. package/src/components/separator.tsx +23 -0
  252. package/src/components/shimmer-text.stories.tsx +23 -0
  253. package/src/components/shimmer-text.test.tsx +35 -0
  254. package/src/components/shimmer-text.tsx +43 -0
  255. package/src/components/sidebar.stories.tsx +25 -0
  256. package/src/components/sidebar.tsx +234 -0
  257. package/src/components/skeleton.stories.tsx +22 -0
  258. package/src/components/skeleton.tsx +96 -0
  259. package/src/components/slider.stories.tsx +20 -0
  260. package/src/components/slider.tsx +176 -0
  261. package/src/components/slideshow.stories.tsx +30 -0
  262. package/src/components/slideshow.tsx +291 -0
  263. package/src/components/source.stories.tsx +32 -0
  264. package/src/components/source.test.tsx +40 -0
  265. package/src/components/source.tsx +161 -0
  266. package/src/components/spinner.stories.tsx +19 -0
  267. package/src/components/spinner.tsx +76 -0
  268. package/src/components/stat-strip.stories.tsx +36 -0
  269. package/src/components/stat-strip.test.tsx +25 -0
  270. package/src/components/stat-strip.tsx +85 -0
  271. package/src/components/stats.stories.tsx +24 -0
  272. package/src/components/stats.tsx +83 -0
  273. package/src/components/step-indicator.stories.tsx +18 -0
  274. package/src/components/step-indicator.test.tsx +18 -0
  275. package/src/components/step-indicator.tsx +286 -0
  276. package/src/components/switch.stories.tsx +26 -0
  277. package/src/components/switch.tsx +32 -0
  278. package/src/components/table.stories.tsx +38 -0
  279. package/src/components/table.tsx +220 -0
  280. package/src/components/tabs.stories.tsx +25 -0
  281. package/src/components/tabs.tsx +276 -0
  282. package/src/components/testimonials.stories.tsx +22 -0
  283. package/src/components/testimonials.tsx +109 -0
  284. package/src/components/text-link.stories.tsx +47 -0
  285. package/src/components/text-link.test.tsx +18 -0
  286. package/src/components/text-link.tsx +88 -0
  287. package/src/components/text.stories.tsx +49 -0
  288. package/src/components/text.tsx +105 -0
  289. package/src/components/thinking-bar.stories.tsx +19 -0
  290. package/src/components/thinking-bar.test.tsx +27 -0
  291. package/src/components/thinking-bar.tsx +64 -0
  292. package/src/components/thinking-steps.stories.tsx +44 -0
  293. package/src/components/thinking-steps.test.tsx +42 -0
  294. package/src/components/thinking-steps.tsx +92 -0
  295. package/src/components/toaster.stories.tsx +80 -0
  296. package/src/components/toaster.tsx +36 -0
  297. package/src/components/toggle.stories.tsx +21 -0
  298. package/src/components/toggle.tsx +103 -0
  299. package/src/components/tool-call-card.stories.tsx +97 -0
  300. package/src/components/tool-call-card.test.tsx +88 -0
  301. package/src/components/tool-call-card.tsx +231 -0
  302. package/src/components/tooltip.stories.tsx +25 -0
  303. package/src/components/tooltip.tsx +43 -0
  304. package/src/components/top-nav.stories.tsx +20 -0
  305. package/src/components/top-nav.tsx +76 -0
  306. package/src/docs/Colors.stories.tsx +192 -0
  307. package/src/docs/GettingStarted.mdx +72 -0
  308. package/src/docs/Mcp.mdx +52 -0
  309. package/src/docs/Typography.stories.tsx +114 -0
  310. package/src/hooks/use-in-view.ts +32 -0
  311. package/src/hooks/use-reduced-motion.ts +26 -0
  312. package/src/index.ts +343 -0
  313. package/src/lib/cn.test.ts +67 -0
  314. package/src/lib/cn.ts +81 -0
  315. package/src/lib/motion.ts +109 -0
  316. package/src/lib/prefix-utilities.test.ts +56 -0
  317. package/src/lib/prefix-utilities.ts +50 -0
  318. package/src/styles/base.css +489 -0
  319. package/src/styles/motion.css +69 -0
  320. package/src/styles/overrides.css +44 -0
  321. package/src/styles/typography.css +173 -0
  322. package/src/theme/theme.css +391 -0
  323. package/src/theme/tokens.ts +29 -0
  324. package/src/theme/types.ts +26 -0
  325. package/README.md +0 -3
package/package.json CHANGED
@@ -1,6 +1,96 @@
1
1
  {
2
2
  "name": "@adres/mgda-ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "files": [
7
+ "src",
8
+ "knowledge",
9
+ "knowledge.json",
10
+ "brand-knowledge.json"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "types": "./src/index.ts",
15
+ "import": "./src/index.ts"
16
+ },
17
+ "./knowledge.json": "./knowledge.json",
18
+ "./styles": "./src/styles/base.css",
19
+ "./components/*": "./src/components/*.tsx",
20
+ "./lib/*": "./src/lib/*.ts",
21
+ "./hooks/*": "./src/hooks/*.ts",
22
+ "./theme.css": "./src/theme/theme.css",
23
+ "./tokens": {
24
+ "types": "./src/theme/tokens.ts",
25
+ "import": "./src/theme/tokens.ts"
26
+ },
27
+ "./brand-knowledge.json": "./brand-knowledge.json"
28
+ },
29
+ "scripts": {
30
+ "lint": "echo \"(lint configured at app level)\"",
31
+ "typecheck": "tsc --noEmit",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest",
34
+ "test:storybook": "node scripts/test-storybook.mjs",
35
+ "storybook": "storybook dev -p 6006",
36
+ "build-storybook": "storybook build -o storybook-static",
37
+ "clean": "rm -rf .turbo *.tsbuildinfo"
38
+ },
39
+ "dependencies": {
40
+ "@radix-ui/react-accordion": "^1.2.12",
41
+ "@radix-ui/react-aspect-ratio": "^1.1.8",
42
+ "@radix-ui/react-avatar": "^1.1.11",
43
+ "@radix-ui/react-checkbox": "^1.3.3",
44
+ "@radix-ui/react-dialog": "^1.1.4",
45
+ "@radix-ui/react-dropdown-menu": "^2.1.4",
46
+ "@radix-ui/react-label": "^2.1.1",
47
+ "@radix-ui/react-popover": "^1.1.4",
48
+ "@radix-ui/react-radio-group": "^1.3.8",
49
+ "@radix-ui/react-select": "^2.2.6",
50
+ "@radix-ui/react-separator": "^1.1.8",
51
+ "@radix-ui/react-slider": "^1.3.6",
52
+ "@radix-ui/react-slot": "^1.1.1",
53
+ "@radix-ui/react-switch": "^1.2.6",
54
+ "@radix-ui/react-tabs": "^1.1.2",
55
+ "@radix-ui/react-tooltip": "^1.1.6",
56
+ "class-variance-authority": "^0.7.1",
57
+ "clsx": "^2.1.1",
58
+ "lucide-react": "^0.469.0",
59
+ "motion": "^11.15.0",
60
+ "sonner": "^1.7.1",
61
+ "tailwind-merge": "^2.6.0",
62
+ "tailwind-variants": "^3.3.1"
63
+ },
64
+ "devDependencies": {
65
+ "@storybook/addon-a11y": "^8.6.18",
66
+ "@storybook/addon-essentials": "^8.6.14",
67
+ "@storybook/blocks": "^8.6.14",
68
+ "@storybook/react": "^8.6.18",
69
+ "@storybook/react-vite": "^8.6.18",
70
+ "@storybook/test": "^8.6.18",
71
+ "@storybook/test-runner": "^0.22.0",
72
+ "@tailwindcss/postcss": "^4.0.0",
73
+ "@tailwindcss/vite": "^4.3.3",
74
+ "@types/react": "^19.0.2",
75
+ "@types/react-dom": "^19.0.2",
76
+ "postcss": "^8.5.0",
77
+ "react": "^19.0.0",
78
+ "react-dom": "^19.0.0",
79
+ "storybook": "^8.6.18",
80
+ "tailwindcss": "^4.0.0",
81
+ "typescript": "^5.7.2",
82
+ "vite": "^6.0.0",
83
+ "playwright": "^1.51.0",
84
+ "vitest": "^3.0.0",
85
+ "wait-on": "^8.0.3"
86
+ },
87
+ "publishConfig": {
88
+ "access": "public",
89
+ "registry": "https://registry.npmjs.org/"
90
+ },
91
+ "peerDependencies": {
92
+ "react": "^19.0.0",
93
+ "react-dom": "^19.0.0",
94
+ "tailwindcss": "^4.0.0"
95
+ }
96
+ }
@@ -0,0 +1,46 @@
1
+ import React from "react"
2
+ import type { Meta, StoryObj } from "@storybook/react"
3
+ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "./accordion"
4
+
5
+ const meta: Meta<typeof Accordion> = {
6
+ title: "Components/Accordion",
7
+ component: Accordion,
8
+ tags: ["autodocs"],
9
+ }
10
+
11
+ export default meta
12
+ type Story = StoryObj<typeof Accordion>
13
+
14
+ export const Default: Story = {
15
+ render: () => (
16
+ <Accordion type="single" collapsible className="ax:w-full ax:max-w-md">
17
+ <AccordionItem value="item-1">
18
+ <AccordionTrigger>What is Adres?</AccordionTrigger>
19
+ <AccordionContent>
20
+ Adres is a multi-brand design system for property and education products.
21
+ </AccordionContent>
22
+ </AccordionItem>
23
+ <AccordionItem value="item-2">
24
+ <AccordionTrigger>Can I switch brands?</AccordionTrigger>
25
+ <AccordionContent>
26
+ Yes, brand tokens load via CSS and can be swapped at runtime.
27
+ </AccordionContent>
28
+ </AccordionItem>
29
+ </Accordion>
30
+ ),
31
+ }
32
+
33
+ export const Multiple: Story = {
34
+ render: () => (
35
+ <Accordion type="multiple" className="ax:w-full ax:max-w-md">
36
+ <AccordionItem value="a">
37
+ <AccordionTrigger>Section A</AccordionTrigger>
38
+ <AccordionContent>Content for section A.</AccordionContent>
39
+ </AccordionItem>
40
+ <AccordionItem value="b">
41
+ <AccordionTrigger>Section B</AccordionTrigger>
42
+ <AccordionContent>Content for section B.</AccordionContent>
43
+ </AccordionItem>
44
+ </Accordion>
45
+ ),
46
+ }
@@ -0,0 +1,74 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AccordionPrimitive from "@radix-ui/react-accordion"
5
+ import { ChevronDown } from "lucide-react"
6
+ import { cn } from "../lib/cn"
7
+
8
+ /**
9
+ * Accordion root prop type - Radix's discriminated union of
10
+ * `type="single"` / `type="multiple"` modes.
11
+ *
12
+ * We re-export `AccordionPrimitive.Root` directly (no forwardRef wrapper)
13
+ * to preserve the discriminated union: `forwardRef` collapses it and
14
+ * TypeScript loses the ability to narrow `value` / `defaultValue` based
15
+ * on the `type` discriminant.
16
+ */
17
+ export type AccordionProps = React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Root>
18
+
19
+ export const Accordion = AccordionPrimitive.Root
20
+
21
+ export const AccordionItem = React.forwardRef<
22
+ React.ElementRef<typeof AccordionPrimitive.Item>,
23
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
24
+ >(({ className, ...props }, ref) => (
25
+ <AccordionPrimitive.Item
26
+ ref={ref}
27
+ className={cn("ax:border-b ax:border-border ax:last:border-0", className)}
28
+ {...props}
29
+ />
30
+ ))
31
+ AccordionItem.displayName = AccordionPrimitive.Item.displayName
32
+
33
+ export const AccordionTrigger = React.forwardRef<
34
+ React.ElementRef<typeof AccordionPrimitive.Trigger>,
35
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
36
+ >(({ className, children, ...props }, ref) => (
37
+ <AccordionPrimitive.Header className="ax:flex">
38
+ <AccordionPrimitive.Trigger
39
+ ref={ref}
40
+ className={cn(
41
+ "ax:flex ax:flex-1 ax:items-center ax:justify-between ax:py-md ax:t-label-sm ax:text-foreground ax:cursor-pointer",
42
+ "ax:[transition:color_var(--motion-fast)_var(--motion-ease-out)]",
43
+ "ax:hover:underline",
44
+ "ax:focus-visible:outline-none ax:focus-visible:ring-2 ax:focus-visible:ring-ring ax:focus-visible:ring-offset-2 ax:focus-visible:ring-offset-background",
45
+ "ax:[&[data-state=open]>svg]:rotate-180",
46
+ className
47
+ )}
48
+ {...props}
49
+ >
50
+ {children}
51
+ <ChevronDown className="ax:size-4 ax:shrink-0 ax:text-muted-foreground ax:[transition:transform_var(--motion-fast)_var(--motion-ease-out)] ax:motion-reduce:transition-none" />
52
+ </AccordionPrimitive.Trigger>
53
+ </AccordionPrimitive.Header>
54
+ ))
55
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
56
+
57
+ export const AccordionContent = React.forwardRef<
58
+ React.ElementRef<typeof AccordionPrimitive.Content>,
59
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
60
+ >(({ className, children, ...props }, ref) => (
61
+ <AccordionPrimitive.Content
62
+ ref={ref}
63
+ className={cn(
64
+ "ax:overflow-hidden ax:t-body-sm ax:text-muted-foreground",
65
+ "ax:data-[state=closed]:animate-accordion-up ax:data-[state=open]:animate-accordion-down",
66
+ "ax:motion-reduce:animate-none",
67
+ className
68
+ )}
69
+ {...props}
70
+ >
71
+ <div className="ax:pb-md ax:pt-0 ax:max-w-prose">{children}</div>
72
+ </AccordionPrimitive.Content>
73
+ ))
74
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName
@@ -0,0 +1,73 @@
1
+ import React from "react"
2
+ import type { Meta, StoryObj } from "@storybook/react"
3
+ import { ActivityRings, type ActivityRing } from "./activity-rings"
4
+
5
+ const defaultRings: ActivityRing[] = [
6
+ { pct: 0.75, className: "ax:stroke-chart-1" },
7
+ { pct: 0.5, className: "ax:stroke-chart-2" },
8
+ { pct: 0.25, className: "ax:stroke-chart-3" },
9
+ ]
10
+
11
+ const meta: Meta<typeof ActivityRings> = {
12
+ title: "Components/ActivityRings",
13
+ component: ActivityRings,
14
+ tags: ["autodocs"],
15
+ parameters: {
16
+ layout: "centered",
17
+ docs: {
18
+ description: {
19
+ component:
20
+ "Concentric progress arcs in one SVG. Pass 1–4 rings outside-in with Tailwind stroke classes such as `ax:stroke-chart-1` or `ax:stroke-primary`.",
21
+ },
22
+ },
23
+ },
24
+ argTypes: {
25
+ rings: { control: false },
26
+ size: { control: { type: "number", min: 48, max: 240, step: 8 } },
27
+ strokeWidth: { control: { type: "number", min: 4, max: 20, step: 1 } },
28
+ ariaLabel: { control: "text" },
29
+ },
30
+ args: {
31
+ size: 120,
32
+ strokeWidth: 12,
33
+ ariaLabel: "Progress rings",
34
+ rings: defaultRings,
35
+ },
36
+ }
37
+
38
+ export default meta
39
+ type Story = StoryObj<typeof ActivityRings>
40
+
41
+ export const Default: Story = {
42
+ render: (args) => (
43
+ <div className="ax:flex ax:items-center ax:gap-lg ax:p-lg">
44
+ <ActivityRings {...args} />
45
+ <ul className="ax:t-body-sm ax:text-muted-foreground ax:space-y-2xs">
46
+ <li>
47
+ <span className="ax:inline-block ax:size-2 ax:rounded-full ax:bg-chart-1 ax:me-xs" />
48
+ Modules - 75%
49
+ </li>
50
+ <li>
51
+ <span className="ax:inline-block ax:size-2 ax:rounded-full ax:bg-chart-2 ax:me-xs" />
52
+ Attendance - 50%
53
+ </li>
54
+ <li>
55
+ <span className="ax:inline-block ax:size-2 ax:rounded-full ax:bg-chart-3 ax:me-xs" />
56
+ Assignments - 25%
57
+ </li>
58
+ </ul>
59
+ </div>
60
+ ),
61
+ }
62
+
63
+ export const SingleRing: Story = {
64
+ args: {
65
+ rings: [{ pct: 0.6, className: "ax:stroke-primary" }],
66
+ ariaLabel: "Single progress ring at 60%",
67
+ },
68
+ render: (args) => (
69
+ <div className="ax:p-lg">
70
+ <ActivityRings {...args} />
71
+ </div>
72
+ ),
73
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Activity rings - concentric Apple-style progress arcs in a single SVG.
3
+ *
4
+ * The components here are pure visual primitives. They know nothing about
5
+ * the domain that the rings represent (courses, fitness, fundraising, etc.);
6
+ * callers compute the percentages and tell the rings which stroke colour to
7
+ * use. Pair `ActivityRings` with your own `computeProgress`-style helper.
8
+ */
9
+
10
+ import * as React from "react"
11
+
12
+ export interface ActivityRing {
13
+ /** Progress for this ring, expressed as a 0–1 fraction. Values are
14
+ * clamped to the legal range. */
15
+ pct: number
16
+ /** Tailwind / project stroke class, e.g. `"ax:stroke-chart-1"`. The ring
17
+ * draws a dimmed track of the same colour at 15% opacity. */
18
+ className: string
19
+ }
20
+
21
+ export interface ActivityRingsProps {
22
+ /** Rings rendered from the *outside in*. Pass 1–4 entries; the spacing
23
+ * is computed from the SVG box so a small set still looks balanced. */
24
+ rings: ActivityRing[]
25
+ /** Visual diameter in CSS pixels. The internal SVG viewBox is always
26
+ * `0 0 120 120`; this prop just scales it. */
27
+ size?: number
28
+ /** Stroke thickness for each ring in viewBox units. Defaults to 12. */
29
+ strokeWidth?: number
30
+ /** Accessible label describing what the rings represent in aggregate. */
31
+ ariaLabel?: string
32
+ }
33
+
34
+ function Ring({
35
+ cx,
36
+ cy,
37
+ r,
38
+ pct,
39
+ strokeWidth,
40
+ className,
41
+ }: {
42
+ cx: number
43
+ cy: number
44
+ r: number
45
+ pct: number
46
+ strokeWidth: number
47
+ className: string
48
+ }) {
49
+ const circ = 2 * Math.PI * r
50
+ const clamped = Math.max(0, Math.min(1, pct))
51
+ return (
52
+ <g>
53
+ <circle
54
+ cx={cx}
55
+ cy={cy}
56
+ r={r}
57
+ fill="none"
58
+ strokeWidth={strokeWidth}
59
+ className={`${className} ax:opacity-15`}
60
+ />
61
+ {clamped > 0 && (
62
+ <circle
63
+ cx={cx}
64
+ cy={cy}
65
+ r={r}
66
+ fill="none"
67
+ strokeWidth={strokeWidth}
68
+ strokeLinecap="round"
69
+ strokeDasharray={circ}
70
+ strokeDashoffset={circ * (1 - clamped)}
71
+ transform={`rotate(-90 ${cx} ${cy})`}
72
+ className={className}
73
+ />
74
+ )}
75
+ </g>
76
+ )
77
+ }
78
+
79
+ /** Concentric rings in a single SVG. Composes 1–4 `Ring`s from the outside
80
+ * in. Ring spacing and starting radius are derived so the set stays
81
+ * visually balanced for typical 2–3 ring counts. */
82
+ export function ActivityRings({
83
+ rings,
84
+ size = 112,
85
+ strokeWidth = 12,
86
+ ariaLabel,
87
+ }: ActivityRingsProps) {
88
+ if (!rings?.length) return null
89
+
90
+ const outerR = 53
91
+ const step = strokeWidth // distance between successive ring centrelines
92
+ return (
93
+ <svg
94
+ viewBox="0 0 120 120"
95
+ width={size}
96
+ height={size}
97
+ className="ax:shrink-0"
98
+ role="img"
99
+ aria-label={ariaLabel}
100
+ >
101
+ {rings.map((ring, i) => (
102
+ <Ring
103
+ key={i}
104
+ cx={60}
105
+ cy={60}
106
+ r={outerR - i * step}
107
+ strokeWidth={strokeWidth}
108
+ pct={ring.pct}
109
+ className={ring.className}
110
+ />
111
+ ))}
112
+ </svg>
113
+ )
114
+ }
115
+
116
+ // Note: the previous `ProgressRing` single-arc component lived here. It was
117
+ // merged into the `Progress` component as `<Progress shape="ring">` so the
118
+ // design system has one mental model for "show one value's progress", see
119
+ // packages/design-system/src/components/progress.tsx. ActivityRings (the
120
+ // concentric multi-value visual) stays separate because it expresses a
121
+ // fundamentally different concept: 2–4 simultaneous progresses, not one.
@@ -0,0 +1,43 @@
1
+ import React from "react"
2
+ import type { Meta, StoryObj } from "@storybook/react"
3
+ import { Alert, AlertDescription, AlertTitle } from "./alert"
4
+
5
+ const meta: Meta<typeof Alert> = {
6
+ title: "Components/Alert",
7
+ component: Alert,
8
+ tags: ["autodocs"],
9
+ args: {
10
+ variant: "default",
11
+ size: "md",
12
+ },
13
+ }
14
+
15
+ export default meta
16
+ type Story = StoryObj<typeof Alert>
17
+
18
+ export const Default: Story = {
19
+ render: (args) => (
20
+ <Alert {...args}>
21
+ <AlertTitle>Heads up</AlertTitle>
22
+ <AlertDescription>You can adjust your notification preferences in settings.</AlertDescription>
23
+ </Alert>
24
+ ),
25
+ }
26
+
27
+ export const Success: Story = {
28
+ render: (args) => (
29
+ <Alert {...args} variant="success">
30
+ <AlertTitle>Payment received</AlertTitle>
31
+ <AlertDescription>Your subscription is now active.</AlertDescription>
32
+ </Alert>
33
+ ),
34
+ }
35
+
36
+ export const Destructive: Story = {
37
+ render: (args) => (
38
+ <Alert {...args} variant="destructive">
39
+ <AlertTitle>Something went wrong</AlertTitle>
40
+ <AlertDescription>Please try again or contact support.</AlertDescription>
41
+ </Alert>
42
+ ),
43
+ }
@@ -0,0 +1,132 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+ import { AlertCircle, CheckCircle2, Info, AlertTriangle } from "lucide-react"
6
+ import { cn } from "../lib/cn"
7
+
8
+ // ─── Types & context ──────────────────────────────────────────────────────────
9
+
10
+ export type AlertSize = "sm" | "md"
11
+
12
+ const AlertContext = React.createContext<{ size: AlertSize }>({ size: "md" })
13
+
14
+ // ─── Variants ─────────────────────────────────────────────────────────────────
15
+
16
+ const alertVariants = cva(
17
+ [
18
+ "ax:relative ax:w-full ax:rounded-md ax:border",
19
+ "ax:grid ax:grid-cols-[auto_1fr] ax:items-start",
20
+ ],
21
+ {
22
+ variants: {
23
+ variant: {
24
+ // Icon color tracks the title color (i.e. the variant's strongest text
25
+ // shade) so the leading glyph and the headline read as one composed
26
+ // signal rather than two competing emphases.
27
+ default: "ax:bg-card ax:text-foreground-strong ax:border-border",
28
+ info: "ax:bg-card ax:text-foreground-strong ax:border-border",
29
+ primary: "ax:bg-primary-weakest/80 ax:text-primary-foreground ax:border-primary-weaker ax:[&>svg]:text-primary-foreground",
30
+ success: "ax:bg-success-weakest/80 ax:text-success-foreground ax:border-success-weaker ax:[&>svg]:text-success-foreground",
31
+ warning: "ax:bg-warning-weakest/80 ax:dark:bg-warning-muted ax:text-warning-foreground ax:border-warning-weaker ax:dark:border-warning-weakest ax:[&>svg]:text-warning-foreground",
32
+ destructive: "ax:bg-destructive-weakest/80 ax:text-destructive-foreground ax:border-destructive-weaker ax:[&>svg]:text-destructive-foreground",
33
+ },
34
+ size: {
35
+ sm: "ax:p-sm ax:gap-x-xs ax:gap-y-2xs ax:text-xs ax:[&>svg]:size-3.5 ax:[&>svg]:mt-px",
36
+ md: "ax:p-md ax:gap-x-sm ax:gap-y-2xs ax:[&>svg]:size-4 ax:[&>svg]:mt-0.5",
37
+ },
38
+ },
39
+ defaultVariants: {
40
+ variant: "default",
41
+ size: "md",
42
+ },
43
+ }
44
+ )
45
+
46
+ const iconMap = {
47
+ default: Info,
48
+ info: Info,
49
+ primary: Info,
50
+ success: CheckCircle2,
51
+ warning: AlertTriangle,
52
+ destructive: AlertCircle,
53
+ } as const
54
+
55
+ // ─── Alert ────────────────────────────────────────────────────────────────────
56
+
57
+ export interface AlertProps
58
+ extends React.HTMLAttributes<HTMLDivElement>,
59
+ VariantProps<typeof alertVariants> {
60
+ size?: AlertSize
61
+ /** Hide the leading icon AND snap content to the first column. Use when the
62
+ * alert appears inline next to another leading element that already conveys
63
+ * the meaning. */
64
+ hideIcon?: boolean
65
+ /** Override the default variant icon with custom content (e.g. <Calendar />,
66
+ * <Sparkles />, <Lock />). The custom icon inherits the variant's color
67
+ * via the alert's `[&>svg]:text-*` selector - pass an SVG element.
68
+ * Remember to set `aria-hidden="true"` on the icon yourself.
69
+ * Ignored when `hideIcon` is true. */
70
+ icon?: React.ReactNode
71
+ }
72
+
73
+ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
74
+ ({ className, variant = "default", size = "md", hideIcon, icon, children, ...props }, ref) => {
75
+ const DefaultIcon = iconMap[variant ?? "default"]
76
+ const iconNode = icon !== undefined ? icon : <DefaultIcon aria-hidden="true" />
77
+ return (
78
+ <AlertContext.Provider value={{ size }}>
79
+ <div
80
+ ref={ref}
81
+ role="alert"
82
+ className={cn(alertVariants({ variant, size }), className)}
83
+ {...props}
84
+ >
85
+ {!hideIcon && iconNode}
86
+ <div className={cn("ax:col-start-2 ax:flex ax:flex-col ax:gap-2xs", hideIcon && "ax:col-start-1")}>
87
+ {children}
88
+ </div>
89
+ </div>
90
+ </AlertContext.Provider>
91
+ )
92
+ }
93
+ )
94
+ Alert.displayName = "Alert"
95
+
96
+ // ─── AlertTitle ───────────────────────────────────────────────────────────────
97
+
98
+ export const AlertTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(
99
+ ({ className, ...props }, ref) => {
100
+ const { size } = React.useContext(AlertContext)
101
+ return (
102
+ <h5
103
+ ref={ref}
104
+ className={cn(size === "sm" ? "ax:t-label-sm" : "ax:t-label-md", className)}
105
+ {...props}
106
+ />
107
+ )
108
+ }
109
+ )
110
+ AlertTitle.displayName = "AlertTitle"
111
+
112
+ // ─── AlertDescription ─────────────────────────────────────────────────────────
113
+
114
+ // Description renders a <div> (not a <p>) so it can host block-level children
115
+ // like lists, paragraphs, or button rows. Type matches the rendered element.
116
+ export const AlertDescription = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
117
+ ({ className, ...props }, ref) => {
118
+ const { size } = React.useContext(AlertContext)
119
+ return (
120
+ <div
121
+ ref={ref}
122
+ className={cn(
123
+ "ax:text-foreground ax:[&_p]:leading-relaxed",
124
+ size === "sm" ? "ax:text-xs" : "ax:t-body-sm",
125
+ className
126
+ )}
127
+ {...props}
128
+ />
129
+ )
130
+ }
131
+ )
132
+ AlertDescription.displayName = "AlertDescription"
@@ -0,0 +1,54 @@
1
+ import React from "react"
2
+ import type { Meta, StoryObj } from "@storybook/react"
3
+ import { AnswerActions } from "./answer-actions"
4
+ import { TooltipProvider } from "./tooltip"
5
+
6
+ const VERSIONS = [
7
+ "Budget for yearly service charges of roughly AED 26,000 to 38,000 for this 1,734 sqft unit.",
8
+ "Expect service charges, home insurance and utilities; service charges come to about AED 26,000 to 38,000 a year.",
9
+ ]
10
+
11
+ const meta: Meta<typeof AnswerActions> = {
12
+ title: "Components/AnswerActions",
13
+ component: AnswerActions,
14
+ tags: ["autodocs"],
15
+ decorators: [(Story) => <TooltipProvider><div style={{ maxWidth: 640 }}><Story /></div></TooltipProvider>],
16
+ args: {
17
+ text: VERSIONS[0],
18
+ negativeReasons: ["Wrong price", "Out of date", "Didn't answer", "Too long"],
19
+ positiveReasons: ["Accurate", "Clear", "Saved me time"],
20
+ },
21
+ }
22
+
23
+ export default meta
24
+ type Story = StoryObj<typeof AnswerActions>
25
+
26
+ export const Default: Story = {}
27
+
28
+ function VersionsDemo(props: React.ComponentProps<typeof AnswerActions>) {
29
+ const [version, setVersion] = React.useState(0)
30
+ return (
31
+ <AnswerActions
32
+ {...props}
33
+ text={VERSIONS[version] ?? ""}
34
+ version={version}
35
+ versionCount={VERSIONS.length}
36
+ onVersionChange={setVersion}
37
+ onRegenerate={() => undefined}
38
+ regenerateDisabled
39
+ />
40
+ )
41
+ }
42
+
43
+ export const WithVersions: Story = { render: (args) => <VersionsDemo {...args} /> }
44
+
45
+ export const WithReport: Story = {
46
+ args: {
47
+ onCopyLink: () => undefined,
48
+ reportReasons: [
49
+ { value: "wrong", label: "Wrong or misleading" },
50
+ { value: "unsafe", label: "Unsafe or offensive" },
51
+ { value: "other", label: "Something else" },
52
+ ],
53
+ },
54
+ }
@@ -0,0 +1,37 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import * as React from "react"
3
+ import { renderToStaticMarkup } from "react-dom/server"
4
+ import { AnswerActions, FeedbackReasonChips } from "./answer-actions"
5
+ import { TooltipProvider } from "./tooltip"
6
+
7
+ const render = (node: React.ReactNode) => renderToStaticMarkup(<TooltipProvider>{node}</TooltipProvider>)
8
+ const REASONS = { negativeReasons: ["Wrong price"], positiveReasons: ["Clear"] }
9
+
10
+ describe("FeedbackReasonChips", () => {
11
+ it("marks selected reasons as pressed", () => {
12
+ const html = render(<FeedbackReasonChips label="What went wrong?" reasons={["Wrong price", "Too long"]} selected={["Too long"]} onToggle={() => undefined} />)
13
+ expect(html).toMatch(/role="group" aria-label="What went wrong\?"/)
14
+ expect(html).toMatch(/aria-pressed="false"[^>]*>Wrong price|>Wrong price<\/button>/)
15
+ expect(html.match(/aria-pressed="true"/g)).toHaveLength(1)
16
+ })
17
+ })
18
+
19
+ describe("AnswerActions", () => {
20
+ it("is a labelled toolbar with copy and rating", () => {
21
+ const html = render(<AnswerActions text="Answer" {...REASONS} />)
22
+ expect(html).toContain('role="toolbar" aria-label="Answer actions"')
23
+ expect(html).toContain('aria-label="Copy"')
24
+ expect(html).toContain('aria-label="Good response"')
25
+ })
26
+
27
+ it("shows the version pager only with several versions", () => {
28
+ expect(render(<AnswerActions text="Answer" {...REASONS} />)).not.toContain("Response versions")
29
+ const html = render(<AnswerActions text="Answer" {...REASONS} version={1} versionCount={3} onVersionChange={() => undefined} />)
30
+ expect(html).toContain("2 of 3")
31
+ })
32
+
33
+ it("offers More actions only when there is something in it", () => {
34
+ expect(render(<AnswerActions text="Answer" {...REASONS} />)).not.toContain("More actions")
35
+ expect(render(<AnswerActions text="Answer" {...REASONS} onCopyLink={() => undefined} />)).toContain("More actions")
36
+ })
37
+ })