@nocoo/basalt 2.1.8 → 3.0.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 (352) hide show
  1. package/README.md +2 -0
  2. package/ai/COMPATIBILITY.md +11 -1
  3. package/ai/DESIGN.md +342 -0
  4. package/ai/INTEGRATION.md +239 -152
  5. package/ai/RECIPES.md +96 -26
  6. package/ai/USAGE.md +5 -5
  7. package/ai/registry.json +2883 -275
  8. package/dist/assets/brand-mark.js.map +1 -1
  9. package/dist/charts/area.js.map +1 -1
  10. package/dist/charts/bar.js.map +1 -1
  11. package/dist/charts/bullet.js.map +1 -1
  12. package/dist/charts/charts.js.map +1 -1
  13. package/dist/charts/config.d.ts +11 -11
  14. package/dist/charts/config.js +4 -4
  15. package/dist/charts/config.js.map +1 -1
  16. package/dist/charts/custom-chart.js.map +1 -1
  17. package/dist/charts/date-navigation.js +10 -10
  18. package/dist/charts/date-navigation.js.map +1 -1
  19. package/dist/charts/donut.js +1 -1
  20. package/dist/charts/donut.js.map +1 -1
  21. package/dist/charts/frame.d.ts +1 -1
  22. package/dist/charts/frame.js +4 -4
  23. package/dist/charts/frame.js.map +1 -1
  24. package/dist/charts/funnel.js.map +1 -1
  25. package/dist/charts/gauge.js +5 -5
  26. package/dist/charts/gauge.js.map +1 -1
  27. package/dist/charts/grouped-bar.js.map +1 -1
  28. package/dist/charts/heatmap-calendar.js +11 -11
  29. package/dist/charts/heatmap-calendar.js.map +1 -1
  30. package/dist/charts/heatmap-matrix.js +8 -8
  31. package/dist/charts/heatmap-matrix.js.map +1 -1
  32. package/dist/charts/item-list.js +1 -1
  33. package/dist/charts/item-list.js.map +1 -1
  34. package/dist/charts/legend.js +19 -19
  35. package/dist/charts/legend.js.map +1 -1
  36. package/dist/charts/line.js.map +1 -1
  37. package/dist/charts/palette.js +2 -2
  38. package/dist/charts/palette.js.map +1 -1
  39. package/dist/charts/radar.js.map +1 -1
  40. package/dist/charts/sample.js.map +1 -1
  41. package/dist/charts/sankey.js.map +1 -1
  42. package/dist/charts/series.js.map +1 -1
  43. package/dist/charts/slot-bar.js +2 -2
  44. package/dist/charts/slot-bar.js.map +1 -1
  45. package/dist/charts/sparkline.js +38 -23
  46. package/dist/charts/sparkline.js.map +1 -1
  47. package/dist/charts/stacked-bar.js.map +1 -1
  48. package/dist/charts/stat-card.d.ts +2 -2
  49. package/dist/charts/stat-card.js +61 -58
  50. package/dist/charts/stat-card.js.map +1 -1
  51. package/dist/charts/timeline.js +18 -9
  52. package/dist/charts/timeline.js.map +1 -1
  53. package/dist/charts/timeseries.js.map +1 -1
  54. package/dist/charts/tooltip.js +16 -16
  55. package/dist/charts/tooltip.js.map +1 -1
  56. package/dist/components/accordion.js +1 -1
  57. package/dist/components/accordion.js.map +1 -1
  58. package/dist/components/alert-dialog.js +4 -4
  59. package/dist/components/alert-dialog.js.map +1 -1
  60. package/dist/components/app-header.d.ts +5 -1
  61. package/dist/components/app-header.js +19 -11
  62. package/dist/components/app-header.js.map +1 -1
  63. package/dist/components/app-shell.d.ts +4 -1
  64. package/dist/components/app-shell.js +8 -5
  65. package/dist/components/app-shell.js.map +1 -1
  66. package/dist/components/approval-card.d.ts +13 -0
  67. package/dist/components/approval-card.js +161 -0
  68. package/dist/components/approval-card.js.map +1 -0
  69. package/dist/components/autocomplete.js.map +1 -1
  70. package/dist/components/avatar.d.ts +12 -0
  71. package/dist/components/avatar.js +39 -18
  72. package/dist/components/avatar.js.map +1 -1
  73. package/dist/components/badge.js +8 -8
  74. package/dist/components/badge.js.map +1 -1
  75. package/dist/components/banner.d.ts +2 -2
  76. package/dist/components/banner.js +9 -8
  77. package/dist/components/banner.js.map +1 -1
  78. package/dist/components/basalt-mark.js +1 -1
  79. package/dist/components/basalt-mark.js.map +1 -1
  80. package/dist/components/battery-meter.js +5 -5
  81. package/dist/components/battery-meter.js.map +1 -1
  82. package/dist/components/breadcrumbs.js +6 -6
  83. package/dist/components/breadcrumbs.js.map +1 -1
  84. package/dist/components/button.js +10 -10
  85. package/dist/components/button.js.map +1 -1
  86. package/dist/components/chat-bubble.js +4 -3
  87. package/dist/components/chat-bubble.js.map +1 -1
  88. package/dist/components/chat-composer.d.ts +21 -3
  89. package/dist/components/chat-composer.js +126 -60
  90. package/dist/components/chat-composer.js.map +1 -1
  91. package/dist/components/chat-header.js +6 -6
  92. package/dist/components/chat-header.js.map +1 -1
  93. package/dist/components/chat-inbox.js +34 -30
  94. package/dist/components/chat-inbox.js.map +1 -1
  95. package/dist/components/chat-markdown.d.ts +8 -0
  96. package/dist/components/chat-markdown.js +122 -0
  97. package/dist/components/chat-markdown.js.map +1 -0
  98. package/dist/components/chat-message.d.ts +26 -0
  99. package/dist/components/chat-message.js +145 -0
  100. package/dist/components/chat-message.js.map +1 -0
  101. package/dist/components/checkbox.js +11 -11
  102. package/dist/components/checkbox.js.map +1 -1
  103. package/dist/components/clipboard-text.js +3 -3
  104. package/dist/components/clipboard-text.js.map +1 -1
  105. package/dist/components/code.d.ts +22 -20
  106. package/dist/components/code.js +94 -32
  107. package/dist/components/code.js.map +1 -1
  108. package/dist/components/collapsible.js +8 -4
  109. package/dist/components/collapsible.js.map +1 -1
  110. package/dist/components/combobox.js.map +1 -1
  111. package/dist/components/command-palette.js +73 -47
  112. package/dist/components/command-palette.js.map +1 -1
  113. package/dist/components/confirm-dialog.d.ts +4 -1
  114. package/dist/components/confirm-dialog.js +20 -18
  115. package/dist/components/confirm-dialog.js.map +1 -1
  116. package/dist/components/context-cards.d.ts +15 -0
  117. package/dist/components/context-cards.js +148 -0
  118. package/dist/components/context-cards.js.map +1 -0
  119. package/dist/components/context-menu.d.ts +1 -1
  120. package/dist/components/context-menu.js +18 -14
  121. package/dist/components/context-menu.js.map +1 -1
  122. package/dist/components/data-table.d.ts +8 -2
  123. package/dist/components/data-table.js +161 -106
  124. package/dist/components/data-table.js.map +1 -1
  125. package/dist/components/date-picker.js +13 -13
  126. package/dist/components/date-picker.js.map +1 -1
  127. package/dist/components/delete-resource.js +1 -1
  128. package/dist/components/delete-resource.js.map +1 -1
  129. package/dist/components/description-list.js +3 -3
  130. package/dist/components/description-list.js.map +1 -1
  131. package/dist/components/dialog.d.ts +2 -2
  132. package/dist/components/dialog.js +8 -8
  133. package/dist/components/dialog.js.map +1 -1
  134. package/dist/components/diff-table.d.ts +15 -0
  135. package/dist/components/diff-table.js +146 -0
  136. package/dist/components/diff-table.js.map +1 -0
  137. package/dist/components/dock.js +2 -2
  138. package/dist/components/dock.js.map +1 -1
  139. package/dist/components/dropdown-menu.js +23 -18
  140. package/dist/components/dropdown-menu.js.map +1 -1
  141. package/dist/components/editable-nav-item.js +63 -58
  142. package/dist/components/editable-nav-item.js.map +1 -1
  143. package/dist/components/empty.js +6 -6
  144. package/dist/components/empty.js.map +1 -1
  145. package/dist/components/fab.js +1 -1
  146. package/dist/components/fab.js.map +1 -1
  147. package/dist/components/field.js +3 -3
  148. package/dist/components/field.js.map +1 -1
  149. package/dist/components/file-dropzone.js +7 -7
  150. package/dist/components/file-dropzone.js.map +1 -1
  151. package/dist/components/filter-bar.js +6 -6
  152. package/dist/components/filter-bar.js.map +1 -1
  153. package/dist/components/flow.js +4 -3
  154. package/dist/components/flow.js.map +1 -1
  155. package/dist/components/grid.d.ts +3 -1
  156. package/dist/components/grid.js +15 -8
  157. package/dist/components/grid.js.map +1 -1
  158. package/dist/components/hover-card.js +1 -1
  159. package/dist/components/hover-card.js.map +1 -1
  160. package/dist/components/icon-picker.d.ts +8 -2
  161. package/dist/components/icon-picker.js +75 -47
  162. package/dist/components/icon-picker.js.map +1 -1
  163. package/dist/components/inline-editable.js +6 -6
  164. package/dist/components/inline-editable.js.map +1 -1
  165. package/dist/components/input-area.js +3 -3
  166. package/dist/components/input-area.js.map +1 -1
  167. package/dist/components/input-group.js +5 -5
  168. package/dist/components/input-group.js.map +1 -1
  169. package/dist/components/input.js +4 -4
  170. package/dist/components/input.js.map +1 -1
  171. package/dist/components/label.js +3 -3
  172. package/dist/components/label.js.map +1 -1
  173. package/dist/components/layer-card.d.ts +9 -4
  174. package/dist/components/layer-card.js +72 -67
  175. package/dist/components/layer-card.js.map +1 -1
  176. package/dist/components/link.js.map +1 -1
  177. package/dist/components/loader.d.ts +16 -10
  178. package/dist/components/loader.js +46 -53
  179. package/dist/components/loader.js.map +1 -1
  180. package/dist/components/loading-screen.js +3 -3
  181. package/dist/components/loading-screen.js.map +1 -1
  182. package/dist/components/menu-bar.js +32 -27
  183. package/dist/components/menu-bar.js.map +1 -1
  184. package/dist/components/meter.d.ts +5 -5
  185. package/dist/components/meter.js +25 -12
  186. package/dist/components/meter.js.map +1 -1
  187. package/dist/components/multi-select.js +66 -62
  188. package/dist/components/multi-select.js.map +1 -1
  189. package/dist/components/navigation-menu.d.ts +2 -2
  190. package/dist/components/navigation-menu.js +22 -8
  191. package/dist/components/navigation-menu.js.map +1 -1
  192. package/dist/components/overlay.js +2 -2
  193. package/dist/components/overlay.js.map +1 -1
  194. package/dist/components/page-header.d.ts +3 -1
  195. package/dist/components/page-header.js +12 -12
  196. package/dist/components/page-header.js.map +1 -1
  197. package/dist/components/pagination.js +3 -3
  198. package/dist/components/pagination.js.map +1 -1
  199. package/dist/components/popover.js +18 -23
  200. package/dist/components/popover.js.map +1 -1
  201. package/dist/components/prompt-bar.d.ts +16 -0
  202. package/dist/components/prompt-bar.js +49 -0
  203. package/dist/components/prompt-bar.js.map +1 -0
  204. package/dist/components/radio.js +9 -9
  205. package/dist/components/radio.js.map +1 -1
  206. package/dist/components/recommendation-card.d.ts +13 -0
  207. package/dist/components/recommendation-card.js +123 -0
  208. package/dist/components/recommendation-card.js.map +1 -0
  209. package/dist/components/resource-list.js +1 -1
  210. package/dist/components/resource-list.js.map +1 -1
  211. package/dist/components/responsive-master-detail.js +7 -7
  212. package/dist/components/responsive-master-detail.js.map +1 -1
  213. package/dist/components/scroll-area.js +3 -3
  214. package/dist/components/scroll-area.js.map +1 -1
  215. package/dist/components/section-rule.d.ts +5 -3
  216. package/dist/components/section-rule.js +12 -12
  217. package/dist/components/section-rule.js.map +1 -1
  218. package/dist/components/segment-control.js +3 -3
  219. package/dist/components/segment-control.js.map +1 -1
  220. package/dist/components/select.js +47 -32
  221. package/dist/components/select.js.map +1 -1
  222. package/dist/components/sensitive-input.js +17 -19
  223. package/dist/components/sensitive-input.js.map +1 -1
  224. package/dist/components/separator.js.map +1 -1
  225. package/dist/components/sheet.d.ts +4 -4
  226. package/dist/components/sheet.js +12 -10
  227. package/dist/components/sheet.js.map +1 -1
  228. package/dist/components/sidebar.d.ts +3 -1
  229. package/dist/components/sidebar.js +150 -138
  230. package/dist/components/sidebar.js.map +1 -1
  231. package/dist/components/skeleton-line.d.ts +1 -1
  232. package/dist/components/skeleton-line.js +2 -2
  233. package/dist/components/skeleton-line.js.map +1 -1
  234. package/dist/components/slider.js +2 -2
  235. package/dist/components/slider.js.map +1 -1
  236. package/dist/components/stat-strip.js +5 -4
  237. package/dist/components/stat-strip.js.map +1 -1
  238. package/dist/components/switch.js +6 -6
  239. package/dist/components/switch.js.map +1 -1
  240. package/dist/components/table-of-contents.js +5 -5
  241. package/dist/components/table-of-contents.js.map +1 -1
  242. package/dist/components/table-pager.js +2 -2
  243. package/dist/components/table-pager.js.map +1 -1
  244. package/dist/components/table.js +4 -4
  245. package/dist/components/table.js.map +1 -1
  246. package/dist/components/tabs.js +7 -6
  247. package/dist/components/tabs.js.map +1 -1
  248. package/dist/components/tag-badge.d.ts +10 -10
  249. package/dist/components/tag-badge.js +11 -11
  250. package/dist/components/tag-badge.js.map +1 -1
  251. package/dist/components/tag-color-picker.d.ts +8 -1
  252. package/dist/components/tag-color-picker.js +33 -25
  253. package/dist/components/tag-color-picker.js.map +1 -1
  254. package/dist/components/text.js +5 -5
  255. package/dist/components/text.js.map +1 -1
  256. package/dist/components/theme-toggle.js +1 -1
  257. package/dist/components/theme-toggle.js.map +1 -1
  258. package/dist/components/thinking.d.ts +16 -0
  259. package/dist/components/thinking.js +85 -0
  260. package/dist/components/thinking.js.map +1 -0
  261. package/dist/components/toast.js +25 -20
  262. package/dist/components/toast.js.map +1 -1
  263. package/dist/components/toggle-group.js +6 -5
  264. package/dist/components/toggle-group.js.map +1 -1
  265. package/dist/components/toggle.js +6 -6
  266. package/dist/components/toggle.js.map +1 -1
  267. package/dist/components/tool-chips.d.ts +12 -0
  268. package/dist/components/tool-chips.js +138 -0
  269. package/dist/components/tool-chips.js.map +1 -0
  270. package/dist/components/toolbar.js +3 -3
  271. package/dist/components/toolbar.js.map +1 -1
  272. package/dist/components/tooltip.js +1 -1
  273. package/dist/components/tooltip.js.map +1 -1
  274. package/dist/components/typeahead-field.js +59 -56
  275. package/dist/components/typeahead-field.js.map +1 -1
  276. package/dist/components/upload-queue.js +15 -14
  277. package/dist/components/upload-queue.js.map +1 -1
  278. package/dist/models/agent-feedback.d.ts +44 -0
  279. package/dist/models/agent-feedback.js +28 -0
  280. package/dist/models/agent-feedback.js.map +1 -0
  281. package/dist/models/avatar.d.ts +2 -0
  282. package/dist/models/avatar.js +15 -0
  283. package/dist/models/avatar.js.map +1 -0
  284. package/dist/models/code.d.ts +6 -0
  285. package/dist/models/code.js +24 -0
  286. package/dist/models/code.js.map +1 -0
  287. package/dist/models/context-cards.d.ts +13 -0
  288. package/dist/models/context-cards.js +17 -0
  289. package/dist/models/context-cards.js.map +1 -0
  290. package/dist/models/diff-table.d.ts +12 -0
  291. package/dist/models/diff-table.js +9 -0
  292. package/dist/models/diff-table.js.map +1 -0
  293. package/dist/models/recommendation.d.ts +26 -0
  294. package/dist/models/recommendation.js +23 -0
  295. package/dist/models/recommendation.js.map +1 -0
  296. package/dist/providers/accent.js +1 -1
  297. package/dist/providers/accent.js.map +1 -1
  298. package/dist/providers/link.js.map +1 -1
  299. package/dist/providers/theme.js +1 -1
  300. package/dist/providers/theme.js.map +1 -1
  301. package/dist/styles/base.css +128 -0
  302. package/dist/styles/standalone.css +1994 -937
  303. package/dist/styles/tailwind.css +179 -13
  304. package/dist/styles/tokens.css +679 -20
  305. package/dist/utils/cn.js +25 -4
  306. package/dist/utils/cn.js.map +1 -1
  307. package/dist/utils/control-surface.d.ts +1 -1
  308. package/dist/utils/control-surface.js +1 -1
  309. package/dist/utils/control-surface.js.map +1 -1
  310. package/dist/utils/navigation.d.ts +3 -0
  311. package/dist/utils/navigation.js +8 -0
  312. package/dist/utils/navigation.js.map +1 -0
  313. package/dist/utils/preference-store.js +1 -1
  314. package/dist/utils/preference-store.js.map +1 -1
  315. package/dist/utils/selection-indicator.d.ts +1 -1
  316. package/dist/utils/selection-indicator.js +49 -72
  317. package/dist/utils/selection-indicator.js.map +1 -1
  318. package/dist/utils/use-checkable-group.js.map +1 -1
  319. package/dist/utils/use-hover-highlight.d.ts +4 -0
  320. package/dist/utils/use-hover-highlight.js +80 -0
  321. package/dist/utils/use-hover-highlight.js.map +1 -0
  322. package/dist/viewmodels/use-approval-card.d.ts +20 -0
  323. package/dist/viewmodels/use-approval-card.js +83 -0
  324. package/dist/viewmodels/use-approval-card.js.map +1 -0
  325. package/dist/viewmodels/use-chat-composer.d.ts +16 -0
  326. package/dist/viewmodels/use-chat-composer.js +34 -0
  327. package/dist/viewmodels/use-chat-composer.js.map +1 -0
  328. package/dist/viewmodels/use-chat-message.d.ts +16 -0
  329. package/dist/viewmodels/use-chat-message.js +26 -0
  330. package/dist/viewmodels/use-chat-message.js.map +1 -0
  331. package/dist/viewmodels/use-code-block.d.ts +8 -0
  332. package/dist/viewmodels/use-code-block.js +38 -0
  333. package/dist/viewmodels/use-code-block.js.map +1 -0
  334. package/dist/viewmodels/use-context-cards.d.ts +17 -0
  335. package/dist/viewmodels/use-context-cards.js +18 -0
  336. package/dist/viewmodels/use-context-cards.js.map +1 -0
  337. package/dist/viewmodels/use-diff-table.d.ts +16 -0
  338. package/dist/viewmodels/use-diff-table.js +42 -0
  339. package/dist/viewmodels/use-diff-table.js.map +1 -0
  340. package/dist/viewmodels/use-loader.d.ts +4 -0
  341. package/dist/viewmodels/use-loader.js +22 -0
  342. package/dist/viewmodels/use-loader.js.map +1 -0
  343. package/dist/viewmodels/use-recommendation-card.d.ts +17 -0
  344. package/dist/viewmodels/use-recommendation-card.js +41 -0
  345. package/dist/viewmodels/use-recommendation-card.js.map +1 -0
  346. package/dist/viewmodels/use-thinking.d.ts +13 -0
  347. package/dist/viewmodels/use-thinking.js +18 -0
  348. package/dist/viewmodels/use-thinking.js.map +1 -0
  349. package/dist/viewmodels/use-tool-chips.d.ts +10 -0
  350. package/dist/viewmodels/use-tool-chips.js +20 -0
  351. package/dist/viewmodels/use-tool-chips.js.map +1 -0
  352. package/package.json +3 -1
package/dist/utils/cn.js CHANGED
@@ -1,11 +1,32 @@
1
1
  "use client";
2
2
  import { clsx as e } from "clsx";
3
- import { twMerge as t } from "tailwind-merge";
3
+ import { extendTailwindMerge as t } from "tailwind-merge";
4
4
  //#region src/utils/cn.ts
5
- function n(...n) {
6
- return t(e(n));
5
+ var n = t({ extend: { theme: {
6
+ spacing: [(e) => e.startsWith("basalt-")],
7
+ radius: [(e) => e.startsWith("basalt-")],
8
+ text: [
9
+ "basalt-xs",
10
+ "basalt-sm",
11
+ "basalt-code",
12
+ "basalt-base",
13
+ "basalt-lg",
14
+ "basalt-xl",
15
+ "basalt-2xl",
16
+ "basalt-3xl",
17
+ "basalt-4xl",
18
+ "basalt-5xl",
19
+ "basalt-6xl",
20
+ "basalt-7xl",
21
+ "basalt-8xl",
22
+ "basalt-9xl",
23
+ "basalt-10xl"
24
+ ]
25
+ } } });
26
+ function r(...t) {
27
+ return n(e(t));
7
28
  }
8
29
  //#endregion
9
- export { n as cn };
30
+ export { r as cn };
10
31
 
11
32
  //# sourceMappingURL=cn.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cn.js","names":[],"sources":["../../src/utils/cn.ts"],"sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n"],"mappings":";;;;AAGA,SAAgB,EAAG,GAAG,GAAsB;CAC3C,OAAO,EAAQ,EAAK,CAAM,CAAC;AAC5B"}
1
+ {"version":3,"file":"cn.js","names":["twMerge","extendTailwindMerge","value","cn","inputs","clsx"],"sources":["../../src/utils/cn.ts"],"sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({\n\textend: {\n\t\ttheme: {\n\t\t\tspacing: [(value: string) => value.startsWith(\"basalt-\")],\n\t\t\tradius: [(value: string) => value.startsWith(\"basalt-\")],\n\t\t\ttext: [\n\t\t\t\t\"basalt-xs\",\n\t\t\t\t\"basalt-sm\",\n\t\t\t\t\"basalt-code\",\n\t\t\t\t\"basalt-base\",\n\t\t\t\t\"basalt-lg\",\n\t\t\t\t\"basalt-xl\",\n\t\t\t\t\"basalt-2xl\",\n\t\t\t\t\"basalt-3xl\",\n\t\t\t\t\"basalt-4xl\",\n\t\t\t\t\"basalt-5xl\",\n\t\t\t\t\"basalt-6xl\",\n\t\t\t\t\"basalt-7xl\",\n\t\t\t\t\"basalt-8xl\",\n\t\t\t\t\"basalt-9xl\",\n\t\t\t\t\"basalt-10xl\",\n\t\t\t],\n\t\t},\n\t},\n});\n\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n"],"mappings":";;;;AAGA,IAAMA,IAAUC,EAAoB,EACnC,QAAQ,EACP,OAAO;CACN,SAAS,EAAE,MAAkBC,EAAM,WAAW,SAAS,CAAC;CACxD,QAAQ,EAAE,MAAkBA,EAAM,WAAW,SAAS,CAAC;CACvD,MAAM;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD;AACD,EACD,EACD,CAAC;AAED,SAAgBC,EAAG,GAAGC,GAAsB;CAC3C,OAAOJ,EAAQK,EAAKD,CAAM,CAAC;AAC5B"}
@@ -1,3 +1,3 @@
1
1
  export declare const BASALT_UI_CLASS = "basalt-ui";
2
- export declare const CONTROL_SURFACE_CLASS = "basalt-ui rounded-basalt-md border border-basalt-border bg-basalt-control text-sm";
2
+ export declare const CONTROL_SURFACE_CLASS = "basalt-ui rounded-basalt-md border border-basalt-border bg-basalt-control";
3
3
  export declare function controlSurfaceClass(className?: string): string;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn as e } from "./cn.js";
3
3
  //#region src/utils/control-surface.ts
4
- var t = "basalt-ui", n = "basalt-ui rounded-basalt-md border border-basalt-border bg-basalt-control text-sm";
4
+ var t = "basalt-ui", n = "basalt-ui rounded-basalt-md border border-basalt-border bg-basalt-control";
5
5
  function r(t) {
6
6
  return e(n, t);
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"control-surface.js","names":[],"sources":["../../src/utils/control-surface.ts"],"sourcesContent":["import { cn } from \"./cn\";\n\nexport const BASALT_UI_CLASS = \"basalt-ui\";\n\nexport const CONTROL_SURFACE_CLASS =\n\t\"basalt-ui rounded-basalt-md border border-basalt-border bg-basalt-control text-sm\";\n\nexport function controlSurfaceClass(className?: string) {\n\treturn cn(CONTROL_SURFACE_CLASS, className);\n}\n"],"mappings":";;;AAEA,IAAa,IAAkB,aAElB,IACZ;AAED,SAAgB,EAAoB,GAAoB;CACvD,OAAO,EAAG,GAAuB,CAAS;AAC3C"}
1
+ {"version":3,"file":"control-surface.js","names":["BASALT_UI_CLASS","CONTROL_SURFACE_CLASS","controlSurfaceClass","cn","className"],"sources":["../../src/utils/control-surface.ts"],"sourcesContent":["import { cn } from \"./cn\";\n\nexport const BASALT_UI_CLASS = \"basalt-ui\";\n\nexport const CONTROL_SURFACE_CLASS =\n\t\"basalt-ui rounded-basalt-md border border-basalt-border bg-basalt-control\";\n\nexport function controlSurfaceClass(className?: string) {\n\treturn cn(CONTROL_SURFACE_CLASS, className);\n}\n"],"mappings":";;;AAEA,IAAaA,IAAkB,aAElBC,IACZ;AAED,SAAgBC,EAAoB,GAAoB;CACvD,OAAOC,EAAGF,GAAuBG,CAAS;AAC3C"}
@@ -0,0 +1,3 @@
1
+ export declare const NAV_LIST_CLASS = "basalt-ui basalt-hover-list flex gap-basalt-nav-gap p-basalt-nav-inset";
2
+ export declare const NAV_ROW_CLASS = "flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0";
3
+ export declare const NAV_ITEM_CLASS = "basalt-ui basalt-nav-item flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0 outline-hidden focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-basalt-ring";
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { FOCUS_INSET as e } from "../components/overlay.js";
3
+ //#region src/utils/navigation.ts
4
+ var t = "basalt-ui basalt-hover-list flex gap-basalt-nav-gap p-basalt-nav-inset", n = "flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0", r = `basalt-ui basalt-nav-item ${n} ${e}`;
5
+ //#endregion
6
+ export { r as NAV_ITEM_CLASS, t as NAV_LIST_CLASS, n as NAV_ROW_CLASS };
7
+
8
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.js","names":["NAV_LIST_CLASS","NAV_ROW_CLASS","NAV_ITEM_CLASS","FOCUS_INSET"],"sources":["../../src/utils/navigation.ts"],"sourcesContent":["import { FOCUS_INSET } from \"../components/overlay\";\n\nexport const NAV_LIST_CLASS =\n\t\"basalt-ui basalt-hover-list flex gap-basalt-nav-gap p-basalt-nav-inset\";\n\nexport const NAV_ROW_CLASS =\n\t\"flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0\";\n\nexport const NAV_ITEM_CLASS = `basalt-ui basalt-nav-item ${NAV_ROW_CLASS} ${FOCUS_INSET}`;\n"],"mappings":";;;AAEA,IAAaA,IACZ,0EAEYC,IACZ,uOAEYC,IAAiB,6BAA6BD,EAAc,GAAGE"}
@@ -54,7 +54,7 @@ function r({ storageKey: r, defaultValue: i, persist: a, isValid: o, normalize:
54
54
  let c = e(r);
55
55
  c.status !== "error" && (o(c.value) ? (u = s(c.value), d = !0) : (u = l, d = !1), m());
56
56
  }, _ = null, v = () => {
57
- typeof window > "u" || p.size === 1 && !_ && (window.addEventListener("storage", g), window.addEventListener(c, h), _ = () => {
57
+ typeof window < "u" && p.size === 1 && !_ && (window.addEventListener("storage", g), window.addEventListener(c, h), _ = () => {
58
58
  window.removeEventListener("storage", g), window.removeEventListener(c, h), _ = null;
59
59
  });
60
60
  }, y = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"preference-store.js","names":[],"sources":["../../src/utils/preference-store.ts"],"sourcesContent":["type PreferenceConfig<T> = {\n\tstorageKey: string;\n\tdefaultValue: T;\n\tpersist: boolean;\n};\n\ntype StorageReadResult = { status: \"success\"; value: string | null } | { status: \"error\" };\n\nfunction safeGetStorageItem(key: string): StorageReadResult {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn { status: \"error\" };\n\t\t}\n\t\tconst value = window.localStorage.getItem(key);\n\t\treturn { status: \"success\", value };\n\t} catch {\n\t\treturn { status: \"error\" };\n\t}\n}\n\nfunction safeSetStorageItem(key: string, value: string): boolean {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn false;\n\t\t}\n\t\twindow.localStorage.setItem(key, value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction isLocalStorageArea(area: Storage | null | undefined): boolean {\n\tif (!area) {\n\t\treturn true;\n\t}\n\ttry {\n\t\tif (typeof window !== \"undefined\" && window.localStorage) {\n\t\t\treturn area === window.localStorage;\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n\treturn false;\n}\n\ninterface PreferenceChangeEventDetail<T> {\n\tkey: string;\n\tvalue: T;\n\twriteSucceeded: boolean;\n}\n\nexport function createPreferenceStore<T extends string>({\n\tstorageKey,\n\tdefaultValue: initialDefaultValue,\n\tpersist,\n\tisValid,\n\tnormalize,\n\teventName,\n}: PreferenceConfig<T> & {\n\tisValid: (value: unknown) => value is T;\n\tnormalize: (value: T) => T;\n\teventName: string;\n}) {\n\tlet defaultValue = normalize(initialDefaultValue);\n\tlet memoryValue = defaultValue;\n\tlet hasExplicitSelection = false;\n\tlet lastSetFailed = false;\n\n\tif (persist) {\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"success\" && isValid(res.value)) {\n\t\t\tmemoryValue = normalize(res.value);\n\t\t\thasExplicitSelection = true;\n\t\t}\n\t}\n\n\tconst listeners = new Set<() => void>();\n\tconst notify = () => {\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t};\n\n\tconst onInternalChange = (event: Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst customEv = event as CustomEvent<PreferenceChangeEventDetail<T>>;\n\t\tif (!customEv.detail || customEv.detail.key !== storageKey) {\n\t\t\treturn;\n\t\t}\n\t\tconst { value, writeSucceeded } = customEv.detail;\n\t\tlastSetFailed = !writeSucceeded;\n\t\tmemoryValue = value;\n\t\thasExplicitSelection = true;\n\t\tnotify();\n\t};\n\n\tconst onStorage = (event: StorageEvent | Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst storageEv = event as Partial<StorageEvent>;\n\t\tif (\"key\" in storageEv && storageEv.key !== undefined) {\n\t\t\tif (!isLocalStorageArea(storageEv.storageArea)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (storageEv.key !== null && storageEv.key !== storageKey) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlastSetFailed = false;\n\t\t\tconst rawValue = storageEv.newValue;\n\t\t\tif (rawValue === null || rawValue === undefined || !isValid(rawValue)) {\n\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\thasExplicitSelection = false;\n\t\t\t} else {\n\t\t\t\tmemoryValue = normalize(rawValue);\n\t\t\t\thasExplicitSelection = true;\n\t\t\t}\n\t\t\tnotify();\n\t\t\treturn;\n\t\t}\n\t\t// A bare storage event must not replace a selection whose write failed.\n\t\tif (lastSetFailed) {\n\t\t\treturn;\n\t\t}\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"error\") {\n\t\t\treturn;\n\t\t}\n\t\tif (isValid(res.value)) {\n\t\t\tmemoryValue = normalize(res.value);\n\t\t\thasExplicitSelection = true;\n\t\t} else {\n\t\t\tmemoryValue = defaultValue;\n\t\t\thasExplicitSelection = false;\n\t\t}\n\t\tnotify();\n\t};\n\n\tlet cleanupStorageListener: (() => void) | null = null;\n\tconst attachStorageListener = () => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tif (listeners.size === 1 && !cleanupStorageListener) {\n\t\t\twindow.addEventListener(\"storage\", onStorage);\n\t\t\twindow.addEventListener(eventName, onInternalChange);\n\t\t\tcleanupStorageListener = () => {\n\t\t\t\twindow.removeEventListener(\"storage\", onStorage);\n\t\t\t\twindow.removeEventListener(eventName, onInternalChange);\n\t\t\t\tcleanupStorageListener = null;\n\t\t\t};\n\t\t}\n\t};\n\n\tconst detachStorageListener = () => {\n\t\tif (listeners.size === 0 && cleanupStorageListener) {\n\t\t\tcleanupStorageListener();\n\t\t}\n\t};\n\n\treturn {\n\t\tgetSnapshot: () => memoryValue,\n\t\tsubscribe: (listener: () => void) => {\n\t\t\tlisteners.add(listener);\n\t\t\tattachStorageListener();\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t\tdetachStorageListener();\n\t\t\t};\n\t\t},\n\t\tsetValue: (next: T) => {\n\t\t\tconst value = normalize(next);\n\t\t\tmemoryValue = value;\n\t\t\thasExplicitSelection = true;\n\t\t\tif (persist) {\n\t\t\t\tconst writeSucceeded = safeSetStorageItem(storageKey, value);\n\t\t\t\tlastSetFailed = !writeSucceeded;\n\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\twindow.dispatchEvent(\n\t\t\t\t\t\t\tnew CustomEvent<PreferenceChangeEventDetail<T>>(eventName, {\n\t\t\t\t\t\t\t\tdetail: { key: storageKey, value, writeSucceeded },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// The local selection still applies when dispatch is unavailable.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tnotify();\n\t\t},\n\t\tupdateConfig: (config: PreferenceConfig<T>) => {\n\t\t\tconst keyChanged = storageKey !== config.storageKey;\n\t\t\tconst persistChanged = persist !== config.persist;\n\t\t\tconst normalizedDefault = normalize(config.defaultValue);\n\t\t\tconst defaultChanged = defaultValue !== normalizedDefault;\n\n\t\t\tconst oldPersist = persist;\n\t\t\tstorageKey = config.storageKey;\n\t\t\tdefaultValue = normalizedDefault;\n\t\t\tpersist = config.persist;\n\n\t\t\tif (keyChanged) {\n\t\t\t\tif (persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = normalize(res.value);\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\t\thasExplicitSelection = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnotify();\n\t\t\t\t}\n\t\t\t} else if (persistChanged) {\n\t\t\t\tif (!oldPersist && persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = normalize(res.value);\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (defaultChanged) {\n\t\t\t\tif (!hasExplicitSelection) {\n\t\t\t\t\tif (persist) {\n\t\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\t\tif (res.status === \"success\" && !isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\tnotify();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"preference-store.js","names":["safeGetStorageItem","key","safeSetStorageItem","value","isLocalStorageArea","area","createPreferenceStore","initialDefaultValue","defaultValue","normalize","memoryValue","hasExplicitSelection","lastSetFailed","persist","res","storageKey","isValid","listeners","notify","listener","onInternalChange","customEv","event","writeSucceeded","onStorage","storageEv","rawValue","cleanupStorageListener","attachStorageListener","eventName","detachStorageListener","next","keyChanged","config","persistChanged","normalizedDefault","defaultChanged","oldPersist"],"sources":["../../src/utils/preference-store.ts"],"sourcesContent":["type PreferenceConfig<T> = {\n\tstorageKey: string;\n\tdefaultValue: T;\n\tpersist: boolean;\n};\n\ntype StorageReadResult = { status: \"success\"; value: string | null } | { status: \"error\" };\n\nfunction safeGetStorageItem(key: string): StorageReadResult {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn { status: \"error\" };\n\t\t}\n\t\tconst value = window.localStorage.getItem(key);\n\t\treturn { status: \"success\", value };\n\t} catch {\n\t\treturn { status: \"error\" };\n\t}\n}\n\nfunction safeSetStorageItem(key: string, value: string): boolean {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn false;\n\t\t}\n\t\twindow.localStorage.setItem(key, value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction isLocalStorageArea(area: Storage | null | undefined): boolean {\n\tif (!area) {\n\t\treturn true;\n\t}\n\ttry {\n\t\tif (typeof window !== \"undefined\" && window.localStorage) {\n\t\t\treturn area === window.localStorage;\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n\treturn false;\n}\n\ninterface PreferenceChangeEventDetail<T> {\n\tkey: string;\n\tvalue: T;\n\twriteSucceeded: boolean;\n}\n\nexport function createPreferenceStore<T extends string>({\n\tstorageKey,\n\tdefaultValue: initialDefaultValue,\n\tpersist,\n\tisValid,\n\tnormalize,\n\teventName,\n}: PreferenceConfig<T> & {\n\tisValid: (value: unknown) => value is T;\n\tnormalize: (value: T) => T;\n\teventName: string;\n}) {\n\tlet defaultValue = normalize(initialDefaultValue);\n\tlet memoryValue = defaultValue;\n\tlet hasExplicitSelection = false;\n\tlet lastSetFailed = false;\n\n\tif (persist) {\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"success\" && isValid(res.value)) {\n\t\t\tmemoryValue = normalize(res.value);\n\t\t\thasExplicitSelection = true;\n\t\t}\n\t}\n\n\tconst listeners = new Set<() => void>();\n\tconst notify = () => {\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t};\n\n\tconst onInternalChange = (event: Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst customEv = event as CustomEvent<PreferenceChangeEventDetail<T>>;\n\t\tif (!customEv.detail || customEv.detail.key !== storageKey) {\n\t\t\treturn;\n\t\t}\n\t\tconst { value, writeSucceeded } = customEv.detail;\n\t\tlastSetFailed = !writeSucceeded;\n\t\tmemoryValue = value;\n\t\thasExplicitSelection = true;\n\t\tnotify();\n\t};\n\n\tconst onStorage = (event: StorageEvent | Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst storageEv = event as Partial<StorageEvent>;\n\t\tif (\"key\" in storageEv && storageEv.key !== undefined) {\n\t\t\tif (!isLocalStorageArea(storageEv.storageArea)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (storageEv.key !== null && storageEv.key !== storageKey) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlastSetFailed = false;\n\t\t\tconst rawValue = storageEv.newValue;\n\t\t\tif (rawValue === null || rawValue === undefined || !isValid(rawValue)) {\n\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\thasExplicitSelection = false;\n\t\t\t} else {\n\t\t\t\tmemoryValue = normalize(rawValue);\n\t\t\t\thasExplicitSelection = true;\n\t\t\t}\n\t\t\tnotify();\n\t\t\treturn;\n\t\t}\n\t\t// A bare storage event must not replace a selection whose write failed.\n\t\tif (lastSetFailed) {\n\t\t\treturn;\n\t\t}\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"error\") {\n\t\t\treturn;\n\t\t}\n\t\tif (isValid(res.value)) {\n\t\t\tmemoryValue = normalize(res.value);\n\t\t\thasExplicitSelection = true;\n\t\t} else {\n\t\t\tmemoryValue = defaultValue;\n\t\t\thasExplicitSelection = false;\n\t\t}\n\t\tnotify();\n\t};\n\n\tlet cleanupStorageListener: (() => void) | null = null;\n\tconst attachStorageListener = () => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tif (listeners.size === 1 && !cleanupStorageListener) {\n\t\t\twindow.addEventListener(\"storage\", onStorage);\n\t\t\twindow.addEventListener(eventName, onInternalChange);\n\t\t\tcleanupStorageListener = () => {\n\t\t\t\twindow.removeEventListener(\"storage\", onStorage);\n\t\t\t\twindow.removeEventListener(eventName, onInternalChange);\n\t\t\t\tcleanupStorageListener = null;\n\t\t\t};\n\t\t}\n\t};\n\n\tconst detachStorageListener = () => {\n\t\tif (listeners.size === 0 && cleanupStorageListener) {\n\t\t\tcleanupStorageListener();\n\t\t}\n\t};\n\n\treturn {\n\t\tgetSnapshot: () => memoryValue,\n\t\tsubscribe: (listener: () => void) => {\n\t\t\tlisteners.add(listener);\n\t\t\tattachStorageListener();\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t\tdetachStorageListener();\n\t\t\t};\n\t\t},\n\t\tsetValue: (next: T) => {\n\t\t\tconst value = normalize(next);\n\t\t\tmemoryValue = value;\n\t\t\thasExplicitSelection = true;\n\t\t\tif (persist) {\n\t\t\t\tconst writeSucceeded = safeSetStorageItem(storageKey, value);\n\t\t\t\tlastSetFailed = !writeSucceeded;\n\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\twindow.dispatchEvent(\n\t\t\t\t\t\t\tnew CustomEvent<PreferenceChangeEventDetail<T>>(eventName, {\n\t\t\t\t\t\t\t\tdetail: { key: storageKey, value, writeSucceeded },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// The local selection still applies when dispatch is unavailable.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tnotify();\n\t\t},\n\t\tupdateConfig: (config: PreferenceConfig<T>) => {\n\t\t\tconst keyChanged = storageKey !== config.storageKey;\n\t\t\tconst persistChanged = persist !== config.persist;\n\t\t\tconst normalizedDefault = normalize(config.defaultValue);\n\t\t\tconst defaultChanged = defaultValue !== normalizedDefault;\n\n\t\t\tconst oldPersist = persist;\n\t\t\tstorageKey = config.storageKey;\n\t\t\tdefaultValue = normalizedDefault;\n\t\t\tpersist = config.persist;\n\n\t\t\tif (keyChanged) {\n\t\t\t\tif (persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = normalize(res.value);\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\t\thasExplicitSelection = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnotify();\n\t\t\t\t}\n\t\t\t} else if (persistChanged) {\n\t\t\t\tif (!oldPersist && persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = normalize(res.value);\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (defaultChanged) {\n\t\t\t\tif (!hasExplicitSelection) {\n\t\t\t\t\tif (persist) {\n\t\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\t\tif (res.status === \"success\" && !isValid(res.value)) {\n\t\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmemoryValue = defaultValue;\n\t\t\t\t\t\tnotify();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- export declare const SELECTION_INDICATOR_MOTION_CLASS = "transition-[left,width,top,height] duration-200 ease-out";
2
+ export declare const SELECTION_INDICATOR_MOTION_CLASS = "basalt-selection-motion";
3
3
  export type SelectionGeometry = {
4
4
  left: number;
5
5
  width: number;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import * as e from "react";
3
3
  //#region src/utils/selection-indicator.ts
4
- var t = "transition-[left,width,top,height] duration-200 ease-out", n = {
4
+ var t = "basalt-selection-motion", n = {
5
5
  left: 0,
6
6
  width: 0,
7
7
  top: 0,
@@ -18,91 +18,68 @@ function i(e) {
18
18
  height: e.offsetHeight
19
19
  };
20
20
  }
21
- function a() {
22
- return typeof window < "u" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
23
- }
24
- function o(e) {
25
- let t = [e];
26
- for (let n of e.children) n instanceof HTMLElement && n.getAttribute("aria-hidden") !== "true" && t.push(n);
27
- return t;
28
- }
29
- function s({ itemSelector: s, enabled: c = !0, mapGeometry: l, ref: u }) {
30
- let d = e.useRef(null), f = e.useMemo(() => (e) => {
31
- d.current = e, r(u, e);
32
- }, [u]), [p, m] = e.useState({
21
+ function a({ itemSelector: a, enabled: o = !0, mapGeometry: s, ref: c }) {
22
+ let l = e.useRef(null), u = e.useCallback((e) => {
23
+ l.current = e, r(c, e);
24
+ }, [c]), [d, f] = e.useState({
33
25
  ...n,
34
26
  visible: !1,
35
27
  animated: !1
36
- }), [h, g] = e.useState(a);
37
- e.useEffect(() => {
38
- let e = window.matchMedia("(prefers-reduced-motion: reduce)"), t = () => g(e.matches);
39
- return t(), e.addEventListener("change", t), () => e.removeEventListener("change", t);
40
- }, []);
41
- let _ = e.useCallback(() => {
42
- let e = d.current;
43
- if (!e || !c) {
44
- m((e) => ({
45
- ...e,
28
+ });
29
+ return e.useLayoutEffect(() => {
30
+ let e = l.current;
31
+ if (!e || !o) {
32
+ f({
46
33
  ...n,
47
34
  visible: !1,
48
35
  animated: !1
49
- }));
50
- return;
51
- }
52
- let t = e.querySelector(s);
53
- if (!t) {
54
- m((e) => ({
55
- ...e,
56
- width: 0,
57
- height: 0,
58
- visible: !1,
59
- animated: !1
60
- }));
36
+ });
61
37
  return;
62
38
  }
63
- let r = (l ?? i)(t, e);
64
- m((e) => ({
65
- ...r,
66
- visible: !0,
67
- animated: e.visible && !h
68
- }));
69
- }, [
70
- c,
71
- s,
72
- l,
73
- h
74
- ]);
75
- return e.useLayoutEffect(() => {
76
- let e = d.current;
77
- if (!e || !c) return;
78
- let t = 0, n = new ResizeObserver(() => {
79
- cancelAnimationFrame(t), t = requestAnimationFrame(_);
80
- }), r = () => {
81
- n.disconnect();
82
- for (let t of o(e)) n.observe(t);
83
- };
84
- r(), _();
85
- let i = new MutationObserver(() => {
86
- cancelAnimationFrame(t), t = requestAnimationFrame(() => {
87
- r(), _();
88
- });
39
+ let t = null, r = 0, c = window.matchMedia("(prefers-reduced-motion: reduce)"), u = () => {
40
+ r = 0;
41
+ let o = e.querySelector(a), l = o ? (s ?? i)(o, e) : n, u = !!o && o.offsetWidth > 0 && o.offsetHeight > 0, d = u && !!t && t !== o && !c.matches;
42
+ t = u ? o : null;
43
+ let p = {
44
+ ...l,
45
+ visible: u,
46
+ animated: d
47
+ };
48
+ f((e) => e.visible === u && e.left === l.left && e.top === l.top && e.width === l.width && e.height === l.height && !(c.matches && e.animated) ? e : p);
49
+ }, d = () => {
50
+ r ||= requestAnimationFrame(u);
51
+ }, p = new ResizeObserver(d), m = () => {
52
+ p.disconnect(), p.observe(e);
53
+ for (let t of e.children) t instanceof HTMLElement && t.getAttribute("aria-hidden") !== "true" && p.observe(t);
54
+ }, h = new MutationObserver((e) => {
55
+ e.some((e) => e.type === "childList") && m(), d();
89
56
  });
90
- return i.observe(e, {
91
- attributes: !0,
57
+ return m(), u(), h.observe(e, {
92
58
  subtree: !0,
93
59
  childList: !0,
94
- characterData: !0,
95
- attributeFilter: ["data-state", "aria-checked"]
96
- }), () => {
97
- cancelAnimationFrame(t), i.disconnect(), n.disconnect();
60
+ attributes: !0,
61
+ attributeFilter: [
62
+ "data-state",
63
+ "aria-checked",
64
+ "aria-current",
65
+ "data-selected",
66
+ "data-disabled",
67
+ "hidden"
68
+ ]
69
+ }), c.addEventListener("change", d), () => {
70
+ cancelAnimationFrame(r), p.disconnect(), h.disconnect(), c.removeEventListener("change", d);
98
71
  };
99
- }, [c, _]), {
100
- ref: f,
101
- state: p,
102
- motionClassName: p.animated && !h ? t : void 0
72
+ }, [
73
+ o,
74
+ a,
75
+ s
76
+ ]), {
77
+ ref: u,
78
+ state: d,
79
+ motionClassName: d.animated ? t : void 0
103
80
  };
104
81
  }
105
82
  //#endregion
106
- export { t as SELECTION_INDICATOR_MOTION_CLASS, r as assignRef, i as measureSelectionItem, s as useSelectionIndicator };
83
+ export { t as SELECTION_INDICATOR_MOTION_CLASS, r as assignRef, i as measureSelectionItem, a as useSelectionIndicator };
107
84
 
108
85
  //# sourceMappingURL=selection-indicator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"selection-indicator.js","names":[],"sources":["../../src/utils/selection-indicator.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport const SELECTION_INDICATOR_MOTION_CLASS =\n\t\"transition-[left,width,top,height] duration-200 ease-out\";\n\nexport type SelectionGeometry = {\n\tleft: number;\n\twidth: number;\n\ttop: number;\n\theight: number;\n};\n\nexport type SelectionIndicatorState = SelectionGeometry & {\n\tvisible: boolean;\n\tanimated: boolean;\n};\n\nconst EMPTY: SelectionGeometry = { left: 0, width: 0, top: 0, height: 0 };\n\nexport function assignRef<T>(ref: React.Ref<T> | undefined, value: T | null) {\n\tif (typeof ref === \"function\") {\n\t\tref(value);\n\t} else if (ref) {\n\t\t(ref as React.MutableRefObject<T | null>).current = value;\n\t}\n}\n\nexport function measureSelectionItem(item: HTMLElement): SelectionGeometry {\n\treturn {\n\t\tleft: item.offsetLeft,\n\t\twidth: item.offsetWidth,\n\t\ttop: item.offsetTop,\n\t\theight: item.offsetHeight,\n\t};\n}\n\nfunction prefersReducedMotion() {\n\treturn (\n\t\ttypeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n\t);\n}\n\nfunction selectionTargets(root: HTMLElement) {\n\tconst targets: HTMLElement[] = [root];\n\tfor (const node of root.children) {\n\t\tif (node instanceof HTMLElement && node.getAttribute(\"aria-hidden\") !== \"true\") {\n\t\t\ttargets.push(node);\n\t\t}\n\t}\n\treturn targets;\n}\n\nexport function useSelectionIndicator({\n\titemSelector,\n\tenabled = true,\n\tmapGeometry,\n\tref,\n}: {\n\titemSelector: string;\n\tenabled?: boolean;\n\tmapGeometry?: (item: HTMLElement, root: HTMLElement) => SelectionGeometry;\n\tref?: React.Ref<HTMLElement | null>;\n}) {\n\tconst rootRef = React.useRef<HTMLElement | null>(null);\n\tconst composedRef = React.useMemo(() => {\n\t\treturn (node: HTMLElement | null) => {\n\t\t\trootRef.current = node;\n\t\t\tassignRef(ref, node);\n\t\t};\n\t}, [ref]);\n\tconst [state, setState] = React.useState<SelectionIndicatorState>({\n\t\t...EMPTY,\n\t\tvisible: false,\n\t\tanimated: false,\n\t});\n\tconst [reduced, setReduced] = React.useState(prefersReducedMotion);\n\n\tReact.useEffect(() => {\n\t\tconst media = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n\t\tconst onChange = () => setReduced(media.matches);\n\t\tonChange();\n\t\tmedia.addEventListener(\"change\", onChange);\n\t\treturn () => media.removeEventListener(\"change\", onChange);\n\t}, []);\n\n\tconst sync = React.useCallback(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root || !enabled) {\n\t\t\tsetState((current) => ({ ...current, ...EMPTY, visible: false, animated: false }));\n\t\t\treturn;\n\t\t}\n\t\tconst item = root.querySelector<HTMLElement>(itemSelector);\n\t\tif (!item) {\n\t\t\tsetState((current) => ({ ...current, width: 0, height: 0, visible: false, animated: false }));\n\t\t\treturn;\n\t\t}\n\t\t// Keep the optional dependency undefined. Production optimizers may inline a\n\t\t// function-valued parameter default, creating a new effect dependency every render.\n\t\tconst geometry = (mapGeometry ?? measureSelectionItem)(item, root);\n\t\tsetState((current) => ({\n\t\t\t...geometry,\n\t\t\tvisible: true,\n\t\t\tanimated: current.visible && !reduced,\n\t\t}));\n\t}, [enabled, itemSelector, mapGeometry, reduced]);\n\n\tReact.useLayoutEffect(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root || !enabled) {\n\t\t\treturn;\n\t\t}\n\t\tlet frame = 0;\n\t\tconst ro = new ResizeObserver(() => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tframe = requestAnimationFrame(sync);\n\t\t});\n\t\tconst observe = () => {\n\t\t\tro.disconnect();\n\t\t\tfor (const node of selectionTargets(root)) {\n\t\t\t\tro.observe(node);\n\t\t\t}\n\t\t};\n\t\tobserve();\n\t\tsync();\n\t\tconst mo = new MutationObserver(() => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tframe = requestAnimationFrame(() => {\n\t\t\t\tobserve();\n\t\t\t\tsync();\n\t\t\t});\n\t\t});\n\t\tmo.observe(root, {\n\t\t\tattributes: true,\n\t\t\tsubtree: true,\n\t\t\tchildList: true,\n\t\t\tcharacterData: true,\n\t\t\tattributeFilter: [\"data-state\", \"aria-checked\"],\n\t\t});\n\t\treturn () => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tmo.disconnect();\n\t\t\tro.disconnect();\n\t\t};\n\t}, [enabled, sync]);\n\n\treturn {\n\t\tref: composedRef,\n\t\tstate,\n\t\tmotionClassName: state.animated && !reduced ? SELECTION_INDICATOR_MOTION_CLASS : undefined,\n\t};\n}\n"],"mappings":";;;AAEA,IAAa,IACZ,4DAcK,IAA2B;CAAE,MAAM;CAAG,OAAO;CAAG,KAAK;CAAG,QAAQ;AAAE;AAExE,SAAgB,EAAa,GAA+B,GAAiB;CAC5E,AAAI,OAAO,KAAQ,aAClB,EAAI,CAAK,IACC,MACV,EAA0C,UAAU;AAEtD;AAEA,SAAgB,EAAqB,GAAsC;CAC1E,OAAO;EACN,MAAM,EAAK;EACX,OAAO,EAAK;EACZ,KAAK,EAAK;EACV,QAAQ,EAAK;CACd;AACD;AAEA,SAAS,IAAuB;CAC/B,OACC,OAAO,SAAW,OAAe,OAAO,WAAW,kCAAkC,CAAC,CAAC;AAEzF;AAEA,SAAS,EAAiB,GAAmB;CAC5C,IAAM,IAAyB,CAAC,CAAI;CACpC,KAAK,IAAM,KAAQ,EAAK,UACvB,AAAI,aAAgB,eAAe,EAAK,aAAa,aAAa,MAAM,UACvE,EAAQ,KAAK,CAAI;CAGnB,OAAO;AACR;AAEA,SAAgB,EAAsB,EACrC,iBACA,aAAU,IACV,gBACA,UAME;CACF,IAAM,IAAU,EAAM,OAA2B,IAAI,GAC/C,IAAc,EAAM,eACjB,MAA6B;EAEpC,AADA,EAAQ,UAAU,GAClB,EAAU,GAAK,CAAI;CACpB,GACE,CAAC,CAAG,CAAC,GACF,CAAC,GAAO,KAAY,EAAM,SAAkC;EACjE,GAAG;EACH,SAAS;EACT,UAAU;CACX,CAAC,GACK,CAAC,GAAS,KAAc,EAAM,SAAS,CAAoB;CAEjE,EAAM,gBAAgB;EACrB,IAAM,IAAQ,OAAO,WAAW,kCAAkC,GAC5D,UAAiB,EAAW,EAAM,OAAO;EAG/C,OAFA,EAAS,GACT,EAAM,iBAAiB,UAAU,CAAQ,SAC5B,EAAM,oBAAoB,UAAU,CAAQ;CAC1D,GAAG,CAAC,CAAC;CAEL,IAAM,IAAO,EAAM,kBAAkB;EACpC,IAAM,IAAO,EAAQ;EACrB,IAAI,CAAC,KAAQ,CAAC,GAAS;GACtB,GAAU,OAAa;IAAE,GAAG;IAAS,GAAG;IAAO,SAAS;IAAO,UAAU;GAAM,EAAE;GACjF;EACD;EACA,IAAM,IAAO,EAAK,cAA2B,CAAY;EACzD,IAAI,CAAC,GAAM;GACV,GAAU,OAAa;IAAE,GAAG;IAAS,OAAO;IAAG,QAAQ;IAAG,SAAS;IAAO,UAAU;GAAM,EAAE;GAC5F;EACD;EAGA,IAAM,KAAY,KAAe,EAAA,CAAsB,GAAM,CAAI;EACjE,GAAU,OAAa;GACtB,GAAG;GACH,SAAS;GACT,UAAU,EAAQ,WAAW,CAAC;EAC/B,EAAE;CACH,GAAG;EAAC;EAAS;EAAc;EAAa;CAAO,CAAC;CAyChD,OAvCA,EAAM,sBAAsB;EAC3B,IAAM,IAAO,EAAQ;EACrB,IAAI,CAAC,KAAQ,CAAC,GACb;EAED,IAAI,IAAQ,GACN,IAAK,IAAI,qBAAqB;GAEnC,AADA,qBAAqB,CAAK,GAC1B,IAAQ,sBAAsB,CAAI;EACnC,CAAC,GACK,UAAgB;GACrB,EAAG,WAAW;GACd,KAAK,IAAM,KAAQ,EAAiB,CAAI,GACvC,EAAG,QAAQ,CAAI;EAEjB;EAEA,AADA,EAAQ,GACR,EAAK;EACL,IAAM,IAAK,IAAI,uBAAuB;GAErC,AADA,qBAAqB,CAAK,GAC1B,IAAQ,4BAA4B;IAEnC,AADA,EAAQ,GACR,EAAK;GACN,CAAC;EACF,CAAC;EAQD,OAPA,EAAG,QAAQ,GAAM;GAChB,YAAY;GACZ,SAAS;GACT,WAAW;GACX,eAAe;GACf,iBAAiB,CAAC,cAAc,cAAc;EAC/C,CAAC,SACY;GAGZ,AAFA,qBAAqB,CAAK,GAC1B,EAAG,WAAW,GACd,EAAG,WAAW;EACf;CACD,GAAG,CAAC,GAAS,CAAI,CAAC,GAEX;EACN,KAAK;EACL;EACA,iBAAiB,EAAM,YAAY,CAAC,IAAU,IAAmC,KAAA;CAClF;AACD"}
1
+ {"version":3,"file":"selection-indicator.js","names":["React","SELECTION_INDICATOR_MOTION_CLASS","EMPTY","assignRef","ref","value","measureSelectionItem","item","useSelectionIndicator","rootRef","composedRef","node","state","setState","root","enabled","previous","frame","media","sync","itemSelector","box","mapGeometry","visible","animated","next","current","schedule","resize","observe","child","mutations","records","record"],"sources":["../../src/utils/selection-indicator.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport const SELECTION_INDICATOR_MOTION_CLASS = \"basalt-selection-motion\";\n\nexport type SelectionGeometry = { left: number; width: number; top: number; height: number };\nexport type SelectionIndicatorState = SelectionGeometry & { visible: boolean; animated: boolean };\nconst EMPTY: SelectionGeometry = { left: 0, width: 0, top: 0, height: 0 };\n\nexport function assignRef<T>(ref: React.Ref<T> | undefined, value: T | null) {\n\tif (typeof ref === \"function\") ref(value);\n\telse if (ref) (ref as React.MutableRefObject<T | null>).current = value;\n}\n\nexport function measureSelectionItem(item: HTMLElement): SelectionGeometry {\n\treturn {\n\t\tleft: item.offsetLeft,\n\t\twidth: item.offsetWidth,\n\t\ttop: item.offsetTop,\n\t\theight: item.offsetHeight,\n\t};\n}\n\nexport function useSelectionIndicator({\n\titemSelector,\n\tenabled = true,\n\tmapGeometry,\n\tref,\n}: {\n\titemSelector: string;\n\tenabled?: boolean;\n\tmapGeometry?: (item: HTMLElement, root: HTMLElement) => SelectionGeometry;\n\tref?: React.Ref<HTMLElement | null>;\n}) {\n\tconst rootRef = React.useRef<HTMLElement | null>(null);\n\tconst composedRef = React.useCallback(\n\t\t(node: HTMLElement | null) => {\n\t\t\trootRef.current = node;\n\t\t\tassignRef(ref, node);\n\t\t},\n\t\t[ref],\n\t);\n\tconst [state, setState] = React.useState<SelectionIndicatorState>({\n\t\t...EMPTY,\n\t\tvisible: false,\n\t\tanimated: false,\n\t});\n\tReact.useLayoutEffect(() => {\n\t\tconst root = rootRef.current;\n\t\tif (!root || !enabled) {\n\t\t\tsetState({ ...EMPTY, visible: false, animated: false });\n\t\t\treturn;\n\t\t}\n\t\tlet previous: HTMLElement | null = null;\n\t\tlet frame = 0;\n\t\tconst media = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n\t\tconst sync = () => {\n\t\t\tframe = 0;\n\t\t\tconst item = root.querySelector<HTMLElement>(itemSelector);\n\t\t\tconst box = item ? (mapGeometry ?? measureSelectionItem)(item, root) : EMPTY;\n\t\t\t// Hidden panels measure zero. They must never become the animation's origin.\n\t\t\tconst visible = !!item && item.offsetWidth > 0 && item.offsetHeight > 0;\n\t\t\tconst animated = visible && !!previous && previous !== item && !media.matches;\n\t\t\tprevious = visible ? item : null;\n\t\t\tconst next = { ...box, visible, animated };\n\t\t\tsetState((current) => {\n\t\t\t\tconst unchanged =\n\t\t\t\t\tcurrent.visible === visible &&\n\t\t\t\t\tcurrent.left === box.left &&\n\t\t\t\t\tcurrent.top === box.top &&\n\t\t\t\t\tcurrent.width === box.width &&\n\t\t\t\t\tcurrent.height === box.height;\n\t\t\t\t// Initial ResizeObserver delivery must not cancel an in-flight selection.\n\t\t\t\treturn unchanged && !(media.matches && current.animated) ? current : next;\n\t\t\t});\n\t\t};\n\t\tconst schedule = () => {\n\t\t\tif (!frame) frame = requestAnimationFrame(sync);\n\t\t};\n\t\tconst resize = new ResizeObserver(schedule);\n\t\tconst observe = () => {\n\t\t\tresize.disconnect();\n\t\t\tresize.observe(root);\n\t\t\tfor (const child of root.children)\n\t\t\t\tif (child instanceof HTMLElement && child.getAttribute(\"aria-hidden\") !== \"true\")\n\t\t\t\t\tresize.observe(child);\n\t\t};\n\t\tconst mutations = new MutationObserver((records) => {\n\t\t\tif (records.some((record) => record.type === \"childList\")) observe();\n\t\t\tschedule();\n\t\t});\n\t\tobserve();\n\t\tsync();\n\t\tmutations.observe(root, {\n\t\t\tsubtree: true,\n\t\t\tchildList: true,\n\t\t\tattributes: true,\n\t\t\tattributeFilter: [\n\t\t\t\t\"data-state\",\n\t\t\t\t\"aria-checked\",\n\t\t\t\t\"aria-current\",\n\t\t\t\t\"data-selected\",\n\t\t\t\t\"data-disabled\",\n\t\t\t\t\"hidden\",\n\t\t\t],\n\t\t});\n\t\tmedia.addEventListener(\"change\", schedule);\n\t\treturn () => {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tresize.disconnect();\n\t\t\tmutations.disconnect();\n\t\t\tmedia.removeEventListener(\"change\", schedule);\n\t\t};\n\t}, [enabled, itemSelector, mapGeometry]);\n\treturn {\n\t\tref: composedRef,\n\t\tstate,\n\t\tmotionClassName: state.animated ? SELECTION_INDICATOR_MOTION_CLASS : undefined,\n\t};\n}\n"],"mappings":";;;AAEA,IAAaC,IAAmC,2BAI1CC,IAA2B;CAAE,MAAM;CAAG,OAAO;CAAG,KAAK;CAAG,QAAQ;AAAE;AAExE,SAAgBC,EAAa,GAA+B,GAAiB;CAC5E,AAAI,OAAOC,KAAQ,aAAYA,EAAIC,CAAK,IAC/BD,MAAK,EAA0C,UAAUC;AACnE;AAEA,SAAgBC,EAAqB,GAAsC;CAC1E,OAAO;EACN,MAAMC,EAAK;EACX,OAAOA,EAAK;EACZ,KAAKA,EAAK;EACV,QAAQA,EAAK;CACd;AACD;AAEA,SAAgBC,EAAsB,EACrC,iBACA,aAAU,IACV,gBACA,UAME;CACF,IAAMC,IAAUT,EAAM,OAA2B,IAAI,GAC/CU,IAAcV,EAAM,aACxB,MAA6B;EAE7B,AADA,EAAQ,UAAUW,GAClBR,EAAUC,GAAKO,CAAI;CACpB,GACA,CAACP,CAAG,CACL,GACM,CAACQ,GAAOC,KAAYb,EAAM,SAAkC;EACjE,GAAGE;EACH,SAAS;EACT,UAAU;CACX,CAAC;CAoED,OAnEAF,EAAM,sBAAsB;EAC3B,IAAMc,IAAOL,EAAQ;EACrB,IAAI,CAACK,KAAQ,CAACC,GAAS;GACtB,EAAS;IAAE,GAAGb;IAAO,SAAS;IAAO,UAAU;GAAM,CAAC;GACtD;EACD;EACA,IAAIc,IAA+B,MAC/BC,IAAQ,GACNC,IAAQ,OAAO,WAAW,kCAAkC,GAC5DC,UAAa;GAClB,IAAQ;GACR,IAAMZ,IAAOO,EAAK,cAA2BM,CAAY,GACnDC,IAAMd,KAAQe,KAAehB,EAAA,CAAsBC,GAAMO,CAAI,IAAIZ,GAEjEqB,IAAU,CAAC,CAAChB,KAAQA,EAAK,cAAc,KAAKA,EAAK,eAAe,GAChEiB,IAAWD,KAAW,CAAC,CAACP,KAAYA,MAAaT,KAAQ,CAACW,EAAM;GACtE,IAAWK,IAAUhB,IAAO;GAC5B,IAAMkB,IAAO;IAAE,GAAGJ;IAAK;IAAS;GAAS;GACzC,GAAU,MAERK,EAAQ,YAAYH,KACpBG,EAAQ,SAASL,EAAI,QACrBK,EAAQ,QAAQL,EAAI,OACpBK,EAAQ,UAAUL,EAAI,SACtBK,EAAQ,WAAWL,EAAI,UAEJ,EAAEH,EAAM,WAAWQ,EAAQ,YAAYA,IAAUD,CACrE;EACF,GACME,UAAiB;GACtB,AAAYV,MAAQ,sBAAsBE,CAAI;EAC/C,GACMS,IAAS,IAAI,eAAeD,CAAQ,GACpCE,UAAgB;GAErB,AADAD,EAAO,WAAW,GAClBA,EAAO,QAAQd,CAAI;GACnB,KAAK,IAAMgB,KAAShB,EAAK,UACxB,AAAIgB,aAAiB,eAAeA,EAAM,aAAa,aAAa,MAAM,UACzEF,EAAO,QAAQE,CAAK;EACvB,GACMC,IAAY,IAAI,kBAAkB,MAAY;GAEnD,AADIC,EAAQ,MAAM,MAAWC,EAAO,SAAS,WAAW,KAAGJ,EAAQ,GACnEF,EAAS;EACV,CAAC;EAiBD,OAhBAE,EAAQ,GACRV,EAAK,GACLY,EAAU,QAAQjB,GAAM;GACvB,SAAS;GACT,WAAW;GACX,YAAY;GACZ,iBAAiB;IAChB;IACA;IACA;IACA;IACA;IACA;GACD;EACD,CAAC,GACDI,EAAM,iBAAiB,UAAUS,CAAQ,SAC5B;GAIZ,AAHA,qBAAqBV,CAAK,GAC1BW,EAAO,WAAW,GAClBG,EAAU,WAAW,GACrBb,EAAM,oBAAoB,UAAUS,CAAQ;EAC7C;CACD,GAAG;EAACZ;EAASK;EAAcE;CAAW,CAAC,GAChC;EACN,KAAKZ;EACL;EACA,iBAAiBE,EAAM,WAAWX,IAAmC,KAAA;CACtE;AACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-checkable-group.js","names":[],"sources":["../../src/utils/use-checkable-group.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport function useCheckableGroup({\n\tvalue,\n\tdefaultValue,\n\tonValueChange,\n\terror,\n\tdescribedBy,\n\tariaInvalid,\n\tform,\n\tref,\n}: {\n\tvalue?: string[];\n\tdefaultValue?: string[];\n\tonValueChange?: (value: string[]) => void;\n\terror?: React.ReactNode;\n\tdescribedBy?: string;\n\tariaInvalid?: React.AriaAttributes[\"aria-invalid\"];\n\tform?: string;\n\tref: React.ForwardedRef<HTMLFieldSetElement>;\n}) {\n\tconst generatedId = React.useId();\n\tconst nodeRef = React.useRef<HTMLFieldSetElement | null>(null);\n\tconst [uncontrolled, setUncontrolled] = React.useState(defaultValue ?? []);\n\tconst current = value ?? uncontrolled;\n\tconst invalid = Boolean(error);\n\tconst errorId = `${generatedId}-error`;\n\tconst mergedDescribedBy =\n\t\t[invalid ? errorId : null, describedBy].filter(Boolean).join(\" \") || undefined;\n\tconst resetEventRef = React.useRef<Event | null>(null);\n\tconst setValue = React.useCallback(\n\t\t(next: string[]) => {\n\t\t\tconst activeReset = resetEventRef.current;\n\t\t\tif (activeReset && activeReset.eventPhase !== Event.NONE) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (value === undefined) {\n\t\t\t\tsetUncontrolled(next);\n\t\t\t}\n\t\t\tonValueChange?.(next);\n\t\t},\n\t\t[onValueChange, value],\n\t);\n\tconst setRefs = React.useCallback(\n\t\t(node: HTMLFieldSetElement | null) => {\n\t\t\tnodeRef.current = node;\n\t\t\tif (!ref) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (typeof ref === \"function\") {\n\t\t\t\tconst cleanup = (ref as React.RefCallback<HTMLFieldSetElement>)(node);\n\t\t\t\tif (typeof cleanup === \"function\") {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tnodeRef.current = null;\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn () => {\n\t\t\t\t\tnodeRef.current = null;\n\t\t\t\t\tref(null);\n\t\t\t\t};\n\t\t\t}\n\t\t\t(ref as React.RefObject<HTMLFieldSetElement | null>).current = node;\n\t\t\treturn () => {\n\t\t\t\tnodeRef.current = null;\n\t\t\t\t(ref as React.RefObject<HTMLFieldSetElement | null>).current = null;\n\t\t\t};\n\t\t},\n\t\t[ref],\n\t);\n\tconst latestConfigRef = React.useRef({\n\t\tdefaultValue,\n\t\tvalue,\n\t});\n\tReact.useEffect(() => {\n\t\tlatestConfigRef.current = {\n\t\t\tdefaultValue,\n\t\t\tvalue,\n\t\t};\n\t});\n\n\tReact.useEffect(() => {\n\t\tconst formEl = nodeRef.current?.form;\n\t\tif (!formEl || (form && formEl.id !== form)) {\n\t\t\treturn;\n\t\t}\n\t\tlet disposed = false;\n\t\tconst timers = new Set<ReturnType<typeof setTimeout>>();\n\t\tconst onReset = (event: Event) => {\n\t\t\tresetEventRef.current = event;\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\ttimers.delete(timer);\n\t\t\t\tif (disposed || event.defaultPrevented) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst cfg = latestConfigRef.current;\n\t\t\t\tif (cfg.value === undefined) {\n\t\t\t\t\tsetUncontrolled(cfg.defaultValue ?? []);\n\t\t\t\t}\n\t\t\t}, 0);\n\t\t\ttimers.add(timer);\n\t\t};\n\t\tformEl.addEventListener(\"reset\", onReset, true);\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tresetEventRef.current = null;\n\t\t\tfor (const timer of timers) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\ttimers.clear();\n\t\t\tformEl.removeEventListener(\"reset\", onReset, true);\n\t\t};\n\t}, [form]);\n\n\treturn {\n\t\tcurrent,\n\t\tsetValue,\n\t\tinvalid,\n\t\terrorId,\n\t\tmergedDescribedBy,\n\t\tsetRefs,\n\t\tariaInvalid: invalid ? true : ariaInvalid,\n\t};\n}\n"],"mappings":";;;AAEA,SAAgB,EAAkB,EACjC,UACA,iBACA,kBACA,UACA,gBACA,gBACA,SACA,UAUE;CACF,IAAM,IAAc,EAAM,MAAM,GAC1B,IAAU,EAAM,OAAmC,IAAI,GACvD,CAAC,GAAc,KAAmB,EAAM,SAAS,KAAgB,CAAC,CAAC,GACnE,IAAU,KAAS,GACnB,IAAU,EAAQ,GAClB,IAAU,GAAG,EAAY,SACzB,IACL,CAAC,IAAU,IAAU,MAAM,CAAW,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA,GAChE,IAAgB,EAAM,OAAqB,IAAI,GAC/C,IAAW,EAAM,aACrB,MAAmB;EACnB,IAAM,IAAc,EAAc;EAC9B,KAAe,EAAY,eAAe,MAAM,SAGhD,MAAU,KAAA,KACb,EAAgB,CAAI,GAErB,IAAgB,CAAI;CACrB,GACA,CAAC,GAAe,CAAK,CACtB,GACM,IAAU,EAAM,aACpB,MAAqC;EACrC,MAAQ,UAAU,GACb,GAGL;OAAI,OAAO,KAAQ,YAAY;IAC9B,IAAM,IAAW,EAA+C,CAAI;IAOpE,OANI,OAAO,KAAY,mBACT;KAEZ,AADA,EAAQ,UAAU,MAClB,EAAQ;IACT,UAEY;KAEZ,AADA,EAAQ,UAAU,MAClB,EAAI,IAAI;IACT;GACD;GAEA,OADA,EAAqD,UAAU,SAClD;IAEZ,AADA,EAAQ,UAAU,MAClB,EAAqD,UAAU;GAChE;EALA;CAMD,GACA,CAAC,CAAG,CACL,GACM,IAAkB,EAAM,OAAO;EACpC;EACA;CACD,CAAC;CAyCD,OAxCA,EAAM,gBAAgB;EACrB,EAAgB,UAAU;GACzB;GACA;EACD;CACD,CAAC,GAED,EAAM,gBAAgB;EACrB,IAAM,IAAS,EAAQ,SAAS;EAChC,IAAI,CAAC,KAAW,KAAQ,EAAO,OAAO,GACrC;EAED,IAAI,IAAW,IACT,oBAAS,IAAI,IAAmC,GAChD,KAAW,MAAiB;GACjC,EAAc,UAAU;GACxB,IAAM,IAAQ,iBAAiB;IAE9B,IADA,EAAO,OAAO,CAAK,GACf,KAAY,EAAM,kBACrB;IAED,IAAM,IAAM,EAAgB;IAC5B,AAAI,EAAI,UAAU,KAAA,KACjB,EAAgB,EAAI,gBAAgB,CAAC,CAAC;GAExC,GAAG,CAAC;GACJ,EAAO,IAAI,CAAK;EACjB;EAEA,OADA,EAAO,iBAAiB,SAAS,GAAS,EAAI,SACjC;GAEZ,AADA,IAAW,IACX,EAAc,UAAU;GACxB,KAAK,IAAM,KAAS,GACnB,aAAa,CAAK;GAGnB,AADA,EAAO,MAAM,GACb,EAAO,oBAAoB,SAAS,GAAS,EAAI;EAClD;CACD,GAAG,CAAC,CAAI,CAAC,GAEF;EACN;EACA;EACA;EACA;EACA;EACA;EACA,aAAa,IAAU,KAAO;CAC/B;AACD"}
1
+ {"version":3,"file":"use-checkable-group.js","names":["React","useCheckableGroup","generatedId","nodeRef","uncontrolled","setUncontrolled","defaultValue","current","value","invalid","error","errorId","mergedDescribedBy","describedBy","resetEventRef","setValue","activeReset","next","onValueChange","setRefs","node","ref","cleanup","latestConfigRef","formEl","form","disposed","timers","onReset","event","timer","cfg","ariaInvalid"],"sources":["../../src/utils/use-checkable-group.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport function useCheckableGroup({\n\tvalue,\n\tdefaultValue,\n\tonValueChange,\n\terror,\n\tdescribedBy,\n\tariaInvalid,\n\tform,\n\tref,\n}: {\n\tvalue?: string[];\n\tdefaultValue?: string[];\n\tonValueChange?: (value: string[]) => void;\n\terror?: React.ReactNode;\n\tdescribedBy?: string;\n\tariaInvalid?: React.AriaAttributes[\"aria-invalid\"];\n\tform?: string;\n\tref: React.ForwardedRef<HTMLFieldSetElement>;\n}) {\n\tconst generatedId = React.useId();\n\tconst nodeRef = React.useRef<HTMLFieldSetElement | null>(null);\n\tconst [uncontrolled, setUncontrolled] = React.useState(defaultValue ?? []);\n\tconst current = value ?? uncontrolled;\n\tconst invalid = Boolean(error);\n\tconst errorId = `${generatedId}-error`;\n\tconst mergedDescribedBy =\n\t\t[invalid ? errorId : null, describedBy].filter(Boolean).join(\" \") || undefined;\n\tconst resetEventRef = React.useRef<Event | null>(null);\n\tconst setValue = React.useCallback(\n\t\t(next: string[]) => {\n\t\t\tconst activeReset = resetEventRef.current;\n\t\t\tif (activeReset && activeReset.eventPhase !== Event.NONE) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (value === undefined) {\n\t\t\t\tsetUncontrolled(next);\n\t\t\t}\n\t\t\tonValueChange?.(next);\n\t\t},\n\t\t[onValueChange, value],\n\t);\n\tconst setRefs = React.useCallback(\n\t\t(node: HTMLFieldSetElement | null) => {\n\t\t\tnodeRef.current = node;\n\t\t\tif (!ref) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (typeof ref === \"function\") {\n\t\t\t\tconst cleanup = (ref as React.RefCallback<HTMLFieldSetElement>)(node);\n\t\t\t\tif (typeof cleanup === \"function\") {\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tnodeRef.current = null;\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn () => {\n\t\t\t\t\tnodeRef.current = null;\n\t\t\t\t\tref(null);\n\t\t\t\t};\n\t\t\t}\n\t\t\t(ref as React.RefObject<HTMLFieldSetElement | null>).current = node;\n\t\t\treturn () => {\n\t\t\t\tnodeRef.current = null;\n\t\t\t\t(ref as React.RefObject<HTMLFieldSetElement | null>).current = null;\n\t\t\t};\n\t\t},\n\t\t[ref],\n\t);\n\tconst latestConfigRef = React.useRef({\n\t\tdefaultValue,\n\t\tvalue,\n\t});\n\tReact.useEffect(() => {\n\t\tlatestConfigRef.current = {\n\t\t\tdefaultValue,\n\t\t\tvalue,\n\t\t};\n\t});\n\n\tReact.useEffect(() => {\n\t\tconst formEl = nodeRef.current?.form;\n\t\tif (!formEl || (form && formEl.id !== form)) {\n\t\t\treturn;\n\t\t}\n\t\tlet disposed = false;\n\t\tconst timers = new Set<ReturnType<typeof setTimeout>>();\n\t\tconst onReset = (event: Event) => {\n\t\t\tresetEventRef.current = event;\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\ttimers.delete(timer);\n\t\t\t\tif (disposed || event.defaultPrevented) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst cfg = latestConfigRef.current;\n\t\t\t\tif (cfg.value === undefined) {\n\t\t\t\t\tsetUncontrolled(cfg.defaultValue ?? []);\n\t\t\t\t}\n\t\t\t}, 0);\n\t\t\ttimers.add(timer);\n\t\t};\n\t\tformEl.addEventListener(\"reset\", onReset, true);\n\t\treturn () => {\n\t\t\tdisposed = true;\n\t\t\tresetEventRef.current = null;\n\t\t\tfor (const timer of timers) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\ttimers.clear();\n\t\t\tformEl.removeEventListener(\"reset\", onReset, true);\n\t\t};\n\t}, [form]);\n\n\treturn {\n\t\tcurrent,\n\t\tsetValue,\n\t\tinvalid,\n\t\terrorId,\n\t\tmergedDescribedBy,\n\t\tsetRefs,\n\t\tariaInvalid: invalid ? true : ariaInvalid,\n\t};\n}\n"],"mappings":";;;AAEA,SAAgBC,EAAkB,EACjC,UACA,iBACA,kBACA,UACA,gBACA,gBACA,SACA,UAUE;CACF,IAAMC,IAAcF,EAAM,MAAM,GAC1BG,IAAUH,EAAM,OAAmC,IAAI,GACvD,CAACI,GAAcC,KAAmBL,EAAM,SAASM,KAAgB,CAAC,CAAC,GACnEC,IAAUC,KAASJ,GACnBK,IAAU,EAAQC,GAClBC,IAAU,GAAGT,EAAY,SACzBU,IACL,CAACH,IAAUE,IAAU,MAAME,CAAW,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA,GAChEC,IAAgBd,EAAM,OAAqB,IAAI,GAC/Ce,IAAWf,EAAM,aACrB,MAAmB;EACnB,IAAMgB,IAAcF,EAAc;EAClC,AAAIE,KAAeA,EAAY,eAAe,MAAM,SAGhDR,MAAU,KAAA,KACbH,EAAgBY,CAAI,GAErBC,IAAgBD,CAAI;CACrB,GACA,CAACC,GAAeV,CAAK,CACtB,GACMW,IAAUnB,EAAM,aACpB,MAAqC;EAErC,IADA,EAAQ,UAAUoB,GACbC,GAGL;OAAI,OAAOA,KAAQ,YAAY;IAC9B,IAAMC,IAAWD,EAA+CD,CAAI;IAOpE,OANI,OAAOE,KAAY,mBACT;KAEZ,AADA,EAAQ,UAAU,MAClBA,EAAQ;IACT,UAEY;KAEZ,AADA,EAAQ,UAAU,MAClBD,EAAI,IAAI;IACT;GACD;GAEA,OADA,EAAqD,UAAUD,SAClD;IAEZ,AADA,EAAQ,UAAU,MAClB,EAAqD,UAAU;GAChE;EALA;CAMD,GACA,CAACC,CAAG,CACL,GACME,IAAkBvB,EAAM,OAAO;EACpC;EACA;CACD,CAAC;CAyCD,OAxCAA,EAAM,gBAAgB;EACrB,EAAgB,UAAU;GACzB;GACA;EACD;CACD,CAAC,GAEDA,EAAM,gBAAgB;EACrB,IAAMwB,IAASrB,EAAQ,SAAS;EAChC,IAAI,CAACqB,KAAWC,KAAQD,EAAO,OAAOC,GACrC;EAED,IAAIC,IAAW,IACTC,oBAAS,IAAI,IAAmC,GAChDC,KAAW,MAAiB;GACjC,EAAc,UAAUC;GACxB,IAAMC,IAAQ,iBAAiB;IAE9B,IADAH,EAAO,OAAOG,CAAK,GACfJ,KAAYG,EAAM,kBACrB;IAED,IAAME,IAAMR,EAAgB;IAC5B,AAAIQ,EAAI,UAAU,KAAA,KACjB1B,EAAgB0B,EAAI,gBAAgB,CAAC,CAAC;GAExC,GAAG,CAAC;GACJ,EAAO,IAAID,CAAK;EACjB;EAEA,OADAN,EAAO,iBAAiB,SAASI,GAAS,EAAI,SACjC;GAEZ,AADA,IAAW,IACX,EAAc,UAAU;GACxB,KAAK,IAAME,KAASH,GACnB,aAAaG,CAAK;GAGnB,AADAH,EAAO,MAAM,GACbH,EAAO,oBAAoB,SAASI,GAAS,EAAI;EAClD;CACD,GAAG,CAACH,CAAI,CAAC,GAEF;EACN;EACA;EACA;EACA;EACA;EACA;EACA,aAAahB,IAAU,KAAOuB;CAC/B;AACD"}
@@ -0,0 +1,4 @@
1
+ import { type Ref } from "react";
2
+ export declare function useHoverHighlight(ref?: Ref<HTMLElement | null>, { restoreOnPointerLeave }?: {
3
+ restoreOnPointerLeave?: boolean;
4
+ }): (root: HTMLElement | null) => (() => void) | undefined;
@@ -0,0 +1,80 @@
1
+ "use client";
2
+ import { assignRef as e } from "./selection-indicator.js";
3
+ import { useCallback as t } from "react";
4
+ //#region src/utils/use-hover-highlight.ts
5
+ var n = "[data-basalt-hover-item]", r = "[data-highlighted], [data-hover-active=\"true\"], [aria-selected=\"true\"], [data-state=\"checked\"], [data-hover-selected=\"true\"], [data-selected=\"true\"]";
6
+ function i(i, { restoreOnPointerLeave: a = !0 } = {}) {
7
+ return t((t) => {
8
+ if (e(i, t), !t) return;
9
+ let o = null, s = !1, c = null, l = null, u = null, d = null, f = !0, p = 0, m = "", h = !0, g = (e) => e && t.contains(e) && e.matches(n) && e.closest(".basalt-hover-list") === t && !e.closest("[hidden], [disabled], [aria-disabled=\"true\"], [data-disabled=\"\"], [data-disabled=\"true\"]") ? e : null, _ = (e) => g(e instanceof Element ? e.closest(n) : null), v = new ResizeObserver(() => {
10
+ h = !0, b();
11
+ }), y = () => {
12
+ if (p = 0, f) {
13
+ d = null, u = null;
14
+ for (let e of t.querySelectorAll(`${n}:is(${r})`)) if (g(e) && (u ||= e, e.matches("[data-highlighted], [data-hover-active=\"true\"]"))) {
15
+ d = e;
16
+ break;
17
+ }
18
+ f = !1;
19
+ }
20
+ let e = s ? null : g(d) ?? g(o) ?? g(c) ?? g(u);
21
+ if (e === l && !h) return;
22
+ e !== l && (l && v.unobserve(l), e && v.observe(e));
23
+ let i = e?.offsetWidth ?? 0, a = e?.offsetHeight ?? 0;
24
+ if (!e || !i || !a) {
25
+ s && (t.dataset.hoverAnimated = "true"), t.dataset.hoverVisible = "false", l = null, m = "", h = !1;
26
+ return;
27
+ }
28
+ let _ = 0, y = 0;
29
+ for (let n = e; n && n !== t; n = n.offsetParent) _ += n.offsetLeft, y += n.offsetTop;
30
+ for (let n = e.parentElement; n && n !== t; n = n.parentElement) _ -= n.scrollLeft, y -= n.scrollTop;
31
+ let b = `${_},${y},${i},${a}`;
32
+ b !== m && (t.dataset.hoverAnimated = l && l !== e && !h ? "true" : "false", t.style.setProperty("--basalt-hover-x", `${_}px`), t.style.setProperty("--basalt-hover-y", `${y}px`), t.style.setProperty("--basalt-hover-width", `${i}px`), t.style.setProperty("--basalt-hover-height", `${a}px`), m = b), t.dataset.hoverVisible = "true", l = e, h = !1;
33
+ };
34
+ function b() {
35
+ p ||= requestAnimationFrame(y);
36
+ }
37
+ let x = (e) => {
38
+ if (e.pointerType === "touch") return;
39
+ s = !1;
40
+ let t = _(e.target);
41
+ t !== o && (o = t, b());
42
+ }, S = () => {
43
+ o = null, s = !a, b();
44
+ }, C = (e) => {
45
+ s = !1, c = _(e.target), o = null, b();
46
+ }, w = (e) => {
47
+ c = _(e.relatedTarget), b();
48
+ }, T = (e) => {
49
+ e.target instanceof Element && (t.contains(e.target) || t.id && e.target.getAttribute("aria-controls") === t.id) && (o = null, s = !1, b());
50
+ }, E = (e) => {
51
+ (e.target !== t || e.type === "scroll") && (h = !0, b());
52
+ }, D = new MutationObserver((e) => {
53
+ f = !0, e.some((e) => e.type === "childList" || e.attributeName === "hidden") && (h = !0), b();
54
+ });
55
+ return D.observe(t, {
56
+ subtree: !0,
57
+ childList: !0,
58
+ attributes: !0,
59
+ attributeFilter: [
60
+ "data-basalt-hover-item",
61
+ "data-highlighted",
62
+ "data-state",
63
+ "aria-selected",
64
+ "data-selected",
65
+ "data-hover-active",
66
+ "data-hover-selected",
67
+ "disabled",
68
+ "aria-disabled",
69
+ "data-disabled",
70
+ "hidden"
71
+ ]
72
+ }), v.observe(t), t.addEventListener("pointerover", x), t.addEventListener("pointerleave", S), t.addEventListener("focusin", C), t.addEventListener("focusout", w), t.ownerDocument.addEventListener("keydown", T), t.addEventListener("scroll", E, !0), t.addEventListener("animationend", E), t.addEventListener("transitionend", E), b(), () => {
73
+ cancelAnimationFrame(p), v.disconnect(), D.disconnect(), t.removeEventListener("pointerover", x), t.removeEventListener("pointerleave", S), t.removeEventListener("focusin", C), t.removeEventListener("focusout", w), t.ownerDocument.removeEventListener("keydown", T), t.removeEventListener("scroll", E, !0), t.removeEventListener("animationend", E), t.removeEventListener("transitionend", E), e(i, null);
74
+ };
75
+ }, [i, a]);
76
+ }
77
+ //#endregion
78
+ export { i as useHoverHighlight };
79
+
80
+ //# sourceMappingURL=use-hover-highlight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hover-highlight.js","names":["ROW","ACTIVE","useHoverHighlight","useCallback","assignRef","ref","root","hovered","pointerExited","focused","previous","selected","active","selectionDirty","frame","geometry","layoutChanged","eligible","node","row","target","resize","schedule","update","item","width","height","x","next","over","event","leave","restoreOnPointerLeave","focus","blur","keyboard","layout","mutations","records","record"],"sources":["../../src/utils/use-hover-highlight.ts"],"sourcesContent":["import { type Ref, useCallback } from \"react\";\nimport { assignRef } from \"./selection-indicator\";\n\nconst ROW = \"[data-basalt-hover-item]\";\nconst ACTIVE =\n\t'[data-highlighted], [data-hover-active=\"true\"], [aria-selected=\"true\"], [data-state=\"checked\"], [data-hover-selected=\"true\"], [data-selected=\"true\"]';\n\nexport function useHoverHighlight(\n\tref?: Ref<HTMLElement | null>,\n\t{ restoreOnPointerLeave = true }: { restoreOnPointerLeave?: boolean } = {},\n) {\n\treturn useCallback(\n\t\t(root: HTMLElement | null) => {\n\t\t\tassignRef(ref, root);\n\t\t\tif (!root) return;\n\t\t\tlet hovered: HTMLElement | null = null;\n\t\t\tlet pointerExited = false;\n\t\t\tlet focused: HTMLElement | null = null;\n\t\t\tlet previous: HTMLElement | null = null;\n\t\t\tlet selected: HTMLElement | null = null;\n\t\t\tlet active: HTMLElement | null = null;\n\t\t\tlet selectionDirty = true;\n\t\t\tlet frame = 0;\n\t\t\tlet geometry = \"\";\n\t\t\tlet layoutChanged = true;\n\t\t\tconst eligible = (node: HTMLElement | null) =>\n\t\t\t\tnode &&\n\t\t\t\troot.contains(node) &&\n\t\t\t\tnode.matches(ROW) &&\n\t\t\t\tnode.closest(\".basalt-hover-list\") === root &&\n\t\t\t\t!node.closest(\n\t\t\t\t\t'[hidden], [disabled], [aria-disabled=\"true\"], [data-disabled=\"\"], [data-disabled=\"true\"]',\n\t\t\t\t)\n\t\t\t\t\t? node\n\t\t\t\t\t: null;\n\t\t\tconst row = (target: EventTarget | null) =>\n\t\t\t\teligible(target instanceof Element ? target.closest<HTMLElement>(ROW) : null);\n\t\t\tconst resize = new ResizeObserver(() => {\n\t\t\t\tlayoutChanged = true;\n\t\t\t\tschedule();\n\t\t\t});\n\t\t\tconst update = () => {\n\t\t\t\tframe = 0;\n\t\t\t\tif (selectionDirty) {\n\t\t\t\t\tactive = null;\n\t\t\t\t\tselected = null;\n\t\t\t\t\tfor (const node of root.querySelectorAll<HTMLElement>(`${ROW}:is(${ACTIVE})`)) {\n\t\t\t\t\t\tif (!eligible(node)) continue;\n\t\t\t\t\t\tif (!selected) selected = node;\n\t\t\t\t\t\tif (node.matches('[data-highlighted], [data-hover-active=\"true\"]')) {\n\t\t\t\t\t\t\tactive = node;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tselectionDirty = false;\n\t\t\t\t}\n\t\t\t\tconst item = pointerExited\n\t\t\t\t\t? null\n\t\t\t\t\t: (eligible(active) ?? eligible(hovered) ?? eligible(focused) ?? eligible(selected));\n\t\t\t\tif (item === previous && !layoutChanged) return;\n\t\t\t\tif (item !== previous) {\n\t\t\t\t\tif (previous) resize.unobserve(previous);\n\t\t\t\t\tif (item) resize.observe(item);\n\t\t\t\t}\n\t\t\t\tconst width = item?.offsetWidth ?? 0;\n\t\t\t\tconst height = item?.offsetHeight ?? 0;\n\t\t\t\tif (!item || !width || !height) {\n\t\t\t\t\tif (pointerExited) root.dataset.hoverAnimated = \"true\";\n\t\t\t\t\troot.dataset.hoverVisible = \"false\";\n\t\t\t\t\tprevious = null;\n\t\t\t\t\tgeometry = \"\";\n\t\t\t\t\tlayoutChanged = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet x = 0,\n\t\t\t\t\ty = 0;\n\t\t\t\tfor (\n\t\t\t\t\tlet node: HTMLElement | null = item;\n\t\t\t\t\tnode && node !== root;\n\t\t\t\t\tnode = node.offsetParent as HTMLElement | null\n\t\t\t\t) {\n\t\t\t\t\tx += node.offsetLeft;\n\t\t\t\t\ty += node.offsetTop;\n\t\t\t\t}\n\t\t\t\tfor (let node = item.parentElement; node && node !== root; node = node.parentElement) {\n\t\t\t\t\tx -= node.scrollLeft;\n\t\t\t\t\ty -= node.scrollTop;\n\t\t\t\t}\n\t\t\t\tconst next = `${x},${y},${width},${height}`;\n\t\t\t\tif (next !== geometry) {\n\t\t\t\t\troot.dataset.hoverAnimated =\n\t\t\t\t\t\tprevious && previous !== item && !layoutChanged ? \"true\" : \"false\";\n\t\t\t\t\troot.style.setProperty(\"--basalt-hover-x\", `${x}px`);\n\t\t\t\t\troot.style.setProperty(\"--basalt-hover-y\", `${y}px`);\n\t\t\t\t\troot.style.setProperty(\"--basalt-hover-width\", `${width}px`);\n\t\t\t\t\troot.style.setProperty(\"--basalt-hover-height\", `${height}px`);\n\t\t\t\t\tgeometry = next;\n\t\t\t\t}\n\t\t\t\troot.dataset.hoverVisible = \"true\";\n\t\t\t\tprevious = item;\n\t\t\t\tlayoutChanged = false;\n\t\t\t};\n\t\t\tfunction schedule() {\n\t\t\t\tif (!frame) frame = requestAnimationFrame(update);\n\t\t\t}\n\t\t\tconst over = (event: PointerEvent) => {\n\t\t\t\tif (event.pointerType === \"touch\") return;\n\t\t\t\tpointerExited = false;\n\t\t\t\tconst next = row(event.target);\n\t\t\t\tif (next !== hovered) {\n\t\t\t\t\thovered = next;\n\t\t\t\t\tschedule();\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst leave = () => {\n\t\t\t\thovered = null;\n\t\t\t\tpointerExited = !restoreOnPointerLeave;\n\t\t\t\tschedule();\n\t\t\t};\n\t\t\tconst focus = (event: FocusEvent) => {\n\t\t\t\tpointerExited = false;\n\t\t\t\tfocused = row(event.target);\n\t\t\t\thovered = null;\n\t\t\t\tschedule();\n\t\t\t};\n\t\t\tconst blur = (event: FocusEvent) => {\n\t\t\t\tfocused = row(event.relatedTarget);\n\t\t\t\tschedule();\n\t\t\t};\n\t\t\tconst keyboard = (event: KeyboardEvent) => {\n\t\t\t\tif (\n\t\t\t\t\t!(event.target instanceof Element) ||\n\t\t\t\t\t(!root.contains(event.target) &&\n\t\t\t\t\t\t(!root.id || event.target.getAttribute(\"aria-controls\") !== root.id))\n\t\t\t\t)\n\t\t\t\t\treturn;\n\t\t\t\thovered = null;\n\t\t\t\tpointerExited = false;\n\t\t\t\tschedule();\n\t\t\t};\n\t\t\tconst layout = (event: Event) => {\n\t\t\t\t// Our pseudo-element transition cannot change row geometry.\n\t\t\t\tif (event.target === root && event.type !== \"scroll\") return;\n\t\t\t\tlayoutChanged = true;\n\t\t\t\tschedule();\n\t\t\t};\n\t\t\tconst mutations = new MutationObserver((records) => {\n\t\t\t\tselectionDirty = true;\n\t\t\t\tif (\n\t\t\t\t\trecords.some((record) => record.type === \"childList\" || record.attributeName === \"hidden\")\n\t\t\t\t)\n\t\t\t\t\tlayoutChanged = true;\n\t\t\t\tschedule();\n\t\t\t});\n\t\t\tmutations.observe(root, {\n\t\t\t\tsubtree: true,\n\t\t\t\tchildList: true,\n\t\t\t\tattributes: true,\n\t\t\t\tattributeFilter: [\n\t\t\t\t\t\"data-basalt-hover-item\",\n\t\t\t\t\t\"data-highlighted\",\n\t\t\t\t\t\"data-state\",\n\t\t\t\t\t\"aria-selected\",\n\t\t\t\t\t\"data-selected\",\n\t\t\t\t\t\"data-hover-active\",\n\t\t\t\t\t\"data-hover-selected\",\n\t\t\t\t\t\"disabled\",\n\t\t\t\t\t\"aria-disabled\",\n\t\t\t\t\t\"data-disabled\",\n\t\t\t\t\t\"hidden\",\n\t\t\t\t],\n\t\t\t});\n\t\t\tresize.observe(root);\n\t\t\troot.addEventListener(\"pointerover\", over);\n\t\t\troot.addEventListener(\"pointerleave\", leave);\n\t\t\troot.addEventListener(\"focusin\", focus);\n\t\t\troot.addEventListener(\"focusout\", blur);\n\t\t\troot.ownerDocument.addEventListener(\"keydown\", keyboard);\n\t\t\troot.addEventListener(\"scroll\", layout, true);\n\t\t\troot.addEventListener(\"animationend\", layout);\n\t\t\troot.addEventListener(\"transitionend\", layout);\n\t\t\tschedule();\n\t\t\treturn () => {\n\t\t\t\tcancelAnimationFrame(frame);\n\t\t\t\tresize.disconnect();\n\t\t\t\tmutations.disconnect();\n\t\t\t\troot.removeEventListener(\"pointerover\", over);\n\t\t\t\troot.removeEventListener(\"pointerleave\", leave);\n\t\t\t\troot.removeEventListener(\"focusin\", focus);\n\t\t\t\troot.removeEventListener(\"focusout\", blur);\n\t\t\t\troot.ownerDocument.removeEventListener(\"keydown\", keyboard);\n\t\t\t\troot.removeEventListener(\"scroll\", layout, true);\n\t\t\t\troot.removeEventListener(\"animationend\", layout);\n\t\t\t\troot.removeEventListener(\"transitionend\", layout);\n\t\t\t\tassignRef(ref, null);\n\t\t\t};\n\t\t},\n\t\t[ref, restoreOnPointerLeave],\n\t);\n}\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type ApprovalAnswers, type ApprovalQuestion } from "../models/agent-feedback.js";
2
+ export declare function useApprovalCardViewModel({ questions, onSubmit, autoAdvance, }: {
3
+ questions: readonly ApprovalQuestion[];
4
+ onSubmit: (answers: ApprovalAnswers) => void | Promise<void>;
5
+ autoAdvance?: boolean;
6
+ }): {
7
+ position: number;
8
+ focusToken: number;
9
+ question: ApprovalQuestion;
10
+ answer: import("../models/agent-feedback.js").ApprovalAnswer | undefined;
11
+ status: "editing" | "submitted" | "submitting";
12
+ error: string;
13
+ canContinue: boolean;
14
+ last: boolean;
15
+ choose: (id: string) => void;
16
+ move: (next: number) => void;
17
+ setCustom(value: string): void;
18
+ continue(): void;
19
+ skip(): void;
20
+ };
@@ -0,0 +1,83 @@
1
+ "use client";
2
+ import { approvalSnapshot as e, validApprovalAnswer as t } from "../models/agent-feedback.js";
3
+ import { useEffect as n, useRef as r, useState as i } from "react";
4
+ //#region src/viewmodels/use-approval-card.ts
5
+ function a({ questions: a, onSubmit: o, autoAdvance: s = !0 }) {
6
+ let [c, l] = i(0), [u, d] = i(0), [f, p] = i({}), [m, h] = i("editing"), [g, _] = i(""), v = r(!1), y = r(!0), b = r(void 0), x = () => {
7
+ clearTimeout(b.current), b.current = void 0;
8
+ };
9
+ n(() => (y.current = !0, () => {
10
+ y.current = !1, clearTimeout(b.current);
11
+ }), []);
12
+ let S = Math.min(c, Math.max(0, a.length - 1)), C = a[S], w = C ? f[C.id] : void 0, T = S === a.length - 1, E = !!(C && t(C, w)), D = (e) => {
13
+ l(e), d((e) => e + 1);
14
+ }, O = (e) => {
15
+ v.current || a.length === 0 || (x(), D(Math.min(Math.max(0, e), a.length - 1)), _(""));
16
+ }, k = (e) => {
17
+ if (!C || v.current || !C.options.some((t) => t.id === e && !t.disabled)) return;
18
+ x();
19
+ let t = w?.selected ?? [];
20
+ p({
21
+ ...f,
22
+ [C.id]: {
23
+ ...w,
24
+ skipped: !1,
25
+ selected: C.type === "single" ? [e] : t.includes(e) ? t.filter((t) => t !== e) : [...t, e]
26
+ }
27
+ }), _(""), C.type === "single" && s && !T && (b.current = setTimeout(() => D(S + 1), 240));
28
+ }, A = async (n) => {
29
+ if (v.current || a.length === 0) return;
30
+ let r = a.findIndex((e) => !t(e, n[e.id]));
31
+ if (r >= 0) {
32
+ D(r);
33
+ return;
34
+ }
35
+ v.current = !0, h("submitting"), _(""), x();
36
+ try {
37
+ await o(e(a, n)), y.current && h("submitted");
38
+ } catch (e) {
39
+ y.current && (_(e instanceof Error ? e.message : "Could not submit answers. Try again."), h("editing"));
40
+ } finally {
41
+ v.current = !1;
42
+ }
43
+ };
44
+ return {
45
+ position: S,
46
+ focusToken: u,
47
+ question: C,
48
+ answer: w,
49
+ status: m,
50
+ error: g,
51
+ canContinue: E,
52
+ last: T,
53
+ choose: k,
54
+ move: O,
55
+ setCustom(e) {
56
+ C?.allowCustom && !v.current && (x(), p({
57
+ ...f,
58
+ [C.id]: {
59
+ selected: w?.selected ?? [],
60
+ custom: e
61
+ }
62
+ }));
63
+ },
64
+ continue() {
65
+ E && !v.current && (T ? A(f) : O(S + 1));
66
+ },
67
+ skip() {
68
+ if (C?.required !== !1 || v.current) return;
69
+ let e = {
70
+ ...f,
71
+ [C.id]: {
72
+ selected: [],
73
+ skipped: !0
74
+ }
75
+ };
76
+ p(e), T ? A(e) : O(S + 1);
77
+ }
78
+ };
79
+ }
80
+ //#endregion
81
+ export { a as useApprovalCardViewModel };
82
+
83
+ //# sourceMappingURL=use-approval-card.js.map