@nocoo/basalt 3.2.0 → 3.2.4

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 (225) hide show
  1. package/README.md +25 -19
  2. package/ai/COMPATIBILITY.md +41 -36
  3. package/ai/DESIGN.md +73 -56
  4. package/ai/INTEGRATION.md +819 -825
  5. package/ai/RECIPES.md +334 -135
  6. package/ai/USAGE.md +2 -2
  7. package/ai/registry.json +454 -97
  8. package/ai/sources.json +2 -2
  9. package/dist/assets/brand-mark.js +1 -2
  10. package/dist/charts/area.js +1 -2
  11. package/dist/charts/bar.js +1 -2
  12. package/dist/charts/bullet.js +1 -2
  13. package/dist/charts/chart-colors.js +1 -2
  14. package/dist/charts/charts.js +1 -2
  15. package/dist/charts/config.js +1 -2
  16. package/dist/charts/custom-chart.js +1 -2
  17. package/dist/charts/date-navigation.js +1 -2
  18. package/dist/charts/donut.js +1 -2
  19. package/dist/charts/frame.js +3 -4
  20. package/dist/charts/frame.js.map +1 -1
  21. package/dist/charts/funnel.js +1 -2
  22. package/dist/charts/gauge.js +1 -2
  23. package/dist/charts/grouped-bar.js +1 -2
  24. package/dist/charts/heatmap-calendar.js +7 -11
  25. package/dist/charts/heatmap-calendar.js.map +1 -1
  26. package/dist/charts/heatmap-matrix.js +4 -5
  27. package/dist/charts/heatmap-matrix.js.map +1 -1
  28. package/dist/charts/item-list.js +1 -2
  29. package/dist/charts/legend.js +1 -2
  30. package/dist/charts/line.js +1 -2
  31. package/dist/charts/palette.js +1 -2
  32. package/dist/charts/radar.js +1 -2
  33. package/dist/charts/sample.js +1 -2
  34. package/dist/charts/sankey.js +1 -2
  35. package/dist/charts/series.js +1 -2
  36. package/dist/charts/slot-bar.js +1 -2
  37. package/dist/charts/sparkline.js +1 -2
  38. package/dist/charts/stacked-bar.js +1 -2
  39. package/dist/charts/stat-card.js +1 -2
  40. package/dist/charts/timeline.js +1 -2
  41. package/dist/charts/timeseries.js +1 -2
  42. package/dist/charts/tooltip.js +31 -27
  43. package/dist/charts/tooltip.js.map +1 -1
  44. package/dist/components/accordion.js +1 -2
  45. package/dist/components/alert-dialog.js +1 -2
  46. package/dist/components/app-header.js +2 -3
  47. package/dist/components/app-header.js.map +1 -1
  48. package/dist/components/app-shell.js +2 -3
  49. package/dist/components/app-shell.js.map +1 -1
  50. package/dist/components/approval-card.js +1 -2
  51. package/dist/components/autocomplete.js +1 -2
  52. package/dist/components/avatar.js +1 -2
  53. package/dist/components/badge.js +1 -2
  54. package/dist/components/banner.js +1 -2
  55. package/dist/components/basalt-mark.js +1 -2
  56. package/dist/components/battery-meter.js +1 -2
  57. package/dist/components/breadcrumbs.js +1 -2
  58. package/dist/components/button.d.ts +1 -1
  59. package/dist/components/button.js +3 -3
  60. package/dist/components/button.js.map +1 -1
  61. package/dist/components/chat-bubble.js +1 -2
  62. package/dist/components/chat-composer.js +2 -3
  63. package/dist/components/chat-composer.js.map +1 -1
  64. package/dist/components/chat-header.js +1 -2
  65. package/dist/components/chat-inbox.js +1 -2
  66. package/dist/components/chat-markdown.js +1 -2
  67. package/dist/components/chat-message.js +2 -3
  68. package/dist/components/chat-message.js.map +1 -1
  69. package/dist/components/checkbox.js +1 -2
  70. package/dist/components/clipboard-text.js +1 -2
  71. package/dist/components/code.js +2 -3
  72. package/dist/components/code.js.map +1 -1
  73. package/dist/components/collapsible.js +1 -2
  74. package/dist/components/collapsible.js.map +1 -1
  75. package/dist/components/combobox.js +1 -2
  76. package/dist/components/command-palette.js +3 -4
  77. package/dist/components/command-palette.js.map +1 -1
  78. package/dist/components/confirm-dialog.js +3 -12
  79. package/dist/components/confirm-dialog.js.map +1 -1
  80. package/dist/components/context-cards.js +2 -3
  81. package/dist/components/context-cards.js.map +1 -1
  82. package/dist/components/context-menu.js +2 -3
  83. package/dist/components/context-menu.js.map +1 -1
  84. package/dist/components/data-table.js +129 -131
  85. package/dist/components/data-table.js.map +1 -1
  86. package/dist/components/date-picker.js +7 -18
  87. package/dist/components/date-picker.js.map +1 -1
  88. package/dist/components/delete-resource.js +1 -2
  89. package/dist/components/description-list.js +1 -2
  90. package/dist/components/dialog.js +1 -2
  91. package/dist/components/diff-table.js +2 -3
  92. package/dist/components/diff-table.js.map +1 -1
  93. package/dist/components/dock.js +1 -2
  94. package/dist/components/dock.js.map +1 -1
  95. package/dist/components/dropdown-menu.js +2 -3
  96. package/dist/components/dropdown-menu.js.map +1 -1
  97. package/dist/components/editable-nav-item.js +3 -4
  98. package/dist/components/editable-nav-item.js.map +1 -1
  99. package/dist/components/empty.js +1 -2
  100. package/dist/components/fab.js +1 -2
  101. package/dist/components/field.js +1 -2
  102. package/dist/components/file-dropzone.js +2 -3
  103. package/dist/components/file-dropzone.js.map +1 -1
  104. package/dist/components/filter-bar.js +2 -3
  105. package/dist/components/filter-bar.js.map +1 -1
  106. package/dist/components/flow.js +1 -2
  107. package/dist/components/grid.js +1 -2
  108. package/dist/components/hover-card.js +1 -2
  109. package/dist/components/icon-picker.js +4 -5
  110. package/dist/components/icon-picker.js.map +1 -1
  111. package/dist/components/inline-editable.js +2 -3
  112. package/dist/components/inline-editable.js.map +1 -1
  113. package/dist/components/input-area.js +1 -2
  114. package/dist/components/input-group.js +4 -5
  115. package/dist/components/input-group.js.map +1 -1
  116. package/dist/components/input.js +1 -2
  117. package/dist/components/label.js +1 -2
  118. package/dist/components/layer-card.js +3 -3
  119. package/dist/components/layer-card.js.map +1 -1
  120. package/dist/components/link.js +2 -3
  121. package/dist/components/link.js.map +1 -1
  122. package/dist/components/loader.js +1 -2
  123. package/dist/components/loading-screen.js +1 -2
  124. package/dist/components/menu-bar.js +3 -4
  125. package/dist/components/menu-bar.js.map +1 -1
  126. package/dist/components/meter.js +1 -2
  127. package/dist/components/multi-select.js +2 -3
  128. package/dist/components/multi-select.js.map +1 -1
  129. package/dist/components/navigation-menu.js +1 -2
  130. package/dist/components/overlay.d.ts +3 -6
  131. package/dist/components/overlay.js +4 -5
  132. package/dist/components/overlay.js.map +1 -1
  133. package/dist/components/page-header.js +1 -2
  134. package/dist/components/pagination.js +1 -2
  135. package/dist/components/popover.js +1 -2
  136. package/dist/components/prompt-bar.js +1 -2
  137. package/dist/components/radio.js +2 -7
  138. package/dist/components/radio.js.map +1 -1
  139. package/dist/components/recommendation-card.js +1 -2
  140. package/dist/components/resource-list.js +1 -2
  141. package/dist/components/responsive-master-detail.js +3 -4
  142. package/dist/components/responsive-master-detail.js.map +1 -1
  143. package/dist/components/scroll-area.js +2 -3
  144. package/dist/components/scroll-area.js.map +1 -1
  145. package/dist/components/section-rule.js +1 -2
  146. package/dist/components/segment-control.js +2 -3
  147. package/dist/components/segment-control.js.map +1 -1
  148. package/dist/components/select.js +2 -3
  149. package/dist/components/select.js.map +1 -1
  150. package/dist/components/sensitive-input.js +2 -3
  151. package/dist/components/sensitive-input.js.map +1 -1
  152. package/dist/components/separator.js +1 -2
  153. package/dist/components/sheet.js +1 -2
  154. package/dist/components/sidebar.d.ts +53 -19
  155. package/dist/components/sidebar.js +201 -100
  156. package/dist/components/sidebar.js.map +1 -1
  157. package/dist/components/skeleton-line.js +1 -2
  158. package/dist/components/slider.js +1 -2
  159. package/dist/components/stat-strip.js +1 -2
  160. package/dist/components/switch.js +1 -2
  161. package/dist/components/table-of-contents.js +1 -2
  162. package/dist/components/table-pager.js +1 -2
  163. package/dist/components/table.js +2 -3
  164. package/dist/components/table.js.map +1 -1
  165. package/dist/components/tabs.js +2 -3
  166. package/dist/components/tabs.js.map +1 -1
  167. package/dist/components/tag-badge.js +1 -2
  168. package/dist/components/tag-color-picker.js +3 -4
  169. package/dist/components/tag-color-picker.js.map +1 -1
  170. package/dist/components/text.js +1 -2
  171. package/dist/components/theme-toggle.js +1 -2
  172. package/dist/components/thinking.js +1 -2
  173. package/dist/components/toast.js +2 -3
  174. package/dist/components/toast.js.map +1 -1
  175. package/dist/components/toggle-group.js +1 -2
  176. package/dist/components/toggle.js +1 -2
  177. package/dist/components/tool-chips.js +1 -2
  178. package/dist/components/toolbar.js +9 -10
  179. package/dist/components/toolbar.js.map +1 -1
  180. package/dist/components/tooltip.js +1 -2
  181. package/dist/components/typeahead-field.js +6 -21
  182. package/dist/components/typeahead-field.js.map +1 -1
  183. package/dist/components/upload-queue.js +1 -2
  184. package/dist/index.d.ts +1 -1
  185. package/dist/index.js +11 -11
  186. package/dist/models/agent-feedback.js +1 -2
  187. package/dist/models/avatar.js +1 -2
  188. package/dist/models/code.js +1 -2
  189. package/dist/models/context-cards.js +1 -2
  190. package/dist/models/diff-table.js +1 -2
  191. package/dist/models/recommendation.js +1 -2
  192. package/dist/providers/accent.js +2 -7
  193. package/dist/providers/accent.js.map +1 -1
  194. package/dist/providers/link.js +1 -2
  195. package/dist/providers/theme.js +2 -7
  196. package/dist/providers/theme.js.map +1 -1
  197. package/dist/styles/base.css +71 -0
  198. package/dist/styles/standalone.css +127 -98
  199. package/dist/styles/tailwind.css +10 -2
  200. package/dist/styles/tokens.css +55 -7
  201. package/dist/utils/cn.js +1 -2
  202. package/dist/utils/control-surface.js +1 -2
  203. package/dist/utils/navigation.d.ts +2 -2
  204. package/dist/utils/navigation.js +2 -3
  205. package/dist/utils/navigation.js.map +1 -1
  206. package/dist/utils/preference-store.js +1 -2
  207. package/dist/utils/selection-indicator.js +1 -2
  208. package/dist/utils/use-checkable-group.js +1 -2
  209. package/dist/utils/use-hover-highlight.js +2 -3
  210. package/dist/utils/use-hover-highlight.js.map +1 -1
  211. package/dist/viewmodels/use-approval-card.js +11 -13
  212. package/dist/viewmodels/use-approval-card.js.map +1 -1
  213. package/dist/viewmodels/use-chat-composer.js +1 -2
  214. package/dist/viewmodels/use-chat-message.js +1 -2
  215. package/dist/viewmodels/use-code-block.js +1 -2
  216. package/dist/viewmodels/use-code-block.js.map +1 -1
  217. package/dist/viewmodels/use-context-cards.js +1 -2
  218. package/dist/viewmodels/use-diff-table.js +1 -2
  219. package/dist/viewmodels/use-diff-table.js.map +1 -1
  220. package/dist/viewmodels/use-loader.js +1 -2
  221. package/dist/viewmodels/use-recommendation-card.js +1 -2
  222. package/dist/viewmodels/use-recommendation-card.js.map +1 -1
  223. package/dist/viewmodels/use-thinking.js +1 -2
  224. package/dist/viewmodels/use-tool-chips.js +1 -2
  225. package/package.json +1 -1
@@ -157,8 +157,10 @@
157
157
  --spacing-basalt-row-content: var(--basalt-space-row-content);
158
158
  --spacing-basalt-action: var(--basalt-size-action);
159
159
  --spacing-basalt-nav-inset: var(--basalt-space-nav-inset);
160
+ --spacing-basalt-sidebar-inset: var(--basalt-space-sidebar-inset);
160
161
  --spacing-basalt-nav-gap: var(--basalt-space-nav-gap);
161
162
  --spacing-basalt-rail: var(--basalt-size-rail);
163
+ --spacing-basalt-sidebar-brand-slot: var(--basalt-size-sidebar-brand-slot);
162
164
  --color-basalt-background: hsl(var(--basalt-background));
163
165
  --color-basalt-foreground: hsl(var(--basalt-foreground));
164
166
  --color-basalt-card: hsl(var(--basalt-card));
@@ -277,8 +279,14 @@
277
279
  }
278
280
 
279
281
  .basalt-chart :focus-visible {
280
- outline: 2px solid hsl(var(--basalt-ring));
281
- outline-offset: 2px;
282
+ outline: var(--basalt-focus-width) solid hsl(var(--basalt-ring));
283
+ outline-offset: var(--basalt-focus-offset);
284
+ }
285
+
286
+ @media (forced-colors: active) {
287
+ .basalt-chart :focus-visible {
288
+ outline: 2px solid Highlight;
289
+ }
282
290
  }
283
291
 
284
292
  @utility duration-basalt-normal {
@@ -4,6 +4,9 @@
4
4
  --basalt-space-md: 0.375rem;
5
5
  --basalt-space-lg: 0.5rem;
6
6
  --basalt-space-default: var(--basalt-space-lg);
7
+ --basalt-focus-width: 0.0625rem;
8
+ --basalt-focus-offset: 0.125rem;
9
+ --basalt-focus-clearance: var(--basalt-space-sm);
7
10
  --basalt-text-xs: 0.75rem;
8
11
  --basalt-text-sm: 0.75rem;
9
12
  --basalt-text-code: 0.875rem;
@@ -122,8 +125,14 @@
122
125
  );
123
126
  --basalt-size-action: var(--basalt-size-control);
124
127
  --basalt-space-nav-inset: var(--basalt-space-lg);
125
- --basalt-space-nav-gap: var(--basalt-space-xs);
128
+ --basalt-space-sidebar-inset: var(--basalt-space-layout);
129
+ --basalt-space-nav-gap: var(--basalt-space-sm);
126
130
  --basalt-size-rail: 4.25rem;
131
+ --basalt-size-sidebar-brand-slot: calc(
132
+ var(--basalt-size-rail) -
133
+ 2 *
134
+ var(--basalt-space-layout-lg)
135
+ );
127
136
  }
128
137
 
129
138
  :root,
@@ -569,6 +578,38 @@
569
578
  min-block-size: calc(1lh + 2 * var(--basalt-space-control-y) + 2 * var(--basalt-border-width));
570
579
  padding-inline: var(--basalt-space-sm);
571
580
  }
581
+ .basalt-action-icon-sm {
582
+ inline-size: var(--basalt-size-control-sm);
583
+ max-inline-size: var(--basalt-size-control-sm);
584
+ min-inline-size: var(--basalt-size-control-sm);
585
+ block-size: var(--basalt-size-control-sm);
586
+ max-block-size: var(--basalt-size-control-sm);
587
+ min-block-size: var(--basalt-size-control-sm);
588
+ padding: 0;
589
+ }
590
+ .basalt-nav-list {
591
+ padding: var(--basalt-space-nav-inset);
592
+ }
593
+ .basalt-sidebar-nav {
594
+ padding-inline: var(--basalt-space-sidebar-inset);
595
+ }
596
+ .basalt-sidebar-brand-action {
597
+ flex-shrink: 0;
598
+ margin-inline-end: calc(-1 * var(--basalt-space-md));
599
+ }
600
+ .p-basalt-nav-inset {
601
+ padding: var(--basalt-space-nav-inset);
602
+ }
603
+ .px-basalt-nav-inset {
604
+ padding-inline: var(--basalt-space-nav-inset);
605
+ }
606
+ .px-basalt-sidebar-inset {
607
+ padding-inline: var(--basalt-space-sidebar-inset);
608
+ }
609
+ .size-basalt-sidebar-brand-slot {
610
+ inline-size: var(--basalt-size-sidebar-brand-slot);
611
+ block-size: var(--basalt-size-sidebar-brand-slot);
612
+ }
572
613
  .basalt-action-inset {
573
614
  border-width: 0;
574
615
  min-block-size: calc(1lh + 2 * var(--basalt-space-control-y));
@@ -622,15 +663,22 @@
622
663
  pointer-events: none;
623
664
  opacity: 0.5;
624
665
  }
625
- [data-basalt-sidebar][data-collapsed]
626
- :is([data-slot="sidebar-header"], [data-slot="sidebar-footer"]) {
627
- justify-content: center;
628
- }
629
666
  [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-footer"] {
630
667
  align-items: center;
631
668
  }
632
- [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-nav"] .basalt-nav-item {
633
- margin-inline: auto;
669
+ [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-nav"] {
670
+ padding-inline: calc((var(--basalt-size-rail) - var(--basalt-size-control)) / 2);
671
+ padding-block-start: calc(var(--basalt-size-control-sm) + var(--basalt-space-lg));
672
+ }
673
+ [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-brand-action"] {
674
+ position: absolute;
675
+ inset-block-start: 100%;
676
+ inset-inline-start: calc(
677
+ (var(--basalt-size-sidebar-brand-slot) - var(--basalt-size-control-sm)) /
678
+ 2
679
+ );
680
+ z-index: 1;
681
+ margin: 0;
634
682
  }
635
683
  @media (prefers-reduced-motion: reduce) {
636
684
  .basalt-nav-item {
package/dist/utils/cn.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { clsx as e } from "clsx";
3
3
  import { extendTailwindMerge as t } from "tailwind-merge";
4
- //#region src/utils/cn.ts
4
+ // src/utils/cn.ts
5
5
  var n = t({ extend: { theme: {
6
6
  spacing: [(e) => e.startsWith("basalt-")],
7
7
  radius: [(e) => e.startsWith("basalt-")],
@@ -26,7 +26,6 @@ var n = t({ extend: { theme: {
26
26
  function r(...t) {
27
27
  return n(e(t));
28
28
  }
29
- //#endregion
30
29
  export { r as cn };
31
30
 
32
31
  //# sourceMappingURL=cn.js.map
@@ -1,11 +1,10 @@
1
1
  "use client";
2
2
  import { cn as e } from "./cn.js";
3
- //#region src/utils/control-surface.ts
3
+ // src/utils/control-surface.ts
4
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
  }
8
- //#endregion
9
8
  export { t as BASALT_UI_CLASS, n as CONTROL_SURFACE_CLASS, r as controlSurfaceClass };
10
9
 
11
10
  //# sourceMappingURL=control-surface.js.map
@@ -1,3 +1,3 @@
1
- export declare const NAV_LIST_CLASS = "basalt-ui basalt-hover-list flex gap-basalt-nav-gap p-basalt-nav-inset";
1
+ export declare const NAV_LIST_CLASS = "basalt-ui basalt-hover-list basalt-nav-list flex gap-basalt-nav-gap";
2
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";
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 basalt-focus basalt-focus-inset";
@@ -1,8 +1,7 @@
1
1
  "use client";
2
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
3
+ // src/utils/navigation.ts
4
+ var t = "basalt-ui basalt-hover-list basalt-nav-list flex gap-basalt-nav-gap", 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}`;
6
5
  export { r as NAV_ITEM_CLASS, t as NAV_LIST_CLASS, n as NAV_ROW_CLASS };
7
6
 
8
7
  //# sourceMappingURL=navigation.js.map
@@ -1 +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"}
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 = \"basalt-ui basalt-hover-list basalt-nav-list flex gap-basalt-nav-gap\";\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,IAAiB,uEAEjBC,IACZ,uOAEYC,IAAiB,6BAA6BD,EAAc,GAAGE"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- //#region src/utils/preference-store.ts
2
+ // src/utils/preference-store.ts
3
3
  function e(e) {
4
4
  try {
5
5
  return typeof window > "u" || !window.localStorage ? { status: "error" } : {
@@ -100,7 +100,6 @@ function r({ storageKey: r, defaultValue: i, persist: a, isValid: o, normalize:
100
100
  }
101
101
  };
102
102
  }
103
- //#endregion
104
103
  export { r as createPreferenceStore };
105
104
 
106
105
  //# sourceMappingURL=preference-store.js.map
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import * as e from "react";
3
- //#region src/utils/selection-indicator.ts
3
+ // src/utils/selection-indicator.ts
4
4
  var t = "basalt-selection-motion", n = {
5
5
  left: 0,
6
6
  width: 0,
@@ -79,7 +79,6 @@ function a({ itemSelector: a, enabled: o = !0, mapGeometry: s, ref: c }) {
79
79
  motionClassName: d.animated ? t : void 0
80
80
  };
81
81
  }
82
- //#endregion
83
82
  export { t as SELECTION_INDICATOR_MOTION_CLASS, r as assignRef, i as measureSelectionItem, a as useSelectionIndicator };
84
83
 
85
84
  //# sourceMappingURL=selection-indicator.js.map
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import * as e from "react";
3
- //#region src/utils/use-checkable-group.ts
3
+ // src/utils/use-checkable-group.ts
4
4
  function t({ value: t, defaultValue: n, onValueChange: r, error: i, describedBy: a, ariaInvalid: o, form: s, ref: c }) {
5
5
  let l = e.useId(), u = e.useRef(null), [d, f] = e.useState(n ?? []), p = t ?? d, m = !!i, h = `${l}-error`, g = [m ? h : null, a].filter(Boolean).join(" ") || void 0, _ = e.useRef(null), v = e.useCallback((e) => {
6
6
  let n = _.current;
@@ -55,7 +55,6 @@ function t({ value: t, defaultValue: n, onValueChange: r, error: i, describedBy:
55
55
  ariaInvalid: m ? !0 : o
56
56
  };
57
57
  }
58
- //#endregion
59
58
  export { t as useCheckableGroup };
60
59
 
61
60
  //# sourceMappingURL=use-checkable-group.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { assignRef as e } from "./selection-indicator.js";
3
3
  import { useCallback as t } from "react";
4
- //#region src/utils/use-hover-highlight.ts
4
+ // src/utils/use-hover-highlight.ts
5
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
6
  function i(i, { restoreOnPointerLeave: a = !0 } = {}) {
7
7
  return t((t) => {
@@ -40,7 +40,7 @@ function i(i, { restoreOnPointerLeave: a = !0 } = {}) {
40
40
  if (e.pointerType === "touch") return;
41
41
  s = !1;
42
42
  let t = v(e.target);
43
- t !== o && (!a && (!t || !o) && (c = !0), o = t, x());
43
+ t !== o && (a || t && o || (c = !0), o = t, x());
44
44
  }, C = () => {
45
45
  o = null, s = !a, a || (c = !0), x();
46
46
  }, w = (e) => {
@@ -76,7 +76,6 @@ function i(i, { restoreOnPointerLeave: a = !0 } = {}) {
76
76
  };
77
77
  }, [i, a]);
78
78
  }
79
- //#endregion
80
79
  export { i as useHoverHighlight };
81
80
 
82
81
  //# sourceMappingURL=use-hover-highlight.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-hover-highlight.js","names":["ROW","ACTIVE","useHoverHighlight","useCallback","assignRef","ref","root","hovered","pointerExited","sequenceBroken","focused","previous","selected","active","selectionDirty","frame","geometry","layoutChanged","eligible","node","row","target","resize","schedule","update","broken","item","restoreOnPointerLeave","width","height","y","next","over","event","leave","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 sequenceBroken = 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 broken = sequenceBroken;\n\t\t\t\tsequenceBroken = false;\n\t\t\t\tif (broken) root.dataset.hoverAnimated = \"false\";\n\t\t\t\tconst item = pointerExited\n\t\t\t\t\t? null\n\t\t\t\t\t: restoreOnPointerLeave\n\t\t\t\t\t\t? (eligible(active) ?? eligible(hovered) ?? eligible(focused) ?? eligible(selected))\n\t\t\t\t\t\t: eligible(hovered);\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 (!restoreOnPointerLeave) root.dataset.hoverAnimated = \"false\";\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 && !broken ? \"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\tif (!restoreOnPointerLeave && (!next || !hovered)) sequenceBroken = true;\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\tif (!restoreOnPointerLeave) sequenceBroken = true;\n\t\t\t\tschedule();\n\t\t\t};\n\t\t\tconst focus = (event: FocusEvent) => {\n\t\t\t\tfocused = row(event.target);\n\t\t\t\tif (!restoreOnPointerLeave) return;\n\t\t\t\tpointerExited = false;\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\tif (!restoreOnPointerLeave) return;\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\tif (!restoreOnPointerLeave) return;\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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"}
1
+ {"version":3,"file":"use-hover-highlight.js","names":["ROW","ACTIVE","useHoverHighlight","useCallback","assignRef","ref","root","hovered","pointerExited","sequenceBroken","focused","previous","selected","active","selectionDirty","frame","geometry","layoutChanged","eligible","node","row","target","resize","schedule","update","broken","item","restoreOnPointerLeave","width","height","y","next","over","event","leave","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 sequenceBroken = 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 broken = sequenceBroken;\n\t\t\t\tsequenceBroken = false;\n\t\t\t\tif (broken) root.dataset.hoverAnimated = \"false\";\n\t\t\t\tconst item = pointerExited\n\t\t\t\t\t? null\n\t\t\t\t\t: restoreOnPointerLeave\n\t\t\t\t\t\t? (eligible(active) ?? eligible(hovered) ?? eligible(focused) ?? eligible(selected))\n\t\t\t\t\t\t: eligible(hovered);\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 (!restoreOnPointerLeave) root.dataset.hoverAnimated = \"false\";\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 && !broken ? \"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\tif (!restoreOnPointerLeave && (!next || !hovered)) sequenceBroken = true;\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\tif (!restoreOnPointerLeave) sequenceBroken = true;\n\t\t\t\tschedule();\n\t\t\t};\n\t\t\tconst focus = (event: FocusEvent) => {\n\t\t\t\tfocused = row(event.target);\n\t\t\t\tif (!restoreOnPointerLeave) return;\n\t\t\t\tpointerExited = false;\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\tif (!restoreOnPointerLeave) return;\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\tif (!restoreOnPointerLeave) return;\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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"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { approvalSnapshot as e, validApprovalAnswer as t } from "../models/agent-feedback.js";
3
3
  import { useEffect as n, useRef as r, useState as i } from "react";
4
- //#region src/viewmodels/use-approval-card.ts
4
+ // src/viewmodels/use-approval-card.ts
5
5
  function a({ questions: a, onSubmit: o, autoAdvance: s = !0 }) {
6
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
7
  clearTimeout(b.current), b.current = void 0;
@@ -28,17 +28,16 @@ function a({ questions: a, onSubmit: o, autoAdvance: s = !0 }) {
28
28
  }, A = async (n) => {
29
29
  if (v.current || a.length === 0) return;
30
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;
31
+ if (r >= 0) D(r);
32
+ else {
33
+ v.current = !0, h("submitting"), _(""), x();
34
+ try {
35
+ await o(e(a, n)), y.current && h("submitted");
36
+ } catch (e) {
37
+ y.current && (_(e instanceof Error ? e.message : "Could not submit answers. Try again."), h("editing"));
38
+ } finally {
39
+ v.current = !1;
40
+ }
42
41
  }
43
42
  };
44
43
  return {
@@ -77,7 +76,6 @@ function a({ questions: a, onSubmit: o, autoAdvance: s = !0 }) {
77
76
  }
78
77
  };
79
78
  }
80
- //#endregion
81
79
  export { a as useApprovalCardViewModel };
82
80
 
83
81
  //# sourceMappingURL=use-approval-card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-approval-card.js","names":["useApprovalCardViewModel","index","setIndex","useState","focusToken","setFocusToken","answers","setAnswers","status","setStatus","error","setError","locked","useRef","mounted","advanceTimer","cancelAdvance","position","questions","question","answer","last","canContinue","validApprovalAnswer","show","next","token","move","choose","option","id","selected","value","autoAdvance","submit","missing","item","nextAnswers","onSubmit","approvalSnapshot","reason"],"sources":["../../src/viewmodels/use-approval-card.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n\ttype ApprovalAnswers,\n\ttype ApprovalQuestion,\n\tapprovalSnapshot,\n\tvalidApprovalAnswer,\n} from \"../models/agent-feedback\";\n\nexport function useApprovalCardViewModel({\n\tquestions,\n\tonSubmit,\n\tautoAdvance = true,\n}: {\n\tquestions: readonly ApprovalQuestion[];\n\tonSubmit: (answers: ApprovalAnswers) => void | Promise<void>;\n\tautoAdvance?: boolean;\n}) {\n\tconst [index, setIndex] = useState(0);\n\tconst [focusToken, setFocusToken] = useState(0);\n\tconst [answers, setAnswers] = useState<ApprovalAnswers>({});\n\tconst [status, setStatus] = useState<\"editing\" | \"submitting\" | \"submitted\">(\"editing\");\n\tconst [error, setError] = useState(\"\");\n\tconst locked = useRef(false);\n\tconst mounted = useRef(true);\n\tconst advanceTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\tconst cancelAdvance = () => {\n\t\tclearTimeout(advanceTimer.current);\n\t\tadvanceTimer.current = undefined;\n\t};\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t\tclearTimeout(advanceTimer.current);\n\t\t};\n\t}, []);\n\tconst position = Math.min(index, Math.max(0, questions.length - 1));\n\tconst question = questions[position];\n\tconst answer = question ? answers[question.id] : undefined;\n\tconst last = position === questions.length - 1;\n\tconst canContinue = Boolean(question && validApprovalAnswer(question, answer));\n\t/** Every programmatic question change asks the view to keep focus inside the card. */\n\tconst show = (next: number) => {\n\t\tsetIndex(next);\n\t\tsetFocusToken((token) => token + 1);\n\t};\n\tconst move = (next: number) => {\n\t\tif (locked.current || questions.length === 0) return;\n\t\tcancelAdvance();\n\t\tshow(Math.min(Math.max(0, next), questions.length - 1));\n\t\tsetError(\"\");\n\t};\n\tconst choose = (id: string) => {\n\t\tif (\n\t\t\t!question ||\n\t\t\tlocked.current ||\n\t\t\t!question.options.some((option) => option.id === id && !option.disabled)\n\t\t)\n\t\t\treturn;\n\t\tcancelAdvance();\n\t\tconst selected = answer?.selected ?? [];\n\t\tsetAnswers({\n\t\t\t...answers,\n\t\t\t[question.id]: {\n\t\t\t\t...answer,\n\t\t\t\tskipped: false,\n\t\t\t\tselected:\n\t\t\t\t\tquestion.type === \"single\"\n\t\t\t\t\t\t? [id]\n\t\t\t\t\t\t: selected.includes(id)\n\t\t\t\t\t\t\t? selected.filter((value) => value !== id)\n\t\t\t\t\t\t\t: [...selected, id],\n\t\t\t},\n\t\t});\n\t\tsetError(\"\");\n\t\tif (question.type === \"single\" && autoAdvance && !last)\n\t\t\tadvanceTimer.current = setTimeout(() => show(position + 1), 240);\n\t};\n\tconst submit = async (nextAnswers: ApprovalAnswers) => {\n\t\tif (locked.current || questions.length === 0) return;\n\t\tconst missing = questions.findIndex((item) => !validApprovalAnswer(item, nextAnswers[item.id]));\n\t\tif (missing >= 0) {\n\t\t\tshow(missing);\n\t\t\treturn;\n\t\t}\n\t\tlocked.current = true;\n\t\tsetStatus(\"submitting\");\n\t\tsetError(\"\");\n\t\tcancelAdvance();\n\t\ttry {\n\t\t\tawait onSubmit(approvalSnapshot(questions, nextAnswers));\n\t\t\tif (mounted.current) setStatus(\"submitted\");\n\t\t} catch (reason) {\n\t\t\tif (mounted.current) {\n\t\t\t\tsetError(reason instanceof Error ? reason.message : \"Could not submit answers. Try again.\");\n\t\t\t\tsetStatus(\"editing\");\n\t\t\t}\n\t\t} finally {\n\t\t\tlocked.current = false;\n\t\t}\n\t};\n\treturn {\n\t\tposition,\n\t\tfocusToken,\n\t\tquestion,\n\t\tanswer,\n\t\tstatus,\n\t\terror,\n\t\tcanContinue,\n\t\tlast,\n\t\tchoose,\n\t\tmove,\n\t\tsetCustom(value: string) {\n\t\t\tif (!question?.allowCustom || locked.current) return;\n\t\t\tcancelAdvance();\n\t\t\tsetAnswers({\n\t\t\t\t...answers,\n\t\t\t\t[question.id]: { selected: answer?.selected ?? [], custom: value },\n\t\t\t});\n\t\t},\n\t\tcontinue() {\n\t\t\tif (!canContinue || locked.current) return;\n\t\t\tif (last) void submit(answers);\n\t\t\telse move(position + 1);\n\t\t},\n\t\tskip() {\n\t\t\tif (question?.required !== false || locked.current) return;\n\t\t\tconst next = { ...answers, [question.id]: { selected: [], skipped: true } };\n\t\t\tsetAnswers(next);\n\t\t\tif (last) void submit(next);\n\t\t\telse move(position + 1);\n\t\t},\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-approval-card.js","names":["useApprovalCardViewModel","index","setIndex","useState","focusToken","setFocusToken","answers","setAnswers","status","setStatus","error","setError","locked","useRef","mounted","advanceTimer","cancelAdvance","position","questions","question","answer","last","canContinue","validApprovalAnswer","show","next","token","move","choose","option","id","selected","value","autoAdvance","submit","missing","item","nextAnswers","onSubmit","approvalSnapshot","reason"],"sources":["../../src/viewmodels/use-approval-card.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n\ttype ApprovalAnswers,\n\ttype ApprovalQuestion,\n\tapprovalSnapshot,\n\tvalidApprovalAnswer,\n} from \"../models/agent-feedback\";\n\nexport function useApprovalCardViewModel({\n\tquestions,\n\tonSubmit,\n\tautoAdvance = true,\n}: {\n\tquestions: readonly ApprovalQuestion[];\n\tonSubmit: (answers: ApprovalAnswers) => void | Promise<void>;\n\tautoAdvance?: boolean;\n}) {\n\tconst [index, setIndex] = useState(0);\n\tconst [focusToken, setFocusToken] = useState(0);\n\tconst [answers, setAnswers] = useState<ApprovalAnswers>({});\n\tconst [status, setStatus] = useState<\"editing\" | \"submitting\" | \"submitted\">(\"editing\");\n\tconst [error, setError] = useState(\"\");\n\tconst locked = useRef(false);\n\tconst mounted = useRef(true);\n\tconst advanceTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\tconst cancelAdvance = () => {\n\t\tclearTimeout(advanceTimer.current);\n\t\tadvanceTimer.current = undefined;\n\t};\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t\tclearTimeout(advanceTimer.current);\n\t\t};\n\t}, []);\n\tconst position = Math.min(index, Math.max(0, questions.length - 1));\n\tconst question = questions[position];\n\tconst answer = question ? answers[question.id] : undefined;\n\tconst last = position === questions.length - 1;\n\tconst canContinue = Boolean(question && validApprovalAnswer(question, answer));\n\t/** Every programmatic question change asks the view to keep focus inside the card. */\n\tconst show = (next: number) => {\n\t\tsetIndex(next);\n\t\tsetFocusToken((token) => token + 1);\n\t};\n\tconst move = (next: number) => {\n\t\tif (locked.current || questions.length === 0) return;\n\t\tcancelAdvance();\n\t\tshow(Math.min(Math.max(0, next), questions.length - 1));\n\t\tsetError(\"\");\n\t};\n\tconst choose = (id: string) => {\n\t\tif (\n\t\t\t!question ||\n\t\t\tlocked.current ||\n\t\t\t!question.options.some((option) => option.id === id && !option.disabled)\n\t\t)\n\t\t\treturn;\n\t\tcancelAdvance();\n\t\tconst selected = answer?.selected ?? [];\n\t\tsetAnswers({\n\t\t\t...answers,\n\t\t\t[question.id]: {\n\t\t\t\t...answer,\n\t\t\t\tskipped: false,\n\t\t\t\tselected:\n\t\t\t\t\tquestion.type === \"single\"\n\t\t\t\t\t\t? [id]\n\t\t\t\t\t\t: selected.includes(id)\n\t\t\t\t\t\t\t? selected.filter((value) => value !== id)\n\t\t\t\t\t\t\t: [...selected, id],\n\t\t\t},\n\t\t});\n\t\tsetError(\"\");\n\t\tif (question.type === \"single\" && autoAdvance && !last)\n\t\t\tadvanceTimer.current = setTimeout(() => show(position + 1), 240);\n\t};\n\tconst submit = async (nextAnswers: ApprovalAnswers) => {\n\t\tif (locked.current || questions.length === 0) return;\n\t\tconst missing = questions.findIndex((item) => !validApprovalAnswer(item, nextAnswers[item.id]));\n\t\tif (missing >= 0) {\n\t\t\tshow(missing);\n\t\t\treturn;\n\t\t}\n\t\tlocked.current = true;\n\t\tsetStatus(\"submitting\");\n\t\tsetError(\"\");\n\t\tcancelAdvance();\n\t\ttry {\n\t\t\tawait onSubmit(approvalSnapshot(questions, nextAnswers));\n\t\t\tif (mounted.current) setStatus(\"submitted\");\n\t\t} catch (reason) {\n\t\t\tif (mounted.current) {\n\t\t\t\tsetError(reason instanceof Error ? reason.message : \"Could not submit answers. Try again.\");\n\t\t\t\tsetStatus(\"editing\");\n\t\t\t}\n\t\t} finally {\n\t\t\tlocked.current = false;\n\t\t}\n\t};\n\treturn {\n\t\tposition,\n\t\tfocusToken,\n\t\tquestion,\n\t\tanswer,\n\t\tstatus,\n\t\terror,\n\t\tcanContinue,\n\t\tlast,\n\t\tchoose,\n\t\tmove,\n\t\tsetCustom(value: string) {\n\t\t\tif (!question?.allowCustom || locked.current) return;\n\t\t\tcancelAdvance();\n\t\t\tsetAnswers({\n\t\t\t\t...answers,\n\t\t\t\t[question.id]: { selected: answer?.selected ?? [], custom: value },\n\t\t\t});\n\t\t},\n\t\tcontinue() {\n\t\t\tif (!canContinue || locked.current) return;\n\t\t\tif (last) void submit(answers);\n\t\t\telse move(position + 1);\n\t\t},\n\t\tskip() {\n\t\t\tif (question?.required !== false || locked.current) return;\n\t\t\tconst next = { ...answers, [question.id]: { selected: [], skipped: true } };\n\t\t\tsetAnswers(next);\n\t\t\tif (last) void submit(next);\n\t\t\telse move(position + 1);\n\t\t},\n\t};\n}\n"],"mappings":";;;;AAQA,SAAgBA,EAAyB,EACxC,cACA,aACA,iBAAc,MAKZ;CACF,IAAM,CAACC,GAAOC,KAAYC,EAAS,CAAC,GAC9B,CAACC,GAAYC,KAAiBF,EAAS,CAAC,GACxC,CAACG,GAASC,KAAcJ,EAA0B,CAAC,CAAC,GACpD,CAACK,GAAQC,KAAaN,EAAiD,SAAS,GAChF,CAACO,GAAOC,KAAYR,EAAS,EAAE,GAC/BS,IAASC,EAAO,EAAK,GACrBC,IAAUD,EAAO,EAAI,GACrBE,IAAeF,EAAkD,KAAA,CAAS,GAC1EG,UAAsB;EAE3B,AADA,aAAaD,EAAa,OAAO,GACjC,EAAa,UAAU,KAAA;CACxB;CACA,SACC,EAAQ,UAAU,UACL;EAEZ,AADA,EAAQ,UAAU,IAClB,aAAaA,EAAa,OAAO;CAClC,IACE,CAAC,CAAC;CACL,IAAME,IAAW,KAAK,IAAIhB,GAAO,KAAK,IAAI,GAAGiB,EAAU,SAAS,CAAC,CAAC,GAC5DC,IAAWD,EAAUD,IACrBG,IAASD,IAAWb,EAAQa,EAAS,MAAM,KAAA,GAC3CE,IAAOJ,MAAaC,EAAU,SAAS,GACvCI,IAAc,GAAQH,KAAYI,EAAoBJ,GAAUC,CAAM,IAEtEI,KAAQ,MAAiB;EAE9B,AADAtB,EAASuB,CAAI,GACbpB,GAAe,MAAUqB,IAAQ,CAAC;CACnC,GACMC,KAAQ,MAAiB;EAC9B,AAAIf,EAAO,WAAWM,EAAU,WAAW,MAC3CF,EAAc,GACdQ,EAAK,KAAK,IAAI,KAAK,IAAI,GAAGC,CAAI,GAAGP,EAAU,SAAS,CAAC,CAAC,GACtDP,EAAS,EAAE;CACZ,GACMiB,KAAU,MAAe;EAC9B,IACC,CAACT,KACDP,EAAO,WACP,CAACO,EAAS,QAAQ,MAAM,MAAWU,EAAO,OAAOC,KAAM,CAACD,EAAO,QAAQ,GAEvE;EACD,EAAc;EACd,IAAME,IAAWX,GAAQ,YAAY,CAAC;EAetC,AAdAb,EAAW;GACV,GAAGD;IACFa,EAAS,KAAK;IACd,GAAGC;IACH,SAAS;IACT,UACCD,EAAS,SAAS,WACf,CAACW,CAAE,IACHC,EAAS,SAASD,CAAE,IACnBC,EAAS,QAAQ,MAAUC,MAAUF,CAAE,IACvC,CAAC,GAAGC,GAAUD,CAAE;GACtB;EACD,CAAC,GACDnB,EAAS,EAAE,GACPQ,EAAS,SAAS,YAAYc,KAAe,CAACZ,MACjD,EAAa,UAAU,iBAAiBG,EAAKP,IAAW,CAAC,GAAG,GAAG;CACjE,GACMiB,IAAS,OAAO,MAAiC;EACtD,IAAItB,EAAO,WAAWM,EAAU,WAAW,GAAG;EAC9C,IAAMiB,IAAUjB,EAAU,WAAW,MAAS,CAACK,EAAoBa,GAAMC,EAAYD,EAAK,GAAG,CAAC;EAC9F,IAAID,KAAW,GACd,EAAKA,CAAO;OAGb;GAGA,AAHA,EAAO,UAAU,IACjB1B,EAAU,YAAY,GACtBE,EAAS,EAAE,GACXK,EAAc;GACd,IAAI;IAEH,AADA,MAAMsB,EAASC,EAAiBrB,GAAWmB,CAAW,CAAC,GACnDvB,EAAQ,WAASL,EAAU,WAAW;GAC3C,SAAS+B,GAAQ;IAChB,AAAI1B,EAAQ,YACXH,EAAS6B,aAAkB,QAAQA,EAAO,UAAU,sCAAsC,GAC1F/B,EAAU,SAAS;GAErB,UAAU;IACT,EAAO,UAAU;GAClB;EAdiB;CAelB;CACA,OAAO;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,UAAU,GAAe;GACxB,AAAKU,GAAU,eAAe,GAAO,YACrCH,EAAc,GACdT,EAAW;IACV,GAAGD;KACFa,EAAS,KAAK;KAAE,UAAUC,GAAQ,YAAY,CAAC;KAAG,QAAQY;IAAM;GAClE,CAAC;EACF;EACA,WAAW;GACV,AAAKV,KAAe,GAAO,YACvBD,IAAMa,EAAY5B,CAAO,IACxBqB,EAAKV,IAAW,CAAC;EACvB;EACA,OAAO;GACN,IAAIE,GAAU,aAAa,MAASP,EAAO,SAAS;GACpD,IAAMa,IAAO;IAAE,GAAGnB;KAAUa,EAAS,KAAK;KAAE,UAAU,CAAC;KAAG,SAAS;IAAK;GAAE;GAE1E,AADAZ,EAAWkB,CAAI,GACXJ,IAAMa,EAAYT,CAAI,IACrBE,EAAKV,IAAW,CAAC;EACvB;CACD;AACD"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { useEffect as e, useRef as t, useState as n } from "react";
3
- //#region src/viewmodels/use-chat-composer.ts
3
+ // src/viewmodels/use-chat-composer.ts
4
4
  function r({ value: r, defaultValue: i = "", onValueChange: a, onSend: o, disabled: s, streaming: c, hasAttachments: l }) {
5
5
  let [u, d] = n(i), [f, p] = n(!1), [m, h] = n(""), g = t(!1), _ = t(!0);
6
6
  e(() => (_.current = !0, () => {
@@ -28,7 +28,6 @@ function r({ value: r, defaultValue: i = "", onValueChange: a, onSend: o, disabl
28
28
  }
29
29
  };
30
30
  }
31
- //#endregion
32
31
  export { r as useChatComposer };
33
32
 
34
33
  //# sourceMappingURL=use-chat-composer.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { contextSourceHref as e } from "../models/context-cards.js";
3
3
  import { useState as t } from "react";
4
- //#region src/viewmodels/use-chat-message.ts
4
+ // src/viewmodels/use-chat-message.ts
5
5
  function n(n, r) {
6
6
  let [i, a] = t(null), [o, s] = t(null);
7
7
  return {
@@ -20,7 +20,6 @@ function n(n, r) {
20
20
  }
21
21
  };
22
22
  }
23
- //#endregion
24
23
  export { n as useChatMessage };
25
24
 
26
25
  //# sourceMappingURL=use-chat-message.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { codeLines as e } from "../models/code.js";
3
3
  import { useEffect as t, useMemo as n, useRef as r, useState as i } from "react";
4
- //#region src/viewmodels/use-code-block.ts
4
+ // src/viewmodels/use-code-block.ts
5
5
  function a(a, o) {
6
6
  let s = n(() => e(a, o), [a, o]), [c, l] = i(null), u = r(!1), d = r(!0);
7
7
  return t(() => (d.current = !0, () => {
@@ -32,7 +32,6 @@ function a(a, o) {
32
32
  }
33
33
  };
34
34
  }
35
- //#endregion
36
35
  export { a as useCodeBlock };
37
36
 
38
37
  //# sourceMappingURL=use-code-block.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-code-block.js","names":["useCodeBlock","lines","useMemo","codeLines","code","highlighted","feedback","setFeedback","useState","locked","useRef","mounted","useEffect","write"],"sources":["../../src/viewmodels/use-code-block.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { codeLines } from \"../models/code\";\n\nexport function useCodeBlock(code: string, highlighted: boolean) {\n\tconst lines = useMemo(() => codeLines(code, highlighted), [code, highlighted]);\n\tconst [feedback, setFeedback] = useState<{\n\t\tcode: string;\n\t\tstatus: \"pending\" | \"copied\" | \"error\";\n\t} | null>(null);\n\tconst locked = useRef(false);\n\tconst mounted = useRef(true);\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t};\n\t}, []);\n\treturn {\n\t\tlines,\n\t\tstatus: feedback?.code === code ? feedback.status : \"idle\",\n\t\tasync copy(write: (text: string) => Promise<void>) {\n\t\t\tif (locked.current) return;\n\t\t\tlocked.current = true;\n\t\t\tsetFeedback({ code, status: \"pending\" });\n\t\t\ttry {\n\t\t\t\tawait write(code);\n\t\t\t\tif (mounted.current) setFeedback({ code, status: \"copied\" });\n\t\t\t} catch {\n\t\t\t\tif (mounted.current) setFeedback({ code, status: \"error\" });\n\t\t\t} finally {\n\t\t\t\tlocked.current = false;\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":";;;;AAGA,SAAgBA,EAAa,GAAc,GAAsB;CAChE,IAAMC,IAAQC,QAAcC,EAAUC,GAAMC,CAAW,GAAG,CAACD,GAAMC,CAAW,CAAC,GACvE,CAACC,GAAUC,KAAeC,EAGtB,IAAI,GACRC,IAASC,EAAO,EAAK,GACrBC,IAAUD,EAAO,EAAI;CAO3B,OANAE,SACC,EAAQ,UAAU,UACL;EACZ,EAAQ,UAAU;CACnB,IACE,CAAC,CAAC,GACE;EACN;EACA,QAAQN,GAAU,SAASF,IAAOE,EAAS,SAAS;EACpD,MAAM,KAAK,GAAwC;GAClD,IAAI,GAAO,SAEX;IADA,EAAO,UAAU,IACjBC,EAAY;KAAE;KAAM,QAAQ;IAAU,CAAC;IACvC,IAAI;KAEH,AADA,MAAMM,EAAMT,CAAI,GACZO,EAAQ,WAASJ,EAAY;MAAE;MAAM,QAAQ;KAAS,CAAC;IAC5D,QAAQ;KACP,AAAII,EAAQ,WAASJ,EAAY;MAAE;MAAM,QAAQ;KAAQ,CAAC;IAC3D,UAAU;KACT,EAAO,UAAU;IAClB;GARuC;EASxC;CACD;AACD"}
1
+ {"version":3,"file":"use-code-block.js","names":["useCodeBlock","lines","useMemo","codeLines","code","highlighted","feedback","setFeedback","useState","locked","useRef","mounted","useEffect","write"],"sources":["../../src/viewmodels/use-code-block.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { codeLines } from \"../models/code\";\n\nexport function useCodeBlock(code: string, highlighted: boolean) {\n\tconst lines = useMemo(() => codeLines(code, highlighted), [code, highlighted]);\n\tconst [feedback, setFeedback] = useState<{\n\t\tcode: string;\n\t\tstatus: \"pending\" | \"copied\" | \"error\";\n\t} | null>(null);\n\tconst locked = useRef(false);\n\tconst mounted = useRef(true);\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t};\n\t}, []);\n\treturn {\n\t\tlines,\n\t\tstatus: feedback?.code === code ? feedback.status : \"idle\",\n\t\tasync copy(write: (text: string) => Promise<void>) {\n\t\t\tif (locked.current) return;\n\t\t\tlocked.current = true;\n\t\t\tsetFeedback({ code, status: \"pending\" });\n\t\t\ttry {\n\t\t\t\tawait write(code);\n\t\t\t\tif (mounted.current) setFeedback({ code, status: \"copied\" });\n\t\t\t} catch {\n\t\t\t\tif (mounted.current) setFeedback({ code, status: \"error\" });\n\t\t\t} finally {\n\t\t\t\tlocked.current = false;\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":";;;;AAGA,SAAgBA,EAAa,GAAc,GAAsB;CAChE,IAAMC,IAAQC,QAAcC,EAAUC,GAAMC,CAAW,GAAG,CAACD,GAAMC,CAAW,CAAC,GACvE,CAACC,GAAUC,KAAeC,EAGtB,IAAI,GACRC,IAASC,EAAO,EAAK,GACrBC,IAAUD,EAAO,EAAI;CAO3B,OANAE,SACC,EAAQ,UAAU,UACL;EACZ,EAAQ,UAAU;CACnB,IACE,CAAC,CAAC,GACE;EACN;EACA,QAAQN,GAAU,SAASF,IAAOE,EAAS,SAAS;EACpD,MAAM,KAAK,GAAwC;GAClD,IAAI,GAAO,SACX;IACA,AADA,EAAO,UAAU,IACjBC,EAAY;KAAE;KAAM,QAAQ;IAAU,CAAC;IACvC,IAAI;KAEH,AADA,MAAMM,EAAMT,CAAI,GACZO,EAAQ,WAASJ,EAAY;MAAE;MAAM,QAAQ;KAAS,CAAC;IAC5D,QAAQ;KACP,AAAII,EAAQ,WAASJ,EAAY;MAAE;MAAM,QAAQ;KAAQ,CAAC;IAC3D,UAAU;KACT,EAAO,UAAU;IAClB;GATiB;EAUlB;CACD;AACD"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { contextSourceHref as e } from "../models/context-cards.js";
3
- //#region src/viewmodels/use-context-cards.ts
3
+ // src/viewmodels/use-context-cards.ts
4
4
  function t(t, n) {
5
5
  return {
6
6
  count: n !== void 0 && Number.isFinite(n) ? Math.max(t.length, Math.floor(n)) : t.length,
@@ -12,7 +12,6 @@ function t(t, n) {
12
12
  }))
13
13
  };
14
14
  }
15
- //#endregion
16
15
  export { t as useContextCardsViewModel };
17
16
 
18
17
  //# sourceMappingURL=use-context-cards.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { selectedDiffRows as e } from "../models/diff-table.js";
3
3
  import { useEffect as t, useRef as n, useState as r } from "react";
4
- //#region src/viewmodels/use-diff-table.ts
4
+ // src/viewmodels/use-diff-table.ts
5
5
  function i({ rows: i, onApply: a, disabled: o = !1 }) {
6
6
  let [s, c] = r([]), [l, u] = r("editing"), [d, f] = r(""), p = n(!1), m = n(!0);
7
7
  t(() => (m.current = !0, () => {
@@ -36,7 +36,6 @@ function i({ rows: i, onApply: a, disabled: o = !1 }) {
36
36
  }
37
37
  };
38
38
  }
39
- //#endregion
40
39
  export { i as useDiffTableViewModel };
41
40
 
42
41
  //# sourceMappingURL=use-diff-table.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-diff-table.js","names":["useDiffTableViewModel","excluded","setExcluded","useState","status","setStatus","error","setError","locked","useRef","mounted","selected","selectedDiffRows","rows","disabled","row","id","current","value","onApply","reason"],"sources":["../../src/viewmodels/use-diff-table.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { type DiffTableRow, selectedDiffRows } from \"../models/diff-table\";\n\nexport function useDiffTableViewModel({\n\trows,\n\tonApply,\n\tdisabled = false,\n}: {\n\trows: readonly DiffTableRow[];\n\tonApply: (changes: readonly DiffTableRow[]) => void | Promise<void>;\n\tdisabled?: boolean;\n}) {\n\tconst [excluded, setExcluded] = useState<string[]>([]);\n\tconst [status, setStatus] = useState<\"editing\" | \"applying\" | \"applied\">(\"editing\");\n\tconst [error, setError] = useState(\"\");\n\tconst locked = useRef(false);\n\tconst mounted = useRef(true);\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t};\n\t}, []);\n\tconst selected = selectedDiffRows(rows, excluded);\n\treturn {\n\t\texcluded,\n\t\tselected,\n\t\tstatus,\n\t\terror,\n\t\tblocked: disabled || status !== \"editing\",\n\t\tadditions: selected.filter((row) => row.change === \"add\").length,\n\t\tremovals: selected.filter((row) => row.change === \"remove\").length,\n\t\ttoggle(id: string) {\n\t\t\tif (\n\t\t\t\tdisabled ||\n\t\t\t\tlocked.current ||\n\t\t\t\tstatus === \"applied\" ||\n\t\t\t\t!rows.some((row) => row.id === id && row.change !== \"unchanged\")\n\t\t\t)\n\t\t\t\treturn;\n\t\t\tsetExcluded((current) =>\n\t\t\t\tcurrent.includes(id) ? current.filter((value) => value !== id) : [...current, id],\n\t\t\t);\n\t\t\tsetError(\"\");\n\t\t},\n\t\tasync apply() {\n\t\t\tif (disabled || locked.current || status === \"applied\" || selected.length === 0) return;\n\t\t\tlocked.current = true;\n\t\t\tsetStatus(\"applying\");\n\t\t\tsetError(\"\");\n\t\t\ttry {\n\t\t\t\tawait onApply(selected.map((row) => ({ ...row, values: { ...row.values } })));\n\t\t\t\tif (mounted.current) setStatus(\"applied\");\n\t\t\t} catch (reason) {\n\t\t\t\tif (mounted.current) {\n\t\t\t\t\tsetError(\n\t\t\t\t\t\treason instanceof Error ? reason.message : \"Could not apply changes. Try again.\",\n\t\t\t\t\t);\n\t\t\t\t\tsetStatus(\"editing\");\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tlocked.current = false;\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":";;;;AAGA,SAAgBA,EAAsB,EACrC,SACA,YACA,cAAW,MAKT;CACF,IAAM,CAACC,GAAUC,KAAeC,EAAmB,CAAC,CAAC,GAC/C,CAACC,GAAQC,KAAaF,EAA6C,SAAS,GAC5E,CAACG,GAAOC,KAAYJ,EAAS,EAAE,GAC/BK,IAASC,EAAO,EAAK,GACrBC,IAAUD,EAAO,EAAI;CAC3B,SACC,EAAQ,UAAU,UACL;EACZ,EAAQ,UAAU;CACnB,IACE,CAAC,CAAC;CACL,IAAME,IAAWC,EAAiBC,GAAMZ,CAAQ;CAChD,OAAO;EACN;EACA;EACA;EACA;EACA,SAASa,KAAYV,MAAW;EAChC,WAAWO,EAAS,QAAQ,MAAQI,EAAI,WAAW,KAAK,CAAC,CAAC;EAC1D,UAAUJ,EAAS,QAAQ,MAAQI,EAAI,WAAW,QAAQ,CAAC,CAAC;EAC5D,OAAO,GAAY;GAClB,AACCD,KACAN,EAAO,WACPJ,MAAW,aACX,CAACS,EAAK,MAAM,MAAQE,EAAI,OAAOC,KAAMD,EAAI,WAAW,WAAW,MAGhEb,GAAa,MACZe,EAAQ,SAASD,CAAE,IAAIC,EAAQ,QAAQ,MAAUC,MAAUF,CAAE,IAAI,CAAC,GAAGC,GAASD,CAAE,CACjF,GACAT,EAAS,EAAE;EACZ;EACA,MAAM,QAAQ;GACb,IAAI,OAAYC,EAAO,WAAWJ,MAAW,aAAaO,EAAS,WAAW,IAG9E;IAFA,EAAO,UAAU,IACjBN,EAAU,UAAU,GACpBE,EAAS,EAAE;IACX,IAAI;KAEH,AADA,MAAMY,EAAQR,EAAS,KAAK,OAAS;MAAE,GAAGI;MAAK,QAAQ,EAAE,GAAGA,EAAI,OAAO;KAAE,EAAE,CAAC,GACxEL,EAAQ,WAASL,EAAU,SAAS;IACzC,SAASe,GAAQ;KAChB,AAAIV,EAAQ,YACXH,EACCa,aAAkB,QAAQA,EAAO,UAAU,qCAC5C,GACAf,EAAU,SAAS;IAErB,UAAU;KACT,EAAO,UAAU;IAClB;GAbW;EAcZ;CACD;AACD"}
1
+ {"version":3,"file":"use-diff-table.js","names":["useDiffTableViewModel","excluded","setExcluded","useState","status","setStatus","error","setError","locked","useRef","mounted","selected","selectedDiffRows","rows","disabled","row","id","current","value","onApply","reason"],"sources":["../../src/viewmodels/use-diff-table.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { type DiffTableRow, selectedDiffRows } from \"../models/diff-table\";\n\nexport function useDiffTableViewModel({\n\trows,\n\tonApply,\n\tdisabled = false,\n}: {\n\trows: readonly DiffTableRow[];\n\tonApply: (changes: readonly DiffTableRow[]) => void | Promise<void>;\n\tdisabled?: boolean;\n}) {\n\tconst [excluded, setExcluded] = useState<string[]>([]);\n\tconst [status, setStatus] = useState<\"editing\" | \"applying\" | \"applied\">(\"editing\");\n\tconst [error, setError] = useState(\"\");\n\tconst locked = useRef(false);\n\tconst mounted = useRef(true);\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t};\n\t}, []);\n\tconst selected = selectedDiffRows(rows, excluded);\n\treturn {\n\t\texcluded,\n\t\tselected,\n\t\tstatus,\n\t\terror,\n\t\tblocked: disabled || status !== \"editing\",\n\t\tadditions: selected.filter((row) => row.change === \"add\").length,\n\t\tremovals: selected.filter((row) => row.change === \"remove\").length,\n\t\ttoggle(id: string) {\n\t\t\tif (\n\t\t\t\tdisabled ||\n\t\t\t\tlocked.current ||\n\t\t\t\tstatus === \"applied\" ||\n\t\t\t\t!rows.some((row) => row.id === id && row.change !== \"unchanged\")\n\t\t\t)\n\t\t\t\treturn;\n\t\t\tsetExcluded((current) =>\n\t\t\t\tcurrent.includes(id) ? current.filter((value) => value !== id) : [...current, id],\n\t\t\t);\n\t\t\tsetError(\"\");\n\t\t},\n\t\tasync apply() {\n\t\t\tif (disabled || locked.current || status === \"applied\" || selected.length === 0) return;\n\t\t\tlocked.current = true;\n\t\t\tsetStatus(\"applying\");\n\t\t\tsetError(\"\");\n\t\t\ttry {\n\t\t\t\tawait onApply(selected.map((row) => ({ ...row, values: { ...row.values } })));\n\t\t\t\tif (mounted.current) setStatus(\"applied\");\n\t\t\t} catch (reason) {\n\t\t\t\tif (mounted.current) {\n\t\t\t\t\tsetError(\n\t\t\t\t\t\treason instanceof Error ? reason.message : \"Could not apply changes. Try again.\",\n\t\t\t\t\t);\n\t\t\t\t\tsetStatus(\"editing\");\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tlocked.current = false;\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":";;;;AAGA,SAAgBA,EAAsB,EACrC,SACA,YACA,cAAW,MAKT;CACF,IAAM,CAACC,GAAUC,KAAeC,EAAmB,CAAC,CAAC,GAC/C,CAACC,GAAQC,KAAaF,EAA6C,SAAS,GAC5E,CAACG,GAAOC,KAAYJ,EAAS,EAAE,GAC/BK,IAASC,EAAO,EAAK,GACrBC,IAAUD,EAAO,EAAI;CAC3B,SACC,EAAQ,UAAU,UACL;EACZ,EAAQ,UAAU;CACnB,IACE,CAAC,CAAC;CACL,IAAME,IAAWC,EAAiBC,GAAMZ,CAAQ;CAChD,OAAO;EACN;EACA;EACA;EACA;EACA,SAASa,KAAYV,MAAW;EAChC,WAAWO,EAAS,QAAQ,MAAQI,EAAI,WAAW,KAAK,CAAC,CAAC;EAC1D,UAAUJ,EAAS,QAAQ,MAAQI,EAAI,WAAW,QAAQ,CAAC,CAAC;EAC5D,OAAO,GAAY;GAClB,AACCD,KACAN,EAAO,WACPJ,MAAW,aACX,CAACS,EAAK,MAAM,MAAQE,EAAI,OAAOC,KAAMD,EAAI,WAAW,WAAW,MAGhEb,GAAa,MACZe,EAAQ,SAASD,CAAE,IAAIC,EAAQ,QAAQ,MAAUC,MAAUF,CAAE,IAAI,CAAC,GAAGC,GAASD,CAAE,CACjF,GACAT,EAAS,EAAE;EACZ;EACA,MAAM,QAAQ;GACb,IAAI,OAAYC,EAAO,WAAWJ,MAAW,aAAaO,EAAS,WAAW,IAC9E;IAEA,AAFA,EAAO,UAAU,IACjBN,EAAU,UAAU,GACpBE,EAAS,EAAE;IACX,IAAI;KAEH,AADA,MAAMY,EAAQR,EAAS,KAAK,OAAS;MAAE,GAAGI;MAAK,QAAQ,EAAE,GAAGA,EAAI,OAAO;KAAE,EAAE,CAAC,GACxEL,EAAQ,WAASL,EAAU,SAAS;IACzC,SAASe,GAAQ;KAChB,AAAIV,EAAQ,YACXH,EACCa,aAAkB,QAAQA,EAAO,UAAU,qCAC5C,GACAf,EAAU,SAAS;IAErB,UAAU;KACT,EAAO,UAAU;IAClB;GAfiB;EAgBlB;CACD;AACD"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { useEffect as e, useRef as t, useState as n } from "react";
3
- //#region src/viewmodels/use-loader.ts
3
+ // src/viewmodels/use-loader.ts
4
4
  function r(r, i) {
5
5
  let a = t(performance.now()), [o, s] = n(0);
6
6
  e(() => {
@@ -16,7 +16,6 @@ function r(r, i) {
16
16
  text: l < 60 ? `${l.toFixed(1)}s` : `${Math.floor(l / 60)}m ${(l % 60).toFixed(1)}s`
17
17
  };
18
18
  }
19
- //#endregion
20
19
  export { r as useLoaderViewModel };
21
20
 
22
21
  //# sourceMappingURL=use-loader.js.map
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { useEffect as e, useRef as t, useState as n } from "react";
3
- //#region src/viewmodels/use-recommendation-card.ts
3
+ // src/viewmodels/use-recommendation-card.ts
4
4
  function r({ options: r, onAccept: i, disabled: a = !1 }) {
5
5
  let [o, s] = n(), [c, l] = n(!1), [u, d] = n(!1), [f, p] = n(), [m, h] = n(""), g = t(!1), _ = t(!0);
6
6
  e(() => (_.current = !0, () => {
@@ -35,7 +35,6 @@ function r({ options: r, onAccept: i, disabled: a = !1 }) {
35
35
  }
36
36
  };
37
37
  }
38
- //#endregion
39
38
  export { r as useRecommendationCardViewModel };
40
39
 
41
40
  //# sourceMappingURL=use-recommendation-card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-recommendation-card.js","names":["useRecommendationCardViewModel","selected","setSelected","useState","open","setOpen","pending","setPending","accepted","setAccepted","error","setError","lock","useRef","mounted","active","options","option","disabled","next","id","onAccept","reason"],"sources":["../../src/viewmodels/use-recommendation-card.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { RecommendationOption } from \"../models/recommendation\";\n\nexport function useRecommendationCardViewModel({\n\toptions,\n\tonAccept,\n\tdisabled = false,\n}: {\n\toptions: readonly RecommendationOption[];\n\tonAccept: (option: RecommendationOption) => void | Promise<void>;\n\tdisabled?: boolean;\n}) {\n\tconst [selected, setSelected] = useState<string>();\n\tconst [open, setOpen] = useState(false);\n\tconst [pending, setPending] = useState(false);\n\tconst [accepted, setAccepted] = useState<string>();\n\tconst [error, setError] = useState(\"\");\n\tconst lock = useRef(false);\n\tconst mounted = useRef(true);\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t};\n\t}, []);\n\tconst active =\n\t\toptions.find((option) => option.id === selected) ??\n\t\toptions.find((option) => !option.disabled) ??\n\t\toptions[0];\n\tconst others = options.filter((option) => option.id !== active?.id);\n\treturn {\n\t\tactive,\n\t\tothers,\n\t\topen,\n\t\tpending,\n\t\terror,\n\t\taccepted: Boolean(active && accepted === active.id),\n\t\tblocked: disabled || pending,\n\t\tsetOpen(next: boolean) {\n\t\t\tif (!disabled && !lock.current) setOpen(next);\n\t\t},\n\t\tselect(id: string) {\n\t\t\tif (\n\t\t\t\tdisabled ||\n\t\t\t\tlock.current ||\n\t\t\t\t!options.some((option) => option.id === id && !option.disabled)\n\t\t\t)\n\t\t\t\treturn;\n\t\t\tsetSelected(id);\n\t\t\tsetAccepted(undefined);\n\t\t\tsetError(\"\");\n\t\t},\n\t\tasync accept() {\n\t\t\tif (!active || disabled || active.disabled || lock.current || accepted === active.id) return;\n\t\t\tlock.current = true;\n\t\t\tsetPending(true);\n\t\t\tsetError(\"\");\n\t\t\ttry {\n\t\t\t\tawait onAccept({ ...active });\n\t\t\t\tif (mounted.current) setAccepted(active.id);\n\t\t\t} catch (reason) {\n\t\t\t\tif (mounted.current)\n\t\t\t\t\tsetError(\n\t\t\t\t\t\treason instanceof Error\n\t\t\t\t\t\t\t? reason.message\n\t\t\t\t\t\t\t: \"Could not accept recommendation. Try again.\",\n\t\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tlock.current = false;\n\t\t\t\tif (mounted.current) setPending(false);\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":";;;AAGA,SAAgBA,EAA+B,EAC9C,YACA,aACA,cAAW,MAKT;CACF,IAAM,CAACC,GAAUC,KAAeC,EAAiB,GAC3C,CAACC,GAAMC,KAAWF,EAAS,EAAK,GAChC,CAACG,GAASC,KAAcJ,EAAS,EAAK,GACtC,CAACK,GAAUC,KAAeN,EAAiB,GAC3C,CAACO,GAAOC,KAAYR,EAAS,EAAE,GAC/BS,IAAOC,EAAO,EAAK,GACnBC,IAAUD,EAAO,EAAI;CAC3B,SACC,EAAQ,UAAU,UACL;EACZ,EAAQ,UAAU;CACnB,IACE,CAAC,CAAC;CACL,IAAME,IACLC,EAAQ,MAAM,MAAWC,EAAO,OAAOhB,CAAQ,KAC/Ce,EAAQ,MAAM,MAAW,CAACC,EAAO,QAAQ,KACzCD,EAAQ;CAET,OAAO;EACN;EACA,QAHcA,EAAQ,QAAQ,MAAWC,EAAO,OAAOF,GAAQ,EAG/D;EACA;EACA;EACA;EACA,UAAU,GAAQA,KAAUP,MAAaO,EAAO;EAChD,SAASG,KAAYZ;EACrB,QAAQ,GAAe;GACtB,AAAI,CAACY,KAAY,CAACN,EAAK,WAASP,EAAQc,CAAI;EAC7C;EACA,OAAO,GAAY;GAClB,AACCD,KACAN,EAAK,WACL,CAACI,EAAQ,MAAM,MAAWC,EAAO,OAAOG,KAAM,CAACH,EAAO,QAAQ,MAG/Df,EAAYkB,CAAE,GACdX,EAAY,KAAA,CAAS,GACrBE,EAAS,EAAE;EACZ;EACA,MAAM,SAAS;GACd,IAAI,GAACI,KAAUG,KAAYH,EAAO,YAAYH,EAAK,WAAWJ,MAAaO,EAAO,KAGlF;IAFA,EAAK,UAAU,IACfR,EAAW,EAAI,GACfI,EAAS,EAAE;IACX,IAAI;KAEH,AADA,MAAMU,EAAS,EAAE,GAAGN,EAAO,CAAC,GACxBD,EAAQ,WAASL,EAAYM,EAAO,EAAE;IAC3C,SAASO,GAAQ;KAChB,AAAIR,EAAQ,WACXH,EACCW,aAAkB,QACfA,EAAO,UACP,6CACJ;IACF,UAAU;KAET,AADA,EAAK,UAAU,IACXR,EAAQ,WAASP,EAAW,EAAK;IACtC;GAdW;EAeZ;CACD;AACD"}
1
+ {"version":3,"file":"use-recommendation-card.js","names":["useRecommendationCardViewModel","selected","setSelected","useState","open","setOpen","pending","setPending","accepted","setAccepted","error","setError","lock","useRef","mounted","active","options","option","disabled","next","id","onAccept","reason"],"sources":["../../src/viewmodels/use-recommendation-card.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { RecommendationOption } from \"../models/recommendation\";\n\nexport function useRecommendationCardViewModel({\n\toptions,\n\tonAccept,\n\tdisabled = false,\n}: {\n\toptions: readonly RecommendationOption[];\n\tonAccept: (option: RecommendationOption) => void | Promise<void>;\n\tdisabled?: boolean;\n}) {\n\tconst [selected, setSelected] = useState<string>();\n\tconst [open, setOpen] = useState(false);\n\tconst [pending, setPending] = useState(false);\n\tconst [accepted, setAccepted] = useState<string>();\n\tconst [error, setError] = useState(\"\");\n\tconst lock = useRef(false);\n\tconst mounted = useRef(true);\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t};\n\t}, []);\n\tconst active =\n\t\toptions.find((option) => option.id === selected) ??\n\t\toptions.find((option) => !option.disabled) ??\n\t\toptions[0];\n\tconst others = options.filter((option) => option.id !== active?.id);\n\treturn {\n\t\tactive,\n\t\tothers,\n\t\topen,\n\t\tpending,\n\t\terror,\n\t\taccepted: Boolean(active && accepted === active.id),\n\t\tblocked: disabled || pending,\n\t\tsetOpen(next: boolean) {\n\t\t\tif (!disabled && !lock.current) setOpen(next);\n\t\t},\n\t\tselect(id: string) {\n\t\t\tif (\n\t\t\t\tdisabled ||\n\t\t\t\tlock.current ||\n\t\t\t\t!options.some((option) => option.id === id && !option.disabled)\n\t\t\t)\n\t\t\t\treturn;\n\t\t\tsetSelected(id);\n\t\t\tsetAccepted(undefined);\n\t\t\tsetError(\"\");\n\t\t},\n\t\tasync accept() {\n\t\t\tif (!active || disabled || active.disabled || lock.current || accepted === active.id) return;\n\t\t\tlock.current = true;\n\t\t\tsetPending(true);\n\t\t\tsetError(\"\");\n\t\t\ttry {\n\t\t\t\tawait onAccept({ ...active });\n\t\t\t\tif (mounted.current) setAccepted(active.id);\n\t\t\t} catch (reason) {\n\t\t\t\tif (mounted.current)\n\t\t\t\t\tsetError(\n\t\t\t\t\t\treason instanceof Error\n\t\t\t\t\t\t\t? reason.message\n\t\t\t\t\t\t\t: \"Could not accept recommendation. Try again.\",\n\t\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tlock.current = false;\n\t\t\t\tif (mounted.current) setPending(false);\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":";;;AAGA,SAAgBA,EAA+B,EAC9C,YACA,aACA,cAAW,MAKT;CACF,IAAM,CAACC,GAAUC,KAAeC,EAAiB,GAC3C,CAACC,GAAMC,KAAWF,EAAS,EAAK,GAChC,CAACG,GAASC,KAAcJ,EAAS,EAAK,GACtC,CAACK,GAAUC,KAAeN,EAAiB,GAC3C,CAACO,GAAOC,KAAYR,EAAS,EAAE,GAC/BS,IAAOC,EAAO,EAAK,GACnBC,IAAUD,EAAO,EAAI;CAC3B,SACC,EAAQ,UAAU,UACL;EACZ,EAAQ,UAAU;CACnB,IACE,CAAC,CAAC;CACL,IAAME,IACLC,EAAQ,MAAM,MAAWC,EAAO,OAAOhB,CAAQ,KAC/Ce,EAAQ,MAAM,MAAW,CAACC,EAAO,QAAQ,KACzCD,EAAQ;CAET,OAAO;EACN;EACA,QAHcA,EAAQ,QAAQ,MAAWC,EAAO,OAAOF,GAAQ,EAG/D;EACA;EACA;EACA;EACA,UAAU,GAAQA,KAAUP,MAAaO,EAAO;EAChD,SAASG,KAAYZ;EACrB,QAAQ,GAAe;GACtB,AAAI,CAACY,KAAY,CAACN,EAAK,WAASP,EAAQc,CAAI;EAC7C;EACA,OAAO,GAAY;GAClB,AACCD,KACAN,EAAK,WACL,CAACI,EAAQ,MAAM,MAAWC,EAAO,OAAOG,KAAM,CAACH,EAAO,QAAQ,MAG/Df,EAAYkB,CAAE,GACdX,EAAY,KAAA,CAAS,GACrBE,EAAS,EAAE;EACZ;EACA,MAAM,SAAS;GACd,IAAI,GAACI,KAAUG,KAAYH,EAAO,YAAYH,EAAK,WAAWJ,MAAaO,EAAO,KAClF;IAEA,AAFA,EAAK,UAAU,IACfR,EAAW,EAAI,GACfI,EAAS,EAAE;IACX,IAAI;KAEH,AADA,MAAMU,EAAS,EAAE,GAAGN,EAAO,CAAC,GACxBD,EAAQ,WAASL,EAAYM,EAAO,EAAE;IAC3C,SAASO,GAAQ;KAChB,AAAIR,EAAQ,WACXH,EACCW,aAAkB,QACfA,EAAO,UACP,6CACJ;IACF,UAAU;KAET,AADA,EAAK,UAAU,IACXR,EAAQ,WAASP,EAAW,EAAK;IACtC;GAhBe;EAiBhB;CACD;AACD"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { summarizeSteps as e } from "../models/agent-feedback.js";
3
3
  import { useState as t } from "react";
4
- //#region src/viewmodels/use-thinking.ts
4
+ // src/viewmodels/use-thinking.ts
5
5
  function n({ steps: n, open: r, defaultOpen: i = !0, onOpenChange: a }) {
6
6
  let [o, s] = t(i);
7
7
  return {
@@ -12,7 +12,6 @@ function n({ steps: n, open: r, defaultOpen: i = !0, onOpenChange: a }) {
12
12
  }
13
13
  };
14
14
  }
15
- //#endregion
16
15
  export { n as useThinkingViewModel };
17
16
 
18
17
  //# sourceMappingURL=use-thinking.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { summarizeSteps as e } from "../models/agent-feedback.js";
3
3
  import { useState as t } from "react";
4
- //#region src/viewmodels/use-tool-chips.ts
4
+ // src/viewmodels/use-tool-chips.ts
5
5
  function n(n, r) {
6
6
  let [i, a] = t(r), [o, s] = t([]);
7
7
  return {
@@ -14,7 +14,6 @@ function n(n, r) {
14
14
  }
15
15
  };
16
16
  }
17
- //#endregion
18
17
  export { n as useToolChipsViewModel };
19
18
 
20
19
  //# sourceMappingURL=use-tool-chips.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocoo/basalt",
3
- "version": "3.2.0",
3
+ "version": "3.2.4",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {