@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,159 @@
1
+ ---
2
+ # >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
3
+ derived:
4
+ schemaVersion: 1
5
+ id: number-stepper
6
+ sourceFile: packages/design-system/src/components/number-stepper.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: NumberStepper
14
+ kind: component
15
+ typeText: "ForwardRefExoticComponent<NumberStepperProps & RefAttributes<HTMLDivElement>>"
16
+ - name: NumberStepperProps
17
+ kind: type
18
+ - name: NumberStepperSize
19
+ kind: type
20
+ primaryExport: NumberStepper
21
+ subcomponents: []
22
+ props:
23
+ NumberStepper:
24
+ - name: ariaLabel
25
+ type: string
26
+ required: false
27
+ declaredIn: self
28
+ doc: "Accessible label for the wrapper. Set this when context isn't obvious from the surrounding label element."
29
+ - name: disabled
30
+ type: boolean
31
+ required: false
32
+ declaredIn: self
33
+ doc: "Disables the whole control (both buttons + input). Per-bound disabling of the +/- buttons still happens automatically at min/max."
34
+ - name: id
35
+ type: string
36
+ required: false
37
+ declaredIn: self
38
+ doc: "Pass-through id for the central <input>, so a sibling <label htmlFor> binds correctly."
39
+ - name: max
40
+ type: number
41
+ required: false
42
+ declaredIn: self
43
+ doc: "Largest value the stepper allows. Defaults to 999."
44
+ - name: min
45
+ type: number
46
+ required: false
47
+ declaredIn: self
48
+ doc: "Smallest value the stepper allows. Defaults to 1."
49
+ - name: onChange
50
+ type: "(next: number) => void"
51
+ required: true
52
+ declaredIn: self
53
+ - name: size
54
+ type: NumberStepperSize
55
+ required: false
56
+ declaredIn: self
57
+ doc: "Visual density. Matches Button / Input size scale."
58
+ - name: step
59
+ type: number
60
+ required: false
61
+ declaredIn: self
62
+ doc: "Increment / decrement amount. Defaults to 1."
63
+ - name: value
64
+ type: number
65
+ required: true
66
+ declaredIn: self
67
+ extendsProps:
68
+ - "Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\">"
69
+ variants:
70
+ size:
71
+ kind: enum
72
+ options:
73
+ - sm
74
+ - md
75
+ - lg
76
+ default: md
77
+ on: NumberStepper
78
+ variantSource: prop-union
79
+ compoundVariants: []
80
+ sizeMaps:
81
+ - HEIGHT
82
+ - ICON_SIZE
83
+ dataSlots: []
84
+ dependsOn:
85
+ internal:
86
+ - button
87
+ - input
88
+ lib:
89
+ - cn
90
+ hooks: []
91
+ external:
92
+ - lucide-react
93
+ - react
94
+ contexts: []
95
+ stories:
96
+ - exportName: Default
97
+ id: components-numberstepper--default
98
+ storybookTitle: Components/NumberStepper
99
+ docsId: components-numberstepper--documentation
100
+ argTypeOptions: {}
101
+ resolvedCleanly: true
102
+ contractHash: "7fa157843630"
103
+ factsHash: e16e9641c8c8
104
+ # >>> AUTHORED - humans own everything below this line. <<<
105
+ status: stable
106
+ summary: "A joined +/-/input control for a bounded integer value, combining Button and Input into one visual unit."
107
+ useWhen:
108
+ - "a bounded integer input where direct typing should stay possible alongside +/- buttons - seat counts, quantity selectors"
109
+ useInstead:
110
+ - id: input
111
+ when: "a plain number input is enough and the +/- buttons are not needed"
112
+ - id: slider
113
+ when: "picking a value by dragging is more natural than typing or clicking, especially for a wide range"
114
+ related:
115
+ - input
116
+ - slider
117
+ a11y:
118
+ notes:
119
+ - "Sets role=\"group\" with ariaLabel (default \"Number\") on the wrapper - override ariaLabel with something specific, e.g. \"Number of seats\", whenever a sibling label does not already make the control's purpose obvious."
120
+ - "The +/- buttons disable automatically at min/max and stay in sync as the user types - there is no need to compute or pass that disabled state separately."
121
+ keyboard:
122
+ - "The central Input is a real number input, so native increment/decrement via arrow keys works there in addition to clicking the +/- buttons; Tab moves through the decrement button, the input, and the increment button as three separate stops."
123
+ radixHandles: false
124
+ pitfalls:
125
+ - "value must round-trip through onChange like any controlled input - the component maintains an internal typing draft so the field does not fight the user mid-edit, but value/onChange still need to update normally between renders."
126
+ - "Typed input only commits live when it parses to a clean, in-bounds integer - an out-of-range or partial value stays as an uncommitted draft until blur, when it is clamped to [min, max] and always committed, even replacing an unparseable string with min."
127
+ - "The wrapper is w-full by default and the three segments split evenly - constrain the parent (e.g. max-w-sm) for a traditional compact stepper, or it stretches to fill its row."
128
+ - "disabled disables the whole control, but the individual +/- buttons already disable themselves independently at min/max regardless of disabled - the two disabling mechanisms are separate and both apply."
129
+ canonicalSnippet: |
130
+ import { NumberStepper } from "@adres/mgda-ui"
131
+
132
+ const seatsLabel = "Number of seats"
133
+
134
+ <NumberStepper value={count} onChange={setCount} min={1} max={10} ariaLabel={seatsLabel} />
135
+ reviewedAt: 2026-09-01
136
+ reviewedAgainstContractHash: "7fa157843630"
137
+ ---
138
+
139
+ ## Usage
140
+
141
+ `NumberStepper` is a bounded integer input that joins a decrement button, a
142
+ central number field, and an increment button into one visual unit - seat
143
+ counts, quantity selectors, anywhere direct typing should stay possible
144
+ alongside +/- clicks. Reach for `Input` alone when the buttons are not
145
+ needed, and `Slider` when dragging suits the range better than typing or
146
+ clicking.
147
+
148
+ The wrapper is `w-full` and its three segments split evenly - constrain the
149
+ parent (e.g. `max-w-sm`) for a compact stepper rather than one that stretches
150
+ to fill its row.
151
+
152
+ Typed input commits live only when it parses to a clean, in-bounds integer;
153
+ an out-of-range or mid-edit value stays as a draft until blur, when it is
154
+ always clamped to `[min, max]` and committed - an unparseable string resolves
155
+ to `min`.
156
+
157
+ `disabled` turns off the whole control, but the +/- buttons already disable
158
+ themselves independently at `min`/`max` regardless of `disabled` - both
159
+ mechanisms apply at once, not one or the other.
@@ -0,0 +1,109 @@
1
+ ---
2
+ # >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
3
+ derived:
4
+ schemaVersion: 1
5
+ id: page-header
6
+ sourceFile: packages/design-system/src/components/page-header.tsx
7
+ client: false
8
+ category: web-app-layout-navigation
9
+ categoryFromBarrel: web-app-layout-navigation
10
+ barrelExported: true
11
+ importPath: "@adres/mgda-ui"
12
+ exports:
13
+ - name: PageHeader
14
+ kind: component
15
+ typeText: "ForwardRefExoticComponent<PageHeaderProps & RefAttributes<HTMLDivElement>>"
16
+ - name: PageHeaderProps
17
+ kind: type
18
+ primaryExport: PageHeader
19
+ subcomponents: []
20
+ props:
21
+ PageHeader:
22
+ - name: children
23
+ type: ReactNode
24
+ required: false
25
+ declaredIn: self
26
+ doc: "Right-aligned slot - typically `<Button>`s, a search input, a `Select`, or any other action(s) the page exposes at the top. Wraps to a new line on narrow viewports rather than truncating."
27
+ - name: subtitle
28
+ type: ReactNode
29
+ required: false
30
+ declaredIn: self
31
+ doc: "Optional subtitle / context line shown directly under the title."
32
+ - name: title
33
+ type: ReactNode
34
+ required: true
35
+ declaredIn: self
36
+ doc: "Page or section title. Rendered as an `<h1>` with `t-h1` typography."
37
+ extendsProps:
38
+ - "Omit<React.HTMLAttributes<HTMLDivElement>, \"title\">"
39
+ variants: {}
40
+ variantSource: none
41
+ compoundVariants: []
42
+ sizeMaps: []
43
+ dataSlots: []
44
+ dependsOn:
45
+ internal: []
46
+ lib:
47
+ - cn
48
+ hooks: []
49
+ external:
50
+ - react
51
+ contexts: []
52
+ stories:
53
+ - exportName: Default
54
+ id: components-pageheader--default
55
+ storybookTitle: Components/PageHeader
56
+ docsId: components-pageheader--documentation
57
+ argTypeOptions: {}
58
+ resolvedCleanly: true
59
+ contractHash: cde2a64fb03f
60
+ factsHash: "8e2d8b1c8eb3"
61
+ # >>> AUTHORED - humans own everything below this line. <<<
62
+ status: stable
63
+ summary: "The top-of-content heading row: an h1 title, optional subtitle, and a right-aligned actions slot."
64
+ useWhen:
65
+ - "the top of a page or major section needs a title plus page-level actions (e.g. \"Import CSV\" / \"Invite students\")"
66
+ - "you want a consistent title+subtitle+actions layout instead of hand-rolling one per page"
67
+ useInstead:
68
+ - id: top-nav
69
+ when: "you need a sticky app-shell bar (breadcrumbs, search, account menu), not an in-content page title"
70
+ related:
71
+ - top-nav
72
+ composesWith:
73
+ - button
74
+ tokens:
75
+ - "--muted-foreground"
76
+ a11y:
77
+ notes:
78
+ - "title renders as a real <h1> - a page should have exactly one PageHeader (or otherwise exactly one <h1>), so don't use it more than once per page."
79
+ - "PageHeader is a server component (no \"use client\") with no interactivity of its own; any focus/keyboard behavior comes entirely from what you put in children."
80
+ requiredProps:
81
+ - "title is required; subtitle and children (actions) are optional"
82
+ keyboard: []
83
+ radixHandles: false
84
+ pitfalls:
85
+ - "title's prop type intentionally shadows and omits the native HTML title attribute (via Omit<..., \"title\">) - you cannot pass a native tooltip title string through props; wrap the component if you need one."
86
+ - "children is the actions slot, not the body content - PageHeader is meant to sit above a page's main content, not wrap it."
87
+ canonicalSnippet: |
88
+ import { PageHeader, Button } from "@adres/mgda-ui"
89
+
90
+ const subtitle = "38 active learners"
91
+
92
+ <PageHeader title="Students" subtitle={subtitle}>
93
+ <Button variant="outline">Import CSV</Button>
94
+ <Button>Invite students</Button>
95
+ </PageHeader>
96
+ reviewedAt: 2026-08-31
97
+ reviewedAgainstContractHash: cde2a64fb03f
98
+ ---
99
+
100
+ ## Usage
101
+
102
+ PageHeader pairs an `<h1>` title with an optional subtitle on the start side
103
+ and a free-form actions slot (`children`) on the end side, baseline-aligned
104
+ so a wrapping multi-line title keeps its actions anchored to the last line.
105
+ Actions wrap onto a new row on narrow viewports rather than truncating or
106
+ overflowing.
107
+
108
+ Use it once per page or major section - it renders the page's single `<h1>`,
109
+ and stacking more than one breaks that heading hierarchy.
@@ -0,0 +1,225 @@
1
+ ---
2
+ # >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
3
+ derived:
4
+ schemaVersion: 1
5
+ id: pagination
6
+ sourceFile: packages/design-system/src/components/pagination.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: Pagination
14
+ kind: component
15
+ typeText: "ForwardRefExoticComponent<PaginationProps & RefAttributes<HTMLElement>>"
16
+ - name: PaginationContent
17
+ kind: component
18
+ typeText: "ForwardRefExoticComponent<Omit<DetailedHTMLProps<HTMLAttributes<HTMLUListElement>, HTMLUListElement>, \"ref\"> & RefAttributes<...>>"
19
+ - name: PaginationEllipsis
20
+ kind: component
21
+ typeText: "ForwardRefExoticComponent<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, \"ref\"> & RefAttributes<...>>"
22
+ - name: PaginationItem
23
+ kind: component
24
+ typeText: "ForwardRefExoticComponent<Omit<DetailedHTMLProps<LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, \"ref\"> & RefAttributes<HTMLLIElement>>"
25
+ - name: PaginationLink
26
+ kind: component
27
+ typeText: "ForwardRefExoticComponent<PaginationLinkProps & RefAttributes<HTMLButtonElement>>"
28
+ - name: PaginationLinkProps
29
+ kind: type
30
+ - name: paginationLinkVariants
31
+ kind: variants
32
+ typeText: "TVReturnType<{ isActive: { true: \"ax:bg-primary-weaker ax:text-primary-foreground ax:dark:bg-primary-strong ax:dark:text-primary-weaker\"; false: \"ax:bg-transparent ax:text-foreground ax:hover:bg-muted\"; }; size: { ...; }...[truncated]"
33
+ - name: PaginationNavLinkProps
34
+ kind: type
35
+ - name: PaginationNext
36
+ kind: component
37
+ typeText: "ForwardRefExoticComponent<PaginationNavLinkProps & RefAttributes<HTMLButtonElement>>"
38
+ - name: PaginationPrevious
39
+ kind: component
40
+ typeText: "ForwardRefExoticComponent<PaginationNavLinkProps & RefAttributes<HTMLButtonElement>>"
41
+ - name: PaginationProps
42
+ kind: type
43
+ primaryExport: Pagination
44
+ subcomponents:
45
+ - PaginationContent
46
+ - PaginationEllipsis
47
+ - PaginationItem
48
+ - PaginationLink
49
+ - PaginationNext
50
+ - PaginationPrevious
51
+ props:
52
+ PaginationLink:
53
+ - name: asChild
54
+ type: boolean
55
+ required: false
56
+ declaredIn: self
57
+ doc: "Render the child element instead of a button (e.g. a router `<Link>`)."
58
+ - name: isActive
59
+ type: boolean
60
+ required: false
61
+ declaredIn: self
62
+ doc: "Marks the current page: sets `aria-current=\"page\"` and the active fill."
63
+ variantKey: true
64
+ - name: size
65
+ type: "\"md\" | \"sm\""
66
+ required: false
67
+ declaredIn: self
68
+ variantKey: true
69
+ PaginationNext:
70
+ - name: asChild
71
+ type: boolean
72
+ required: false
73
+ declaredIn: self
74
+ doc: "Render the child element instead of a button (e.g. a router `<Link>`)."
75
+ - name: size
76
+ type: "\"md\" | \"sm\""
77
+ required: false
78
+ declaredIn: self
79
+ variantKey: true
80
+ PaginationPrevious:
81
+ - name: asChild
82
+ type: boolean
83
+ required: false
84
+ declaredIn: self
85
+ doc: "Render the child element instead of a button (e.g. a router `<Link>`)."
86
+ - name: size
87
+ type: "\"md\" | \"sm\""
88
+ required: false
89
+ declaredIn: self
90
+ variantKey: true
91
+ extendsProps:
92
+ - "React.ComponentPropsWithoutRef<\"nav\">"
93
+ variants:
94
+ isActive:
95
+ kind: boolean
96
+ default: false
97
+ on: Pagination
98
+ size:
99
+ kind: enum
100
+ options:
101
+ - sm
102
+ - md
103
+ default: md
104
+ on: Pagination
105
+ variantSource: tv
106
+ compoundVariants: []
107
+ sizeMaps: []
108
+ dataSlots: []
109
+ dependsOn:
110
+ internal: []
111
+ lib:
112
+ - cn
113
+ hooks: []
114
+ external:
115
+ - "@radix-ui/react-slot"
116
+ - lucide-react
117
+ - react
118
+ - tailwind-variants
119
+ contexts: []
120
+ stories:
121
+ - exportName: Default
122
+ id: components-pagination--default
123
+ - exportName: WithEllipsis
124
+ id: components-pagination--with-ellipsis
125
+ - exportName: Small
126
+ id: components-pagination--small
127
+ - exportName: DisabledEdges
128
+ id: components-pagination--disabled-edges
129
+ storybookTitle: Components/Pagination
130
+ docsId: components-pagination--documentation
131
+ argTypeOptions: {}
132
+ resolvedCleanly: true
133
+ contractHash: "85bf65cd1ffe"
134
+ factsHash: fe8f4aa628e9
135
+ # >>> AUTHORED - humans own everything below this line. <<<
136
+ status: stable
137
+ summary: "Page-range navigation - numbered links, Previous/Next, and an ellipsis for skipped ranges."
138
+ useWhen:
139
+ - "navigating a long, numbered result set (search results, a table, a product grid) where jumping to an arbitrary page is useful"
140
+ - "the list is paged server-side or client-side and the total page count is known up front"
141
+ useInstead:
142
+ - id: data-table
143
+ when: "the paged content already lives inside a DataTable - wire its own pagination footer instead of composing a separate Pagination beside it"
144
+ - id: button
145
+ when: "the affordance is a single 'load more', not numbered pages"
146
+ related:
147
+ - button
148
+ - data-table
149
+ a11y:
150
+ notes:
151
+ - "Pagination sets role=\"navigation\" and aria-label=\"pagination\" on the root nav landmark."
152
+ - "PaginationLink sets aria-current=\"page\" on the active page - that's the only signal a screen reader gets about which page is current, so isActive must always be passed accurately."
153
+ - "PaginationEllipsis is aria-hidden - it's decorative, not a real, focusable page."
154
+ requiredProps:
155
+ - "Every PaginationLink, PaginationPrevious and PaginationNext needs an accessible name - number links get it from their visible text; an icon-only override needs an explicit aria-label."
156
+ keyboard:
157
+ - "Every item is a native button, so Tab moves between them individually - there is no roving tabindex or arrow-key paging like a tablist would provide."
158
+ radixHandles: false
159
+ tokens:
160
+ - "--primary-weaker"
161
+ - "--primary-strong"
162
+ - "--primary-foreground"
163
+ - "--muted"
164
+ - "--foreground"
165
+ - "--button-radius"
166
+ - "--ring"
167
+ pitfalls:
168
+ - "Pagination ships the primitives only, not a page-range calculator - compute which numbers and ellipses to render yourself (see the WithEllipsis story); there is no pageCount prop that does it for you."
169
+ - "PaginationPrevious/PaginationNext don't disable themselves at the edges - pass disabled explicitly when page is 1 or pageCount."
170
+ - "size lives on each PaginationLink/PaginationPrevious/PaginationNext individually, not on the Pagination root - unlike ButtonGroup there is no shared context, so a link left without a matching size silently defaults to md next to sm siblings."
171
+ canonicalSnippet: |
172
+ import {
173
+ Pagination, PaginationContent, PaginationItem, PaginationLink,
174
+ PaginationPrevious, PaginationNext,
175
+ } from "@adres/mgda-ui"
176
+
177
+ <Pagination>
178
+ <PaginationContent>
179
+ <PaginationItem>
180
+ <PaginationPrevious disabled={page === 1} onClick={() => setPage(page - 1)} />
181
+ </PaginationItem>
182
+ {[1, 2, 3].map((n) => (
183
+ <PaginationItem key={n}>
184
+ <PaginationLink isActive={n === page} onClick={() => setPage(n)}>{n}</PaginationLink>
185
+ </PaginationItem>
186
+ ))}
187
+ <PaginationItem>
188
+ <PaginationNext disabled={page === 3} onClick={() => setPage(page + 1)} />
189
+ </PaginationItem>
190
+ </PaginationContent>
191
+ </Pagination>
192
+ reviewedAt: 2026-10-16
193
+ reviewedAgainstContractHash: "85bf65cd1ffe"
194
+ ---
195
+
196
+ ## Usage
197
+
198
+ `Pagination` is a set of composable parts, not a single opinionated widget:
199
+ `Pagination` (the `nav` landmark), `PaginationContent` (the `ul`), `PaginationItem`
200
+ (each `li`), `PaginationLink` (a page number), `PaginationPrevious`/`PaginationNext`
201
+ (the edge controls), and `PaginationEllipsis` (a decorative truncation marker).
202
+ It follows the shadcn/ui pattern - plain semantic elements styled with design-system
203
+ tokens, no Radix primitive underneath, because page navigation doesn't need
204
+ focus-trapping or portal behaviour, just a nav landmark and native buttons.
205
+
206
+ The component does not compute a page range for you. For a short list, render every
207
+ page number directly. For a long one, decide which numbers and which
208
+ `PaginationEllipsis` markers to show around the current page yourself (the
209
+ `WithEllipsis` story shows a simple "first, current neighbourhood, last" pattern).
210
+
211
+ `size` ("sm" | "md", default "md") is set per `PaginationLink`/`PaginationPrevious`/
212
+ `PaginationNext` - keep it consistent across one `Pagination` instance by passing
213
+ the same value to every item, typically from a variable rather than a shared root
214
+ prop.
215
+
216
+ ## Anatomy
217
+
218
+ | Part | Role |
219
+ | --- | --- |
220
+ | `Pagination` | The `nav` root. Sets `role="navigation"` and `aria-label="pagination"`. |
221
+ | `PaginationContent` | The `ul` that lays items out in a row. |
222
+ | `PaginationItem` | A plain `li` wrapper around one link, control, or ellipsis. |
223
+ | `PaginationLink` | A page-number button. `isActive` sets `aria-current="page"` and the active fill; supports `asChild` to render a router `Link` instead of a `button`. |
224
+ | `PaginationPrevious` / `PaginationNext` | `PaginationLink` preconfigured with a chevron icon, a default "Previous"/"Next" label (hidden below `sm`, overridable via `children`), and a default `aria-label`. |
225
+ | `PaginationEllipsis` | A decorative, `aria-hidden` "more pages" marker - not a real page. |
@@ -0,0 +1,159 @@
1
+ ---
2
+ # >>> DERIVED - regenerated by `npm run knowledge:sync`. Do not edit. <<<
3
+ derived:
4
+ schemaVersion: 1
5
+ id: popover
6
+ sourceFile: packages/design-system/src/components/popover.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: Popover
14
+ kind: component
15
+ radixSource: "@radix-ui/react-popover#Root"
16
+ typeText: "FC<PopoverProps>"
17
+ - name: PopoverAnchor
18
+ kind: component
19
+ radixSource: "@radix-ui/react-popover#Anchor"
20
+ typeText: "ForwardRefExoticComponent<PopoverAnchorProps & RefAttributes<HTMLDivElement>>"
21
+ - name: PopoverClose
22
+ kind: component
23
+ radixSource: "@radix-ui/react-popover#Close"
24
+ typeText: "ForwardRefExoticComponent<PopoverCloseProps & RefAttributes<HTMLButtonElement>>"
25
+ - name: PopoverContent
26
+ kind: component
27
+ typeText: "ForwardRefExoticComponent<PopoverContentProps & RefAttributes<HTMLDivElement>>"
28
+ - name: PopoverContentProps
29
+ kind: type
30
+ - name: PopoverSize
31
+ kind: type
32
+ - name: PopoverTrigger
33
+ kind: component
34
+ radixSource: "@radix-ui/react-popover#Trigger"
35
+ typeText: "ForwardRefExoticComponent<PopoverTriggerProps & RefAttributes<HTMLButtonElement>>"
36
+ primaryExport: Popover
37
+ subcomponents:
38
+ - PopoverAnchor
39
+ - PopoverClose
40
+ - PopoverContent
41
+ - PopoverTrigger
42
+ props:
43
+ PopoverContent:
44
+ - name: size
45
+ type: "\"lg\" | \"md\" | \"sm\""
46
+ required: false
47
+ declaredIn: self
48
+ variantKey: true
49
+ extendsProps: []
50
+ variants:
51
+ size:
52
+ kind: enum
53
+ options:
54
+ - sm
55
+ - md
56
+ - lg
57
+ default: md
58
+ on: Popover
59
+ variantSource: cva
60
+ compoundVariants: []
61
+ sizeMaps: []
62
+ dataSlots: []
63
+ dependsOn:
64
+ internal: []
65
+ lib:
66
+ - cn
67
+ hooks: []
68
+ external:
69
+ - "@radix-ui/react-popover"
70
+ - class-variance-authority
71
+ - react
72
+ contexts: []
73
+ stories:
74
+ - exportName: Default
75
+ id: components-popover--default
76
+ storybookTitle: Components/Popover
77
+ docsId: components-popover--documentation
78
+ argTypeOptions: {}
79
+ resolvedCleanly: true
80
+ contractHash: "77fe5ab62468"
81
+ factsHash: "56a35d049707"
82
+ # >>> AUTHORED - humans own everything below this line. <<<
83
+ status: stable
84
+ summary: "A click-triggered floating panel that can hold interactive content - forms, buttons, richer context - anchored to a trigger element."
85
+ useWhen:
86
+ - "the trigger needs to reveal interactive content (a form, buttons, custom content) rather than a flat list of actions"
87
+ - "supplementary content should appear next to a specific element, dismissed by clicking outside or pressing Escape"
88
+ useInstead:
89
+ - id: dropdown-menu
90
+ when: "the content is just a list of selectable actions or options"
91
+ - id: tooltip
92
+ when: "the content is a short, non-interactive label shown on hover or focus, not click"
93
+ - id: drawer
94
+ when: "the content needs a full edge-to-edge panel rather than a small anchored one"
95
+ related:
96
+ - dropdown-menu
97
+ - tooltip
98
+ - drawer
99
+ tokens:
100
+ - "--popover"
101
+ - "--popover-foreground"
102
+ - "--border"
103
+ a11y:
104
+ notes:
105
+ - "Wrap the real trigger element with PopoverTrigger asChild so Radix attaches its keyboard and ARIA handling directly to it."
106
+ - "Unlike DropdownMenu, PopoverContent can hold any interactive content (inputs, buttons), and Radix manages focus trapping and Escape-to-close the same way."
107
+ keyboard:
108
+ - "Escape closes the popover and returns focus to the trigger. Tab moves through interactive content inside PopoverContent normally - it is not restricted to a roving-menu pattern the way DropdownMenu is."
109
+ radixHandles: true
110
+ pitfalls:
111
+ - "size only sets width and padding - it does not scale nested typography the way Dialog/Drawer's size drives a type ramp, so headings or body text inside PopoverContent still need their own sizing."
112
+ - "className on PopoverTrigger/PopoverAnchor/PopoverClose cannot be demonstrated in this file's machine-checked canonicalSnippet, because the extractor did not resolve their props from the inlined Radix generics - the same gap as dropdown-menu/drawer. See the fuller example in ## Usage."
113
+ - "PopoverAnchor lets the popover open away from its trigger (e.g. anchor to a table cell while the trigger is a button elsewhere) - most usages do not need it, since PopoverTrigger already anchors by default."
114
+ canonicalSnippet: |
115
+ import { Button, Popover, PopoverContent, PopoverTrigger } from "@adres/mgda-ui"
116
+
117
+ <Popover>
118
+ <PopoverTrigger asChild>
119
+ <Button variant="outline">Open popover</Button>
120
+ </PopoverTrigger>
121
+ <PopoverContent size="md">
122
+ <p>Popover content with helpful context.</p>
123
+ </PopoverContent>
124
+ </Popover>
125
+ reviewedAt: 2026-08-31
126
+ reviewedAgainstContractHash: "77fe5ab62468"
127
+ ---
128
+
129
+ ## Usage
130
+
131
+ `Popover` is for interactive or richer content anchored to a trigger element
132
+ - a form, a set of buttons, or custom context - dismissed by clicking outside
133
+ or pressing Escape. Reach for `DropdownMenu` instead when the content is just
134
+ a flat list of selectable actions, and `Tooltip` when it is a short label
135
+ shown on hover rather than click.
136
+
137
+ `size` (`sm`/`md`/`lg`) sets the panel's width and padding only; it does not
138
+ scale nested typography, unlike `Dialog`/`Drawer`. A common alternative is
139
+ overriding width directly via `className`:
140
+
141
+ ```tsx
142
+ <PopoverContent className="ax:w-64">
143
+ <p className="ax:t-body-sm">Popover content with helpful context.</p>
144
+ </PopoverContent>
145
+ ```
146
+
147
+ `className` is not in this file's machine-checked `canonicalSnippet` for the
148
+ same extractor-gap reason noted in `dropdown-menu.md`/`drawer.md` - use the
149
+ example above as the real usage reference.
150
+
151
+ ## Anatomy
152
+
153
+ | Part | Role |
154
+ | --- | --- |
155
+ | `Popover` | Root. Holds open state. A direct Radix `Root` re-export. |
156
+ | `PopoverTrigger` | Opens the popover. Use `asChild` to wrap a real `Button`. |
157
+ | `PopoverAnchor` | Optional - anchors the popover to a different element than its trigger. Rarely needed. |
158
+ | `PopoverContent` | The floating panel. Sets `size`, and renders its own portal and positioning. Can hold any interactive content. |
159
+ | `PopoverClose` | Radix `Close`. Wrap a `Button` with `asChild` to dismiss from inside the content. |