@inshorts/glint-ui 0.5.3 → 0.6.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 (341) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +3 -9
  3. package/dist/alert.cjs +96 -0
  4. package/dist/alert.cjs.map +1 -0
  5. package/dist/alert.d.cts +29 -0
  6. package/dist/alert.d.ts +29 -0
  7. package/dist/alert.js +10 -0
  8. package/dist/alert.js.map +1 -0
  9. package/dist/autocomplete.cjs +578 -0
  10. package/dist/autocomplete.cjs.map +1 -0
  11. package/dist/autocomplete.d.cts +56 -0
  12. package/dist/autocomplete.d.ts +56 -0
  13. package/dist/autocomplete.js +11 -0
  14. package/dist/autocomplete.js.map +1 -0
  15. package/dist/badge.cjs +89 -0
  16. package/dist/badge.cjs.map +1 -0
  17. package/dist/badge.d.cts +25 -0
  18. package/dist/badge.d.ts +25 -0
  19. package/dist/badge.js +10 -0
  20. package/dist/badge.js.map +1 -0
  21. package/dist/breadcrumb.cjs +88 -0
  22. package/dist/breadcrumb.cjs.map +1 -0
  23. package/dist/breadcrumb.d.cts +14 -0
  24. package/dist/breadcrumb.d.ts +14 -0
  25. package/dist/breadcrumb.js +8 -0
  26. package/dist/breadcrumb.js.map +1 -0
  27. package/dist/button.cjs +143 -0
  28. package/dist/button.cjs.map +1 -0
  29. package/dist/button.d.cts +34 -0
  30. package/dist/button.d.ts +34 -0
  31. package/dist/button.js +9 -0
  32. package/dist/button.js.map +1 -0
  33. package/dist/card.cjs +111 -0
  34. package/dist/card.cjs.map +1 -0
  35. package/dist/card.d.cts +15 -0
  36. package/dist/card.d.ts +15 -0
  37. package/dist/card.js +18 -0
  38. package/dist/card.js.map +1 -0
  39. package/dist/checkbox.cjs +66 -0
  40. package/dist/checkbox.cjs.map +1 -0
  41. package/{src/checkbox.tsx → dist/checkbox.d.cts} +5 -22
  42. package/dist/checkbox.d.ts +25 -0
  43. package/dist/checkbox.js +10 -0
  44. package/dist/checkbox.js.map +1 -0
  45. package/dist/chunk-43ZUFY63.js +85 -0
  46. package/dist/chunk-43ZUFY63.js.map +1 -0
  47. package/dist/chunk-67ACNS42.js +29 -0
  48. package/dist/chunk-67ACNS42.js.map +1 -0
  49. package/dist/chunk-6URKHMCF.js +76 -0
  50. package/dist/chunk-6URKHMCF.js.map +1 -0
  51. package/dist/chunk-ASU6CUTZ.js +85 -0
  52. package/dist/chunk-ASU6CUTZ.js.map +1 -0
  53. package/dist/chunk-EWSBFU54.js +53 -0
  54. package/dist/chunk-EWSBFU54.js.map +1 -0
  55. package/dist/chunk-G4ZQUSAJ.js +38 -0
  56. package/dist/chunk-G4ZQUSAJ.js.map +1 -0
  57. package/dist/chunk-GMCUXEFI.js +67 -0
  58. package/dist/chunk-GMCUXEFI.js.map +1 -0
  59. package/dist/chunk-HBBOR43A.js +85 -0
  60. package/dist/chunk-HBBOR43A.js.map +1 -0
  61. package/dist/chunk-HCA5ODCD.js +11 -0
  62. package/dist/chunk-HCA5ODCD.js.map +1 -0
  63. package/dist/chunk-HYRJYUPI.js +26 -0
  64. package/dist/chunk-HYRJYUPI.js.map +1 -0
  65. package/dist/chunk-IRCTGJQB.js +26 -0
  66. package/dist/chunk-IRCTGJQB.js.map +1 -0
  67. package/dist/chunk-JDE5XYPT.js +30 -0
  68. package/dist/chunk-JDE5XYPT.js.map +1 -0
  69. package/dist/chunk-JSJEEKR3.js +59 -0
  70. package/dist/chunk-JSJEEKR3.js.map +1 -0
  71. package/dist/chunk-KR3BCFP7.js +85 -0
  72. package/dist/chunk-KR3BCFP7.js.map +1 -0
  73. package/dist/chunk-MQT5RAQV.js +202 -0
  74. package/dist/chunk-MQT5RAQV.js.map +1 -0
  75. package/dist/chunk-MUPW2TFJ.js +102 -0
  76. package/dist/chunk-MUPW2TFJ.js.map +1 -0
  77. package/dist/chunk-PM2VE7DJ.js +100 -0
  78. package/dist/chunk-PM2VE7DJ.js.map +1 -0
  79. package/dist/chunk-PPYR3O3L.js +44 -0
  80. package/dist/chunk-PPYR3O3L.js.map +1 -0
  81. package/dist/chunk-PUTC52SI.js +98 -0
  82. package/dist/chunk-PUTC52SI.js.map +1 -0
  83. package/dist/chunk-PVK4WQJZ.js +513 -0
  84. package/dist/chunk-PVK4WQJZ.js.map +1 -0
  85. package/dist/chunk-PWAKTEXF.js +18 -0
  86. package/dist/chunk-PWAKTEXF.js.map +1 -0
  87. package/dist/chunk-QTFWORA7.js +26 -0
  88. package/dist/chunk-QTFWORA7.js.map +1 -0
  89. package/dist/chunk-RUPL2H6V.js +49 -0
  90. package/dist/chunk-RUPL2H6V.js.map +1 -0
  91. package/dist/chunk-S7PVZAPL.js +28 -0
  92. package/dist/chunk-S7PVZAPL.js.map +1 -0
  93. package/dist/chunk-SQDV2AKJ.js +49 -0
  94. package/dist/chunk-SQDV2AKJ.js.map +1 -0
  95. package/dist/chunk-T2KXVH3O.js +297 -0
  96. package/dist/chunk-T2KXVH3O.js.map +1 -0
  97. package/dist/chunk-T4WCCHJQ.js +29 -0
  98. package/dist/chunk-T4WCCHJQ.js.map +1 -0
  99. package/dist/chunk-UC3ZIQPE.js +93 -0
  100. package/dist/chunk-UC3ZIQPE.js.map +1 -0
  101. package/dist/chunk-UE7JY7VR.js +28 -0
  102. package/dist/chunk-UE7JY7VR.js.map +1 -0
  103. package/dist/chunk-WVNRFO5F.js +70 -0
  104. package/dist/chunk-WVNRFO5F.js.map +1 -0
  105. package/dist/chunk-Y5WCT6XN.js +93 -0
  106. package/dist/chunk-Y5WCT6XN.js.map +1 -0
  107. package/dist/chunk-YDICVETX.js +151 -0
  108. package/dist/chunk-YDICVETX.js.map +1 -0
  109. package/dist/chunk-YSU4VWRD.js +90 -0
  110. package/dist/chunk-YSU4VWRD.js.map +1 -0
  111. package/dist/chunk-ZFSQVMLJ.js +126 -0
  112. package/dist/chunk-ZFSQVMLJ.js.map +1 -0
  113. package/dist/chunk-ZHATD73Y.js +46 -0
  114. package/dist/chunk-ZHATD73Y.js.map +1 -0
  115. package/dist/chunk-ZLAA4DGG.js +111 -0
  116. package/dist/chunk-ZLAA4DGG.js.map +1 -0
  117. package/dist/chunk-ZP252OJZ.js +56 -0
  118. package/dist/chunk-ZP252OJZ.js.map +1 -0
  119. package/dist/clipboard.cjs +125 -0
  120. package/dist/clipboard.cjs.map +1 -0
  121. package/dist/clipboard.d.cts +52 -0
  122. package/dist/clipboard.d.ts +52 -0
  123. package/dist/clipboard.js +23 -0
  124. package/dist/clipboard.js.map +1 -0
  125. package/dist/collapsible.cjs +94 -0
  126. package/dist/collapsible.cjs.map +1 -0
  127. package/dist/collapsible.d.cts +21 -0
  128. package/dist/collapsible.d.ts +21 -0
  129. package/dist/collapsible.js +9 -0
  130. package/dist/collapsible.js.map +1 -0
  131. package/dist/confirm-dialog.cjs +369 -0
  132. package/dist/confirm-dialog.cjs.map +1 -0
  133. package/dist/confirm-dialog.d.cts +16 -0
  134. package/dist/confirm-dialog.d.ts +16 -0
  135. package/dist/confirm-dialog.js +13 -0
  136. package/dist/confirm-dialog.js.map +1 -0
  137. package/dist/copy-button.cjs +102 -0
  138. package/dist/copy-button.cjs.map +1 -0
  139. package/dist/copy-button.d.cts +18 -0
  140. package/dist/copy-button.d.ts +18 -0
  141. package/dist/copy-button.js +10 -0
  142. package/dist/copy-button.js.map +1 -0
  143. package/dist/data-table.cjs +140 -0
  144. package/dist/data-table.cjs.map +1 -0
  145. package/dist/data-table.d.cts +81 -0
  146. package/dist/data-table.d.ts +81 -0
  147. package/dist/data-table.js +8 -0
  148. package/dist/data-table.js.map +1 -0
  149. package/dist/date-range-picker/dateRange.cjs +138 -0
  150. package/dist/date-range-picker/dateRange.cjs.map +1 -0
  151. package/dist/date-range-picker/dateRange.d.cts +57 -0
  152. package/dist/date-range-picker/dateRange.d.ts +57 -0
  153. package/dist/date-range-picker/dateRange.js +31 -0
  154. package/dist/date-range-picker/dateRange.js.map +1 -0
  155. package/dist/date-range-picker/index.cjs +375 -0
  156. package/dist/date-range-picker/index.cjs.map +1 -0
  157. package/dist/date-range-picker/index.d.cts +18 -0
  158. package/dist/date-range-picker/index.d.ts +18 -0
  159. package/dist/date-range-picker/index.js +10 -0
  160. package/dist/date-range-picker/index.js.map +1 -0
  161. package/dist/dialogLayer.cjs +121 -0
  162. package/dist/dialogLayer.cjs.map +1 -0
  163. package/dist/dialogLayer.d.cts +11 -0
  164. package/dist/dialogLayer.d.ts +11 -0
  165. package/dist/dialogLayer.js +8 -0
  166. package/dist/dialogLayer.js.map +1 -0
  167. package/dist/feature-access-gate.cjs +160 -0
  168. package/dist/feature-access-gate.cjs.map +1 -0
  169. package/dist/feature-access-gate.d.cts +14 -0
  170. package/dist/feature-access-gate.d.ts +14 -0
  171. package/dist/feature-access-gate.js +11 -0
  172. package/dist/feature-access-gate.js.map +1 -0
  173. package/dist/field.cjs +58 -0
  174. package/dist/field.cjs.map +1 -0
  175. package/dist/field.d.cts +23 -0
  176. package/dist/field.d.ts +23 -0
  177. package/dist/field.js +8 -0
  178. package/dist/field.js.map +1 -0
  179. package/dist/image-uploader.cjs +293 -0
  180. package/dist/image-uploader.cjs.map +1 -0
  181. package/dist/image-uploader.d.cts +34 -0
  182. package/dist/image-uploader.d.ts +34 -0
  183. package/dist/image-uploader.js +12 -0
  184. package/dist/image-uploader.js.map +1 -0
  185. package/dist/index.cjs +3012 -0
  186. package/dist/index.cjs.map +1 -0
  187. package/dist/index.d.cts +41 -0
  188. package/dist/index.d.ts +41 -0
  189. package/dist/index.js +232 -0
  190. package/dist/index.js.map +1 -0
  191. package/dist/input.cjs +58 -0
  192. package/dist/input.cjs.map +1 -0
  193. package/dist/input.d.cts +7 -0
  194. package/dist/input.d.ts +7 -0
  195. package/dist/input.js +10 -0
  196. package/dist/input.js.map +1 -0
  197. package/dist/label.cjs +67 -0
  198. package/dist/label.cjs.map +1 -0
  199. package/dist/label.d.cts +7 -0
  200. package/dist/label.d.ts +7 -0
  201. package/dist/label.js +9 -0
  202. package/dist/label.js.map +1 -0
  203. package/dist/modal.cjs +212 -0
  204. package/dist/modal.cjs.map +1 -0
  205. package/dist/modal.d.cts +39 -0
  206. package/dist/modal.d.ts +39 -0
  207. package/dist/modal.js +12 -0
  208. package/dist/modal.js.map +1 -0
  209. package/dist/page-header.cjs +78 -0
  210. package/dist/page-header.cjs.map +1 -0
  211. package/dist/page-header.d.cts +35 -0
  212. package/dist/page-header.d.ts +35 -0
  213. package/dist/page-header.js +8 -0
  214. package/dist/page-header.js.map +1 -0
  215. package/dist/pagination.cjs +237 -0
  216. package/dist/pagination.cjs.map +1 -0
  217. package/dist/pagination.d.cts +15 -0
  218. package/dist/pagination.d.ts +15 -0
  219. package/dist/pagination.js +11 -0
  220. package/dist/pagination.js.map +1 -0
  221. package/dist/panel-brand-mark.cjs +59 -0
  222. package/dist/panel-brand-mark.cjs.map +1 -0
  223. package/dist/panel-brand-mark.d.cts +13 -0
  224. package/dist/panel-brand-mark.d.ts +13 -0
  225. package/dist/panel-brand-mark.js +8 -0
  226. package/dist/panel-brand-mark.js.map +1 -0
  227. package/dist/panel-sign-in.cjs +256 -0
  228. package/dist/panel-sign-in.cjs.map +1 -0
  229. package/dist/panel-sign-in.d.cts +31 -0
  230. package/dist/panel-sign-in.d.ts +31 -0
  231. package/dist/panel-sign-in.js +14 -0
  232. package/dist/panel-sign-in.js.map +1 -0
  233. package/dist/segmented-control.cjs +126 -0
  234. package/dist/segmented-control.cjs.map +1 -0
  235. package/dist/segmented-control.d.cts +60 -0
  236. package/dist/segmented-control.d.ts +60 -0
  237. package/dist/segmented-control.js +9 -0
  238. package/dist/segmented-control.js.map +1 -0
  239. package/dist/select.cjs +648 -0
  240. package/dist/select.cjs.map +1 -0
  241. package/dist/select.d.cts +30 -0
  242. package/dist/select.d.ts +30 -0
  243. package/dist/select.js +12 -0
  244. package/dist/select.js.map +1 -0
  245. package/dist/separator.cjs +70 -0
  246. package/dist/separator.cjs.map +1 -0
  247. package/dist/separator.d.cts +13 -0
  248. package/dist/separator.d.ts +13 -0
  249. package/dist/separator.js +9 -0
  250. package/dist/separator.js.map +1 -0
  251. package/dist/side-drawer.cjs +321 -0
  252. package/dist/side-drawer.cjs.map +1 -0
  253. package/dist/side-drawer.d.cts +21 -0
  254. package/dist/side-drawer.d.ts +21 -0
  255. package/dist/side-drawer.js +13 -0
  256. package/dist/side-drawer.js.map +1 -0
  257. package/dist/spinner.cjs +57 -0
  258. package/dist/spinner.cjs.map +1 -0
  259. package/{src/spinner.tsx → dist/spinner.d.cts} +11 -22
  260. package/dist/spinner.d.ts +27 -0
  261. package/dist/spinner.js +8 -0
  262. package/dist/spinner.js.map +1 -0
  263. package/dist/spreadsheet-grid.cjs +238 -0
  264. package/dist/spreadsheet-grid.cjs.map +1 -0
  265. package/dist/spreadsheet-grid.d.cts +48 -0
  266. package/dist/spreadsheet-grid.d.ts +48 -0
  267. package/dist/spreadsheet-grid.js +8 -0
  268. package/dist/spreadsheet-grid.js.map +1 -0
  269. package/dist/state-panel.cjs +86 -0
  270. package/dist/state-panel.cjs.map +1 -0
  271. package/dist/state-panel.d.cts +23 -0
  272. package/dist/state-panel.d.ts +23 -0
  273. package/dist/state-panel.js +9 -0
  274. package/dist/state-panel.js.map +1 -0
  275. package/dist/switch.cjs +87 -0
  276. package/dist/switch.cjs.map +1 -0
  277. package/dist/switch.d.cts +13 -0
  278. package/dist/switch.d.ts +13 -0
  279. package/dist/switch.js +9 -0
  280. package/dist/switch.js.map +1 -0
  281. package/dist/table.cjs +139 -0
  282. package/dist/table.cjs.map +1 -0
  283. package/dist/table.d.cts +16 -0
  284. package/dist/table.d.ts +16 -0
  285. package/dist/table.js +22 -0
  286. package/dist/table.js.map +1 -0
  287. package/dist/tabs.cjs +168 -0
  288. package/dist/tabs.cjs.map +1 -0
  289. package/dist/tabs.d.cts +59 -0
  290. package/dist/tabs.d.ts +59 -0
  291. package/dist/tabs.js +11 -0
  292. package/dist/tabs.js.map +1 -0
  293. package/dist/textarea.cjs +66 -0
  294. package/dist/textarea.cjs.map +1 -0
  295. package/dist/textarea.d.cts +18 -0
  296. package/dist/textarea.d.ts +18 -0
  297. package/dist/textarea.js +10 -0
  298. package/dist/textarea.js.map +1 -0
  299. package/dist/utils.cjs +35 -0
  300. package/dist/utils.cjs.map +1 -0
  301. package/dist/utils.d.cts +5 -0
  302. package/dist/utils.d.ts +5 -0
  303. package/dist/utils.js +7 -0
  304. package/dist/utils.js.map +1 -0
  305. package/package.json +395 -19
  306. package/src/alert.tsx +0 -74
  307. package/src/autocomplete.tsx +0 -666
  308. package/src/badge.tsx +0 -60
  309. package/src/breadcrumb.tsx +0 -71
  310. package/src/button.tsx +0 -113
  311. package/src/card.tsx +0 -79
  312. package/src/clipboard.ts +0 -144
  313. package/src/collapsible.tsx +0 -63
  314. package/src/confirm-dialog.tsx +0 -84
  315. package/src/copy-button.tsx +0 -58
  316. package/src/data-table.tsx +0 -190
  317. package/src/date-range-picker/dateRange.ts +0 -142
  318. package/src/date-range-picker/index.tsx +0 -366
  319. package/src/dialogLayer.ts +0 -142
  320. package/src/feature-access-gate.tsx +0 -38
  321. package/src/field.tsx +0 -56
  322. package/src/image-uploader.tsx +0 -181
  323. package/src/index.ts +0 -37
  324. package/src/input.tsx +0 -16
  325. package/src/label.tsx +0 -23
  326. package/src/modal.tsx +0 -117
  327. package/src/page-header.tsx +0 -75
  328. package/src/pagination.tsx +0 -116
  329. package/src/panel-brand-mark.tsx +0 -32
  330. package/src/panel-sign-in.tsx +0 -134
  331. package/src/segmented-control.tsx +0 -155
  332. package/src/select.tsx +0 -105
  333. package/src/separator.tsx +0 -32
  334. package/src/side-drawer.tsx +0 -87
  335. package/src/spreadsheet-grid.tsx +0 -264
  336. package/src/state-panel.tsx +0 -46
  337. package/src/switch.tsx +0 -46
  338. package/src/table.tsx +0 -110
  339. package/src/tabs.tsx +0 -201
  340. package/src/textarea.tsx +0 -32
  341. package/src/utils.ts +0 -6
@@ -0,0 +1,85 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-HCA5ODCD.js";
4
+
5
+ // src/segmented-control.tsx
6
+ import * as React from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var TONES = {
9
+ emphasis: {
10
+ on: "bg-slate-950 text-white dark:bg-white dark:text-slate-950",
11
+ off: "text-muted-foreground hover:bg-muted"
12
+ },
13
+ primary: {
14
+ on: "bg-primary text-primary-foreground",
15
+ off: "text-muted-foreground hover:bg-muted"
16
+ }
17
+ };
18
+ var TRACKS = {
19
+ contained: "border-border inline-flex rounded-md border p-0.5",
20
+ loose: "flex flex-wrap gap-2"
21
+ };
22
+ function SegmentedControl({
23
+ options,
24
+ value,
25
+ onChange,
26
+ ariaLabel,
27
+ variant = "contained",
28
+ tone = "emphasis",
29
+ fill = false,
30
+ className
31
+ }) {
32
+ const refs = React.useRef(/* @__PURE__ */ new Map());
33
+ function onKeyDown(event) {
34
+ const step = event.key === "ArrowRight" || event.key === "ArrowDown" ? 1 : event.key === "ArrowLeft" || event.key === "ArrowUp" ? -1 : 0;
35
+ if (step === 0) return;
36
+ const selectable = options.filter((option) => !option.disabled);
37
+ if (selectable.length < 2) return;
38
+ const current = selectable.findIndex((option) => option.value === value);
39
+ const next = selectable[(current + step + selectable.length) % selectable.length];
40
+ event.preventDefault();
41
+ onChange(next.value);
42
+ refs.current.get(next.value)?.focus();
43
+ }
44
+ return /* @__PURE__ */ jsx(
45
+ "div",
46
+ {
47
+ role: "radiogroup",
48
+ "aria-label": ariaLabel,
49
+ onKeyDown,
50
+ className: cn(TRACKS[variant], className),
51
+ children: options.map((option) => {
52
+ const checked = option.value === value;
53
+ return /* @__PURE__ */ jsx(
54
+ "button",
55
+ {
56
+ ref: (node) => {
57
+ refs.current.set(option.value, node);
58
+ },
59
+ type: "button",
60
+ role: "radio",
61
+ "aria-checked": checked,
62
+ disabled: option.disabled,
63
+ title: option.title,
64
+ tabIndex: checked ? 0 : -1,
65
+ onClick: () => onChange(option.value),
66
+ className: cn(
67
+ "cursor-pointer rounded px-3 py-1 text-sm font-medium transition",
68
+ "focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
69
+ "disabled:cursor-not-allowed disabled:opacity-50",
70
+ fill && "flex-1",
71
+ checked ? TONES[tone].on : TONES[tone].off
72
+ ),
73
+ children: option.label
74
+ },
75
+ option.value
76
+ );
77
+ })
78
+ }
79
+ );
80
+ }
81
+
82
+ export {
83
+ SegmentedControl
84
+ };
85
+ //# sourceMappingURL=chunk-ASU6CUTZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/segmented-control.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\n/**\n * The one-of-N picker seven panels were each drawing by hand.\n *\n * Not `Tabs`, which is a bottom-bordered strip sitting above the content it\n * switches. This is the inline version — a bordered track with the selected\n * option filled in — used for a filter or a setting that sits among other\n * controls rather than heading a panel.\n *\n * **Roles are the reason to use this.** The seven copies had three different\n * ideas about what they were: one said `tablist`/`tab`, one said\n * `group`/`aria-pressed`, and the other five said nothing at all — so on five\n * of seven a screen reader heard a row of unlabelled buttons with no\n * indication which one was active. None of the three was right. `tablist`\n * without a `tabpanel` is a promise the markup does not keep, and\n * `aria-pressed` describes independent toggles, not a choice of one. Picking a\n * value out of a fixed set is a radio group, so that is what this is, with the\n * roving tabindex and arrow keys that come with the role.\n *\n * `tone` keeps both active colours the panels had drifted into: `emphasis` is\n * the near-black/near-white fill five of them used, `primary` the violet\n * accent the other two did. They are genuinely different colours rather than\n * one spelled two ways, so collapsing them is a visual change to two panels\n * and belongs in its own reviewable diff — the same call `DataTable` makes\n * about its two header variants.\n */\nexport interface SegmentedOption<Value extends string> {\n value: Value;\n label: React.ReactNode;\n disabled?: boolean;\n /**\n * Hover text. Worth setting on a disabled option — \"Everyone\" going grey\n * says nothing about which permission would bring it back.\n */\n title?: string;\n}\n\nexport interface SegmentedControlProps<Value extends string> {\n options: ReadonlyArray<SegmentedOption<Value>>;\n value: Value;\n onChange: (value: Value) => void;\n /**\n * Required: the group never has a visible label — the options name the\n * choice between them, which tells you nothing about what is being chosen.\n */\n ariaLabel: string;\n /**\n * `contained` — one bordered track around the options (five panels).\n * `loose` — free-standing pills with a gap between them (two panels).\n */\n variant?: \"contained\" | \"loose\";\n /** See the note above: two real colours, not one spelled twice. */\n tone?: \"emphasis\" | \"primary\";\n /** Options share the width equally, for a control that fills its column. */\n fill?: boolean;\n className?: string;\n}\n\nconst TONES = {\n emphasis: {\n on: \"bg-slate-950 text-white dark:bg-white dark:text-slate-950\",\n off: \"text-muted-foreground hover:bg-muted\",\n },\n primary: {\n on: \"bg-primary text-primary-foreground\",\n off: \"text-muted-foreground hover:bg-muted\",\n },\n} as const;\n\nconst TRACKS = {\n contained: \"border-border inline-flex rounded-md border p-0.5\",\n loose: \"flex flex-wrap gap-2\",\n} as const;\n\nexport function SegmentedControl<Value extends string>({\n options,\n value,\n onChange,\n ariaLabel,\n variant = \"contained\",\n tone = \"emphasis\",\n fill = false,\n className,\n}: SegmentedControlProps<Value>) {\n const refs = React.useRef(new Map<Value, HTMLButtonElement | null>());\n\n function onKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n const step =\n event.key === \"ArrowRight\" || event.key === \"ArrowDown\"\n ? 1\n : event.key === \"ArrowLeft\" || event.key === \"ArrowUp\"\n ? -1\n : 0;\n if (step === 0) return;\n\n const selectable = options.filter((option) => !option.disabled);\n if (selectable.length < 2) return;\n\n const current = selectable.findIndex((option) => option.value === value);\n // Wraps, which is what a radio group is expected to do.\n const next =\n selectable[(current + step + selectable.length) % selectable.length];\n\n event.preventDefault();\n onChange(next.value);\n // The newly checked option has to take focus, or the next arrow press is\n // still measured from the old one.\n refs.current.get(next.value)?.focus();\n }\n\n return (\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n onKeyDown={onKeyDown}\n className={cn(TRACKS[variant], className)}\n >\n {options.map((option) => {\n const checked = option.value === value;\n return (\n <button\n key={option.value}\n ref={(node) => {\n refs.current.set(option.value, node);\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={checked}\n disabled={option.disabled}\n title={option.title}\n // Only the checked option is reachable by Tab; arrows move within\n // the group. Without this a keyboard user pages through every\n // option to get past the control.\n tabIndex={checked ? 0 : -1}\n onClick={() => onChange(option.value)}\n className={cn(\n \"cursor-pointer rounded px-3 py-1 text-sm font-medium transition\",\n \"focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n fill && \"flex-1\",\n checked ? TONES[tone].on : TONES[tone].off,\n )}\n >\n {option.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;AAEA,YAAY,WAAW;AA2Hb;AA9DV,IAAM,QAAQ;AAAA,EACZ,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,KAAK;AAAA,EACP;AAAA,EACA,SAAS;AAAA,IACP,IAAI;AAAA,IACJ,KAAK;AAAA,EACP;AACF;AAEA,IAAM,SAAS;AAAA,EACb,WAAW;AAAA,EACX,OAAO;AACT;AAEO,SAAS,iBAAuC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP;AACF,GAAiC;AAC/B,QAAM,OAAa,aAAO,oBAAI,IAAqC,CAAC;AAEpE,WAAS,UAAU,OAA4C;AAC7D,UAAM,OACJ,MAAM,QAAQ,gBAAgB,MAAM,QAAQ,cACxC,IACA,MAAM,QAAQ,eAAe,MAAM,QAAQ,YACzC,KACA;AACR,QAAI,SAAS,EAAG;AAEhB,UAAM,aAAa,QAAQ,OAAO,CAAC,WAAW,CAAC,OAAO,QAAQ;AAC9D,QAAI,WAAW,SAAS,EAAG;AAE3B,UAAM,UAAU,WAAW,UAAU,CAAC,WAAW,OAAO,UAAU,KAAK;AAEvE,UAAM,OACJ,YAAY,UAAU,OAAO,WAAW,UAAU,WAAW,MAAM;AAErE,UAAM,eAAe;AACrB,aAAS,KAAK,KAAK;AAGnB,SAAK,QAAQ,IAAI,KAAK,KAAK,GAAG,MAAM;AAAA,EACtC;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ;AAAA,MACA,WAAW,GAAG,OAAO,OAAO,GAAG,SAAS;AAAA,MAEvC,kBAAQ,IAAI,CAAC,WAAW;AACvB,cAAM,UAAU,OAAO,UAAU;AACjC,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,KAAK,CAAC,SAAS;AACb,mBAAK,QAAQ,IAAI,OAAO,OAAO,IAAI;AAAA,YACrC;AAAA,YACA,MAAK;AAAA,YACL,MAAK;AAAA,YACL,gBAAc;AAAA,YACd,UAAU,OAAO;AAAA,YACjB,OAAO,OAAO;AAAA,YAId,UAAU,UAAU,IAAI;AAAA,YACxB,SAAS,MAAM,SAAS,OAAO,KAAK;AAAA,YACpC,WAAW;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,cACA,QAAQ;AAAA,cACR,UAAU,MAAM,IAAI,EAAE,KAAK,MAAM,IAAI,EAAE;AAAA,YACzC;AAAA,YAEC,iBAAO;AAAA;AAAA,UAtBH,OAAO;AAAA,QAuBd;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -0,0 +1,53 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-HCA5ODCD.js";
4
+
5
+ // src/collapsible.tsx
6
+ import { ChevronDown } from "lucide-react";
7
+ import * as React from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ function CollapsibleSection({
10
+ title,
11
+ icon,
12
+ defaultOpen = true,
13
+ right,
14
+ className,
15
+ children
16
+ }) {
17
+ const [open, setOpen] = React.useState(defaultOpen);
18
+ const bodyId = React.useId();
19
+ return /* @__PURE__ */ jsxs("div", { className: cn("border-border rounded-lg border", className), children: [
20
+ /* @__PURE__ */ jsxs(
21
+ "button",
22
+ {
23
+ type: "button",
24
+ "aria-expanded": open,
25
+ "aria-controls": bodyId,
26
+ onClick: () => setOpen((current) => !current),
27
+ className: "hover:bg-muted/50 flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm font-semibold transition",
28
+ children: [
29
+ /* @__PURE__ */ jsx(
30
+ ChevronDown,
31
+ {
32
+ size: 14,
33
+ "aria-hidden": true,
34
+ className: cn(
35
+ "shrink-0 transition-transform",
36
+ open ? "" : "-rotate-90"
37
+ )
38
+ }
39
+ ),
40
+ icon,
41
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: title }),
42
+ right
43
+ ]
44
+ }
45
+ ),
46
+ /* @__PURE__ */ jsx("div", { id: bodyId, hidden: !open, className: "space-y-3 px-3 pt-1 pb-3", children })
47
+ ] });
48
+ }
49
+
50
+ export {
51
+ CollapsibleSection
52
+ };
53
+ //# sourceMappingURL=chunk-EWSBFU54.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/collapsible.tsx"],"sourcesContent":["\"use client\";\n\nimport { ChevronDown } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\n/**\n * A titled section that folds away.\n *\n * For sidebar panels that are long but not always in use — the body stays\n * mounted so its state (a loaded list, a half-filled filter) survives being\n * collapsed, rather than being thrown away and refetched on the way back.\n */\nexport function CollapsibleSection({\n title,\n icon,\n defaultOpen = true,\n right,\n className,\n children,\n}: {\n title: string;\n /** Optional leading glyph, shown between the chevron and the title. */\n icon?: React.ReactNode;\n defaultOpen?: boolean;\n /** Optional trailing content in the header, e.g. a count. */\n right?: React.ReactNode;\n className?: string;\n children: React.ReactNode;\n}) {\n const [open, setOpen] = React.useState(defaultOpen);\n const bodyId = React.useId();\n\n return (\n <div className={cn(\"border-border rounded-lg border\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n aria-controls={bodyId}\n onClick={() => setOpen((current) => !current)}\n className=\"hover:bg-muted/50 flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm font-semibold transition\"\n >\n <ChevronDown\n size={14}\n aria-hidden\n className={cn(\n \"shrink-0 transition-transform\",\n open ? \"\" : \"-rotate-90\",\n )}\n />\n {icon}\n <span className=\"flex-1\">{title}</span>\n {right}\n </button>\n {/* Hidden rather than unmounted, so collapsing does not discard the\n panel's state or refetch what it had already loaded. */}\n <div id={bodyId} hidden={!open} className=\"space-y-3 px-3 pt-1 pb-3\">\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAEA,SAAS,mBAAmB;AAC5B,YAAY,WAAW;AAiCjB,SAOE,KAPF;AAtBC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,QAAM,CAAC,MAAM,OAAO,IAAU,eAAS,WAAW;AAClD,QAAM,SAAe,YAAM;AAE3B,SACE,qBAAC,SAAI,WAAW,GAAG,mCAAmC,SAAS,GAC7D;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,SAAS,MAAM,QAAQ,CAAC,YAAY,CAAC,OAAO;AAAA,QAC5C,WAAU;AAAA,QAEV;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,eAAW;AAAA,cACX,WAAW;AAAA,gBACT;AAAA,gBACA,OAAO,KAAK;AAAA,cACd;AAAA;AAAA,UACF;AAAA,UACC;AAAA,UACD,oBAAC,UAAK,WAAU,UAAU,iBAAM;AAAA,UAC/B;AAAA;AAAA;AAAA,IACH;AAAA,IAGA,oBAAC,SAAI,IAAI,QAAQ,QAAQ,CAAC,MAAM,WAAU,4BACvC,UACH;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,38 @@
1
+ import {
2
+ Spinner
3
+ } from "./chunk-UE7JY7VR.js";
4
+ import {
5
+ cn
6
+ } from "./chunk-HCA5ODCD.js";
7
+
8
+ // src/state-panel.tsx
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ function StatePanel({
11
+ loading,
12
+ className,
13
+ children,
14
+ ...props
15
+ }) {
16
+ return /* @__PURE__ */ jsxs(
17
+ "div",
18
+ {
19
+ role: loading ? "status" : void 0,
20
+ "aria-live": loading ? "polite" : void 0,
21
+ className: cn(
22
+ "border-border bg-background/80 text-muted-foreground rounded-lg border px-4 py-6 text-center text-sm",
23
+ loading && "flex items-center justify-center gap-2",
24
+ className
25
+ ),
26
+ ...props,
27
+ children: [
28
+ loading ? /* @__PURE__ */ jsx(Spinner, { size: "md" }) : null,
29
+ children
30
+ ]
31
+ }
32
+ );
33
+ }
34
+
35
+ export {
36
+ StatePanel
37
+ };
38
+ //# sourceMappingURL=chunk-G4ZQUSAJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/state-panel.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { Spinner } from \"./spinner\";\nimport { cn } from \"./utils\";\n\n/**\n * The bordered block a list shows instead of rows: loading, or nothing found.\n *\n * Fourteen copies of the same\n * `border-border bg-background/80 … rounded-lg border px-4 py-6 text-center`\n * across the panels, each with its own wording — \"Loading users…\", \"Loading\n * taxonomy…\", \"Loading showcases…\". The wording is worth keeping (it says what\n * is loading), the markup is not.\n *\n * `loading` adds two things the hand-rolled versions did not have: a spinner,\n * so a slow panel does not look like an empty one, and `role=\"status\"` with\n * `aria-live=\"polite\"`, so a screen reader is told the list arrived instead of\n * silently finding rows on the next tab press.\n */\nexport interface StatePanelProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Shows a spinner and announces politely. */\n loading?: boolean;\n}\n\nexport function StatePanel({\n loading,\n className,\n children,\n ...props\n}: StatePanelProps) {\n return (\n <div\n role={loading ? \"status\" : undefined}\n aria-live={loading ? \"polite\" : undefined}\n className={cn(\n \"border-border bg-background/80 text-muted-foreground rounded-lg border px-4 py-6 text-center text-sm\",\n loading && \"flex items-center justify-center gap-2\",\n className,\n )}\n {...props}\n >\n {loading ? <Spinner size=\"md\" /> : null}\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AA+BI,SAUa,KAVb;AAPG,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAoB;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,UAAU,WAAW;AAAA,MAC3B,aAAW,UAAU,WAAW;AAAA,MAChC,WAAW;AAAA,QACT;AAAA,QACA,WAAW;AAAA,QACX;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA,kBAAU,oBAAC,WAAQ,MAAK,MAAK,IAAK;AAAA,QAClC;AAAA;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -0,0 +1,67 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-HCA5ODCD.js";
4
+
5
+ // src/card.tsx
6
+ import * as React from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var Card = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
9
+ "div",
10
+ {
11
+ ref,
12
+ className: cn(
13
+ "bg-card text-card-foreground rounded-xl border shadow",
14
+ className
15
+ ),
16
+ ...props
17
+ }
18
+ ));
19
+ Card.displayName = "Card";
20
+ var CardHeader = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
21
+ "div",
22
+ {
23
+ ref,
24
+ className: cn("flex flex-col space-y-1.5 p-6", className),
25
+ ...props
26
+ }
27
+ ));
28
+ CardHeader.displayName = "CardHeader";
29
+ var CardTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30
+ "div",
31
+ {
32
+ ref,
33
+ className: cn("leading-none font-semibold tracking-tight", className),
34
+ ...props
35
+ }
36
+ ));
37
+ CardTitle.displayName = "CardTitle";
38
+ var CardDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
39
+ "div",
40
+ {
41
+ ref,
42
+ className: cn("text-muted-foreground text-sm", className),
43
+ ...props
44
+ }
45
+ ));
46
+ CardDescription.displayName = "CardDescription";
47
+ var CardContent = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
48
+ CardContent.displayName = "CardContent";
49
+ var CardFooter = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
50
+ "div",
51
+ {
52
+ ref,
53
+ className: cn("flex items-center p-6 pt-0", className),
54
+ ...props
55
+ }
56
+ ));
57
+ CardFooter.displayName = "CardFooter";
58
+
59
+ export {
60
+ Card,
61
+ CardHeader,
62
+ CardTitle,
63
+ CardDescription,
64
+ CardContent,
65
+ CardFooter
66
+ };
67
+ //# sourceMappingURL=chunk-GMCUXEFI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/card.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\n/**\n * Surface container for grouped content. Prefer a bare section when there is\n * no need for border / padding chrome — cards are for interactive or\n * self-contained blocks, not every stack of text.\n */\nexport const Card = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"bg-card text-card-foreground rounded-xl border shadow\",\n className,\n )}\n {...props}\n />\n));\nCard.displayName = \"Card\";\n\nexport const CardHeader = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex flex-col space-y-1.5 p-6\", className)}\n {...props}\n />\n));\nCardHeader.displayName = \"CardHeader\";\n\nexport const CardTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"leading-none font-semibold tracking-tight\", className)}\n {...props}\n />\n));\nCardTitle.displayName = \"CardTitle\";\n\nexport const CardDescription = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n));\nCardDescription.displayName = \"CardDescription\";\n\nexport const CardContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"p-6 pt-0\", className)} {...props} />\n));\nCardContent.displayName = \"CardContent\";\n\nexport const CardFooter = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex items-center p-6 pt-0\", className)}\n {...props}\n />\n));\nCardFooter.displayName = \"CardFooter\";\n"],"mappings":";;;;;AAAA,YAAY,WAAW;AAarB;AAJK,IAAM,OAAa,iBAGxB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,KAAK,cAAc;AAEZ,IAAM,aAAmB,iBAG9B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACvD,GAAG;AAAA;AACN,CACD;AACD,WAAW,cAAc;AAElB,IAAM,YAAkB,iBAG7B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,6CAA6C,SAAS;AAAA,IACnE,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;AAEjB,IAAM,kBAAwB,iBAGnC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACvD,GAAG;AAAA;AACN,CACD;AACD,gBAAgB,cAAc;AAEvB,IAAM,cAAoB,iBAG/B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,oBAAC,SAAI,KAAU,WAAW,GAAG,YAAY,SAAS,GAAI,GAAG,OAAO,CACjE;AACD,YAAY,cAAc;AAEnB,IAAM,aAAmB,iBAG9B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,8BAA8B,SAAS;AAAA,IACpD,GAAG;AAAA;AACN,CACD;AACD,WAAW,cAAc;","names":[]}
@@ -0,0 +1,85 @@
1
+ // src/dialogLayer.ts
2
+ import * as React from "react";
3
+ var layers = [];
4
+ var FOCUSABLE = [
5
+ "a[href]",
6
+ "button:not([disabled])",
7
+ "input:not([disabled])",
8
+ "select:not([disabled])",
9
+ "textarea:not([disabled])",
10
+ '[tabindex]:not([tabindex="-1"])'
11
+ ].join(",");
12
+ function isVisible(element) {
13
+ if (element.closest("[hidden]")) return false;
14
+ if (element.getAttribute("aria-hidden") === "true") return false;
15
+ return typeof element.checkVisibility === "function" ? element.checkVisibility() : true;
16
+ }
17
+ function focusableWithin(container) {
18
+ return Array.from(container.querySelectorAll(FOCUSABLE)).filter(
19
+ isVisible
20
+ );
21
+ }
22
+ function useDialogLayer({
23
+ active,
24
+ containerRef,
25
+ onEscape
26
+ }) {
27
+ const escapeRef = React.useRef(onEscape);
28
+ React.useEffect(() => {
29
+ escapeRef.current = onEscape;
30
+ });
31
+ React.useEffect(() => {
32
+ if (!active) return;
33
+ const layer = /* @__PURE__ */ Symbol("dialog-layer");
34
+ layers.push(layer);
35
+ const isTopLayer = () => layers[layers.length - 1] === layer;
36
+ const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
37
+ const container = containerRef.current;
38
+ if (container && !container.contains(document.activeElement)) {
39
+ const [first] = focusableWithin(container);
40
+ (container.hasAttribute("tabindex") ? container : first)?.focus();
41
+ }
42
+ function handleKeyDown(event) {
43
+ if (!isTopLayer()) return;
44
+ if (event.key === "Escape") {
45
+ escapeRef.current?.();
46
+ return;
47
+ }
48
+ if (event.key !== "Tab") return;
49
+ const panel = containerRef.current;
50
+ if (!panel) return;
51
+ const items = focusableWithin(panel);
52
+ if (items.length === 0) {
53
+ event.preventDefault();
54
+ panel.focus();
55
+ return;
56
+ }
57
+ const first = items[0];
58
+ const last = items[items.length - 1];
59
+ const active2 = document.activeElement;
60
+ const outside = !panel.contains(active2);
61
+ if (event.shiftKey && (active2 === first || outside)) {
62
+ event.preventDefault();
63
+ last.focus();
64
+ } else if (!event.shiftKey && (active2 === last || outside)) {
65
+ event.preventDefault();
66
+ first.focus();
67
+ }
68
+ }
69
+ document.addEventListener("keydown", handleKeyDown);
70
+ const previousOverflow = document.body.style.overflow;
71
+ document.body.style.overflow = "hidden";
72
+ return () => {
73
+ document.removeEventListener("keydown", handleKeyDown);
74
+ document.body.style.overflow = previousOverflow;
75
+ const index = layers.indexOf(layer);
76
+ if (index !== -1) layers.splice(index, 1);
77
+ if (previouslyFocused?.isConnected) previouslyFocused.focus();
78
+ };
79
+ }, [active, containerRef]);
80
+ }
81
+
82
+ export {
83
+ useDialogLayer
84
+ };
85
+ //# sourceMappingURL=chunk-HBBOR43A.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dialogLayer.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\n/**\n * The keyboard and focus behaviour every dialog needs, in one place.\n *\n * `Modal` and `SideDrawer` each had a copy of the scroll lock and an Escape\n * handler, and neither did anything about focus: opening a dialog left focus\n * on the button behind it, Tab walked the page underneath — through the\n * full-screen backdrop button, among other things — and closing left focus\n * wherever it had wandered. That is the whole keyboard story for thirty\n * dialogs, so it is fixed once here rather than thirty times.\n */\n\n/**\n * Open dialogs, innermost last.\n *\n * Nesting is real here — \"Create audience group\" opens on top of \"Send\n * notification\" — and without an ordering both would answer the same Escape\n * and fight over the same Tab. Only the top layer acts.\n */\nconst layers: symbol[] = [];\n\nconst FOCUSABLE = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\",\");\n\n/**\n * Deliberately not `offsetParent` or `getClientRects`: the first is null for\n * anything `position: fixed`, which a dialog panel usually is, and the second\n * is empty for *everything* under a test renderer that does no layout — which\n * would collapse the trap to \"no focusable elements\" in every test.\n */\nfunction isVisible(element: HTMLElement): boolean {\n if (element.closest(\"[hidden]\")) return false;\n if (element.getAttribute(\"aria-hidden\") === \"true\") return false;\n return typeof element.checkVisibility === \"function\"\n ? element.checkVisibility()\n : true;\n}\n\nfunction focusableWithin(container: HTMLElement): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n isVisible,\n );\n}\n\nexport function useDialogLayer({\n active,\n containerRef,\n onEscape,\n}: {\n active: boolean;\n /** The panel. Focus is moved into it and kept inside it. */\n containerRef: React.RefObject<HTMLElement | null>;\n /** Called on Escape, only while this is the top layer. Omit to ignore it. */\n onEscape?: () => void;\n}): void {\n // Read through a ref so a caller passing a fresh closure every render does\n // not tear the listener down and rebuild it on every keystroke.\n const escapeRef = React.useRef(onEscape);\n React.useEffect(() => {\n escapeRef.current = onEscape;\n });\n\n React.useEffect(() => {\n if (!active) return;\n\n const layer = Symbol(\"dialog-layer\");\n layers.push(layer);\n const isTopLayer = () => layers[layers.length - 1] === layer;\n\n const previouslyFocused =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n\n const container = containerRef.current;\n // Something inside may have claimed focus already — an `autoFocus` input —\n // and that choice is better than any this could make.\n if (container && !container.contains(document.activeElement)) {\n const [first] = focusableWithin(container);\n // The panel itself, not its first control: the first control is a Delete\n // button often enough that focusing it would put a destructive action\n // one Enter away from an accidental keypress.\n (container.hasAttribute(\"tabindex\") ? container : first)?.focus();\n }\n\n function handleKeyDown(event: KeyboardEvent) {\n if (!isTopLayer()) return;\n\n if (event.key === \"Escape\") {\n escapeRef.current?.();\n return;\n }\n\n if (event.key !== \"Tab\") return;\n const panel = containerRef.current;\n if (!panel) return;\n\n const items = focusableWithin(panel);\n if (items.length === 0) {\n event.preventDefault();\n panel.focus();\n return;\n }\n\n const first = items[0]!;\n const last = items[items.length - 1]!;\n const active = document.activeElement;\n const outside = !panel.contains(active);\n\n if (event.shiftKey && (active === first || outside)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (active === last || outside)) {\n event.preventDefault();\n first.focus();\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown);\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n document.body.style.overflow = previousOverflow;\n const index = layers.indexOf(layer);\n if (index !== -1) layers.splice(index, 1);\n // Back where it came from, so closing a dialog opened by keyboard does\n // not drop the caret at the top of the document.\n if (previouslyFocused?.isConnected) previouslyFocused.focus();\n };\n }, [active, containerRef]);\n}\n"],"mappings":";AAEA,YAAY,WAAW;AAoBvB,IAAM,SAAmB,CAAC;AAE1B,IAAM,YAAY;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAQV,SAAS,UAAU,SAA+B;AAChD,MAAI,QAAQ,QAAQ,UAAU,EAAG,QAAO;AACxC,MAAI,QAAQ,aAAa,aAAa,MAAM,OAAQ,QAAO;AAC3D,SAAO,OAAO,QAAQ,oBAAoB,aACtC,QAAQ,gBAAgB,IACxB;AACN;AAEA,SAAS,gBAAgB,WAAuC;AAC9D,SAAO,MAAM,KAAK,UAAU,iBAA8B,SAAS,CAAC,EAAE;AAAA,IACpE;AAAA,EACF;AACF;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF,GAMS;AAGP,QAAM,YAAkB,aAAO,QAAQ;AACvC,EAAM,gBAAU,MAAM;AACpB,cAAU,UAAU;AAAA,EACtB,CAAC;AAED,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,OAAQ;AAEb,UAAM,QAAQ,uBAAO,cAAc;AACnC,WAAO,KAAK,KAAK;AACjB,UAAM,aAAa,MAAM,OAAO,OAAO,SAAS,CAAC,MAAM;AAEvD,UAAM,oBACJ,SAAS,yBAAyB,cAC9B,SAAS,gBACT;AAEN,UAAM,YAAY,aAAa;AAG/B,QAAI,aAAa,CAAC,UAAU,SAAS,SAAS,aAAa,GAAG;AAC5D,YAAM,CAAC,KAAK,IAAI,gBAAgB,SAAS;AAIzC,OAAC,UAAU,aAAa,UAAU,IAAI,YAAY,QAAQ,MAAM;AAAA,IAClE;AAEA,aAAS,cAAc,OAAsB;AAC3C,UAAI,CAAC,WAAW,EAAG;AAEnB,UAAI,MAAM,QAAQ,UAAU;AAC1B,kBAAU,UAAU;AACpB;AAAA,MACF;AAEA,UAAI,MAAM,QAAQ,MAAO;AACzB,YAAM,QAAQ,aAAa;AAC3B,UAAI,CAAC,MAAO;AAEZ,YAAM,QAAQ,gBAAgB,KAAK;AACnC,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,eAAe;AACrB,cAAM,MAAM;AACZ;AAAA,MACF;AAEA,YAAM,QAAQ,MAAM,CAAC;AACrB,YAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,YAAMA,UAAS,SAAS;AACxB,YAAM,UAAU,CAAC,MAAM,SAASA,OAAM;AAEtC,UAAI,MAAM,aAAaA,YAAW,SAAS,UAAU;AACnD,cAAM,eAAe;AACrB,aAAK,MAAM;AAAA,MACb,WAAW,CAAC,MAAM,aAAaA,YAAW,QAAQ,UAAU;AAC1D,cAAM,eAAe;AACrB,cAAM,MAAM;AAAA,MACd;AAAA,IACF;AAEA,aAAS,iBAAiB,WAAW,aAAa;AAClD,UAAM,mBAAmB,SAAS,KAAK,MAAM;AAC7C,aAAS,KAAK,MAAM,WAAW;AAE/B,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,aAAa;AACrD,eAAS,KAAK,MAAM,WAAW;AAC/B,YAAM,QAAQ,OAAO,QAAQ,KAAK;AAClC,UAAI,UAAU,GAAI,QAAO,OAAO,OAAO,CAAC;AAGxC,UAAI,mBAAmB,YAAa,mBAAkB,MAAM;AAAA,IAC9D;AAAA,EACF,GAAG,CAAC,QAAQ,YAAY,CAAC;AAC3B;","names":["active"]}
@@ -0,0 +1,11 @@
1
+ // src/utils.ts
2
+ import { clsx } from "clsx";
3
+ import { twMerge } from "tailwind-merge";
4
+ function cn(...inputs) {
5
+ return twMerge(clsx(inputs));
6
+ }
7
+
8
+ export {
9
+ cn
10
+ };
11
+ //# sourceMappingURL=chunk-HCA5ODCD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";AAAA,SAA0B,YAAY;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;","names":[]}
@@ -0,0 +1,26 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-HCA5ODCD.js";
4
+
5
+ // src/checkbox.tsx
6
+ import * as React from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var checkboxClass = "accent-primary border-border focus-visible:ring-ring size-4 shrink-0 cursor-pointer rounded border focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50";
9
+ var Checkbox = React.forwardRef(
10
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
11
+ "input",
12
+ {
13
+ ref,
14
+ type: "checkbox",
15
+ className: cn(checkboxClass, className),
16
+ ...props
17
+ }
18
+ )
19
+ );
20
+ Checkbox.displayName = "Checkbox";
21
+
22
+ export {
23
+ checkboxClass,
24
+ Checkbox
25
+ };
26
+ //# sourceMappingURL=chunk-HYRJYUPI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/checkbox.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\n/**\n * The native checkbox, sized and coloured once.\n *\n * Twenty-six of these were scattered across thirteen files and twenty of them\n * carried **no class at all** — browser defaults, so they were a different size\n * to the six that set `size-4` and drew their tick in the operating system's\n * accent rather than the panel's.\n *\n * This deliberately stays a native `<input type=\"checkbox\">` rather than an\n * `appearance-none` box with an SVG tick. Native gets indeterminate state,\n * form participation, platform focus behaviour and assistive-technology support\n * for free, and a custom one would have to re-earn all of it to look slightly\n * different.\n *\n * `border` and `rounded` mostly do not render on a native checkbox — they are\n * kept because the six styled copies had them and removing them would be a\n * silent change to those. `accent-primary` and `size-4` are what actually show.\n */\nexport const checkboxClass =\n \"accent-primary border-border focus-visible:ring-ring size-4 shrink-0 cursor-pointer rounded border focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50\";\n\nexport type CheckboxProps = Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n \"type\"\n>;\n\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n ({ className, ...props }, ref) => (\n <input\n ref={ref}\n type=\"checkbox\"\n className={cn(checkboxClass, className)}\n {...props}\n />\n ),\n);\n\nCheckbox.displayName = \"Checkbox\";\n"],"mappings":";;;;;AAAA,YAAY,WAAW;AAgCnB;AAVG,IAAM,gBACX;AAOK,IAAM,WAAiB;AAAA,EAC5B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,MAAK;AAAA,MACL,WAAW,GAAG,eAAe,SAAS;AAAA,MACrC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,cAAc;","names":[]}
@@ -0,0 +1,26 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-HCA5ODCD.js";
4
+
5
+ // src/textarea.tsx
6
+ import * as React from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var textareaClass = "border-border bg-background focus-visible:ring-ring w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50";
9
+ var Textarea = React.forwardRef(
10
+ ({ className, rows = 3, ...props }, ref) => /* @__PURE__ */ jsx(
11
+ "textarea",
12
+ {
13
+ ref,
14
+ rows,
15
+ className: cn(textareaClass, className),
16
+ ...props
17
+ }
18
+ )
19
+ );
20
+ Textarea.displayName = "Textarea";
21
+
22
+ export {
23
+ textareaClass,
24
+ Textarea
25
+ };
26
+ //# sourceMappingURL=chunk-IRCTGJQB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/textarea.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\n/**\n * The multi-line counterpart to `Input`.\n *\n * There was no shared textarea, so sixteen of them were styled individually\n * and no two agreed — different borders, different focus rings, some with no\n * focus ring at all, which is a keyboard user losing their place.\n *\n * Deliberately not `inputClass`: that fixes `h-9`, which is a one-line\n * control. Everything else is shared so a textarea and an input sitting in the\n * same form look related.\n */\nexport const textareaClass =\n \"border-border bg-background focus-visible:ring-ring w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50\";\n\nexport type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, rows = 3, ...props }, ref) => (\n <textarea\n ref={ref}\n rows={rows}\n className={cn(textareaClass, className)}\n {...props}\n />\n ),\n);\n\nTextarea.displayName = \"Textarea\";\n"],"mappings":";;;;;AAAA,YAAY,WAAW;AAsBnB;AAPG,IAAM,gBACX;AAIK,IAAM,WAAiB;AAAA,EAC5B,CAAC,EAAE,WAAW,OAAO,GAAG,GAAG,MAAM,GAAG,QAClC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,WAAW,GAAG,eAAe,SAAS;AAAA,MACrC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,cAAc;","names":[]}
@@ -0,0 +1,30 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-HCA5ODCD.js";
4
+
5
+ // src/panel-brand-mark.tsx
6
+ import { jsx } from "react/jsx-runtime";
7
+ function PanelBrandMark({
8
+ children,
9
+ size = "md",
10
+ className,
11
+ ...props
12
+ }) {
13
+ return /* @__PURE__ */ jsx(
14
+ "div",
15
+ {
16
+ className: cn(
17
+ "bg-primary text-primary-foreground grid shrink-0 place-items-center rounded-lg",
18
+ size === "sm" ? "h-9 w-9" : "h-10 w-10",
19
+ className
20
+ ),
21
+ ...props,
22
+ children
23
+ }
24
+ );
25
+ }
26
+
27
+ export {
28
+ PanelBrandMark
29
+ };
30
+ //# sourceMappingURL=chunk-JDE5XYPT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/panel-brand-mark.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\nexport type PanelBrandMarkProps = React.HTMLAttributes<HTMLDivElement> & {\n /** Icon inside the mark (lucide, etc.). */\n children: React.ReactNode;\n size?: \"sm\" | \"md\";\n};\n\n/**\n * Quiet brand tile for sidebar / sign-in — solid primary, no decorative gradients.\n */\nexport function PanelBrandMark({\n children,\n size = \"md\",\n className,\n ...props\n}: PanelBrandMarkProps) {\n return (\n <div\n className={cn(\n \"bg-primary text-primary-foreground grid shrink-0 place-items-center rounded-lg\",\n size === \"sm\" ? \"h-9 w-9\" : \"h-10 w-10\",\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n"],"mappings":";;;;;AAoBI;AAPG,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA,GAAG;AACL,GAAwB;AACtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,SAAS,OAAO,YAAY;AAAA,QAC5B;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -0,0 +1,59 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-HCA5ODCD.js";
4
+
5
+ // src/breadcrumb.tsx
6
+ import { ChevronRight } from "lucide-react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ function Breadcrumb({ items, className }) {
9
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: cn("text-sm", className), children: /* @__PURE__ */ jsx("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
10
+ const isLast = index === items.length - 1;
11
+ const isInteractive = !isLast && (item.href || item.onClick);
12
+ return /* @__PURE__ */ jsxs(
13
+ "li",
14
+ {
15
+ className: "flex items-center gap-1.5",
16
+ children: [
17
+ index > 0 && /* @__PURE__ */ jsx(
18
+ ChevronRight,
19
+ {
20
+ className: "text-muted-foreground/70 size-3.5 shrink-0",
21
+ "aria-hidden": true
22
+ }
23
+ ),
24
+ isInteractive ? item.href ? /* @__PURE__ */ jsx(
25
+ "a",
26
+ {
27
+ href: item.href,
28
+ className: "text-muted-foreground hover:text-foreground transition",
29
+ children: item.label
30
+ }
31
+ ) : /* @__PURE__ */ jsx(
32
+ "button",
33
+ {
34
+ type: "button",
35
+ onClick: item.onClick,
36
+ className: "text-muted-foreground hover:text-foreground transition",
37
+ children: item.label
38
+ }
39
+ ) : /* @__PURE__ */ jsx(
40
+ "span",
41
+ {
42
+ className: cn(
43
+ isLast ? "text-foreground font-medium" : "text-muted-foreground"
44
+ ),
45
+ "aria-current": isLast ? "page" : void 0,
46
+ children: item.label
47
+ }
48
+ )
49
+ ]
50
+ },
51
+ `${item.label}-${index}`
52
+ );
53
+ }) }) });
54
+ }
55
+
56
+ export {
57
+ Breadcrumb
58
+ };
59
+ //# sourceMappingURL=chunk-JSJEEKR3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/breadcrumb.tsx"],"sourcesContent":["import { ChevronRight } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\nexport type BreadcrumbItem = {\n label: string;\n href?: string;\n onClick?: () => void;\n};\n\ninterface BreadcrumbProps {\n items: BreadcrumbItem[];\n className?: string;\n}\n\nexport function Breadcrumb({ items, className }: BreadcrumbProps) {\n return (\n <nav aria-label=\"Breadcrumb\" className={cn(\"text-sm\", className)}>\n <ol className=\"flex flex-wrap items-center gap-1.5\">\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n const isInteractive = !isLast && (item.href || item.onClick);\n\n return (\n <li\n key={`${item.label}-${index}`}\n className=\"flex items-center gap-1.5\"\n >\n {index > 0 && (\n <ChevronRight\n className=\"text-muted-foreground/70 size-3.5 shrink-0\"\n aria-hidden\n />\n )}\n {isInteractive ? (\n item.href ? (\n <a\n href={item.href}\n className=\"text-muted-foreground hover:text-foreground transition\"\n >\n {item.label}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={item.onClick}\n className=\"text-muted-foreground hover:text-foreground transition\"\n >\n {item.label}\n </button>\n )\n ) : (\n <span\n className={cn(\n isLast\n ? \"text-foreground font-medium\"\n : \"text-muted-foreground\",\n )}\n aria-current={isLast ? \"page\" : undefined}\n >\n {item.label}\n </span>\n )}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n"],"mappings":";;;;;AAAA,SAAS,oBAAoB;AAyBjB,SAKI,KALJ;AATL,SAAS,WAAW,EAAE,OAAO,UAAU,GAAoB;AAChE,SACE,oBAAC,SAAI,cAAW,cAAa,WAAW,GAAG,WAAW,SAAS,GAC7D,8BAAC,QAAG,WAAU,uCACX,gBAAM,IAAI,CAAC,MAAM,UAAU;AAC1B,UAAM,SAAS,UAAU,MAAM,SAAS;AACxC,UAAM,gBAAgB,CAAC,WAAW,KAAK,QAAQ,KAAK;AAEpD,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAET;AAAA,kBAAQ,KACP;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAW;AAAA;AAAA,UACb;AAAA,UAED,gBACC,KAAK,OACH;AAAA,YAAC;AAAA;AAAA,cACC,MAAM,KAAK;AAAA,cACX,WAAU;AAAA,cAET,eAAK;AAAA;AAAA,UACR,IAEA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,KAAK;AAAA,cACd,WAAU;AAAA,cAET,eAAK;AAAA;AAAA,UACR,IAGF;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT,SACI,gCACA;AAAA,cACN;AAAA,cACA,gBAAc,SAAS,SAAS;AAAA,cAE/B,eAAK;AAAA;AAAA,UACR;AAAA;AAAA;AAAA,MApCG,GAAG,KAAK,KAAK,IAAI,KAAK;AAAA,IAsC7B;AAAA,EAEJ,CAAC,GACH,GACF;AAEJ;","names":[]}