@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
@@ -0,0 +1,238 @@
1
+ ---
2
+ # >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
3
+ derived:
4
+ schemaVersion: 1
5
+ id: dropdown-menu
6
+ sourceFile: packages/design-system/src/components/dropdown-menu.tsx
7
+ client: true
8
+ category: web-app-overlays
9
+ categoryFromBarrel: web-app-overlays
10
+ barrelExported: true
11
+ importPath: "@adres/mgda-ui"
12
+ exports:
13
+ - name: DropdownMenu
14
+ kind: component
15
+ radixSource: "@radix-ui/react-dropdown-menu#Root"
16
+ typeText: "FC<DropdownMenuProps>"
17
+ - name: DropdownMenuCheckboxItem
18
+ kind: component
19
+ typeText: "ForwardRefExoticComponent<Omit<DropdownMenuCheckboxItemProps & RefAttributes<HTMLDivElement>, \"ref\"> & RefAttributes<HTMLDivElement>>"
20
+ - name: DropdownMenuContent
21
+ kind: component
22
+ typeText: "ForwardRefExoticComponent<DropdownMenuContentProps & RefAttributes<HTMLDivElement>>"
23
+ - name: DropdownMenuContentProps
24
+ kind: type
25
+ - name: DropdownMenuGroup
26
+ kind: component
27
+ radixSource: "@radix-ui/react-dropdown-menu#Group"
28
+ typeText: "ForwardRefExoticComponent<DropdownMenuGroupProps & RefAttributes<HTMLDivElement>>"
29
+ - name: DropdownMenuItem
30
+ kind: component
31
+ typeText: "ForwardRefExoticComponent<DropdownMenuItemProps & RefAttributes<HTMLDivElement>>"
32
+ - name: DropdownMenuItemProps
33
+ kind: type
34
+ - name: DropdownMenuLabel
35
+ kind: component
36
+ typeText: "ForwardRefExoticComponent<Omit<DropdownMenuLabelProps & RefAttributes<HTMLDivElement>, \"ref\"> & { inset?: boolean | undefined; } & RefAttributes<...>>"
37
+ - name: DropdownMenuPortal
38
+ kind: component
39
+ radixSource: "@radix-ui/react-dropdown-menu#Portal"
40
+ typeText: "FC<DropdownMenuPortalProps>"
41
+ - name: DropdownMenuRadioGroup
42
+ kind: component
43
+ radixSource: "@radix-ui/react-dropdown-menu#RadioGroup"
44
+ typeText: "ForwardRefExoticComponent<DropdownMenuRadioGroupProps & RefAttributes<HTMLDivElement>>"
45
+ - name: DropdownMenuRadioItem
46
+ kind: component
47
+ typeText: "ForwardRefExoticComponent<Omit<DropdownMenuRadioItemProps & RefAttributes<HTMLDivElement>, \"ref\"> & RefAttributes<HTMLDivElement>>"
48
+ - name: DropdownMenuSeparator
49
+ kind: component
50
+ typeText: "ForwardRefExoticComponent<Omit<DropdownMenuSeparatorProps & RefAttributes<HTMLDivElement>, \"ref\"> & RefAttributes<HTMLDivElement>>"
51
+ - name: DropdownMenuShortcut
52
+ kind: component
53
+ typeText: "{ ({ className, ...props }: HTMLAttributes<HTMLSpanElement>): Element; displayName: string; }"
54
+ - name: DropdownMenuSub
55
+ kind: component
56
+ radixSource: "@radix-ui/react-dropdown-menu#Sub"
57
+ typeText: "FC<DropdownMenuSubProps>"
58
+ - name: DropdownMenuSubContent
59
+ kind: component
60
+ typeText: "ForwardRefExoticComponent<Omit<DropdownMenuSubContentProps & RefAttributes<HTMLDivElement>, \"ref\"> & RefAttributes<HTMLDivElement>>"
61
+ - name: DropdownMenuSubTrigger
62
+ kind: component
63
+ typeText: "ForwardRefExoticComponent<Omit<DropdownMenuSubTriggerProps & RefAttributes<HTMLDivElement>, \"ref\"> & { inset?: boolean | undefined; } & RefAttributes<...>>"
64
+ - name: DropdownMenuTrigger
65
+ kind: component
66
+ radixSource: "@radix-ui/react-dropdown-menu#Trigger"
67
+ typeText: "ForwardRefExoticComponent<DropdownMenuTriggerProps & RefAttributes<HTMLButtonElement>>"
68
+ primaryExport: DropdownMenu
69
+ subcomponents:
70
+ - DropdownMenuCheckboxItem
71
+ - DropdownMenuContent
72
+ - DropdownMenuGroup
73
+ - DropdownMenuItem
74
+ - DropdownMenuLabel
75
+ - DropdownMenuPortal
76
+ - DropdownMenuRadioGroup
77
+ - DropdownMenuRadioItem
78
+ - DropdownMenuSeparator
79
+ - DropdownMenuShortcut
80
+ - DropdownMenuSub
81
+ - DropdownMenuSubContent
82
+ - DropdownMenuSubTrigger
83
+ - DropdownMenuTrigger
84
+ props:
85
+ DropdownMenuItem:
86
+ - name: inset
87
+ type: boolean
88
+ required: false
89
+ declaredIn: self
90
+ doc: "Indents the item to align with siblings that have a checkbox/radio indicator column."
91
+ - name: variant
92
+ type: "\"default\" | \"destructive\""
93
+ required: false
94
+ declaredIn: self
95
+ doc: "Colour treatment. `destructive` tints text + icon + hover/highlight background."
96
+ DropdownMenuLabel:
97
+ - name: inset
98
+ type: boolean
99
+ required: false
100
+ declaredIn: self
101
+ DropdownMenuSubTrigger:
102
+ - name: inset
103
+ type: boolean
104
+ required: false
105
+ declaredIn: self
106
+ extendsProps: []
107
+ variants:
108
+ variant:
109
+ kind: enum
110
+ options:
111
+ - default
112
+ - destructive
113
+ default: default
114
+ on: DropdownMenuItem
115
+ variantSource: prop-union
116
+ compoundVariants: []
117
+ sizeMaps: []
118
+ dataSlots: []
119
+ dependsOn:
120
+ internal: []
121
+ lib:
122
+ - cn
123
+ hooks: []
124
+ external:
125
+ - "@radix-ui/react-dropdown-menu"
126
+ - lucide-react
127
+ - react
128
+ contexts: []
129
+ stories:
130
+ - exportName: Default
131
+ id: components-dropdownmenu--default
132
+ storybookTitle: Components/DropdownMenu
133
+ docsId: components-dropdownmenu--documentation
134
+ argTypeOptions: {}
135
+ resolvedCleanly: true
136
+ contractHash: a3688fbae91f
137
+ factsHash: "23cea40a2ea6"
138
+ # >>> AUTHORED - humans own everything below this line. <<<
139
+ status: stable
140
+ summary: "A Radix-based dropdown menu triggered by a button, with items, checkboxes, radios, submenus, and a destructive row variant."
141
+ useWhen:
142
+ - "a button or icon triggers a list of actions or options, closing after a selection"
143
+ - "the menu needs checkbox or radio items, a nested submenu, or a destructive action row"
144
+ useInstead:
145
+ - id: select
146
+ when: "the trigger represents a form value being chosen, not a list of actions"
147
+ - id: popover
148
+ when: "the content is more than a list of commands - a form, rich content, or anything beyond selectable rows"
149
+ related:
150
+ - select
151
+ - popover
152
+ tokens:
153
+ - "--popover"
154
+ - "--popover-foreground"
155
+ - "--border"
156
+ - "--muted"
157
+ - "--destructive"
158
+ - "--destructive-strong"
159
+ a11y:
160
+ notes:
161
+ - "Wrap the real trigger element (typically a Button) with DropdownMenuTrigger asChild so Radix attaches its keyboard and ARIA handling directly to it instead of adding an extra wrapping element."
162
+ - "DropdownMenuShortcut is purely visual - it does not wire the actual keyboard shortcut to anything, so the real key handler must be registered separately if the shortcut should actually work."
163
+ keyboard:
164
+ - "Radix supplies full menu keyboard behavior: arrow keys move between items, Enter/Space activates, Escape closes, and typing jumps to a matching item's first letter - none of this needs to be built by hand."
165
+ radixHandles: true
166
+ pitfalls:
167
+ - "inset only aligns an item, label, or sub-trigger's text with siblings that have a checkbox/radio indicator column - it has no other layout effect."
168
+ - "DropdownMenuCheckboxItem and DropdownMenuRadioItem only manage their own visual indicator - the checked or selected state is still yours to own (checked/onCheckedChange, or value/onValueChange on the parent DropdownMenuRadioGroup)."
169
+ - "DropdownMenuShortcut only renders text - it is decoration, not a keybinding. Adding it does not wire up the shortcut."
170
+ - "Most of DropdownMenuContent's and DropdownMenuTrigger's real props (align, side, asChild, sideOffset) come straight from Radix's own types via an inlined generic, which the extractor does not resolve into derived.props/extendsProps - the same gap noted for separator/aspect-ratio in 15b-ii. The machine-checked canonicalSnippet below is intentionally minimal because of this; see the fuller example in ## Usage."
171
+ canonicalSnippet: |
172
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@adres/mgda-ui"
173
+
174
+ <DropdownMenu>
175
+ <DropdownMenuTrigger>Account</DropdownMenuTrigger>
176
+ <DropdownMenuContent>
177
+ <DropdownMenuItem onSelect={() => {}}>Profile</DropdownMenuItem>
178
+ <DropdownMenuItem variant="destructive" onSelect={() => {}}>Sign out</DropdownMenuItem>
179
+ </DropdownMenuContent>
180
+ </DropdownMenu>
181
+ reviewedAt: 2026-08-31
182
+ reviewedAgainstContractHash: a3688fbae91f
183
+ ---
184
+
185
+ ## Usage
186
+
187
+ `DropdownMenu` is for a list of actions or options triggered from a button -
188
+ reach for it when the trigger represents a set of commands, not a form value
189
+ being chosen (`Select`) or richer content like a form (`Popover`).
190
+
191
+ Wrap the real trigger element with `asChild` so Radix attaches its behavior
192
+ directly to it instead of adding an extra wrapping button - this is the real,
193
+ recommended usage, shown here since `asChild`/`align` cannot appear in this
194
+ file's machine-checked `canonicalSnippet` (see the pitfall on why):
195
+
196
+ ```tsx
197
+ import {
198
+ Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem,
199
+ DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,
200
+ } from "@adres/mgda-ui"
201
+
202
+ <DropdownMenu>
203
+ <DropdownMenuTrigger asChild>
204
+ <Button variant="outline">Account</Button>
205
+ </DropdownMenuTrigger>
206
+ <DropdownMenuContent align="start">
207
+ <DropdownMenuLabel>My account</DropdownMenuLabel>
208
+ <DropdownMenuSeparator />
209
+ <DropdownMenuItem>Profile</DropdownMenuItem>
210
+ <DropdownMenuItem>Billing</DropdownMenuItem>
211
+ <DropdownMenuItem variant="destructive">Sign out</DropdownMenuItem>
212
+ </DropdownMenuContent>
213
+ </DropdownMenu>
214
+ ```
215
+
216
+ Set `variant="destructive"` on a `DropdownMenuItem` for a destructive action
217
+ row - it tints text, icon, and hover background together. Use
218
+ `DropdownMenuSub` + `DropdownMenuSubTrigger` + `DropdownMenuSubContent` for a
219
+ nested submenu, and `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` (with
220
+ `DropdownMenuRadioGroup`) when a row needs to reflect a selection state you
221
+ own yourself.
222
+
223
+ ## Anatomy
224
+
225
+ | Part | Role |
226
+ | --- | --- |
227
+ | `DropdownMenu` | Root. Holds open state. A direct Radix `Root` re-export. |
228
+ | `DropdownMenuTrigger` | Opens the menu. Use `asChild` to wrap a real `Button`. |
229
+ | `DropdownMenuContent` | The floating panel. Portals itself and handles positioning and animation. |
230
+ | `DropdownMenuItem` | A single action row. `variant="destructive"` tints it; `inset` aligns it with indicator-column siblings. |
231
+ | `DropdownMenuCheckboxItem` | A row with a checkbox indicator; you own the `checked` state. |
232
+ | `DropdownMenuRadioGroup` / `DropdownMenuRadioItem` | A mutually-exclusive group of rows; you own the `value` state on the group. |
233
+ | `DropdownMenuLabel` | A non-interactive section heading. |
234
+ | `DropdownMenuSeparator` | A visual divider between groups of rows. |
235
+ | `DropdownMenuGroup` | Groups related items semantically without adding a visible separator. |
236
+ | `DropdownMenuShortcut` | A right-aligned, purely visual keyboard-shortcut hint. |
237
+ | `DropdownMenuSub` / `DropdownMenuSubTrigger` / `DropdownMenuSubContent` | A nested submenu: root, the row that opens it, and its floating panel. |
238
+ | `DropdownMenuPortal` | Escape hatch. Already rendered by `DropdownMenuContent`/`DropdownMenuSubContent`. |
@@ -0,0 +1,153 @@
1
+ ---
2
+ # >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
3
+ derived:
4
+ schemaVersion: 1
5
+ id: dropzone
6
+ sourceFile: packages/design-system/src/components/dropzone.tsx
7
+ client: true
8
+ category: web-app-patterns
9
+ categoryFromBarrel: web-app-patterns
10
+ barrelExported: true
11
+ importPath: "@adres/mgda-ui"
12
+ exports:
13
+ - name: Dropzone
14
+ kind: component
15
+ typeText: "ForwardRefExoticComponent<DropzoneProps & RefAttributes<HTMLDivElement>>"
16
+ - name: DropzoneError
17
+ kind: type
18
+ - name: DropzoneErrorReason
19
+ kind: type
20
+ - name: DropzoneProps
21
+ kind: type
22
+ primaryExport: Dropzone
23
+ subcomponents: []
24
+ props:
25
+ Dropzone:
26
+ - name: accept
27
+ type: string
28
+ required: false
29
+ declaredIn: self
30
+ doc: "Accept attribute passed through to the underlying `<input>` (e.g. `\".csv\"`, `\"image/*\"`). Also enforced on drag-and-drop - browsers don't natively validate `accept` for drops."
31
+ - name: disabled
32
+ type: boolean
33
+ required: false
34
+ declaredIn: self
35
+ doc: "Disables the drop target and Browse button."
36
+ - name: file
37
+ type: File
38
+ required: false
39
+ declaredIn: self
40
+ doc: "Currently-selected file. When set, the dropzone collapses to a selected-file row with a \"Replace\" button."
41
+ - name: maxSize
42
+ type: number
43
+ required: false
44
+ declaredIn: self
45
+ doc: "Maximum file size in bytes. Files exceeding this trigger `onError` rather than `onFile`."
46
+ - name: onError
47
+ type: "((error: DropzoneError) => void)"
48
+ required: false
49
+ declaredIn: self
50
+ doc: "Called when a dropped or picked file fails validation (wrong type, exceeds `maxSize`). The file is NOT forwarded to `onFile`."
51
+ - name: onFile
52
+ type: "(file: File) => void"
53
+ required: true
54
+ declaredIn: self
55
+ doc: "Called when a file is dropped or selected via the file picker AND passes type / size validation."
56
+ - name: processing
57
+ type: boolean
58
+ required: false
59
+ declaredIn: self
60
+ doc: "While true, the dropzone shows a spinner + \"Processing...\" instead of the upload affordances. Drive this from the parent's upload state."
61
+ - name: prompt
62
+ type: string
63
+ required: false
64
+ declaredIn: self
65
+ doc: "Localizable prompt text. Defaults to a CSV-flavored prompt."
66
+ - name: templateHref
67
+ type: string
68
+ required: false
69
+ declaredIn: self
70
+ doc: "Optional helper link rendered under the Browse button."
71
+ - name: templateLabel
72
+ type: string
73
+ required: false
74
+ declaredIn: self
75
+ extendsProps:
76
+ - "Omit<React.HTMLAttributes<HTMLDivElement>, \"onError\">"
77
+ variants: {}
78
+ variantSource: none
79
+ compoundVariants: []
80
+ sizeMaps: []
81
+ dataSlots: []
82
+ dependsOn:
83
+ internal:
84
+ - button
85
+ - spinner
86
+ lib:
87
+ - cn
88
+ hooks: []
89
+ external:
90
+ - lucide-react
91
+ - react
92
+ contexts: []
93
+ stories:
94
+ - exportName: Default
95
+ id: components-dropzone--default
96
+ storybookTitle: Components/Dropzone
97
+ docsId: components-dropzone--documentation
98
+ argTypeOptions: {}
99
+ resolvedCleanly: true
100
+ contractHash: e7ee09c72838
101
+ factsHash: b68586b1b136
102
+ # >>> AUTHORED - humans own everything below this line. <<<
103
+ status: stable
104
+ summary: "A fully-controlled file dropzone with drag-and-drop, a browse button, type/size validation, and three states: empty, selected, and processing."
105
+ useWhen:
106
+ - "a single-file upload with drag-and-drop plus a fallback browse button - a CSV import, a document upload"
107
+ useInstead:
108
+ - id: input-button
109
+ when: "the upload is a plain browse-only flow with no drag target needed"
110
+ related:
111
+ - input-button
112
+ a11y:
113
+ notes:
114
+ - "The drop target itself is not natively focusable or keyboard-operable - the Browse button is the keyboard path to select a file; drag-and-drop is a pointer-only affordance layered on top of it, not a replacement for it."
115
+ - "Validation errors (onError) are not announced automatically - there is no built-in live region or visible error message; render one from the DropzoneError passed to onError."
116
+ radixHandles: false
117
+ pitfalls:
118
+ - "Dropzone is fully controlled - file and processing are props you own, not internal state. Passing onFile without also updating file yourself means the component never visually reflects a successful selection."
119
+ - "onFile only fires after validation passes - a rejected file (wrong type, over maxSize) goes to onError instead and never reaches onFile; there is no need to re-validate in your own handler."
120
+ - "accept is enforced twice for a reason: browsers apply it natively to the file picker, but do not apply it to drag-and-drop - the component re-validates accept in JavaScript specifically to cover the drop path. A permissive accept on the input alone is not enough."
121
+ - "processing takes over the entire render regardless of file - once processing is true, the file row and its Replace button disappear, so there is no way to swap the file mid-upload without first clearing processing."
122
+ canonicalSnippet: |
123
+ import { Dropzone } from "@adres/mgda-ui"
124
+
125
+ <Dropzone
126
+ accept=".csv"
127
+ maxSize={5 * 1024 * 1024}
128
+ file={file}
129
+ onFile={setFile}
130
+ onError={(err) => console.error(err.message)}
131
+ />
132
+ reviewedAt: 2026-09-01
133
+ reviewedAgainstContractHash: e7ee09c72838
134
+ ---
135
+
136
+ ## Usage
137
+
138
+ `Dropzone` is a fully-controlled, single-file upload target - drag-and-drop
139
+ onto the whole surface, or a `Browse File` button as the keyboard-accessible
140
+ fallback. Reach for `InputButton` instead when the flow is browse-only with
141
+ no need for a drag target.
142
+
143
+ The component has three states driven entirely by props: empty (the drag or
144
+ browse prompt), selected (`file` is set - a compact row with a `Replace`
145
+ button), and `processing` (a spinner, which takes over regardless of
146
+ `file`). You own `file` and `processing` in the parent and update them from
147
+ `onFile`/`onError`.
148
+
149
+ `accept` and `maxSize` gate what reaches `onFile` - a file that fails either
150
+ check goes to `onError` instead, with a `reason` (`"invalid-type"` or
151
+ `"too-large"`) and a ready-to-display `message`. `accept` is re-validated in
152
+ JavaScript specifically because browsers do not enforce the native `accept`
153
+ attribute on drag-and-drop, only on the file picker.
@@ -0,0 +1,161 @@
1
+ ---
2
+ # >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
3
+ derived:
4
+ schemaVersion: 1
5
+ id: email-chips-input
6
+ sourceFile: packages/design-system/src/components/email-chips-input.tsx
7
+ client: true
8
+ category: web-app-patterns
9
+ categoryFromBarrel: web-app-patterns
10
+ barrelExported: true
11
+ importPath: "@adres/mgda-ui"
12
+ exports:
13
+ - name: EmailChip
14
+ kind: type
15
+ - name: EmailChipsInput
16
+ kind: component
17
+ typeText: "ForwardRefExoticComponent<EmailChipsInputProps & RefAttributes<HTMLDivElement>>"
18
+ - name: EmailChipsInputProps
19
+ kind: type
20
+ - name: EmailChipsInputVariant
21
+ kind: type
22
+ primaryExport: EmailChipsInput
23
+ subcomponents: []
24
+ props:
25
+ EmailChipsInput:
26
+ - name: chips
27
+ type: "EmailChip[]"
28
+ required: true
29
+ declaredIn: self
30
+ - name: disabled
31
+ type: boolean
32
+ required: false
33
+ declaredIn: self
34
+ doc: "Disables the input and chip-removal buttons."
35
+ - name: id
36
+ type: string
37
+ required: false
38
+ declaredIn: self
39
+ doc: "id for the inner <input>, so a sibling <Label htmlFor> binds correctly."
40
+ - name: invalid
41
+ type: boolean
42
+ required: false
43
+ declaredIn: self
44
+ doc: "Tints the wrapper border destructive and sets `aria-invalid` on the inner input. Consumer-controlled - independent of per-chip validity."
45
+ - name: onChange
46
+ type: "(chips: EmailChip[]) => void"
47
+ required: true
48
+ declaredIn: self
49
+ - name: onDuplicate
50
+ type: "(() => void)"
51
+ required: false
52
+ declaredIn: self
53
+ doc: "Fired when the user tries to add an address that's already in the list. Useful for surfacing a non-blocking warning toast."
54
+ - name: placeholder
55
+ type: string
56
+ required: false
57
+ declaredIn: self
58
+ - name: variant
59
+ type: EmailChipsInputVariant
60
+ required: false
61
+ declaredIn: self
62
+ doc: "Tone applied to valid chips. `default` is neutral, `primary` tints brand, `destructive` tints destructive. Invalid chips always render in destructive regardless of variant - the error signal stays distinct."
63
+ extendsProps:
64
+ - "Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\">"
65
+ variants:
66
+ variant:
67
+ kind: enum
68
+ options:
69
+ - default
70
+ - primary
71
+ - destructive
72
+ default: default
73
+ on: EmailChipsInput
74
+ variantSource: prop-union
75
+ compoundVariants: []
76
+ sizeMaps:
77
+ - VARIANT_VALID_CLASS
78
+ dataSlots: []
79
+ dependsOn:
80
+ internal:
81
+ - tooltip
82
+ lib:
83
+ - cn
84
+ hooks: []
85
+ external:
86
+ - lucide-react
87
+ - react
88
+ contexts: []
89
+ stories:
90
+ - exportName: Default
91
+ id: components-emailchipsinput--default
92
+ - exportName: WithValues
93
+ id: components-emailchipsinput--with-values
94
+ - exportName: WithInvalid
95
+ id: components-emailchipsinput--with-invalid
96
+ - exportName: Primary
97
+ id: components-emailchipsinput--primary
98
+ - exportName: Destructive
99
+ id: components-emailchipsinput--destructive
100
+ - exportName: Invalid
101
+ id: components-emailchipsinput--invalid
102
+ - exportName: Disabled
103
+ id: components-emailchipsinput--disabled
104
+ storybookTitle: Components/EmailChipsInput
105
+ docsId: components-emailchipsinput--documentation
106
+ argTypeOptions: {}
107
+ resolvedCleanly: true
108
+ contractHash: "6de3b913a41b"
109
+ factsHash: "20ca26e967ec"
110
+ # >>> AUTHORED - humans own everything below this line. <<<
111
+ status: stable
112
+ summary: "A multi-email input that turns each accepted address into a removable chip, with paste-splitting and non-blocking per-chip validation."
113
+ useWhen:
114
+ - "collecting multiple email addresses in one field - invite lists, notification recipients, CC/BCC-style entry"
115
+ useInstead:
116
+ - id: input
117
+ when: "collecting a single email address, not a list"
118
+ related:
119
+ - input
120
+ a11y:
121
+ notes:
122
+ - "Each chip's remove button carries its own aria-label (\"Remove {email}\"), since the X icon alone has no accessible name."
123
+ - "Invalid chips get a Tooltip explaining why, wrapped in TooltipProvider automatically - no separate provider setup is needed at the call site."
124
+ - "invalid sets aria-invalid on the inner input and tints the wrapper - it is a consumer-controlled prop for form-level validation, independent of each chip's own valid flag. Pass it based on whatever the form's overall validity rule is, e.g. \"at least one chip\", not derived automatically from the chips array."
125
+ keyboard:
126
+ - "Enter or , commits the current text as a chip. Backspace on an empty input removes the last chip - a fast way to correct a mis-typed entry without reaching for the mouse."
127
+ radixHandles: false
128
+ pitfalls:
129
+ - "Validation is local (regex) and non-blocking - an invalid-looking address still becomes a chip, just tinted destructive with valid: false. Nothing stops form submission on its own; filter chip.valid before using the list."
130
+ - "Pasting a list only splits on the paste path when the pasted text looks list-shaped (contains a separator) - a single pasted address goes through the normal typed-entry flow instead, so it is not committed as a chip until Enter or blur."
131
+ - "Blur commits whatever is currently typed as a chip, if non-empty - clicking away from a half-typed address does not discard it, it adds it. This can surprise a user who meant to cancel by clicking elsewhere."
132
+ - "onDuplicate fires but the duplicate address is silently dropped either way, in both the single-add and paste-many paths - there is no prop to allow duplicates."
133
+ canonicalSnippet: |
134
+ import { EmailChipsInput } from "@adres/mgda-ui"
135
+
136
+ <EmailChipsInput chips={chips} onChange={setChips} variant="primary" />
137
+ reviewedAt: 2026-09-01
138
+ reviewedAgainstContractHash: "6de3b913a41b"
139
+ ---
140
+
141
+ ## Usage
142
+
143
+ `EmailChipsInput` collects multiple email addresses in one field, turning
144
+ each accepted entry into a removable chip - invite lists, notification
145
+ recipients, CC/BCC-style entry. Reach for `Input` instead when the field is
146
+ a single email address, not a list.
147
+
148
+ Add a chip with `Enter` or `,`, or by pasting a separator-delimited list
149
+ (commas, semicolons, newlines, tabs, or mixed) - the component splits and
150
+ de-dupes a paste automatically. `Backspace` on an empty input removes the
151
+ last chip.
152
+
153
+ Validation is local and non-blocking: every entry becomes a chip regardless
154
+ of whether it looks like a valid address, with invalid ones tinted
155
+ destructive and given an explanatory tooltip. Filter `chip.valid` before
156
+ treating the list as ready to submit - the component never blocks adding an
157
+ invalid-looking address.
158
+
159
+ `variant` only tints valid chips; invalid ones always render destructive
160
+ regardless of `variant`, so the error signal stays visually distinct no
161
+ matter the brand tone in use.
@@ -0,0 +1,106 @@
1
+ ---
2
+ # >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
3
+ derived:
4
+ schemaVersion: 1
5
+ id: empty-state
6
+ sourceFile: packages/design-system/src/components/empty-state.tsx
7
+ client: false
8
+ category: web-app-core-primitives
9
+ categoryFromBarrel: web-app-core-primitives
10
+ barrelExported: true
11
+ importPath: "@adres/mgda-ui"
12
+ exports:
13
+ - name: EmptyState
14
+ kind: component
15
+ typeText: "({ className, icon, title, description, action, ...props }: EmptyStateProps) => Element"
16
+ - name: EmptyStateProps
17
+ kind: type
18
+ primaryExport: EmptyState
19
+ subcomponents: []
20
+ props:
21
+ EmptyState:
22
+ - name: action
23
+ type: ReactNode
24
+ required: false
25
+ declaredIn: self
26
+ - name: description
27
+ type: string
28
+ required: false
29
+ declaredIn: self
30
+ - name: icon
31
+ type: ReactNode
32
+ required: false
33
+ declaredIn: self
34
+ - name: title
35
+ type: string
36
+ required: true
37
+ declaredIn: self
38
+ extendsProps:
39
+ - "React.HTMLAttributes<HTMLDivElement>"
40
+ variants: {}
41
+ variantSource: none
42
+ compoundVariants: []
43
+ sizeMaps: []
44
+ dataSlots: []
45
+ dependsOn:
46
+ internal: []
47
+ lib:
48
+ - cn
49
+ hooks: []
50
+ external:
51
+ - react
52
+ contexts: []
53
+ stories:
54
+ - exportName: Default
55
+ id: components-emptystate--default
56
+ storybookTitle: Components/EmptyState
57
+ docsId: components-emptystate--documentation
58
+ argTypeOptions: {}
59
+ resolvedCleanly: true
60
+ contractHash: "855787802b2a"
61
+ factsHash: "15a5f0623e3d"
62
+ # >>> AUTHORED - humans own everything below this line. <<<
63
+ status: stable
64
+ summary: "A centered placeholder for a surface with no content yet, pairing an optional icon with a title, description, and action."
65
+ useWhen:
66
+ - "a list, table, or panel genuinely has zero items to show, not still loading"
67
+ - "guiding the user toward the action that would fill the empty surface, e.g. \"Create your first project\""
68
+ useInstead:
69
+ - id: skeleton
70
+ when: "content is still loading, not confirmed empty"
71
+ - id: alert
72
+ when: "reporting a message or error tied to the page, not describing an empty content area"
73
+ related:
74
+ - skeleton
75
+ - alert
76
+ a11y:
77
+ notes:
78
+ - "title renders as an h3 - check that the surrounding page's heading hierarchy still makes sense with an h3 appearing where the empty content would have been."
79
+ - "The icon wrapper has no aria-hidden set automatically - a purely decorative icon (the common case) needs aria-hidden=\"true\" set on the icon element you pass in yourself."
80
+ radixHandles: false
81
+ pitfalls:
82
+ - "title is the only required prop, but description and action are what make an empty state actually useful - a bare title alone often reads as a dead end rather than guidance."
83
+ - "There is no built-in aria-hidden on the icon wrapper - EmptyState does not add it, so a decorative icon needs it set explicitly by the caller."
84
+ canonicalSnippet: |
85
+ import { Button, EmptyState } from "@adres/mgda-ui"
86
+
87
+ <EmptyState
88
+ title="No projects yet"
89
+ description="Create your first project to get started."
90
+ action={<Button size="sm">New project</Button>}
91
+ />
92
+ reviewedAt: 2026-08-31
93
+ reviewedAgainstContractHash: "855787802b2a"
94
+ ---
95
+
96
+ ## Usage
97
+
98
+ `EmptyState` fills the center of a surface that genuinely has nothing to show
99
+ - an empty list, table, or search result - never a surface that is still
100
+ loading (use `Skeleton` for that) or a message about the page itself (use
101
+ `Alert`).
102
+
103
+ Pair `title` with a `description` that explains why it is empty or what to do
104
+ next, and an `action` (typically a `Button`) that does that next thing - a
105
+ bare title alone often reads as a dead end rather than guidance. `icon` is
106
+ optional decoration in a circular muted badge above the title.