@zyncat/ui 0.8.0

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 (334) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +133 -0
  3. package/dist/alert.css +132 -0
  4. package/dist/alert.d.ts +46 -0
  5. package/dist/alert.js +80 -0
  6. package/dist/alert.js.map +1 -0
  7. package/dist/avatar-group.d.ts +24 -0
  8. package/dist/avatar-group.js +23 -0
  9. package/dist/avatar-group.js.map +1 -0
  10. package/dist/avatar.css +200 -0
  11. package/dist/avatar.d.ts +35 -0
  12. package/dist/avatar.js +67 -0
  13. package/dist/avatar.js.map +1 -0
  14. package/dist/badge.css +182 -0
  15. package/dist/badge.d.ts +34 -0
  16. package/dist/badge.js +4 -0
  17. package/dist/badge.js.map +1 -0
  18. package/dist/button.css +269 -0
  19. package/dist/button.d.ts +44 -0
  20. package/dist/button.js +4 -0
  21. package/dist/button.js.map +1 -0
  22. package/dist/checkbox.css +177 -0
  23. package/dist/checkbox.d.ts +35 -0
  24. package/dist/checkbox.js +5 -0
  25. package/dist/checkbox.js.map +1 -0
  26. package/dist/chunk-2ERBBFZS.js +12 -0
  27. package/dist/chunk-2ERBBFZS.js.map +1 -0
  28. package/dist/chunk-2HORSLXJ.js +191 -0
  29. package/dist/chunk-2HORSLXJ.js.map +1 -0
  30. package/dist/chunk-36WVAQKL.js +40 -0
  31. package/dist/chunk-36WVAQKL.js.map +1 -0
  32. package/dist/chunk-3SBCBYB7.js +575 -0
  33. package/dist/chunk-3SBCBYB7.js.map +1 -0
  34. package/dist/chunk-4R2GQO43.js +125 -0
  35. package/dist/chunk-4R2GQO43.js.map +1 -0
  36. package/dist/chunk-64UU4LGU.js +258 -0
  37. package/dist/chunk-64UU4LGU.js.map +1 -0
  38. package/dist/chunk-7SZCJ7WI.js +35 -0
  39. package/dist/chunk-7SZCJ7WI.js.map +1 -0
  40. package/dist/chunk-BIDVNLJO.js +38 -0
  41. package/dist/chunk-BIDVNLJO.js.map +1 -0
  42. package/dist/chunk-CONSWNIV.js +17 -0
  43. package/dist/chunk-CONSWNIV.js.map +1 -0
  44. package/dist/chunk-EQ32F2QJ.js +75 -0
  45. package/dist/chunk-EQ32F2QJ.js.map +1 -0
  46. package/dist/chunk-GY7JOPUQ.js +111 -0
  47. package/dist/chunk-GY7JOPUQ.js.map +1 -0
  48. package/dist/chunk-I4XQ4PV2.js +30 -0
  49. package/dist/chunk-I4XQ4PV2.js.map +1 -0
  50. package/dist/chunk-JSKXZMLH.js +67 -0
  51. package/dist/chunk-JSKXZMLH.js.map +1 -0
  52. package/dist/chunk-L3Q3VDIW.js +295 -0
  53. package/dist/chunk-L3Q3VDIW.js.map +1 -0
  54. package/dist/chunk-LDC3RIYA.js +62 -0
  55. package/dist/chunk-LDC3RIYA.js.map +1 -0
  56. package/dist/chunk-MKIQFK7S.js +43 -0
  57. package/dist/chunk-MKIQFK7S.js.map +1 -0
  58. package/dist/chunk-MMRIQNEN.js +20 -0
  59. package/dist/chunk-MMRIQNEN.js.map +1 -0
  60. package/dist/chunk-MXOPCFWR.js +59 -0
  61. package/dist/chunk-MXOPCFWR.js.map +1 -0
  62. package/dist/chunk-NEF5XAHG.js +17 -0
  63. package/dist/chunk-NEF5XAHG.js.map +1 -0
  64. package/dist/chunk-NNXJCLTV.js +22 -0
  65. package/dist/chunk-NNXJCLTV.js.map +1 -0
  66. package/dist/chunk-O4N2OBTR.js +94 -0
  67. package/dist/chunk-O4N2OBTR.js.map +1 -0
  68. package/dist/chunk-PMECHR3A.js +38 -0
  69. package/dist/chunk-PMECHR3A.js.map +1 -0
  70. package/dist/chunk-QDK66S4G.js +44 -0
  71. package/dist/chunk-QDK66S4G.js.map +1 -0
  72. package/dist/chunk-QGNC7LH5.js +8 -0
  73. package/dist/chunk-QGNC7LH5.js.map +1 -0
  74. package/dist/chunk-QMSJZCK3.js +398 -0
  75. package/dist/chunk-QMSJZCK3.js.map +1 -0
  76. package/dist/chunk-S5ZTZANS.js +57 -0
  77. package/dist/chunk-S5ZTZANS.js.map +1 -0
  78. package/dist/chunk-S7B34VGN.js +14 -0
  79. package/dist/chunk-S7B34VGN.js.map +1 -0
  80. package/dist/chunk-TCUCYFT7.js +25 -0
  81. package/dist/chunk-TCUCYFT7.js.map +1 -0
  82. package/dist/chunk-TYHR4VNM.js +193 -0
  83. package/dist/chunk-TYHR4VNM.js.map +1 -0
  84. package/dist/chunk-U5QQZC3U.js +56 -0
  85. package/dist/chunk-U5QQZC3U.js.map +1 -0
  86. package/dist/chunk-UE63OOVG.js +13 -0
  87. package/dist/chunk-UE63OOVG.js.map +1 -0
  88. package/dist/chunk-VTJTGVZZ.js +22 -0
  89. package/dist/chunk-VTJTGVZZ.js.map +1 -0
  90. package/dist/chunk-W3SHPKSB.js +49 -0
  91. package/dist/chunk-W3SHPKSB.js.map +1 -0
  92. package/dist/chunk-XZAEIQDR.js +188 -0
  93. package/dist/chunk-XZAEIQDR.js.map +1 -0
  94. package/dist/chunk-YGGCQNNU.js +92 -0
  95. package/dist/chunk-YGGCQNNU.js.map +1 -0
  96. package/dist/collapse.css +88 -0
  97. package/dist/collapse.d.ts +46 -0
  98. package/dist/collapse.js +5 -0
  99. package/dist/collapse.js.map +1 -0
  100. package/dist/count-badge.d.ts +13 -0
  101. package/dist/count-badge.js +13 -0
  102. package/dist/count-badge.js.map +1 -0
  103. package/dist/date-field.d.ts +25 -0
  104. package/dist/date-field.js +87 -0
  105. package/dist/date-field.js.map +1 -0
  106. package/dist/date-picker.css +595 -0
  107. package/dist/date-range-field.d.ts +33 -0
  108. package/dist/date-range-field.js +404 -0
  109. package/dist/date-range-field.js.map +1 -0
  110. package/dist/datetime-field.d.ts +29 -0
  111. package/dist/datetime-field.js +155 -0
  112. package/dist/datetime-field.js.map +1 -0
  113. package/dist/dialog.css +180 -0
  114. package/dist/dialog.d.ts +42 -0
  115. package/dist/dialog.js +128 -0
  116. package/dist/dialog.js.map +1 -0
  117. package/dist/dom-props-C0jrllBw.d.ts +5 -0
  118. package/dist/field-chrome-CMPOQSLs.d.ts +28 -0
  119. package/dist/field-shell-Cuda-feL.d.ts +24 -0
  120. package/dist/glide.d.ts +15 -0
  121. package/dist/glide.js +5 -0
  122. package/dist/glide.js.map +1 -0
  123. package/dist/icon.css +33 -0
  124. package/dist/input.css +333 -0
  125. package/dist/mcp.js +359 -0
  126. package/dist/motion-devtools.css +265 -0
  127. package/dist/motion-devtools.d.ts +51 -0
  128. package/dist/motion-devtools.js +354 -0
  129. package/dist/motion-devtools.js.map +1 -0
  130. package/dist/motion-scale-Canq4stZ.d.ts +18 -0
  131. package/dist/motion-tokens.d.ts +28 -0
  132. package/dist/motion-tokens.js +3 -0
  133. package/dist/motion-tokens.js.map +1 -0
  134. package/dist/multi-select.d.ts +44 -0
  135. package/dist/multi-select.js +109 -0
  136. package/dist/multi-select.js.map +1 -0
  137. package/dist/number-field.d.ts +36 -0
  138. package/dist/number-field.js +112 -0
  139. package/dist/number-field.js.map +1 -0
  140. package/dist/odometer.css +62 -0
  141. package/dist/otp-field.d.ts +31 -0
  142. package/dist/otp-field.js +98 -0
  143. package/dist/otp-field.js.map +1 -0
  144. package/dist/overlay.css +23 -0
  145. package/dist/pagination.css +43 -0
  146. package/dist/pagination.d.ts +29 -0
  147. package/dist/pagination.js +107 -0
  148. package/dist/pagination.js.map +1 -0
  149. package/dist/popover.css +69 -0
  150. package/dist/popover.d.ts +35 -0
  151. package/dist/popover.js +15 -0
  152. package/dist/popover.js.map +1 -0
  153. package/dist/radio-group.css +300 -0
  154. package/dist/radio-group.d.ts +52 -0
  155. package/dist/radio-group.js +115 -0
  156. package/dist/radio-group.js.map +1 -0
  157. package/dist/select.css +416 -0
  158. package/dist/select.d.ts +49 -0
  159. package/dist/select.js +99 -0
  160. package/dist/select.js.map +1 -0
  161. package/dist/sheet.css +26 -0
  162. package/dist/sheet.d.ts +31 -0
  163. package/dist/sheet.js +14 -0
  164. package/dist/sheet.js.map +1 -0
  165. package/dist/status-badge.d.ts +19 -0
  166. package/dist/status-badge.js +72 -0
  167. package/dist/status-badge.js.map +1 -0
  168. package/dist/table.css +348 -0
  169. package/dist/table.d.ts +75 -0
  170. package/dist/table.js +262 -0
  171. package/dist/table.js.map +1 -0
  172. package/dist/tabs.css +208 -0
  173. package/dist/tabs.d.ts +71 -0
  174. package/dist/tabs.js +181 -0
  175. package/dist/tabs.js.map +1 -0
  176. package/dist/tag.css +248 -0
  177. package/dist/tag.d.ts +52 -0
  178. package/dist/tag.js +72 -0
  179. package/dist/tag.js.map +1 -0
  180. package/dist/text-field.d.ts +28 -0
  181. package/dist/text-field.js +69 -0
  182. package/dist/text-field.js.map +1 -0
  183. package/dist/textarea.css +219 -0
  184. package/dist/textarea.d.ts +38 -0
  185. package/dist/textarea.js +144 -0
  186. package/dist/textarea.js.map +1 -0
  187. package/dist/time-field.d.ts +28 -0
  188. package/dist/time-field.js +66 -0
  189. package/dist/time-field.js.map +1 -0
  190. package/dist/timing-7JA_zQHP.d.ts +27 -0
  191. package/dist/toast-store.d.ts +86 -0
  192. package/dist/toast-store.js +3 -0
  193. package/dist/toast-store.js.map +1 -0
  194. package/dist/toast.css +257 -0
  195. package/dist/toast.d.ts +12 -0
  196. package/dist/toast.js +310 -0
  197. package/dist/toast.js.map +1 -0
  198. package/dist/toggle-tag.d.ts +34 -0
  199. package/dist/toggle-tag.js +57 -0
  200. package/dist/toggle-tag.js.map +1 -0
  201. package/dist/toggle.css +152 -0
  202. package/dist/toggle.d.ts +31 -0
  203. package/dist/toggle.js +75 -0
  204. package/dist/toggle.js.map +1 -0
  205. package/dist/tooltip.css +86 -0
  206. package/dist/tooltip.d.ts +30 -0
  207. package/dist/tooltip.js +268 -0
  208. package/dist/tooltip.js.map +1 -0
  209. package/dist/types-SGMShK7R.d.ts +22 -0
  210. package/llms.txt +196 -0
  211. package/next.d.mts +7 -0
  212. package/next.mjs +59 -0
  213. package/package.json +257 -0
  214. package/src/components/composites/alert/Alert.tsx +141 -0
  215. package/src/components/composites/alert/alert.css +132 -0
  216. package/src/components/composites/date-picker/DateField.tsx +80 -0
  217. package/src/components/composites/date-picker/DateRangeField.tsx +110 -0
  218. package/src/components/composites/date-picker/DateTimeField.tsx +162 -0
  219. package/src/components/composites/date-picker/TimeField.tsx +78 -0
  220. package/src/components/composites/date-picker/calendar-panel.tsx +216 -0
  221. package/src/components/composites/date-picker/date-picker.css +595 -0
  222. package/src/components/composites/date-picker/date-utils.ts +56 -0
  223. package/src/components/composites/date-picker/field-shell.tsx +85 -0
  224. package/src/components/composites/date-picker/range-panel.tsx +363 -0
  225. package/src/components/composites/date-picker/time-core.tsx +290 -0
  226. package/src/components/composites/date-picker/use-day-focus.ts +35 -0
  227. package/src/components/composites/dialog/Dialog.tsx +198 -0
  228. package/src/components/composites/dialog/dialog.css +180 -0
  229. package/src/components/composites/pagination/Pagination.tsx +131 -0
  230. package/src/components/composites/pagination/pagination.css +43 -0
  231. package/src/components/composites/popover/Popover.tsx +141 -0
  232. package/src/components/composites/popover/popover.css +69 -0
  233. package/src/components/composites/select/MultiSelect.tsx +133 -0
  234. package/src/components/composites/select/Select.tsx +122 -0
  235. package/src/components/composites/select/core/index.ts +4 -0
  236. package/src/components/composites/select/core/menu.tsx +100 -0
  237. package/src/components/composites/select/core/panel.tsx +154 -0
  238. package/src/components/composites/select/core/trigger.tsx +74 -0
  239. package/src/components/composites/select/core/types.ts +39 -0
  240. package/src/components/composites/select/core/use-listbox.ts +182 -0
  241. package/src/components/composites/select/select.css +416 -0
  242. package/src/components/composites/sheet/Sheet.tsx +135 -0
  243. package/src/components/composites/sheet/sheet.css +26 -0
  244. package/src/components/composites/sheet/use-sheet-drag.ts +126 -0
  245. package/src/components/composites/table/Table.tsx +377 -0
  246. package/src/components/composites/table/table.css +348 -0
  247. package/src/components/composites/tabs/Tabs.tsx +278 -0
  248. package/src/components/composites/tabs/tabs.css +208 -0
  249. package/src/components/composites/toast/Toast.tsx +380 -0
  250. package/src/components/composites/toast/toast-store.ts +295 -0
  251. package/src/components/composites/toast/toast.css +257 -0
  252. package/src/components/composites/tooltip/Tooltip.tsx +110 -0
  253. package/src/components/composites/tooltip/tooltip-host.tsx +184 -0
  254. package/src/components/composites/tooltip/tooltip-store.ts +81 -0
  255. package/src/components/composites/tooltip/tooltip.css +86 -0
  256. package/src/components/dev/MotionDevtools.tsx +200 -0
  257. package/src/components/dev/motion-devtools.css +265 -0
  258. package/src/components/dev/slowmo-engine.ts +230 -0
  259. package/src/components/internal/glass/glass.css +100 -0
  260. package/src/components/internal/glass/glint.ts +9 -0
  261. package/src/components/internal/hooks/use-controllable.ts +21 -0
  262. package/src/components/internal/hooks/use-scroll-edges.ts +46 -0
  263. package/src/components/internal/icon/Icon.tsx +66 -0
  264. package/src/components/internal/icon/IconSlot.tsx +10 -0
  265. package/src/components/internal/icon/icon.css +33 -0
  266. package/src/components/internal/overlay/focus.ts +68 -0
  267. package/src/components/internal/overlay/layer.tsx +149 -0
  268. package/src/components/internal/overlay/modal.tsx +141 -0
  269. package/src/components/internal/overlay/overlay.css +23 -0
  270. package/src/components/internal/overlay/position.ts +103 -0
  271. package/src/components/internal/utils/cx.ts +3 -0
  272. package/src/components/internal/utils/token-px.ts +8 -0
  273. package/src/components/primitives/avatar/Avatar.tsx +120 -0
  274. package/src/components/primitives/avatar/AvatarGroup.tsx +56 -0
  275. package/src/components/primitives/avatar/avatar.css +200 -0
  276. package/src/components/primitives/badge/Badge.tsx +75 -0
  277. package/src/components/primitives/badge/CountBadge.tsx +20 -0
  278. package/src/components/primitives/badge/StatusBadge.tsx +111 -0
  279. package/src/components/primitives/badge/badge.css +182 -0
  280. package/src/components/primitives/badge/odometer.css +62 -0
  281. package/src/components/primitives/badge/odometer.tsx +36 -0
  282. package/src/components/primitives/button/Button.tsx +102 -0
  283. package/src/components/primitives/button/button.css +269 -0
  284. package/src/components/primitives/checkbox/Checkbox.tsx +76 -0
  285. package/src/components/primitives/checkbox/check-glyph.tsx +28 -0
  286. package/src/components/primitives/checkbox/checkbox.css +177 -0
  287. package/src/components/primitives/collapse/Collapse.tsx +86 -0
  288. package/src/components/primitives/collapse/collapse.css +88 -0
  289. package/src/components/primitives/collapse/collapse.typecheck.tsx +29 -0
  290. package/src/components/primitives/input/NumberField.tsx +139 -0
  291. package/src/components/primitives/input/OtpField.tsx +134 -0
  292. package/src/components/primitives/input/TextField.tsx +110 -0
  293. package/src/components/primitives/input/field-chrome.tsx +83 -0
  294. package/src/components/primitives/input/input.css +333 -0
  295. package/src/components/primitives/radio-group/RadioGroup.tsx +183 -0
  296. package/src/components/primitives/radio-group/radio-group.css +300 -0
  297. package/src/components/primitives/tag/Tag.tsx +143 -0
  298. package/src/components/primitives/tag/ToggleTag.tsx +97 -0
  299. package/src/components/primitives/tag/tag.css +248 -0
  300. package/src/components/primitives/textarea/Textarea.tsx +190 -0
  301. package/src/components/primitives/textarea/textarea.css +219 -0
  302. package/src/components/primitives/toggle/Toggle.tsx +105 -0
  303. package/src/components/primitives/toggle/toggle.css +152 -0
  304. package/src/css.d.ts +1 -0
  305. package/src/dom-props.ts +1 -0
  306. package/src/engine/animate.ts +141 -0
  307. package/src/engine/drag.ts +53 -0
  308. package/src/engine/ease.ts +155 -0
  309. package/src/engine/flip.ts +59 -0
  310. package/src/engine/index.ts +13 -0
  311. package/src/mcp/server.ts +420 -0
  312. package/src/motion/element.tsx +53 -0
  313. package/src/motion/flip.tsx +87 -0
  314. package/src/motion/glide.tsx +47 -0
  315. package/src/motion/motion-timing.ts +33 -0
  316. package/src/motion/presence-context.ts +18 -0
  317. package/src/motion/presence.tsx +91 -0
  318. package/src/motion/timing.ts +49 -0
  319. package/src/motion/use-motion.ts +64 -0
  320. package/src/styles.css +26 -0
  321. package/src/tokens/avatar.css +20 -0
  322. package/src/tokens/color.css +58 -0
  323. package/src/tokens/elevation.css +22 -0
  324. package/src/tokens/fonts.css +3 -0
  325. package/src/tokens/glass.css +20 -0
  326. package/src/tokens/icons.css +7 -0
  327. package/src/tokens/layers.css +6 -0
  328. package/src/tokens/motion-scale.ts +17 -0
  329. package/src/tokens/motion-tokens.ts +92 -0
  330. package/src/tokens/motion.css +49 -0
  331. package/src/tokens/radius.css +11 -0
  332. package/src/tokens/semantic.css +65 -0
  333. package/src/tokens/spacing.css +26 -0
  334. package/src/tokens/typography.css +52 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tabsir Ahammed
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # Zyncat UI
2
+
3
+ A premium React design system - modern CSS + a small, closed token vocabulary, applied
4
+ consistently. Restraint, calm motion, no Tailwind, no CSS-in-JS, no UI libraries.
5
+
6
+ **React 19 - TypeScript - ships compiled ESM + types.** Import the whole library or a single
7
+ component; link one base stylesheet - each component loads its own CSS automatically.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @zyncat/ui
13
+ # peers (you likely already have them):
14
+ pnpm add react react-dom
15
+ ```
16
+
17
+ | Peer | Range | Used for |
18
+ | --------------------- | ----- | -------------------------------------------------------------------- |
19
+ | `react` / `react-dom` | `^19` | components; `createRoot`/`createPortal` for imperative toast/tooltip |
20
+
21
+ Enter/exit, layout and gesture animation are built in (a small WAAPI engine) - no animation library to install.
22
+
23
+ Icons are **bundled** (a small curated Phosphor set) - there is no icon peer to install.
24
+
25
+ ## Use it
26
+
27
+ No bundler config and no `transpilePackages` - the package ships built ESM with the `'use client'`
28
+ directives intact, so Next.js App Router boundaries just work.
29
+
30
+ ```tsx
31
+ import { Button, toast } from '@zyncat/ui';
32
+ import '@zyncat/ui/styles.css'; // base layer - link once, at the app root
33
+ ```
34
+
35
+ `styles.css` is the **base layer only** - fonts, design tokens (the `:root` custom
36
+ properties) and the shared `glass` utility. Link it exactly once at the app root.
37
+
38
+ You never import per-component CSS: every component imports its own stylesheet, so your
39
+ bundler code-splits and lazy-loads it with the component. Import `@zyncat/ui/dialog` and
40
+ only `dialog.css` ships (plus the `overlay`/`icon` styles it reuses, deduped) - not the
41
+ other 30 components' CSS.
42
+
43
+ ### Import a single component
44
+
45
+ Every component is also a subpath export, so you can pull just one:
46
+
47
+ ```tsx
48
+ import { Button } from '@zyncat/ui/button';
49
+ import { DateField } from '@zyncat/ui/date-field';
50
+ ```
51
+
52
+ The barrel is side-effect-free and tree-shakes, so `import { Button } from '@zyncat/ui'` is
53
+ equally lean in a bundler - subpaths help in non-bundled or explicit setups. CSS follows the
54
+ same module graph: components you don't use drop their stylesheets too.
55
+
56
+ ## Components
57
+
58
+ | Group | Components |
59
+ | ------------------- | --------------------------------------------------------------------------------------------- |
60
+ | Primitives | Button, Collapse, Badge, StatusBadge, CountBadge |
61
+ | Forms | TextField, NumberField, OtpField, Textarea, Checkbox, Toggle, RadioGroup, Select, MultiSelect |
62
+ | Data | Avatar, AvatarGroup, Tag, ToggleTag, Table, Pagination |
63
+ | Date, time & tabs | DateField, DateTimeField, DateRangeField, TimeField, Tabs |
64
+ | Overlays & feedback | Alert, Toast, Tooltip, Dialog, Popover, Sheet |
65
+
66
+ Each is a named export from the barrel and a subpath (`@zyncat/ui/<kebab-name>`). Props are
67
+ documented inline in the types; see [`llms.txt`](./llms.txt) for per-component examples.
68
+
69
+ ## For AI coding agents
70
+
71
+ **MCP server (preferred).** The package bundles a zero-dependency MCP server (stdio) so agents
72
+ query the API surface instead of grepping `node_modules`: `list_components` (index + conventions),
73
+ `get_component` (usage docs + complete prop types, shared type chunks inlined), `search_api`
74
+ (which component owns a prop/type/token), `get_tokens` (the token vocabulary with real values).
75
+ Register it in the consuming project - for Claude Code, `.mcp.json` at the project root:
76
+
77
+ ```json
78
+ { "mcpServers": { "zyncat-ui": { "command": "node", "args": ["./node_modules/@zyncat/ui/dist/mcp.js"] } } }
79
+ ```
80
+
81
+ Any MCP client works (also exposed as the `zyncat-ui-mcp` bin). The server reads the installed
82
+ package's `llms.txt`, `dist/*.d.ts` and `src/tokens/*.css` at call time, so answers always match
83
+ the installed version.
84
+
85
+ Without MCP, the same contract is readable directly:
86
+
87
+ - **`node_modules/@zyncat/ui/dist/*.d.ts`** - every component's props carry inline TSDoc. This is
88
+ the machine-readable source of truth (e.g. `dist/button.d.ts` fully describes `ButtonProps`).
89
+ - **`llms.txt`** (package root) - a compact, per-component index: purpose - import - a minimal
90
+ example. Cheaper to scan than every `.d.ts`.
91
+ - This README.
92
+
93
+ ## Copy-paste instead
94
+
95
+ The tarball also ships `src/`, so you can lift a component straight from
96
+ `node_modules/@zyncat/ui/src/components/<name>/` into your project. Components aren't fully
97
+ self-contained - they share `src/tokens/`, the `motion-tokens` bridge, the internal `icon/`, and a
98
+ few `*-core` helpers - so copy those alongside. (A shadcn-style registry/CLI could automate this
99
+ later.)
100
+
101
+ ## Icons
102
+
103
+ Components render their own glyphs from a small curated Phosphor set, **bundled in** - no icon peer
104
+ to install. Zyncat UI does **not** export an `Icon` component, so where a prop takes an icon
105
+ (`iconLeft`, `leadingIcon`, a `Tag`'s `icon`, ...) pass your own node - any `ReactNode` (e.g. an
106
+ `@phosphor-icons/react` element, if you choose to use it).
107
+
108
+ ## What's inside
109
+
110
+ ```
111
+ src/ source (also shipped, for copy-paste)
112
+ -- index.ts public barrel
113
+ -- styles.css base layer: fonts + tokens + glass (link once)
114
+ -- tokens/ CSS custom properties + motion-tokens.ts (JS and CSS motion bridge)
115
+ -- components/ <domain>/Name.tsx + name.css (each Tsx imports its own CSS -> lazy-loaded)
116
+ dist/ compiled ESM + .d.ts - what you import
117
+ ```
118
+
119
+ ## Notes
120
+
121
+ - **Fonts.** `src/tokens/fonts.css` pulls Geist + Geist Mono from Google Fonts via a remote
122
+ `@import`. Self-host the families to drop the render-blocking network hop.
123
+ - **Styling is token-driven.** Re-skin by overriding the CSS custom properties in your own
124
+ stylesheet loaded after `@zyncat/ui/styles.css` - never fork the source.
125
+
126
+ ## Develop
127
+
128
+ ```bash
129
+ pnpm install
130
+ pnpm build # tsup - dist/ (ESM + .d.ts)
131
+ pnpm typecheck # tsc --noEmit
132
+ pnpm format # prettier --write
133
+ ```
package/dist/alert.css ADDED
@@ -0,0 +1,132 @@
1
+ /* alert.css - the persistent in-flow status message: a lit tinted pane per tone. */
2
+
3
+ .alert-shell {
4
+ overflow: hidden;
5
+ }
6
+
7
+ .alert {
8
+ /* tone hooks - repointed by [data-tone] below; info is the default */
9
+ --alert-hue: var(--info);
10
+ --alert-fg: var(--info-text);
11
+ --alert-bg: var(--info-subtle);
12
+ --alert-wash: var(--accent-wash); /* info's wash = accent (teal) */
13
+
14
+ box-sizing: border-box;
15
+ display: flex;
16
+ align-items: center;
17
+ gap: var(--space-3);
18
+ padding: var(--space-3) var(--space-4);
19
+ /* the lit pane: top-light gradient over the tint + 1px inner highlight (Button's lighting model) */
20
+ background: linear-gradient(180deg, color-mix(in oklab, var(--bg-surface) 45%, var(--alert-bg)), var(--alert-bg));
21
+ border: var(--border-hairline) solid color-mix(in oklab, var(--alert-hue) 30%, transparent);
22
+ border-radius: var(--radius-lg);
23
+ box-shadow: inset 0 1px 0 0 rgb(255 255 255 / 0.55);
24
+ }
25
+
26
+ .alert[data-tone='success'] {
27
+ --alert-hue: var(--success);
28
+ --alert-fg: var(--success-text);
29
+ --alert-bg: var(--success-subtle);
30
+ --alert-wash: var(--success-wash);
31
+ }
32
+ .alert[data-tone='warning'] {
33
+ --alert-hue: var(--warning);
34
+ --alert-fg: var(--warning-text);
35
+ --alert-bg: var(--warning-subtle);
36
+ --alert-wash: var(--warning-wash);
37
+ }
38
+ .alert[data-tone='danger'] {
39
+ --alert-hue: var(--danger);
40
+ --alert-fg: var(--danger-text);
41
+ --alert-bg: var(--danger-subtle);
42
+ --alert-wash: var(--danger-wash);
43
+ }
44
+
45
+ /* with a description: glyph rides the title line, controls stay centered */
46
+ .alert:has(.alert__desc) {
47
+ align-items: flex-start;
48
+ }
49
+ .alert:has(.alert__desc) .alert__action,
50
+ .alert:has(.alert__desc) .alert__close {
51
+ align-self: center;
52
+ }
53
+
54
+ .alert--banner {
55
+ border-radius: 0;
56
+ border-block-start: 0;
57
+ border-inline: 0;
58
+ padding-inline: var(--space-6);
59
+ }
60
+
61
+ /* Glyph - one --leading-body tall so it centers on the title line. */
62
+ .alert__icon {
63
+ flex: none;
64
+ display: grid;
65
+ place-items: center;
66
+ height: var(--leading-body);
67
+ color: var(--alert-hue);
68
+ }
69
+
70
+ .alert__body {
71
+ flex: 1 1 auto;
72
+ min-width: 0;
73
+ }
74
+ .alert__title {
75
+ margin: 0;
76
+ font: var(--type-label);
77
+ color: var(--alert-fg);
78
+ text-wrap: pretty;
79
+ }
80
+ .alert__desc {
81
+ margin: var(--space-1) 0 0;
82
+ font: var(--type-caption);
83
+ color: color-mix(in oklab, var(--alert-fg) 56%, var(--text-body));
84
+ text-wrap: pretty;
85
+ }
86
+
87
+ /* Action - the system .btn .btn--sm re-skinned to the pane's tone (alert-local chrome, not a global Button variant). */
88
+ .alert__action {
89
+ flex: none;
90
+ color: var(--alert-fg);
91
+ background: transparent;
92
+ }
93
+ .alert__action:hover:not(:disabled) {
94
+ color: var(--alert-fg);
95
+ background: var(--alert-wash);
96
+ }
97
+ .alert__action:active:not(:disabled) {
98
+ background: color-mix(in oklab, var(--alert-hue) 16%, transparent);
99
+ transform: translateY(var(--space-px));
100
+ }
101
+ .alert[data-tone='danger'] .alert__action {
102
+ --btn-ring: var(--ring-danger);
103
+ }
104
+
105
+ /* Dismiss - always visible (alerts persist; no hover-reveal like toast). */
106
+ .alert__close {
107
+ flex: none;
108
+ appearance: none;
109
+ display: grid;
110
+ place-items: center;
111
+ width: var(--space-6);
112
+ height: var(--space-6);
113
+ margin: 0;
114
+ padding: 0;
115
+ border: none;
116
+ border-radius: var(--radius-sm);
117
+ background: transparent;
118
+ color: color-mix(in oklab, var(--alert-fg) 64%, transparent);
119
+ cursor: pointer;
120
+ transition: var(--transition-control);
121
+ }
122
+ .alert__close:hover {
123
+ background: color-mix(in oklab, var(--alert-fg) 9%, transparent);
124
+ color: var(--alert-fg);
125
+ }
126
+ .alert__close:active {
127
+ background: color-mix(in oklab, var(--alert-fg) 14%, transparent);
128
+ }
129
+ .alert__close:focus-visible {
130
+ outline: none;
131
+ box-shadow: var(--focus-ring);
132
+ }
@@ -0,0 +1,46 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties, HTMLAttributes } from 'react';
3
+ import { D as DisableableAnimation } from './timing-7JA_zQHP.js';
4
+ import { D as DataAttributes } from './dom-props-C0jrllBw.js';
5
+ import './motion-scale-Canq4stZ.js';
6
+
7
+ type AlertTone = 'info' | 'success' | 'warning' | 'danger';
8
+ interface AlertAction {
9
+ /** Sentence-case label, e.g. "Update billing". */
10
+ label: string;
11
+ onClick?: () => void;
12
+ }
13
+ interface AlertOwnProps {
14
+ /** Status of the message; info/success are polite, warning/danger assertive. Default 'info'. */
15
+ tone?: AlertTone;
16
+ /** The message - sentence case, ideally one line. */
17
+ title: ReactNode;
18
+ /** Optional description; stays neutral - tone marks the message, not the prose. */
19
+ children?: ReactNode;
20
+ /** One action max, rendered as the system secondary small button. */
21
+ action?: AlertAction;
22
+ /** Renders the always-visible close button. Uncontrolled unless `open` is given. */
23
+ dismissible?: boolean;
24
+ /** Fires on dismiss. With `open` set, the parent owns hiding the alert. */
25
+ onDismiss?: () => void;
26
+ /** Controlled visibility; omit for uncontrolled. Exit eases shut (height collapse). */
27
+ open?: boolean;
28
+ /** App-level strip: square corners, hairline below only. Paint modifier. */
29
+ banner?: boolean;
30
+ /** Override the tone glyph; pass null to render no glyph. */
31
+ icon?: ReactNode | null;
32
+ /** Extra class(es) merged onto the alert. */
33
+ className?: string;
34
+ /** Inline styles merged onto the alert. */
35
+ style?: CSSProperties;
36
+ /** Enter/exit timing - motion tokens only, or `null` to disable (the height collapse snaps).
37
+ * @default height 'slow'/'entrance'; opacity in 'base'/'entrance', out 'fast'/'exit' */
38
+ animation?: DisableableAnimation;
39
+ }
40
+ interface AlertProps extends AlertOwnProps {
41
+ /** Standard <div> attributes (aria-*, data-*, ...) forwarded to the alert. */
42
+ htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof AlertOwnProps> & DataAttributes;
43
+ }
44
+ declare function Alert({ tone, title, children, action, dismissible, onDismiss, open, banner, icon, className, style, htmlProps, animation, }: AlertProps): react.JSX.Element;
45
+
46
+ export { Alert, type AlertAction, type AlertProps, type AlertTone };
package/dist/alert.js ADDED
@@ -0,0 +1,80 @@
1
+ 'use client';import { Motion } from './chunk-36WVAQKL.js';
2
+ import { resolveMotionTiming } from './chunk-NEF5XAHG.js';
3
+ import { Presence } from './chunk-MXOPCFWR.js';
4
+ import './chunk-W3SHPKSB.js';
5
+ import './chunk-JSKXZMLH.js';
6
+ import './chunk-L3Q3VDIW.js';
7
+ import { IconSlot } from './chunk-2ERBBFZS.js';
8
+ import { Icon } from './chunk-3SBCBYB7.js';
9
+ import { useControllable } from './chunk-MMRIQNEN.js';
10
+ import './chunk-S5ZTZANS.js';
11
+ import { Button } from './chunk-U5QQZC3U.js';
12
+ import './chunk-VTJTGVZZ.js';
13
+ import { cx } from './chunk-QGNC7LH5.js';
14
+ import './alert.css';
15
+ import { jsx, jsxs } from 'react/jsx-runtime';
16
+
17
+ var ALERT_HEIGHT_TIMING = {
18
+ open: { duration: "slow", ease: "entrance" },
19
+ close: { duration: "slow", ease: "entrance" }
20
+ };
21
+ var ALERT_OPACITY_TIMING = {
22
+ open: { duration: "base", ease: "entrance" },
23
+ close: { duration: "fast", ease: "exit" }
24
+ };
25
+ var TONE_GLYPH = {
26
+ info: "info",
27
+ success: "check-circle",
28
+ warning: "warning",
29
+ danger: "warning-circle"
30
+ };
31
+ var TONE_ROLE = { info: "status", success: "status", warning: "alert", danger: "alert" };
32
+ function Alert({
33
+ tone = "info",
34
+ title,
35
+ children = null,
36
+ action = null,
37
+ dismissible = false,
38
+ onDismiss,
39
+ open,
40
+ banner = false,
41
+ icon,
42
+ className = "",
43
+ style,
44
+ htmlProps,
45
+ animation
46
+ }) {
47
+ const [isOpen, setOpen] = useControllable(open, true, onDismiss);
48
+ const dismiss = () => setOpen(false);
49
+ const h = resolveMotionTiming(animation, ALERT_HEIGHT_TIMING);
50
+ const o = resolveMotionTiming(animation, ALERT_OPACITY_TIMING);
51
+ const cls = cx("alert", banner && "alert--banner", className);
52
+ return /* @__PURE__ */ jsx(Presence, { initial: false, children: isOpen && /* @__PURE__ */ jsx(
53
+ Motion,
54
+ {
55
+ className: "alert-shell",
56
+ animate: [
57
+ { height: [0, "auto"], timing: h.open },
58
+ { opacity: [0, 1], timing: o.open }
59
+ ],
60
+ exit: [
61
+ { height: ["auto", 0], timing: h.close },
62
+ { opacity: [1, 0], timing: o.close }
63
+ ],
64
+ children: /* @__PURE__ */ jsxs("div", { className: cls, style, "data-tone": tone, role: TONE_ROLE[tone] || "status", ...htmlProps, children: [
65
+ icon === null ? null : /* @__PURE__ */ jsx("span", { className: "alert__icon", "aria-hidden": "true", children: icon !== void 0 ? /* @__PURE__ */ jsx(IconSlot, { size: "md", children: icon }) : /* @__PURE__ */ jsx(Icon, { name: TONE_GLYPH[tone] || "info", size: "md" }) }),
66
+ /* @__PURE__ */ jsxs("div", { className: "alert__body", children: [
67
+ /* @__PURE__ */ jsx("p", { className: "alert__title", children: title }),
68
+ children != null && /* @__PURE__ */ jsx("p", { className: "alert__desc", children })
69
+ ] }),
70
+ action && /* @__PURE__ */ jsx(Button, { variant: "unstyled", size: "sm", className: "alert__action", onClick: action.onClick, children: action.label }),
71
+ dismissible && /* @__PURE__ */ jsx("button", { type: "button", className: "alert__close", "aria-label": "Dismiss", onClick: dismiss, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: "sm" }) })
72
+ ] })
73
+ },
74
+ "alert-shell"
75
+ ) });
76
+ }
77
+
78
+ export { Alert };
79
+ //# sourceMappingURL=alert.js.map
80
+ //# sourceMappingURL=alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/composites/alert/Alert.tsx"],"names":[],"mappings":"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","file":"alert.js","sourcesContent":["'use client';\n\nimport './alert.css';\nimport type { CSSProperties, HTMLAttributes, ReactNode } from 'react';\nimport { Presence } from '../../../motion/presence';\nimport { Motion } from '../../../motion/element';\nimport { resolveMotionTiming } from '../../../motion/motion-timing';\nimport type { DisableableAnimation } from '../../../motion/timing';\nimport { Icon, type IconName } from '../../internal/icon/Icon';\nimport { Button } from '../../primitives/button/Button';\nimport { IconSlot } from '../../internal/icon/IconSlot';\nimport { useControllable } from '../../internal/hooks/use-controllable';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\nexport type AlertTone = 'info' | 'success' | 'warning' | 'danger';\n\nexport interface AlertAction {\n /** Sentence-case label, e.g. \"Update billing\". */\n label: string;\n onClick?: () => void;\n}\n\ninterface AlertOwnProps {\n /** Status of the message; info/success are polite, warning/danger assertive. Default 'info'. */\n tone?: AlertTone;\n /** The message - sentence case, ideally one line. */\n title: ReactNode;\n /** Optional description; stays neutral - tone marks the message, not the prose. */\n children?: ReactNode;\n /** One action max, rendered as the system secondary small button. */\n action?: AlertAction;\n /** Renders the always-visible close button. Uncontrolled unless `open` is given. */\n dismissible?: boolean;\n /** Fires on dismiss. With `open` set, the parent owns hiding the alert. */\n onDismiss?: () => void;\n /** Controlled visibility; omit for uncontrolled. Exit eases shut (height collapse). */\n open?: boolean;\n /** App-level strip: square corners, hairline below only. Paint modifier. */\n banner?: boolean;\n /** Override the tone glyph; pass null to render no glyph. */\n icon?: ReactNode | null;\n /** Extra class(es) merged onto the alert. */\n className?: string;\n /** Inline styles merged onto the alert. */\n style?: CSSProperties;\n /** Enter/exit timing - motion tokens only, or `null` to disable (the height collapse snaps).\n * @default height 'slow'/'entrance'; opacity in 'base'/'entrance', out 'fast'/'exit' */\n animation?: DisableableAnimation;\n}\n\nexport interface AlertProps extends AlertOwnProps {\n /** Standard <div> attributes (aria-*, data-*, ...) forwarded to the alert. */\n htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof AlertOwnProps> & DataAttributes;\n}\n\nconst ALERT_HEIGHT_TIMING = {\n open: { duration: 'slow', ease: 'entrance' },\n close: { duration: 'slow', ease: 'entrance' },\n} as const;\nconst ALERT_OPACITY_TIMING = {\n open: { duration: 'base', ease: 'entrance' },\n close: { duration: 'fast', ease: 'exit' },\n} as const;\n\nconst TONE_GLYPH: Record<AlertTone, IconName> = {\n info: 'info',\n success: 'check-circle',\n warning: 'warning',\n danger: 'warning-circle',\n};\nconst TONE_ROLE: Record<AlertTone, string> = { info: 'status', success: 'status', warning: 'alert', danger: 'alert' };\n\nexport function Alert({\n tone = 'info',\n title,\n children = null,\n action = null,\n dismissible = false,\n onDismiss,\n open,\n banner = false,\n icon,\n className = '',\n style,\n htmlProps,\n animation,\n}: AlertProps) {\n const [isOpen, setOpen] = useControllable(open, true, onDismiss);\n const dismiss = () => setOpen(false);\n\n const h = resolveMotionTiming(animation, ALERT_HEIGHT_TIMING);\n const o = resolveMotionTiming(animation, ALERT_OPACITY_TIMING);\n\n const cls = cx('alert', banner && 'alert--banner', className);\n\n return (\n <Presence initial={false}>\n {isOpen && (\n <Motion\n key=\"alert-shell\"\n className=\"alert-shell\"\n animate={[\n { height: [0, 'auto'], timing: h.open },\n { opacity: [0, 1], timing: o.open },\n ]}\n exit={[\n { height: ['auto', 0], timing: h.close },\n { opacity: [1, 0], timing: o.close },\n ]}\n >\n <div className={cls} style={style} data-tone={tone} role={TONE_ROLE[tone] || 'status'} {...htmlProps}>\n {icon === null ? null : (\n <span className=\"alert__icon\" aria-hidden=\"true\">\n {icon !== undefined ? (\n <IconSlot size=\"md\">{icon}</IconSlot>\n ) : (\n <Icon name={TONE_GLYPH[tone] || 'info'} size=\"md\" />\n )}\n </span>\n )}\n <div className=\"alert__body\">\n <p className=\"alert__title\">{title}</p>\n {children != null && <p className=\"alert__desc\">{children}</p>}\n </div>\n {action && (\n <Button variant=\"unstyled\" size=\"sm\" className=\"alert__action\" onClick={action.onClick}>\n {action.label}\n </Button>\n )}\n {dismissible && (\n <button type=\"button\" className=\"alert__close\" aria-label=\"Dismiss\" onClick={dismiss}>\n <Icon name=\"close\" size=\"sm\" />\n </button>\n )}\n </div>\n </Motion>\n )}\n </Presence>\n );\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties, HTMLAttributes } from 'react';
3
+ import { AvatarSize } from './avatar.js';
4
+ import { D as DataAttributes } from './dom-props-C0jrllBw.js';
5
+
6
+ interface AvatarGroupOwnProps {
7
+ /** The `Avatar` elements to stack; each is cloned to force `size`, then sliced to `max`. */
8
+ children: ReactNode;
9
+ /** Max visible avatars before "+N" overflow chip. Default 5. */
10
+ max?: number;
11
+ /** Uniform size applied to all children. Default 'md'. */
12
+ size?: AvatarSize;
13
+ /** Extra class(es) merged onto the group wrapper. */
14
+ className?: string;
15
+ /** Inline styles merged onto the group wrapper. */
16
+ style?: CSSProperties;
17
+ }
18
+ interface AvatarGroupProps extends AvatarGroupOwnProps {
19
+ /** Standard <span> attributes forwarded to the group wrapper. */
20
+ htmlProps?: Omit<HTMLAttributes<HTMLSpanElement>, keyof AvatarGroupOwnProps> & DataAttributes;
21
+ }
22
+ declare function AvatarGroup({ children, max, size, className, style, htmlProps }: AvatarGroupProps): react.JSX.Element;
23
+
24
+ export { AvatarGroup, type AvatarGroupProps };
@@ -0,0 +1,23 @@
1
+ 'use client';import { cx } from './chunk-QGNC7LH5.js';
2
+ import './avatar.css';
3
+ import { Children, isValidElement, cloneElement } from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ function AvatarGroup({ children, max = 5, size = "md", className = "", style, htmlProps }) {
7
+ const items = Children.toArray(children);
8
+ const visible = max > 0 ? items.slice(0, max) : items;
9
+ const overflow = items.length - visible.length;
10
+ return /* @__PURE__ */ jsxs("span", { className: cx("avatar-group", className), style, ...htmlProps, children: [
11
+ visible.map(
12
+ (child, i) => isValidElement(child) ? cloneElement(child, { size, key: child.key ?? i }) : child
13
+ ),
14
+ overflow > 0 && /* @__PURE__ */ jsx("span", { className: `avatar avatar--${size} avatar--overflow`, role: "img", "aria-label": `${overflow} more`, children: /* @__PURE__ */ jsx("span", { className: "avatar__face", children: /* @__PURE__ */ jsxs("span", { className: "avatar__initials", children: [
15
+ "+",
16
+ overflow
17
+ ] }) }) })
18
+ ] });
19
+ }
20
+
21
+ export { AvatarGroup };
22
+ //# sourceMappingURL=avatar-group.js.map
23
+ //# sourceMappingURL=avatar-group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/primitives/avatar/AvatarGroup.tsx"],"names":[],"mappings":";;;;;AAkCO,SAAS,WAAA,CAAY,EAAE,QAAA,EAAU,GAAA,GAAM,CAAA,EAAG,IAAA,GAAO,IAAA,EAAM,SAAA,GAAY,EAAA,EAAI,KAAA,EAAO,SAAA,EAAU,EAAqB;AAClH,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,OAAA,CAAQ,QAAQ,CAAA;AACvC,EAAA,MAAM,UAAU,GAAA,GAAM,CAAA,GAAI,MAAM,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA,GAAI,KAAA;AAChD,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,MAAA,GAAS,OAAA,CAAQ,MAAA;AAExC,EAAA,uBACE,IAAA,CAAC,UAAK,SAAA,EAAW,EAAA,CAAG,gBAAgB,SAAS,CAAA,EAAG,KAAA,EAAe,GAAG,SAAA,EAC/D,QAAA,EAAA;AAAA,IAAA,OAAA,CAAQ,GAAA;AAAA,MAAI,CAAC,KAAA,EAAO,CAAA,KACnB,cAAA,CAAe,KAAK,CAAA,GAChB,YAAA,CAAa,KAAA,EAA8C,EAAE,MAAM,GAAA,EAAK,KAAA,CAAM,GAAA,IAAO,CAAA,EAAG,CAAA,GACxF;AAAA,KACN;AAAA,IACC,QAAA,GAAW,qBACV,GAAA,CAAC,MAAA,EAAA,EAAK,WAAW,CAAA,eAAA,EAAkB,IAAI,qBAAqB,IAAA,EAAK,KAAA,EAAM,cAAY,CAAA,EAAG,QAAQ,SAC5F,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,cAAA,EACd,QAAA,kBAAA,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kBAAA,EAAmB,QAAA,EAAA;AAAA,MAAA,GAAA;AAAA,MAAE;AAAA,KAAA,EAAS,GAChD,CAAA,EACF;AAAA,GAAA,EAEJ,CAAA;AAEJ","file":"avatar-group.js","sourcesContent":["'use client';\n\nimport './avatar.css';\nimport {\n Children,\n cloneElement,\n isValidElement,\n type CSSProperties,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport type { AvatarSize } from './Avatar';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\ninterface AvatarGroupOwnProps {\n /** The `Avatar` elements to stack; each is cloned to force `size`, then sliced to `max`. */\n children: ReactNode;\n /** Max visible avatars before \"+N\" overflow chip. Default 5. */\n max?: number;\n /** Uniform size applied to all children. Default 'md'. */\n size?: AvatarSize;\n /** Extra class(es) merged onto the group wrapper. */\n className?: string;\n /** Inline styles merged onto the group wrapper. */\n style?: CSSProperties;\n}\n\nexport interface AvatarGroupProps extends AvatarGroupOwnProps {\n /** Standard <span> attributes forwarded to the group wrapper. */\n htmlProps?: Omit<HTMLAttributes<HTMLSpanElement>, keyof AvatarGroupOwnProps> & DataAttributes;\n}\n\nexport function AvatarGroup({ children, max = 5, size = 'md', className = '', style, htmlProps }: AvatarGroupProps) {\n const items = Children.toArray(children);\n const visible = max > 0 ? items.slice(0, max) : items;\n const overflow = items.length - visible.length;\n\n return (\n <span className={cx('avatar-group', className)} style={style} {...htmlProps}>\n {visible.map((child, i) =>\n isValidElement(child)\n ? cloneElement(child as ReactElement<{ size?: AvatarSize }>, { size, key: child.key ?? i })\n : child,\n )}\n {overflow > 0 && (\n <span className={`avatar avatar--${size} avatar--overflow`} role=\"img\" aria-label={`${overflow} more`}>\n <span className=\"avatar__face\">\n <span className=\"avatar__initials\">+{overflow}</span>\n </span>\n </span>\n )}\n </span>\n );\n}\n"]}