@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/dist/tabs.js ADDED
@@ -0,0 +1,181 @@
1
+ 'use client';import { useScrollEdges } from './chunk-BIDVNLJO.js';
2
+ import { useGlide, GlidePill } from './chunk-MKIQFK7S.js';
3
+ import { resolveMotionTiming } from './chunk-NEF5XAHG.js';
4
+ import { animate } from './chunk-L3Q3VDIW.js';
5
+ import { IconSlot } from './chunk-2ERBBFZS.js';
6
+ import { UIMotion } from './chunk-S5ZTZANS.js';
7
+ import './chunk-VTJTGVZZ.js';
8
+ import { cx } from './chunk-QGNC7LH5.js';
9
+ import './tabs.css';
10
+ import { useId, useRef, useLayoutEffect } from 'react';
11
+ import { jsx, jsxs } from 'react/jsx-runtime';
12
+
13
+ var SM = UIMotion;
14
+ var TABS_EDGE_PAD = 24;
15
+ var TABS_ENTER_X = 20;
16
+ function Tabs({ items = [], value, onChange, name, ariaLabel, className = "", style, htmlProps }) {
17
+ const autoId = useId();
18
+ const base = name || autoId;
19
+ const listRef = useRef(null);
20
+ const inkRef = useRef(null);
21
+ const tabRefs = useRef({});
22
+ const placedRef = useRef(false);
23
+ const valueRef = useRef(value);
24
+ valueRef.current = value;
25
+ const glide = useGlide(listRef);
26
+ const place = (animated) => {
27
+ const list = listRef.current, ink = inkRef.current;
28
+ const el = valueRef.current != null ? tabRefs.current[valueRef.current] : null;
29
+ if (!list || !ink) return;
30
+ if (!el) {
31
+ ink.style.opacity = "0";
32
+ placedRef.current = false;
33
+ return;
34
+ }
35
+ const next = { x: el.offsetLeft, w: el.offsetWidth };
36
+ ink.style.opacity = "1";
37
+ if (!animated || !placedRef.current || SM.reduced) {
38
+ animate(ink, { x: [next.x], width: [next.w], timing: { duration: 0 } });
39
+ } else {
40
+ const lr = list.getBoundingClientRect();
41
+ const ir = ink.getBoundingClientRect();
42
+ const cur = { x: ir.left - lr.left + list.scrollLeft, w: ir.width };
43
+ if (Math.abs(cur.x - next.x) > 0.5 || Math.abs(cur.w - next.w) > 0.5) {
44
+ const dir = next.x + next.w / 2 >= cur.x + cur.w / 2 ? 1 : -1;
45
+ const span = dir === 1 ? next.x + next.w - cur.x : cur.x + cur.w - next.x;
46
+ const lead = dir === 1 ? cur.x : next.x;
47
+ animate(ink, {
48
+ x: [cur.x, lead, next.x],
49
+ width: [cur.w, span, next.w],
50
+ timing: { duration: SM.dur.slow, times: [0, 0.55, 1], ease: [SM.ease.standard, SM.ease.entrance] }
51
+ });
52
+ }
53
+ }
54
+ placedRef.current = true;
55
+ };
56
+ const syncEdges = useScrollEdges(listRef, (edges, el) => {
57
+ el.dataset.fade = ((edges.left ? "start " : "") + (edges.right ? "end" : "")).trim();
58
+ });
59
+ useLayoutEffect(() => {
60
+ place(true);
61
+ const l = listRef.current, el = value != null ? tabRefs.current[value] : null;
62
+ if (l && el && l.scrollWidth > l.clientWidth) {
63
+ const behavior = SM.reduced ? "auto" : "smooth";
64
+ if (el.offsetLeft < l.scrollLeft + TABS_EDGE_PAD) {
65
+ l.scrollTo({ left: el.offsetLeft - TABS_EDGE_PAD, behavior });
66
+ } else if (el.offsetLeft + el.offsetWidth > l.scrollLeft + l.clientWidth - TABS_EDGE_PAD) {
67
+ l.scrollTo({ left: el.offsetLeft + el.offsetWidth - l.clientWidth + TABS_EDGE_PAD, behavior });
68
+ }
69
+ }
70
+ }, [value]);
71
+ useLayoutEffect(() => {
72
+ const ro = new ResizeObserver(() => {
73
+ place(false);
74
+ syncEdges();
75
+ });
76
+ if (listRef.current) ro.observe(listRef.current);
77
+ Object.values(tabRefs.current).forEach((el) => el && ro.observe(el));
78
+ syncEdges();
79
+ return () => ro.disconnect();
80
+ }, [items.length]);
81
+ const select = (v) => {
82
+ if (v === value || !onChange) return;
83
+ const idx = (x) => items.findIndex((i) => i.value === x);
84
+ onChange(v, idx(v) >= idx(value) ? 1 : -1);
85
+ };
86
+ const onKeyDown = (e) => {
87
+ const enabled = items.filter((i) => !i.disabled);
88
+ if (!enabled.length) return;
89
+ let next = null;
90
+ if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
91
+ const step = e.key === "ArrowRight" ? 1 : -1;
92
+ const i = enabled.findIndex((it) => it.value === value);
93
+ next = enabled[(i + step + enabled.length) % enabled.length];
94
+ } else if (e.key === "Home") {
95
+ next = enabled[0];
96
+ } else if (e.key === "End") {
97
+ next = enabled[enabled.length - 1];
98
+ }
99
+ if (!next) return;
100
+ e.preventDefault();
101
+ select(next.value);
102
+ const el = tabRefs.current[next.value];
103
+ if (el) el.focus();
104
+ };
105
+ const focusValue = items.some((i) => i.value === value && !i.disabled) ? value : (items.find((i) => !i.disabled) || {}).value;
106
+ return /* @__PURE__ */ jsx("div", { className: cx("tabs", className), style, ...htmlProps, children: /* @__PURE__ */ jsxs(
107
+ "div",
108
+ {
109
+ className: "tabs__list",
110
+ role: "tablist",
111
+ "aria-label": ariaLabel,
112
+ ref: listRef,
113
+ onKeyDown,
114
+ onPointerLeave: glide.leave,
115
+ children: [
116
+ /* @__PURE__ */ jsx(GlidePill, { className: "tab__hover", glide }),
117
+ items.map((it) => {
118
+ const selected = it.value === value;
119
+ return /* @__PURE__ */ jsx(
120
+ "button",
121
+ {
122
+ type: "button",
123
+ role: "tab",
124
+ id: base + "-tab-" + it.value,
125
+ "aria-selected": selected,
126
+ "aria-controls": name ? name + "-panel-" + it.value : void 0,
127
+ tabIndex: it.value === focusValue ? 0 : -1,
128
+ disabled: it.disabled,
129
+ className: "tab" + (selected ? " is-selected" : ""),
130
+ ref: (el) => {
131
+ tabRefs.current[it.value] = el;
132
+ },
133
+ onClick: () => select(it.value),
134
+ onPointerEnter: it.disabled ? void 0 : (e) => glide.enter(e.currentTarget.firstElementChild),
135
+ children: /* @__PURE__ */ jsxs("span", { className: "tab__pad", children: [
136
+ it.icon && /* @__PURE__ */ jsx(IconSlot, { size: "sm", children: it.icon }),
137
+ /* @__PURE__ */ jsx("span", { className: "tab__label", children: it.label }),
138
+ it.count != null && /* @__PURE__ */ jsx("span", { className: "tab__count", children: it.count })
139
+ ] })
140
+ },
141
+ it.value
142
+ );
143
+ }),
144
+ /* @__PURE__ */ jsx("span", { className: "tabs__ink", ref: inkRef, "aria-hidden": "true" }, "ink")
145
+ ]
146
+ }
147
+ ) });
148
+ }
149
+ var TABPANEL_TIMING = {
150
+ open: { duration: "base", ease: "entrance" },
151
+ close: { duration: "base", ease: "entrance" }
152
+ };
153
+ function TabPanel({ tab, name, dir = 0, className = "", style, children, animation, htmlProps }) {
154
+ const enter = resolveMotionTiming(animation, TABPANEL_TIMING).open;
155
+ const innerRef = useRef(null);
156
+ const enterRef = useRef(null);
157
+ useLayoutEffect(() => {
158
+ const el = innerRef.current;
159
+ if (!el) return;
160
+ enterRef.current?.stop();
161
+ enterRef.current = animate(el, { x: [dir * TABS_ENTER_X, 0], y: [4, 0], timing: enter });
162
+ return () => enterRef.current?.stop();
163
+ }, [tab]);
164
+ return /* @__PURE__ */ jsx(
165
+ "div",
166
+ {
167
+ role: "tabpanel",
168
+ tabIndex: 0,
169
+ id: name ? `${name}-panel-${tab}` : void 0,
170
+ "aria-labelledby": name ? `${name}-tab-${tab}` : void 0,
171
+ className: cx("tab-panel", className),
172
+ style,
173
+ ...htmlProps,
174
+ children: /* @__PURE__ */ jsx("div", { ref: innerRef, className: "tab-panel__inner", children })
175
+ }
176
+ );
177
+ }
178
+
179
+ export { TabPanel, Tabs };
180
+ //# sourceMappingURL=tabs.js.map
181
+ //# sourceMappingURL=tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/composites/tabs/Tabs.tsx"],"names":[],"mappings":"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","file":"tabs.js","sourcesContent":["'use client';\n\nimport './tabs.css';\nimport {\n useId,\n useLayoutEffect,\n useRef,\n type CSSProperties,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { animate } from '../../../engine';\nimport { UIMotion } from '../../../tokens/motion-tokens';\nimport { IconSlot } from '../../internal/icon/IconSlot';\nimport { GlidePill, useGlide } from '../../../motion/glide';\nimport { useScrollEdges } from '../../internal/hooks/use-scroll-edges';\nimport { type DisableableAnimation } from '../../../motion/timing';\nimport { resolveMotionTiming } from '../../../motion/motion-timing';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\nconst SM = UIMotion;\n\n/** One tab in the row. */\nexport interface TabItem {\n /** Stable identity - also used in the tab/panel id pair. */\n value: string;\n /** Visible tab text. */\n label: ReactNode;\n /** Leading icon - your own node. */\n icon?: ReactNode;\n /** Rendered mono + tabular. Pass a number or a preformatted string. */\n count?: number | string;\n /** Dims the tab, blocks selection, and skips it during arrow-key travel. */\n disabled?: boolean;\n}\n\ninterface TabsOwnProps {\n /** The tab row, in order. @default [] */\n items: TabItem[];\n /** Controlled - the value of the active tab (null/undefined hides the ink). */\n value: string | null | undefined;\n /**\n * Fires on click and on arrow-key travel (automatic activation).\n * `dir` is the direction of travel (+1 right / -1 left) - hand it to\n * TabPanel so content enters from the side the user moved toward.\n */\n onChange?: (value: string, dir: 1 | -1) => void;\n /**\n * Shared id prefix wiring tab and panel aria. Give Tabs and its TabPanel the\n * same `name`; omit it when the tabs have no managed panel.\n */\n name?: string;\n /** Accessible name for the tablist (e.g. \"Section views\"). */\n ariaLabel?: string;\n /** Extra class(es) merged onto the root. */\n className?: string;\n /** Inline styles merged onto the root. */\n style?: CSSProperties;\n}\n\nexport interface TabsProps extends TabsOwnProps {\n /** Standard <div> attributes (data-*, aria-*, ...) forwarded to the root. */\n htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof TabsOwnProps> & DataAttributes;\n}\n\nconst TABS_EDGE_PAD = 24;\nconst TABS_ENTER_X = 20;\n\nexport function Tabs({ items = [], value, onChange, name, ariaLabel, className = '', style, htmlProps }: TabsProps) {\n const autoId = useId();\n const base = name || autoId;\n\n const listRef = useRef<HTMLDivElement>(null);\n const inkRef = useRef<HTMLSpanElement>(null);\n const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});\n const placedRef = useRef(false);\n const valueRef = useRef(value);\n valueRef.current = value;\n\n const glide = useGlide(listRef);\n\n const place = (animated: boolean) => {\n const list = listRef.current,\n ink = inkRef.current;\n const el = valueRef.current != null ? tabRefs.current[valueRef.current] : null;\n if (!list || !ink) return;\n if (!el) {\n ink.style.opacity = '0';\n placedRef.current = false;\n return;\n }\n const next = { x: el.offsetLeft, w: el.offsetWidth };\n ink.style.opacity = '1';\n\n if (!animated || !placedRef.current || SM.reduced) {\n animate(ink, { x: [next.x], width: [next.w], timing: { duration: 0 } });\n } else {\n const lr = list.getBoundingClientRect();\n const ir = ink.getBoundingClientRect();\n const cur = { x: ir.left - lr.left + list.scrollLeft, w: ir.width };\n if (Math.abs(cur.x - next.x) > 0.5 || Math.abs(cur.w - next.w) > 0.5) {\n const dir = next.x + next.w / 2 >= cur.x + cur.w / 2 ? 1 : -1;\n const span = dir === 1 ? next.x + next.w - cur.x : cur.x + cur.w - next.x;\n const lead = dir === 1 ? cur.x : next.x;\n animate(ink, {\n x: [cur.x, lead, next.x],\n width: [cur.w, span, next.w],\n timing: { duration: SM.dur.slow, times: [0, 0.55, 1], ease: [SM.ease.standard, SM.ease.entrance] },\n });\n }\n }\n placedRef.current = true;\n };\n\n const syncEdges = useScrollEdges(listRef, (edges, el) => {\n el.dataset.fade = ((edges.left ? 'start ' : '') + (edges.right ? 'end' : '')).trim();\n });\n\n useLayoutEffect(() => {\n place(true);\n const l = listRef.current,\n el = value != null ? tabRefs.current[value] : null;\n if (l && el && l.scrollWidth > l.clientWidth) {\n const behavior: ScrollBehavior = SM.reduced ? 'auto' : 'smooth';\n if (el.offsetLeft < l.scrollLeft + TABS_EDGE_PAD) {\n l.scrollTo({ left: el.offsetLeft - TABS_EDGE_PAD, behavior });\n } else if (el.offsetLeft + el.offsetWidth > l.scrollLeft + l.clientWidth - TABS_EDGE_PAD) {\n l.scrollTo({ left: el.offsetLeft + el.offsetWidth - l.clientWidth + TABS_EDGE_PAD, behavior });\n }\n }\n }, [value]);\n\n useLayoutEffect(() => {\n const ro = new ResizeObserver(() => {\n place(false);\n syncEdges();\n });\n if (listRef.current) ro.observe(listRef.current);\n Object.values(tabRefs.current).forEach((el) => el && ro.observe(el));\n syncEdges();\n return () => ro.disconnect();\n }, [items.length]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const select = (v: string) => {\n if (v === value || !onChange) return;\n const idx = (x: string | null | undefined) => items.findIndex((i) => i.value === x);\n onChange(v, idx(v) >= idx(value) ? 1 : -1);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n const enabled = items.filter((i) => !i.disabled);\n if (!enabled.length) return;\n let next: TabItem | null = null;\n if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {\n const step = e.key === 'ArrowRight' ? 1 : -1;\n const i = enabled.findIndex((it) => it.value === value);\n next = enabled[(i + step + enabled.length) % enabled.length];\n } else if (e.key === 'Home') {\n next = enabled[0];\n } else if (e.key === 'End') {\n next = enabled[enabled.length - 1];\n }\n if (!next) return;\n e.preventDefault();\n select(next.value);\n const el = tabRefs.current[next.value];\n if (el) el.focus();\n };\n\n const focusValue = items.some((i) => i.value === value && !i.disabled)\n ? value\n : (items.find((i) => !i.disabled) || ({} as Partial<TabItem>)).value;\n\n return (\n <div className={cx('tabs', className)} style={style} {...htmlProps}>\n <div\n className=\"tabs__list\"\n role=\"tablist\"\n aria-label={ariaLabel}\n ref={listRef}\n onKeyDown={onKeyDown}\n onPointerLeave={glide.leave}\n >\n <GlidePill className=\"tab__hover\" glide={glide} />\n {items.map((it) => {\n const selected = it.value === value;\n return (\n <button\n key={it.value}\n type=\"button\"\n role=\"tab\"\n id={base + '-tab-' + it.value}\n aria-selected={selected}\n aria-controls={name ? name + '-panel-' + it.value : undefined}\n tabIndex={it.value === focusValue ? 0 : -1}\n disabled={it.disabled}\n className={'tab' + (selected ? ' is-selected' : '')}\n ref={(el) => {\n tabRefs.current[it.value] = el;\n }}\n onClick={() => select(it.value)}\n onPointerEnter={\n it.disabled ? undefined : (e) => glide.enter(e.currentTarget.firstElementChild as HTMLElement)\n }\n >\n <span className=\"tab__pad\">\n {it.icon && <IconSlot size=\"sm\">{it.icon}</IconSlot>}\n <span className=\"tab__label\">{it.label}</span>\n {it.count != null && <span className=\"tab__count\">{it.count}</span>}\n </span>\n </button>\n );\n })}\n <span className=\"tabs__ink\" key=\"ink\" ref={inkRef} aria-hidden=\"true\"></span>\n </div>\n </div>\n );\n}\n\ninterface TabPanelOwnProps {\n /** The active tab's value - changing it cuts to the new content. */\n tab: string;\n /** Same `name` as the paired Tabs - wires role/id/aria-labelledby. */\n name?: string;\n /** Direction of travel from Tabs' onChange; 0 = plain fade. */\n dir?: -1 | 0 | 1;\n /** Panel content - only this inner node animates in on `tab` change; the root chrome stays static. */\n children?: ReactNode;\n /** Entrance timing for the inner content - motion tokens only, or `null` to disable.\n * @default duration 'base' + ease 'entrance' */\n animation?: DisableableAnimation;\n /** Extra class(es) merged onto the root. */\n className?: string;\n /** Inline styles merged onto the root. */\n style?: CSSProperties;\n}\n\nexport interface TabPanelProps extends TabPanelOwnProps {\n /** Standard <div> attributes (data-*, aria-*, ...) forwarded to the root. */\n htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof TabPanelOwnProps> & DataAttributes;\n}\n\nconst TABPANEL_TIMING = {\n open: { duration: 'base', ease: 'entrance' },\n close: { duration: 'base', ease: 'entrance' },\n} as const;\n\nexport function TabPanel({ tab, name, dir = 0, className = '', style, children, animation, htmlProps }: TabPanelProps) {\n const enter = resolveMotionTiming(animation, TABPANEL_TIMING).open;\n const innerRef = useRef<HTMLDivElement | null>(null);\n const enterRef = useRef<ReturnType<typeof animate> | null>(null);\n\n useLayoutEffect(() => {\n const el = innerRef.current;\n if (!el) return;\n enterRef.current?.stop();\n enterRef.current = animate(el, { x: [dir * TABS_ENTER_X, 0], y: [4, 0], timing: enter });\n return () => enterRef.current?.stop();\n }, [tab]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <div\n role=\"tabpanel\"\n tabIndex={0}\n id={name ? `${name}-panel-${tab}` : undefined}\n aria-labelledby={name ? `${name}-tab-${tab}` : undefined}\n className={cx('tab-panel', className)}\n style={style}\n {...htmlProps}\n >\n <div ref={innerRef} className=\"tab-panel__inner\">\n {children}\n </div>\n </div>\n );\n}\n"]}
package/dist/tag.css ADDED
@@ -0,0 +1,248 @@
1
+ /* Tag / chip - interactive label (button-family chrome): base .tag + .tag--toggle sibling. */
2
+
3
+ .tag {
4
+ --tag-h: var(--control-height-sm);
5
+ /* button-family DNA: lit from above + a contact shadow (.btn--secondary) */
6
+ --tag-shadow: inset 0 1px 0 0 rgb(255 255 255 / 0.6), 0 1px 2px 0 rgb(var(--shadow-rgb) / 0.05);
7
+
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: var(--space-1);
11
+ height: var(--tag-h);
12
+ max-width: 100%;
13
+ padding-inline: var(--space-2);
14
+ border: var(--border-hairline) solid var(--border-default);
15
+ border-radius: var(--radius-sm);
16
+ background: var(--bg-surface);
17
+ color: var(--text-body);
18
+
19
+ font-family: var(--font-sans);
20
+ font-size: var(--size-caption);
21
+ line-height: 1;
22
+ font-weight: var(--weight-medium);
23
+ letter-spacing: var(--tracking-normal);
24
+ white-space: nowrap;
25
+ vertical-align: middle;
26
+ user-select: none;
27
+ -webkit-user-select: none;
28
+ box-shadow: var(--tag-shadow);
29
+
30
+ /* no transform transition here - Motion writes transforms on grouped tags (section C) */
31
+ transition: var(--transition-control);
32
+ }
33
+
34
+ .tag__label {
35
+ min-width: 0;
36
+ overflow: hidden;
37
+ text-overflow: ellipsis;
38
+ }
39
+
40
+ .tag--sm {
41
+ --tag-h: var(--space-5);
42
+ font-size: var(--size-micro);
43
+ }
44
+
45
+ .tag__icon {
46
+ display: inline-flex;
47
+ flex: none;
48
+ }
49
+ .tag__icon svg,
50
+ .tag__icon i {
51
+ display: block;
52
+ }
53
+
54
+ /* Dual-weight icon crossfade - transitions, not animations, so nothing plays on first paint. */
55
+ .tag__icon--dual {
56
+ display: inline-grid;
57
+ }
58
+ .tag__icon--dual > :is(i, svg) {
59
+ grid-area: 1 / 1;
60
+ transition:
61
+ opacity var(--duration-base) var(--ease-standard),
62
+ transform var(--duration-base) var(--ease-standard);
63
+ }
64
+ .tag__icon--dual > :is(i, svg):last-child {
65
+ opacity: 0;
66
+ transform: scale(0.6);
67
+ }
68
+ .tag--toggle[aria-pressed='true'] .tag__icon--dual > :is(i, svg):first-child {
69
+ opacity: 0;
70
+ }
71
+ .tag--toggle[aria-pressed='true'] .tag__icon--dual > :is(i, svg):last-child {
72
+ opacity: 1;
73
+ transform: scale(1);
74
+ transition:
75
+ opacity var(--duration-fast) var(--ease-standard),
76
+ transform var(--duration-slow) var(--ease-spring);
77
+ }
78
+
79
+ .tag__count {
80
+ font-family: var(--font-mono);
81
+ font-size: var(--size-micro);
82
+ font-variant-numeric: tabular-nums;
83
+ color: var(--text-subtle);
84
+ transition: color var(--duration-fast) var(--ease-standard);
85
+ }
86
+
87
+ .tag__remove {
88
+ display: inline-flex;
89
+ align-items: center;
90
+ justify-content: center;
91
+ flex: none;
92
+ width: calc(var(--tag-h) - var(--space-2));
93
+ height: calc(var(--tag-h) - var(--space-2));
94
+ margin-right: calc(var(--space-1) * -1);
95
+ padding: 0;
96
+ border: 0;
97
+ border-radius: var(--radius-full);
98
+ background: transparent;
99
+ color: var(--text-subtle);
100
+ cursor: pointer;
101
+ appearance: none;
102
+ -webkit-tap-highlight-color: transparent;
103
+ transition:
104
+ color var(--duration-fast) var(--ease-standard),
105
+ background-color var(--duration-fast) var(--ease-standard),
106
+ transform var(--duration-fast) var(--ease-standard);
107
+ }
108
+ .tag__remove svg {
109
+ display: block;
110
+ width: var(--space-3);
111
+ height: var(--space-3);
112
+ transition: transform var(--duration-base) var(--ease-standard);
113
+ }
114
+ .tag__remove:hover {
115
+ color: var(--text-strong);
116
+ background: var(--bg-muted);
117
+ }
118
+ .tag__remove:hover svg {
119
+ transform: rotate(30deg);
120
+ }
121
+ .tag__remove:active {
122
+ transform: scale(0.9);
123
+ }
124
+ .tag__remove:focus-visible {
125
+ outline: none;
126
+ box-shadow: var(--focus-ring);
127
+ }
128
+
129
+ .tag:has(.tag__remove:hover):not([data-disabled]),
130
+ .tag:has(.tag__remove:focus-visible) {
131
+ color: var(--text-muted);
132
+ border-color: var(--border-strong);
133
+ }
134
+
135
+ .tag--toggle {
136
+ cursor: pointer;
137
+ appearance: none;
138
+ -webkit-tap-highlight-color: transparent;
139
+ transition:
140
+ var(--transition-control),
141
+ transform var(--duration-fast) var(--ease-standard);
142
+ }
143
+ .tag--toggle:hover:not(:disabled) {
144
+ color: var(--text-strong);
145
+ border-color: var(--border-strong);
146
+ background: var(--neutral-wash);
147
+ }
148
+ .tag--toggle:active:not(:disabled) {
149
+ transform: translateY(var(--space-px));
150
+ background: var(--bg-muted);
151
+ --tag-shadow: inset 0 1px 2px 0 rgb(var(--shadow-rgb) / 0.07);
152
+ }
153
+ /* composed ring - never erases the resting shadow (.btn pattern) */
154
+ .tag--toggle:focus-visible {
155
+ outline: none;
156
+ box-shadow: var(--tag-shadow), var(--focus-ring);
157
+ }
158
+
159
+ /* Selected = accent wash, never a solid fill; the top sheen comes off (matte), the contact shadow stays. */
160
+ .tag--toggle[aria-pressed='true'] {
161
+ color: var(--text-accent);
162
+ border-color: var(--accent-border);
163
+ background: var(--accent-wash);
164
+ --tag-shadow: 0 1px 2px 0 rgb(var(--shadow-rgb) / 0.05);
165
+ }
166
+ .tag--toggle[aria-pressed='true']:hover:not(:disabled) {
167
+ color: var(--accent-active);
168
+ border-color: var(--accent-border);
169
+ background: var(--accent-wash);
170
+ }
171
+ .tag--toggle[aria-pressed='true']:active:not(:disabled) {
172
+ background: var(--accent-subtle);
173
+ }
174
+ .tag--toggle[aria-pressed='true'] .tag__count {
175
+ color: inherit;
176
+ }
177
+
178
+ /* Tick slot (Collapse width mechanism); the negative margin cancels the flex gap while collapsed, the inner margin restores it when open. */
179
+ .tag__check {
180
+ margin-right: calc(var(--space-1) * -1);
181
+ }
182
+ .tag__check svg {
183
+ display: block;
184
+ width: var(--space-3);
185
+ height: var(--space-3);
186
+ margin-right: var(--space-1);
187
+ }
188
+ .tag__check path {
189
+ stroke: currentColor;
190
+ stroke-dasharray: 1;
191
+ stroke-dashoffset: 1;
192
+ transition: stroke-dashoffset var(--duration-base) var(--ease-standard);
193
+ }
194
+ .tag--toggle[aria-pressed='true'] .tag__check path {
195
+ stroke-dashoffset: 0;
196
+ transition: stroke-dashoffset var(--duration-slow) var(--ease-entrance) 60ms;
197
+ }
198
+
199
+ .tag[data-disabled],
200
+ .tag--toggle:disabled {
201
+ color: var(--text-disabled);
202
+ border-color: var(--border-subtle);
203
+ background: var(--bg-surface);
204
+ cursor: default;
205
+ --tag-shadow: none;
206
+ }
207
+ .tag[data-disabled] .tag__count,
208
+ .tag--toggle:disabled .tag__count {
209
+ color: var(--text-disabled);
210
+ }
211
+ .tag[data-disabled] .tag__remove {
212
+ color: var(--text-disabled);
213
+ background: transparent;
214
+ cursor: default;
215
+ pointer-events: none;
216
+ }
217
+ .tag--toggle:disabled {
218
+ transform: none;
219
+ }
220
+ .tag--toggle:disabled[aria-pressed='true'] {
221
+ background: var(--bg-muted);
222
+ border-color: var(--border-subtle);
223
+ }
224
+
225
+ .tag-group {
226
+ display: flex;
227
+ flex-wrap: wrap;
228
+ align-items: center;
229
+ gap: var(--space-2);
230
+ }
231
+
232
+ @media (prefers-reduced-motion: reduce) {
233
+ .tag__remove svg {
234
+ transition: none;
235
+ }
236
+ .tag__remove:hover svg {
237
+ transform: none;
238
+ }
239
+ .tag__remove:active {
240
+ transform: none;
241
+ }
242
+ .tag--toggle:active:not(:disabled) {
243
+ transform: none;
244
+ }
245
+ .tag__icon--dual > :is(i, svg) {
246
+ transition: none;
247
+ }
248
+ }
package/dist/tag.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties, HTMLAttributes, Ref } 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
+ interface TagOwnProps {
8
+ /** Tag content; a string label also seeds the default remove-button `aria-label`. */
9
+ children: ReactNode;
10
+ /** Your own icon node, sized small and tinted to the tag's text. */
11
+ icon?: ReactNode | null;
12
+ /** Presence adds the remove button; called on click - remove the item yourself. */
13
+ onRemove?: (() => void) | null;
14
+ /** Accessible label for the remove button. Defaults to "Remove {label}" for string labels. */
15
+ removeLabel?: string;
16
+ /** 'md' = 28px (default) - 'sm' = 24px for dense rows. */
17
+ size?: 'md' | 'sm';
18
+ /** Set `data-disabled` on the tag and disable its remove button. @default false */
19
+ disabled?: boolean;
20
+ /** Extra class(es) merged onto the root element. */
21
+ className?: string;
22
+ /** Inline styles merged onto the root element. */
23
+ style?: CSSProperties;
24
+ }
25
+ /** Tag - the removable, editable label (stateless; the parent owns the list). */
26
+ interface TagProps extends TagOwnProps {
27
+ /** Standard <span> attributes forwarded to the tag root. */
28
+ htmlProps?: Omit<HTMLAttributes<HTMLSpanElement>, keyof TagOwnProps> & DataAttributes;
29
+ /** Ref to the tag root span. */
30
+ ref?: Ref<HTMLSpanElement>;
31
+ }
32
+ interface TagGroupOwnProps {
33
+ /** Accessible name for the group (role="group"). */
34
+ ariaLabel?: string;
35
+ /** The `Tag`s; adds, removals and reflow are animated. */
36
+ children?: ReactNode;
37
+ /** Extra class(es) merged onto the group wrapper. */
38
+ className?: string;
39
+ /** Inline styles merged onto the group wrapper. */
40
+ style?: CSSProperties;
41
+ /** Add/remove/reflow timing for the member tags - motion tokens only, or `null` to disable. */
42
+ animation?: DisableableAnimation;
43
+ }
44
+ /** TagGroup - wrapping flex row + removal/insertion choreography. */
45
+ interface TagGroupProps extends TagGroupOwnProps {
46
+ /** Standard <div> attributes forwarded to the group wrapper. */
47
+ htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof TagGroupOwnProps> & DataAttributes;
48
+ }
49
+ declare function Tag({ children, icon, onRemove, removeLabel, size, disabled, className, style, htmlProps, ref, }: TagProps): react.JSX.Element;
50
+ declare function TagGroup({ ariaLabel, className, style, children, htmlProps, animation }: TagGroupProps): react.JSX.Element;
51
+
52
+ export { Tag, TagGroup, type TagGroupProps, type TagProps };
package/dist/tag.js ADDED
@@ -0,0 +1,72 @@
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 './chunk-S5ZTZANS.js';
9
+ import './chunk-VTJTGVZZ.js';
10
+ import { cx } from './chunk-QGNC7LH5.js';
11
+ import './tag.css';
12
+ import { createContext, useContext } from 'react';
13
+ import { jsxs, jsx } from 'react/jsx-runtime';
14
+
15
+ var TAG_TIMING = { open: { duration: "base", ease: "entrance" }, close: { duration: "fast", ease: "exit" } };
16
+ var TAG_LAYOUT_TIMING = {
17
+ open: { duration: "slow", ease: "entrance" },
18
+ close: { duration: "slow", ease: "entrance" }
19
+ };
20
+ var TagGroupContext = createContext(null);
21
+ function TagRemoveGlyph() {
22
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M3 3 L9 9 M9 3 L3 9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
23
+ }
24
+ function Tag({
25
+ children,
26
+ icon = null,
27
+ onRemove = null,
28
+ removeLabel,
29
+ size = "md",
30
+ disabled = false,
31
+ className = "",
32
+ style,
33
+ htmlProps,
34
+ ref
35
+ }) {
36
+ const cls = cx("tag", size === "sm" && "tag--sm", className);
37
+ const xLabel = removeLabel || (typeof children === "string" ? "Remove " + children : "Remove");
38
+ const group = useContext(TagGroupContext);
39
+ return /* @__PURE__ */ jsxs(
40
+ Motion,
41
+ {
42
+ as: "span",
43
+ ref,
44
+ animate: group?.animate,
45
+ exit: group?.exit,
46
+ layout: group?.layout,
47
+ className: cls,
48
+ style,
49
+ "data-disabled": disabled ? "true" : void 0,
50
+ ...htmlProps,
51
+ children: [
52
+ icon && /* @__PURE__ */ jsx("span", { className: "tag__icon", children: /* @__PURE__ */ jsx(IconSlot, { size: "sm", children: icon }) }),
53
+ /* @__PURE__ */ jsx("span", { className: "tag__label", children }),
54
+ onRemove && /* @__PURE__ */ jsx("button", { type: "button", className: "tag__remove", "aria-label": xLabel, disabled, onClick: onRemove, children: /* @__PURE__ */ jsx(TagRemoveGlyph, {}) })
55
+ ]
56
+ }
57
+ );
58
+ }
59
+ function TagGroup({ ariaLabel, className = "", style, children, htmlProps, animation }) {
60
+ const step = resolveMotionTiming(animation, TAG_TIMING);
61
+ const layout = resolveMotionTiming(animation, TAG_LAYOUT_TIMING).open;
62
+ const motion = {
63
+ animate: { opacity: [0, 1], scale: [0.9, 1], timing: step.open },
64
+ exit: { opacity: [1, 0], scale: [1, 0.9], timing: step.close },
65
+ layout: { timing: layout }
66
+ };
67
+ return /* @__PURE__ */ jsx("div", { className: cx("tag-group", className), style, role: "group", "aria-label": ariaLabel, ...htmlProps, children: /* @__PURE__ */ jsx(TagGroupContext.Provider, { value: motion, children: /* @__PURE__ */ jsx(Presence, { initial: false, children }) }) });
68
+ }
69
+
70
+ export { Tag, TagGroup };
71
+ //# sourceMappingURL=tag.js.map
72
+ //# sourceMappingURL=tag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/primitives/tag/Tag.tsx"],"names":[],"mappings":"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","file":"tag.js","sourcesContent":["'use client';\n\nimport './tag.css';\nimport { createContext, useContext, type CSSProperties, type HTMLAttributes, type ReactNode, type Ref } 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 type { FlipTuning } from '../../../motion/flip';\nimport type { Layer } from '../../../engine';\nimport { IconSlot } from '../../internal/icon/IconSlot';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\nconst TAG_TIMING = { open: { duration: 'base', ease: 'entrance' }, close: { duration: 'fast', ease: 'exit' } } as const;\nconst TAG_LAYOUT_TIMING = {\n open: { duration: 'slow', ease: 'entrance' },\n close: { duration: 'slow', ease: 'entrance' },\n} as const;\n\ninterface TagGroupMotion {\n animate: Layer;\n exit: Layer;\n layout: FlipTuning;\n}\n\nconst TagGroupContext = createContext<TagGroupMotion | null>(null);\n\ninterface TagOwnProps {\n /** Tag content; a string label also seeds the default remove-button `aria-label`. */\n children: ReactNode;\n /** Your own icon node, sized small and tinted to the tag's text. */\n icon?: ReactNode | null;\n /** Presence adds the remove button; called on click - remove the item yourself. */\n onRemove?: (() => void) | null;\n /** Accessible label for the remove button. Defaults to \"Remove {label}\" for string labels. */\n removeLabel?: string;\n /** 'md' = 28px (default) - 'sm' = 24px for dense rows. */\n size?: 'md' | 'sm';\n /** Set `data-disabled` on the tag and disable its remove button. @default false */\n disabled?: boolean;\n /** Extra class(es) merged onto the root element. */\n className?: string;\n /** Inline styles merged onto the root element. */\n style?: CSSProperties;\n}\n\n/** Tag - the removable, editable label (stateless; the parent owns the list). */\nexport interface TagProps extends TagOwnProps {\n /** Standard <span> attributes forwarded to the tag root. */\n htmlProps?: Omit<HTMLAttributes<HTMLSpanElement>, keyof TagOwnProps> & DataAttributes;\n /** Ref to the tag root span. */\n ref?: Ref<HTMLSpanElement>;\n}\n\ninterface TagGroupOwnProps {\n /** Accessible name for the group (role=\"group\"). */\n ariaLabel?: string;\n /** The `Tag`s; adds, removals and reflow are animated. */\n children?: ReactNode;\n /** Extra class(es) merged onto the group wrapper. */\n className?: string;\n /** Inline styles merged onto the group wrapper. */\n style?: CSSProperties;\n /** Add/remove/reflow timing for the member tags - motion tokens only, or `null` to disable. */\n animation?: DisableableAnimation;\n}\n\n/** TagGroup - wrapping flex row + removal/insertion choreography. */\nexport interface TagGroupProps extends TagGroupOwnProps {\n /** Standard <div> attributes forwarded to the group wrapper. */\n htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof TagGroupOwnProps> & DataAttributes;\n}\n\nfunction TagRemoveGlyph() {\n return (\n <svg viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3 L9 9 M9 3 L3 9\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nexport function Tag({\n children,\n icon = null,\n onRemove = null,\n removeLabel,\n size = 'md',\n disabled = false,\n className = '',\n style,\n htmlProps,\n ref,\n}: TagProps) {\n const cls = cx('tag', size === 'sm' && 'tag--sm', className);\n const xLabel = removeLabel || (typeof children === 'string' ? 'Remove ' + children : 'Remove');\n const group = useContext(TagGroupContext);\n\n return (\n <Motion\n as=\"span\"\n ref={ref}\n animate={group?.animate}\n exit={group?.exit}\n layout={group?.layout}\n className={cls}\n style={style}\n data-disabled={disabled ? 'true' : undefined}\n {...htmlProps}\n >\n {icon && (\n <span className=\"tag__icon\">\n <IconSlot size=\"sm\">{icon}</IconSlot>\n </span>\n )}\n <span className=\"tag__label\">{children}</span>\n {onRemove && (\n <button type=\"button\" className=\"tag__remove\" aria-label={xLabel} disabled={disabled} onClick={onRemove}>\n <TagRemoveGlyph />\n </button>\n )}\n </Motion>\n );\n}\n\nexport function TagGroup({ ariaLabel, className = '', style, children, htmlProps, animation }: TagGroupProps) {\n const step = resolveMotionTiming(animation, TAG_TIMING);\n const layout = resolveMotionTiming(animation, TAG_LAYOUT_TIMING).open;\n\n const motion = {\n animate: { opacity: [0, 1], scale: [0.9, 1], timing: step.open },\n exit: { opacity: [1, 0], scale: [1, 0.9], timing: step.close },\n layout: { timing: layout },\n };\n\n return (\n <div className={cx('tag-group', className)} style={style} role=\"group\" aria-label={ariaLabel} {...htmlProps}>\n <TagGroupContext.Provider value={motion}>\n <Presence initial={false}>{children}</Presence>\n </TagGroupContext.Provider>\n </div>\n );\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import * as react from 'react';
2
+ import { InputHTMLAttributes, ReactNode, CSSProperties } from 'react';
3
+ import { b as FieldMessagingProps } from './field-chrome-CMPOQSLs.js';
4
+ import { D as DataAttributes } from './dom-props-C0jrllBw.js';
5
+
6
+ /** The native <input> props TextField surfaces at the top level (the rest live in `htmlProps`). */
7
+ type TextFieldNative = Pick<InputHTMLAttributes<HTMLInputElement>, 'placeholder' | 'value' | 'onChange' | 'disabled' | 'readOnly' | 'maxLength' | 'minLength' | 'hidden' | 'pattern' | 'onKeyDown'>;
8
+ interface TextFieldOwnProps extends FieldMessagingProps, TextFieldNative {
9
+ /** Leading icon - your own icon node (sized to the control). Decorative. */
10
+ leadingIcon?: ReactNode;
11
+ /** Show a clear button when there's a value. */
12
+ clearable?: boolean;
13
+ /** Control height: sm 28 - md 36 (default) - lg 40. */
14
+ size?: 'sm' | 'md' | 'lg';
15
+ /** Extra class(es) merged onto the field root. */
16
+ className?: string;
17
+ /** Inline styles merged onto the field root. */
18
+ style?: CSSProperties;
19
+ /** Available text like types */
20
+ type?: 'text' | 'search' | 'email' | 'url' | 'password';
21
+ }
22
+ interface TextFieldProps extends TextFieldOwnProps {
23
+ /** Standard <input> attributes (name, autoComplete, maxLength, aria-*, ...) forwarded to the input. */
24
+ htmlProps?: Omit<InputHTMLAttributes<HTMLInputElement>, keyof TextFieldOwnProps | 'size'> & DataAttributes;
25
+ }
26
+ declare function TextField({ label, helper, error, warning, success, leadingIcon, clearable, size, value, htmlProps, className, style, optional, ...rest }: TextFieldProps): react.JSX.Element;
27
+
28
+ export { TextField, type TextFieldProps };