@timbal-ai/timbal-react 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/README.md +25 -0
  3. package/dist/app.cjs +855 -640
  4. package/dist/app.d.cts +4 -4
  5. package/dist/app.d.ts +4 -4
  6. package/dist/app.esm.js +6 -6
  7. package/dist/{chart-artifact-2OTDTRwM.d.ts → chart-artifact-C2pZQsaP.d.ts} +81 -29
  8. package/dist/{chart-artifact-CS3qyGIY.d.cts → chart-artifact-VAqgH-My.d.cts} +81 -29
  9. package/dist/{chat-ClmzWzCX.d.cts → chat-DDsp-Vzz.d.cts} +1 -1
  10. package/dist/{chat-ClmzWzCX.d.ts → chat-DDsp-Vzz.d.ts} +1 -1
  11. package/dist/chat.cjs +26 -26
  12. package/dist/chat.d.cts +3 -3
  13. package/dist/chat.d.ts +3 -3
  14. package/dist/chat.esm.js +3 -3
  15. package/dist/{chunk-TZI3ID3C.esm.js → chunk-24B4I4XC.esm.js} +3 -3
  16. package/dist/{chunk-SZDYIRMB.esm.js → chunk-6SQMTBPL.esm.js} +618 -530
  17. package/dist/{chunk-QIABF4KB.esm.js → chunk-ELEY66OH.esm.js} +2 -2
  18. package/dist/{chunk-WMKPT5BV.esm.js → chunk-HSL36SJ4.esm.js} +6 -6
  19. package/dist/chunk-JJOO4PR5.esm.js +391 -0
  20. package/dist/{chunk-AZL2WANO.esm.js → chunk-MBS7XHV2.esm.js} +28 -28
  21. package/dist/{chunk-5ECRZ5O7.esm.js → chunk-NO5AWNWT.esm.js} +224 -57
  22. package/dist/{chunk-ZNYAETFD.esm.js → chunk-R4RQT2XQ.esm.js} +2 -2
  23. package/dist/{chunk-JYDJRGDE.esm.js → chunk-TMP7RIA7.esm.js} +2 -2
  24. package/dist/{chunk-IGHBLJV3.esm.js → chunk-WQIQW7EM.esm.js} +3 -2
  25. package/dist/{chunk-B4XAC4G7.esm.js → chunk-YYEI6XME.esm.js} +361 -527
  26. package/dist/{circular-progress-CDsJwIPF.d.cts → circular-progress-B9nnwzCu.d.cts} +1 -1
  27. package/dist/{circular-progress-CDsJwIPF.d.ts → circular-progress-B9nnwzCu.d.ts} +1 -1
  28. package/dist/index.cjs +1327 -852
  29. package/dist/index.d.cts +9 -8
  30. package/dist/index.d.ts +9 -8
  31. package/dist/index.esm.js +40 -20
  32. package/dist/{kanban-U5xNe9py.d.cts → kanban-FFBeaZPS.d.cts} +4 -4
  33. package/dist/{kanban-U5xNe9py.d.ts → kanban-FFBeaZPS.d.ts} +4 -4
  34. package/dist/{layout-B8r6Jbat.d.ts → layout-CuKeSY74.d.ts} +1 -1
  35. package/dist/{layout-Cu7Ijn04.d.cts → layout-PzVwkJyL.d.cts} +1 -1
  36. package/dist/site.cjs +71 -0
  37. package/dist/site.d.cts +15 -1
  38. package/dist/site.d.ts +15 -1
  39. package/dist/site.esm.js +12 -311
  40. package/dist/studio.cjs +31 -31
  41. package/dist/studio.d.cts +2 -2
  42. package/dist/studio.d.ts +2 -2
  43. package/dist/studio.esm.js +7 -7
  44. package/dist/{timbal-v2-button-B7vPs7gg.d.ts → timbal-v2-button-DCAZNyUx.d.cts} +1 -1
  45. package/dist/{timbal-v2-button-B7vPs7gg.d.cts → timbal-v2-button-DCAZNyUx.d.ts} +1 -1
  46. package/dist/ui.cjs +77 -77
  47. package/dist/ui.d.cts +3 -3
  48. package/dist/ui.d.ts +3 -3
  49. package/dist/ui.esm.js +15 -15
  50. package/dist/{welcome-NXZlcihe.d.cts → welcome-B00oH5Io.d.cts} +1 -1
  51. package/dist/{welcome-DduQAC4K.d.ts → welcome-DU-4NTjZ.d.ts} +1 -1
  52. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -38,7 +38,7 @@ __export(index_exports, {
38
38
  AccordionContent: () => AccordionContent,
39
39
  AccordionItem: () => AccordionItem,
40
40
  AccordionTrigger: () => AccordionTrigger,
41
- ActionBarPrimitive: () => import_react79.ActionBarPrimitive,
41
+ ActionBarPrimitive: () => import_react84.ActionBarPrimitive,
42
42
  Alert: () => Alert,
43
43
  AlertDescription: () => AlertDescription,
44
44
  AlertDialog: () => AlertDialog,
@@ -63,8 +63,8 @@ __export(index_exports, {
63
63
  ArtifactRegistryProvider: () => ArtifactRegistryProvider,
64
64
  ArtifactView: () => ArtifactView,
65
65
  AspectRatio: () => AspectRatio,
66
- AssistantRuntimeProvider: () => import_react79.AssistantRuntimeProvider,
67
- AuiIf: () => import_react79.AuiIf,
66
+ AssistantRuntimeProvider: () => import_react84.AssistantRuntimeProvider,
67
+ AuiIf: () => import_react84.AuiIf,
68
68
  AuthGuard: () => AuthGuard,
69
69
  Avatar: () => Avatar,
70
70
  AvatarFallback: () => AvatarFallback,
@@ -121,7 +121,7 @@ __export(index_exports, {
121
121
  CommandSeparator: () => CommandSeparator,
122
122
  CommandShortcut: () => CommandShortcut,
123
123
  Composer: () => Composer,
124
- ComposerPrimitive: () => import_react79.ComposerPrimitive,
124
+ ComposerPrimitive: () => import_react84.ComposerPrimitive,
125
125
  ConnectionRow: () => ConnectionRow,
126
126
  ConnectionRowList: () => ConnectionRowList,
127
127
  ContextMenu: () => ContextMenu,
@@ -140,6 +140,7 @@ __export(index_exports, {
140
140
  ContextMenuTrigger: () => ContextMenuTrigger,
141
141
  CopyButton: () => CopyButton,
142
142
  DEFAULT_UPLOAD_ACCEPT: () => DEFAULT_UPLOAD_ACCEPT,
143
+ DURATION: () => DURATION,
143
144
  DangerZone: () => DangerZone,
144
145
  DangerZoneAction: () => DangerZoneAction,
145
146
  DataTable: () => DataTable,
@@ -173,6 +174,7 @@ __export(index_exports, {
173
174
  DropdownMenuSubContent: () => DropdownMenuSubContent,
174
175
  DropdownMenuSubTrigger: () => DropdownMenuSubTrigger,
175
176
  DropdownMenuTrigger: () => DropdownMenuTrigger,
177
+ EASE: () => EASE,
176
178
  EmptyState: () => EmptyState,
177
179
  ExpandableSection: () => ExpandableSection,
178
180
  Field: () => Field,
@@ -218,7 +220,9 @@ __export(index_exports, {
218
220
  KbdGroup: () => KbdGroup,
219
221
  Label: () => Label3,
220
222
  LineAreaChart: () => LineAreaChart,
223
+ Magnetic: () => Magnetic,
221
224
  MarkdownText: () => MarkdownText,
225
+ Marquee: () => Marquee,
222
226
  MemoPillSegmentedTabs: () => MemoPillSegmentedTabs,
223
227
  Menubar: () => Menubar,
224
228
  MenubarCheckboxItem: () => MenubarCheckboxItem,
@@ -234,7 +238,7 @@ __export(index_exports, {
234
238
  MenubarSubContent: () => MenubarSubContent,
235
239
  MenubarSubTrigger: () => MenubarSubTrigger,
236
240
  MenubarTrigger: () => MenubarTrigger,
237
- MessagePrimitive: () => import_react79.MessagePrimitive,
241
+ MessagePrimitive: () => import_react84.MessagePrimitive,
238
242
  MetricChartCard: () => MetricChartCard,
239
243
  MetricRow: () => MetricRow,
240
244
  MetricTile: () => MetricTile,
@@ -257,6 +261,7 @@ __export(index_exports, {
257
261
  PaginationLink: () => PaginationLink,
258
262
  PaginationNext: () => PaginationNext,
259
263
  PaginationPrevious: () => PaginationPrevious,
264
+ Parallax: () => Parallax,
260
265
  PieChart: () => PieChart,
261
266
  PillSegmentedTabs: () => PillSegmentedTabs,
262
267
  PlanBadge: () => PlanBadge,
@@ -273,8 +278,11 @@ __export(index_exports, {
273
278
  RadioGroupItem: () => RadioGroupItem,
274
279
  Rating: () => Rating,
275
280
  ResourceCard: () => ResourceCard,
281
+ Reveal: () => Reveal,
276
282
  SEMANTIC_COLOR_TOKENS: () => SEMANTIC_COLOR_TOKENS,
283
+ SITE_AGENT_INSTRUCTIONS: () => SITE_AGENT_INSTRUCTIONS,
277
284
  SLOP_BUDGETS: () => SLOP_BUDGETS,
285
+ SPRING: () => SPRING,
278
286
  STUDIO_NAV_MODE: () => STUDIO_NAV_MODE,
279
287
  ScrollArea: () => ScrollArea,
280
288
  ScrollBar: () => ScrollBar,
@@ -334,9 +342,10 @@ __export(index_exports, {
334
342
  TableHeader: () => TableHeader,
335
343
  TableRow: () => TableRow,
336
344
  TagInput: () => TagInput,
345
+ TextReveal: () => TextReveal,
337
346
  Textarea: () => Textarea,
338
347
  Thread: () => Thread,
339
- ThreadPrimitive: () => import_react79.ThreadPrimitive,
348
+ ThreadPrimitive: () => import_react84.ThreadPrimitive,
340
349
  TimbalChat: () => TimbalChat,
341
350
  TimbalChatShell: () => TimbalChatShell,
342
351
  TimbalMark: () => TimbalMark,
@@ -435,15 +444,15 @@ __export(index_exports, {
435
444
  useAppShellChat: () => useAppShellChat,
436
445
  useAppShellNav: () => useAppShellNav,
437
446
  useArtifactRegistry: () => useArtifactRegistry,
438
- useComposerRuntime: () => import_react79.useComposerRuntime,
447
+ useComposerRuntime: () => import_react84.useComposerRuntime,
439
448
  useInterval: () => useInterval,
440
449
  useLiveQuery: () => useLiveQuery,
441
- useMessageRuntime: () => import_react79.useMessageRuntime,
450
+ useMessageRuntime: () => import_react84.useMessageRuntime,
442
451
  useOptionalSession: () => useOptionalSession,
443
452
  useResolvedSuggestions: () => useResolvedSuggestions,
444
453
  useSession: () => useSession,
445
- useThread: () => import_react79.useThread,
446
- useThreadRuntime: () => import_react79.useThreadRuntime,
454
+ useThread: () => import_react84.useThread,
455
+ useThreadRuntime: () => import_react84.useThreadRuntime,
447
456
  useTimbalRuntime: () => useTimbalRuntime,
448
457
  useTimbalStream: () => useTimbalStream,
449
458
  useToast: () => useToast,
@@ -1413,22 +1422,22 @@ var TIMBAL_V2_MODAL_SURFACE = cn(
1413
1422
  );
1414
1423
  var TIMBAL_V2_PRIMARY_GRADIENT = "bg-gradient-to-b from-primary-fill-from to-primary-fill-to";
1415
1424
  var TIMBAL_V2_SIZE_HEIGHT = {
1416
- xs: "min-h-8 h-8",
1417
- sm: "min-h-9 h-9",
1418
- md: "min-h-10 h-10",
1419
- lg: "min-h-11 h-11"
1425
+ xs: "min-h-7 h-7",
1426
+ sm: "min-h-8 h-8",
1427
+ md: "min-h-9 h-9",
1428
+ lg: "min-h-10 h-10"
1420
1429
  };
1421
1430
  var TIMBAL_V2_SIZE_ICON = {
1422
- xs: "min-h-8 min-w-8 size-8",
1431
+ xs: "min-h-7 min-w-7 size-7",
1423
1432
  sm: "min-h-8 min-w-8 size-8",
1424
- md: "min-h-10 min-w-10 size-10",
1425
- lg: "min-h-11 min-w-11 size-11"
1433
+ md: "min-h-9 min-w-9 size-9",
1434
+ lg: "min-h-10 min-w-10 size-10"
1426
1435
  };
1427
1436
  var TIMBAL_V2_SIZE_LABEL_PX = {
1428
- xs: "px-3",
1429
- sm: "px-4",
1430
- md: "px-5",
1431
- lg: "px-6"
1437
+ xs: "px-2.5",
1438
+ sm: "px-3",
1439
+ md: "px-3.5",
1440
+ lg: "px-4.5"
1432
1441
  };
1433
1442
  var TIMBAL_V2_FILL = {
1434
1443
  primary: [
@@ -1595,7 +1604,7 @@ function DialogContent({
1595
1604
  "data-slot": "dialog-content",
1596
1605
  className: cn(
1597
1606
  TIMBAL_V2_MODAL_SURFACE,
1598
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-[70] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl p-6 duration-200 outline-none sm:max-w-lg",
1607
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-[70] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl p-5 duration-200 outline-none sm:max-w-lg",
1599
1608
  className
1600
1609
  ),
1601
1610
  ...props,
@@ -1692,9 +1701,9 @@ function avatarChartVariantClass(_seed) {
1692
1701
  return AVATAR_PRIMARY_FALLBACK_CLASS;
1693
1702
  }
1694
1703
  var AVATAR_SIZE_CLASS = {
1695
- default: "size-8",
1696
- sm: "size-6",
1697
- lg: "size-10"
1704
+ default: "size-7",
1705
+ sm: "size-5",
1706
+ lg: "size-9"
1698
1707
  };
1699
1708
  function Avatar({
1700
1709
  className,
@@ -3875,16 +3884,16 @@ var buttonVariants = (0, import_class_variance_authority.cva)(
3875
3884
  )
3876
3885
  },
3877
3886
  size: {
3878
- xs: "h-8 gap-1 rounded-md px-2.5 text-xs",
3879
- sm: "h-9 gap-1.5 rounded-lg px-3 text-sm",
3880
- md: "h-10 gap-1.5 rounded-lg px-3.5 text-sm",
3881
- lg: "h-11 gap-2 rounded-lg px-4 text-base",
3882
- xl: "h-12 gap-2 rounded-lg px-5 text-base",
3883
- default: "h-10 gap-1.5 rounded-lg px-3.5 text-sm",
3884
- icon: "h-10 w-10 rounded-lg",
3885
- "icon-xs": "h-8 w-8 rounded-md",
3886
- "icon-sm": "h-9 w-9 rounded-lg",
3887
- "icon-lg": "h-11 w-11 rounded-lg"
3887
+ xs: "h-7 gap-1 rounded-md px-2 text-xs",
3888
+ sm: "h-8 gap-1 rounded-md px-2.5 text-xs",
3889
+ md: "h-9 gap-1.5 rounded-lg px-3 text-sm",
3890
+ lg: "h-10 gap-1.5 rounded-lg px-3.5 text-sm",
3891
+ xl: "h-11 gap-2 rounded-lg px-4 text-base",
3892
+ default: "h-9 gap-1.5 rounded-lg px-3 text-sm",
3893
+ icon: "h-9 w-9 rounded-lg",
3894
+ "icon-xs": "h-7 w-7 rounded-md",
3895
+ "icon-sm": "h-8 w-8 rounded-md",
3896
+ "icon-lg": "h-10 w-10 rounded-lg"
3888
3897
  },
3889
3898
  shape: {
3890
3899
  pill: "rounded-full!",
@@ -4141,7 +4150,7 @@ var BadgeNode = ({ node }) => {
4141
4150
  "span",
4142
4151
  {
4143
4152
  className: cn(
4144
- "aui-ui-badge inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
4153
+ "aui-ui-badge inline-flex w-fit shrink-0 items-center rounded-full px-2 py-0.5 text-xs font-medium",
4145
4154
  BADGE_TONE[node.tone ?? "default"],
4146
4155
  node.className
4147
4156
  ),
@@ -5790,8 +5799,8 @@ var import_lucide_react9 = require("lucide-react");
5790
5799
 
5791
5800
  // src/design/control-surface.ts
5792
5801
  var CONTROL_SIZE = {
5793
- sm: "h-9 px-3",
5794
- default: "h-10 px-3"
5802
+ sm: "h-8 px-2.5",
5803
+ default: "h-9 px-3"
5795
5804
  };
5796
5805
  var CONTROL_SHAPE = {
5797
5806
  field: "rounded-lg",
@@ -5819,7 +5828,7 @@ var overlayListPanelClass = cn(
5819
5828
  overlaySurfaceClass,
5820
5829
  "overflow-hidden rounded-lg p-0 outline-hidden"
5821
5830
  );
5822
- var overlayItemClass = "relative flex cursor-default items-center gap-2 rounded-md px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground";
5831
+ var overlayItemClass = "relative flex cursor-default items-center gap-2 rounded-md px-2 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground";
5823
5832
 
5824
5833
  // src/chat/workforce-selector.tsx
5825
5834
  var import_jsx_runtime38 = require("react/jsx-runtime");
@@ -5944,8 +5953,8 @@ var SIDEBAR_MOBILE_PX = 272;
5944
5953
  var SIDEBAR_GAP_PX = 12;
5945
5954
  var SIDEBAR_CONTENT_GAP_PX = 8;
5946
5955
  var TOPBAR_GAP_PX = 8;
5947
- var TOPBAR_HEIGHT_PX = 48;
5948
- var PILL_HEIGHT_PX = 40;
5956
+ var TOPBAR_HEIGHT_PX = 44;
5957
+ var PILL_HEIGHT_PX = 36;
5949
5958
  var SIDEBAR_INSET_PX_EXPANDED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_PX + SIDEBAR_CONTENT_GAP_PX;
5950
5959
  var SIDEBAR_INSET_PX_COLLAPSED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_COLLAPSED_PX + SIDEBAR_CONTENT_GAP_PX;
5951
5960
  var px = (n) => `${n / 16}rem`;
@@ -6526,7 +6535,7 @@ function DropdownMenuCheckboxItem({
6526
6535
  import_radix_ui6.DropdownMenu.CheckboxItem,
6527
6536
  {
6528
6537
  "data-slot": "dropdown-menu-checkbox-item",
6529
- className: cn(overlayItemClass, "py-1.5 pr-2 pl-8", className),
6538
+ className: cn(overlayItemClass, "py-1 pr-2 pl-8", className),
6530
6539
  checked,
6531
6540
  ...props,
6532
6541
  children: [
@@ -6556,7 +6565,7 @@ function DropdownMenuRadioItem({
6556
6565
  import_radix_ui6.DropdownMenu.RadioItem,
6557
6566
  {
6558
6567
  "data-slot": "dropdown-menu-radio-item",
6559
- className: cn(overlayItemClass, "py-1.5 pr-2 pl-8", className),
6568
+ className: cn(overlayItemClass, "py-1 pr-2 pl-8", className),
6560
6569
  ...props,
6561
6570
  children: [
6562
6571
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_radix_ui6.DropdownMenu.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_lucide_react10.CircleIcon, { className: "size-2 fill-current" }) }) }),
@@ -7810,10 +7819,10 @@ var pillSegmentedTrackFlushClass = cn(
7810
7819
  "h-[var(--studio-chrome-pill-height)] items-center gap-0.5 overflow-visible p-0.5"
7811
7820
  );
7812
7821
  var pillSegmentedSegmentClass = cn(
7813
- "relative flex items-center gap-1.5 rounded-full px-4 py-1.5 text-xs font-normal transition-colors"
7822
+ "relative flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-normal transition-colors"
7814
7823
  );
7815
7824
  var pillSegmentedFlushSegmentClass = cn(
7816
- "relative box-border inline-flex h-9 min-h-9 items-center justify-center gap-1.5 rounded-full px-3.5 py-0",
7825
+ "relative box-border inline-flex h-8 min-h-8 items-center justify-center gap-1.5 rounded-full px-3 py-0",
7817
7826
  "text-sm font-normal leading-tight transition-colors"
7818
7827
  );
7819
7828
  var pillSegmentedActiveIndicatorClass = cn(
@@ -8224,7 +8233,7 @@ Presentational groups \u2014 import from the package root, not from these paths:
8224
8233
 
8225
8234
  | Folder | Components |
8226
8235
  |--------|------------|
8227
- | \`data/\` | \`MetricRow\`, \`MetricChartCard\`, \`MetricTile\`, \`DataTable\`, \`FilterBar\`, \`FilterField\`, \`ChartPanel\` |
8236
+ | \`data/\` | \`MetricRow\`, \`MetricChartCard\`, \`MetricTile\`, \`DataTable\`, \`FilterBar\`, \`FilterField\`, \`FilterDropdown\`, \`ChartPanel\` |
8228
8237
  | \`integrations/\` | \`IntegrationCard\`, \`ConnectionRow\`, \`ConnectionRowList\`, \`IntegrationsEmptyState\`, \`PlanBadge\` |
8229
8238
  | \`settings/\` | \`SettingsSection\`, \`FieldRow\`, \`DangerZone\`, \`FloatingUnsavedChangesBar\` |
8230
8239
  | \`surfaces/\` | \`StatTile\`, \`InfoCard\`, \`AlertCard\`, \`CatalogCard\`, \`ResourceCard\`, \`DescriptionList\`, \`ExpandableSection\`, \`StatusDot\`, \`StatusBadge\`, \`EmptyState\` |
@@ -8293,6 +8302,7 @@ The cause of slop is dropping **below** the curated block layer into raw primiti
8293
8302
  | \`StatusBadge\` | Status pill: \`tone\` (\`default\`\\|\`primary\`\\|\`success\`\\|\`warn\`\\|\`danger\`\\|\`muted\`), children. Use \`danger\` for critical/error severity. |
8294
8303
  | \`FilterBar\` | Horizontal filter row \u2014 bottom-aligns controls. Mix \`SearchInput\` with labeled \`FilterField\` + \`Select\` (or \`Field\` + \`Select\`); labels sit above, control baselines match. |
8295
8304
  | \`FilterField\` | Optional label wrapper for a filter control inside \`FilterBar\` (severity, status, \u2026). Omit \`label\` for search-only fields. |
8305
+ | \`FilterDropdown\` | Single-button **multi-facet** filter popover for dense list/table views \u2014 **data-driven**: pass \`fields\` describing your **actual columns** (each \`{ id, label, type }\` where \`type\` is \`multiselect\` \\| \`text\` \\| \`daterange\` \\| \`numeric\`; \`multiselect\` takes \`options: [{ value, label, hint?, icon? }]\`). State is keyed by field \`id\` \u2014 controlled (\`value\` + \`onChange\`) or uncontrolled (\`defaultValue\`). Renders **removable active-filter pills** next to the trigger by default (\`showActiveChips\`); wire \`onChange\` to actually filter your rows. **Always derive \`fields\` from the table's columns/data; never ship the default example facets.** Use when one \`FilterBar\` row isn't enough. |
8296
8306
  | \`SearchInput\` | Filter field with consistent app styling. |
8297
8307
  | \`DataTable\` | Sortable table: \`columns\`, \`rows\`, \`getRowKey\`, optional \`sort\` / \`onSortChange\`, \`emptyTitle\`, \`showRowCount\`, \`caption\`, \`truncate: true\` on columns with long text. **Scales:** \`pageSize\` (built-in client pager), \`selectable\` + \`onSelectionChange\` (checkbox column for bulk actions), \`loading\` (skeleton rows). \`onRowClick\` for row \u2192 detail (open a \`Sheet\`). |
8298
8308
  | \`Avatar\` / \`AvatarFallback\` | User initials: \`variant="secondary"\` (or \`primary\` / \`chart\` alias) on **both** \`Avatar\` and \`AvatarFallback\` \u2014 same chrome as catalog **Action** buttons (\`Button variant="secondary"\`: elevated gradient, \`border-border\`, \`shadow-card\`, \`text-foreground\`). Never dark primary CTA fill or raw \`bg-blue-600\`. |
@@ -8351,6 +8361,21 @@ Charts run on **recharts** with shadcn \`ChartContainer\` / \`ChartTooltipConten
8351
8361
  | \`Banner\` | Page-level announcement bar: \`tone\` (\`default\`\\|\`primary\`\\|\`success\`\\|\`warn\`\\|\`danger\`), \`icon\`, \`title\`, body as children, right-aligned \`actions\`, \`onDismiss\` (renders the dismiss X). For in-form/field messages use \`InfoCard\` or \`Alert\` instead. |
8352
8362
  | \`Timeline\` | Vertical event log: \`items: [{ id, title, description?, meta?, tone?, icon? }]\`. Presentational \u2014 pass already-formatted timestamps in \`meta\`. |
8353
8363
 
8364
+ #### More \`/ui\` primitives (import from \`/ui\` or the package root)
8365
+
8366
+ These ship in the same design system but aren't re-exported from \`/app\`. Reach for them before hand-rolling \u2014 they're all dependency-free and on the shared tokens / control surface.
8367
+
8368
+ | Component | Use for |
8369
+ |-----------|---------|
8370
+ | \`Stepper\` | Ordered step indicator for wizards / onboarding (horizontal or vertical; complete / active / upcoming states). |
8371
+ | \`Rating\` | Star rating \u2014 interactive (keyboard + hover preview) or \`readOnly\`; controlled or uncontrolled. |
8372
+ | \`NumberField\` | Numeric input with \u2212/+ steppers on the control surface; clamps to \`min\`/\`max\`, steps by \`step\`. |
8373
+ | \`TagInput\` | Chips / token input; commits on Enter/comma, removes on Backspace, optional \`dedupe\`/\`max\`. |
8374
+ | \`AvatarGroup\` | Overlapping avatar stack with an optional \`+N\` overflow chip (\`max\`, \`spacing\`). |
8375
+ | \`CircularProgress\` | Lightweight SVG progress ring \u2014 determinate (optional center label) or indeterminate. |
8376
+ | \`CopyButton\` | Click-to-copy with a transient check confirmation; icon-only or with a label. |
8377
+ | \`Snippet\` | Single-line code / command on the elevated surface with a built-in copy button. |
8378
+
8354
8379
  Studio chrome (\`StudioSidebar\`, \`ModeToggle\`, \u2026) lives in \`@timbal-ai/timbal-react/studio\` \u2014 optional, not required for every dashboard.
8355
8380
 
8356
8381
  ### Block recipes \u2014 compose these (don't clone wholesale)
@@ -8417,6 +8442,7 @@ import {
8417
8442
  DataTable,
8418
8443
  FilterBar,
8419
8444
  FilterField,
8445
+ FilterDropdown,
8420
8446
  AlertCard,
8421
8447
  CatalogCard,
8422
8448
  } from "@timbal-ai/timbal-react/app";
@@ -9612,30 +9638,36 @@ var Sparkline = ({
9612
9638
  height = 28,
9613
9639
  strokeWidth = 1.5,
9614
9640
  className,
9615
- ariaLabel = "Trend"
9641
+ ariaLabel = "Trend",
9642
+ interactive = false,
9643
+ labels,
9644
+ formatValue
9616
9645
  }) => {
9617
9646
  const uid = (0, import_react57.useId)();
9647
+ const containerRef = (0, import_react57.useRef)(null);
9648
+ const [activeIndex, setActiveIndex] = (0, import_react57.useState)(null);
9618
9649
  const values = data.map((d) => typeof d === "number" ? d : toNum(d[dataKey]));
9619
9650
  if (values.length === 0) {
9620
9651
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: cn("inline-block", className), style: { width, height } });
9621
9652
  }
9622
- const pad = strokeWidth + 1;
9653
+ const padX = 0;
9654
+ const padY = strokeWidth + 1;
9623
9655
  const min = Math.min(...values);
9624
9656
  const max = Math.max(...values);
9625
9657
  const range = max - min || 1;
9626
- const innerW = width - pad * 2;
9627
- const innerH = height - pad * 2;
9658
+ const innerW = width - padX * 2;
9659
+ const innerH = height - padY * 2;
9628
9660
  const points = values.map((v, i) => ({
9629
- x: pad + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
9630
- y: pad + innerH - (v - min) / range * innerH
9661
+ x: padX + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
9662
+ y: padY + innerH - (v - min) / range * innerH
9631
9663
  }));
9632
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
9664
+ const svg = /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
9633
9665
  "svg",
9634
9666
  {
9635
9667
  width,
9636
9668
  height,
9637
9669
  viewBox: `0 0 ${width} ${height}`,
9638
- className: cn("block", className),
9670
+ className: cn("block", interactive ? "h-full w-full" : className),
9639
9671
  role: "img",
9640
9672
  "aria-label": ariaLabel,
9641
9673
  preserveAspectRatio: "none",
@@ -9645,7 +9677,7 @@ var Sparkline = ({
9645
9677
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
9646
9678
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
9647
9679
  ] }) }),
9648
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("path", { d: monotoneAreaPath(points, height - pad), fill: `url(#${uid}-spark)` })
9680
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("path", { d: monotoneAreaPath(points, height - padY), fill: `url(#${uid}-spark)` })
9649
9681
  ] }),
9650
9682
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
9651
9683
  "path",
@@ -9657,7 +9689,81 @@ var Sparkline = ({
9657
9689
  strokeLinecap: "round",
9658
9690
  strokeLinejoin: "round"
9659
9691
  }
9660
- )
9692
+ ),
9693
+ interactive && activeIndex != null && points[activeIndex] ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
9694
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
9695
+ "line",
9696
+ {
9697
+ x1: points[activeIndex].x,
9698
+ x2: points[activeIndex].x,
9699
+ y1: 0,
9700
+ y2: height,
9701
+ stroke: color,
9702
+ strokeWidth: 1,
9703
+ strokeOpacity: 0.3,
9704
+ vectorEffect: "non-scaling-stroke"
9705
+ }
9706
+ ),
9707
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
9708
+ "circle",
9709
+ {
9710
+ cx: points[activeIndex].x,
9711
+ cy: points[activeIndex].y,
9712
+ r: 2.75,
9713
+ fill: color,
9714
+ stroke: "var(--background, #fff)",
9715
+ strokeWidth: 1.5,
9716
+ vectorEffect: "non-scaling-stroke"
9717
+ }
9718
+ )
9719
+ ] }) : null
9720
+ ]
9721
+ }
9722
+ );
9723
+ if (!interactive) return svg;
9724
+ const onMove = (e) => {
9725
+ const rect = e.currentTarget.getBoundingClientRect();
9726
+ if (rect.width === 0) return;
9727
+ const fraction = (e.clientX - rect.left) / rect.width;
9728
+ const index = Math.max(
9729
+ 0,
9730
+ Math.min(values.length - 1, Math.round(fraction * (values.length - 1)))
9731
+ );
9732
+ setActiveIndex(index);
9733
+ };
9734
+ const active = activeIndex != null ? points[activeIndex] : null;
9735
+ const formattedValue = activeIndex != null ? formatValue ? formatValue(values[activeIndex], activeIndex) : formatCompact(values[activeIndex]) : null;
9736
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
9737
+ "span",
9738
+ {
9739
+ ref: containerRef,
9740
+ className: cn("relative block touch-none", className),
9741
+ style: { width: "100%", height: "100%" },
9742
+ onPointerMove: onMove,
9743
+ onPointerLeave: () => setActiveIndex(null),
9744
+ children: [
9745
+ svg,
9746
+ active ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
9747
+ "span",
9748
+ {
9749
+ "aria-hidden": true,
9750
+ className: cn(
9751
+ "pointer-events-none absolute z-30 -translate-x-1/2 -translate-y-full whitespace-nowrap",
9752
+ "rounded-xl border px-3 py-2 text-[11px] font-medium leading-none tabular-nums shadow-[0_12px_40px_-10px_rgba(0,0,0,0.55)]",
9753
+ "border-white/10 bg-gradient-to-b from-neutral-800 to-neutral-950 text-white",
9754
+ "dark:border-black/10 dark:from-white dark:to-neutral-100 dark:text-neutral-900"
9755
+ ),
9756
+ style: {
9757
+ left: `${active.x / width * 100}%`,
9758
+ top: `${active.y / height * 100}%`,
9759
+ marginTop: -8
9760
+ },
9761
+ children: [
9762
+ labels?.[activeIndex] != null ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "mr-1.5 text-neutral-300 dark:text-neutral-500", children: labels[activeIndex] }) : null,
9763
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { children: formattedValue })
9764
+ ]
9765
+ }
9766
+ ) : null
9661
9767
  ]
9662
9768
  }
9663
9769
  );
@@ -9675,6 +9781,15 @@ var inlineTrendToneClass = {
9675
9781
  down: "text-rose-500/90 dark:text-rose-400/95 font-medium",
9676
9782
  neutral: "text-muted-foreground/80"
9677
9783
  };
9784
+ var sparklineToneColor = {
9785
+ up: "var(--primary, #3b82f6)",
9786
+ down: "var(--destructive, #f43f5e)",
9787
+ neutral: "var(--muted-foreground, #64748b)"
9788
+ };
9789
+ var sparklineBandBleed = {
9790
+ default: "-mx-4 -mb-3 h-10",
9791
+ compact: "-mx-3 -mb-2 h-8"
9792
+ };
9678
9793
  var activeToneClass = {
9679
9794
  default: "bg-foreground dark:bg-white",
9680
9795
  primary: "bg-primary",
@@ -9704,8 +9819,10 @@ var MetricTile = ({
9704
9819
  ariaLabel,
9705
9820
  className
9706
9821
  }) => {
9822
+ const density = useAppDensity();
9707
9823
  const metricTileBaseClass = useAppDensityClass("metricTile");
9708
9824
  const hasSparkline = Boolean(sparkline || sparklineData);
9825
+ const bandBleed = sparklineBandBleed[density === "compact" ? "compact" : "default"];
9709
9826
  const content = /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
9710
9827
  active ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
9711
9828
  "span",
@@ -9717,17 +9834,6 @@ var MetricTile = ({
9717
9834
  )
9718
9835
  }
9719
9836
  ) : null,
9720
- hasSparkline ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "absolute inset-x-0 bottom-0.5 h-9 w-full overflow-hidden pointer-events-none z-0 opacity-45 dark:opacity-35 select-none", children: sparkline ?? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
9721
- Sparkline,
9722
- {
9723
- data: sparklineData,
9724
- width: 160,
9725
- height: 36,
9726
- className: "w-full h-full",
9727
- color: trendTone === "up" ? "var(--primary, #3b82f6)" : trendTone === "down" ? "var(--destructive, #f43f5e)" : "var(--muted-foreground, #64748b)",
9728
- ...sparklineConfig
9729
- }
9730
- ) }) : null,
9731
9837
  /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "relative z-10 flex flex-col gap-1 w-full text-left", children: [
9732
9838
  /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "text-xs font-semibold text-muted-foreground/80 tracking-tight", children: label }),
9733
9839
  /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "flex items-center gap-2", children: [
@@ -9746,7 +9852,28 @@ var MetricTile = ({
9746
9852
  }
9747
9853
  ) : null
9748
9854
  ] })
9749
- ] })
9855
+ ] }),
9856
+ hasSparkline ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
9857
+ "div",
9858
+ {
9859
+ className: cn(
9860
+ "relative z-10 mt-2",
9861
+ bandBleed
9862
+ ),
9863
+ children: sparkline ?? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
9864
+ Sparkline,
9865
+ {
9866
+ data: sparklineData,
9867
+ width: 160,
9868
+ height: 40,
9869
+ interactive: true,
9870
+ className: "h-full w-full opacity-90",
9871
+ color: sparklineToneColor[trendTone],
9872
+ ...sparklineConfig
9873
+ }
9874
+ )
9875
+ }
9876
+ ) : null
9750
9877
  ] });
9751
9878
  const divider = showDivider ? metricCellDividerClass : void 0;
9752
9879
  if (onSelect) {
@@ -10447,7 +10574,7 @@ var StatusBadge = ({
10447
10574
  "span",
10448
10575
  {
10449
10576
  className: cn(
10450
- "aui-app-status-badge inline-flex items-center gap-1.5 rounded-full px-2 py-0.5",
10577
+ "aui-app-status-badge inline-flex w-fit shrink-0 items-center gap-1.5 rounded-full px-2 py-0.5",
10451
10578
  "text-xs font-medium leading-none ring-1 ring-inset",
10452
10579
  statusBadgeToneClass[tone],
10453
10580
  className
@@ -10861,7 +10988,7 @@ function CopyButton({
10861
10988
  "inline-flex items-center justify-center gap-1.5 rounded-md text-sm font-medium text-muted-foreground transition-colors",
10862
10989
  "hover:bg-accent hover:text-foreground data-[copied=true]:text-emerald-600 dark:data-[copied=true]:text-emerald-400",
10863
10990
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15",
10864
- children ? "h-8 px-2" : "size-8",
10991
+ children ? "h-7 px-1.5" : "size-7",
10865
10992
  className
10866
10993
  ),
10867
10994
  ...props,
@@ -11592,7 +11719,7 @@ var FilterField = ({
11592
11719
 
11593
11720
  // src/app/data/FilterDropdown.tsx
11594
11721
  var import_react73 = require("react");
11595
- var import_lucide_react24 = require("lucide-react");
11722
+ var import_lucide_react25 = require("lucide-react");
11596
11723
 
11597
11724
  // src/ui/checkbox.tsx
11598
11725
  var import_radix_ui7 = require("radix-ui");
@@ -11625,23 +11752,178 @@ function Checkbox({
11625
11752
  );
11626
11753
  }
11627
11754
 
11628
- // src/ui/popover.tsx
11755
+ // src/ui/select.tsx
11629
11756
  var import_radix_ui8 = require("radix-ui");
11757
+ var import_lucide_react24 = require("lucide-react");
11630
11758
  var import_jsx_runtime105 = require("react/jsx-runtime");
11759
+ function Select({
11760
+ ...props
11761
+ }) {
11762
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Select.Root, { "data-slot": "select", ...props });
11763
+ }
11764
+ function SelectGroup({
11765
+ ...props
11766
+ }) {
11767
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Select.Group, { "data-slot": "select-group", ...props });
11768
+ }
11769
+ function SelectValue({
11770
+ ...props
11771
+ }) {
11772
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Select.Value, { "data-slot": "select-value", ...props });
11773
+ }
11774
+ function SelectTrigger({
11775
+ className,
11776
+ size = "default",
11777
+ children,
11778
+ ...props
11779
+ }) {
11780
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(
11781
+ import_radix_ui8.Select.Trigger,
11782
+ {
11783
+ "data-slot": "select-trigger",
11784
+ "data-size": size,
11785
+ className: cn(
11786
+ controlClass({ size }),
11787
+ "flex w-fit items-center justify-between gap-2 whitespace-nowrap *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
11788
+ className
11789
+ ),
11790
+ ...props,
11791
+ children: [
11792
+ children,
11793
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Select.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_lucide_react24.ChevronDownIcon, { className: "size-4 opacity-50" }) })
11794
+ ]
11795
+ }
11796
+ );
11797
+ }
11798
+ function SelectContent({
11799
+ className,
11800
+ children,
11801
+ position = "popper",
11802
+ ...props
11803
+ }) {
11804
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Select.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(
11805
+ import_radix_ui8.Select.Content,
11806
+ {
11807
+ "data-slot": "select-content",
11808
+ className: cn(
11809
+ overlayListPanelClass,
11810
+ "relative max-h-[var(--radix-select-content-available-height)] min-w-[8rem] origin-[var(--radix-select-content-transform-origin)] overflow-x-hidden overflow-y-auto",
11811
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
11812
+ className
11813
+ ),
11814
+ position,
11815
+ ...props,
11816
+ children: [
11817
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(SelectScrollUpButton, {}),
11818
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
11819
+ import_radix_ui8.Select.Viewport,
11820
+ {
11821
+ className: cn(
11822
+ "p-1",
11823
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
11824
+ ),
11825
+ children
11826
+ }
11827
+ ),
11828
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(SelectScrollDownButton, {})
11829
+ ]
11830
+ }
11831
+ ) });
11832
+ }
11833
+ function SelectLabel({
11834
+ className,
11835
+ ...props
11836
+ }) {
11837
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
11838
+ import_radix_ui8.Select.Label,
11839
+ {
11840
+ "data-slot": "select-label",
11841
+ className: cn("px-2 py-1.5 text-xs font-medium text-muted-foreground", className),
11842
+ ...props
11843
+ }
11844
+ );
11845
+ }
11846
+ function SelectItem({
11847
+ className,
11848
+ children,
11849
+ ...props
11850
+ }) {
11851
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(
11852
+ import_radix_ui8.Select.Item,
11853
+ {
11854
+ "data-slot": "select-item",
11855
+ className: cn(
11856
+ overlayItemClass,
11857
+ "w-full py-1 pr-8 pl-2 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
11858
+ className
11859
+ ),
11860
+ ...props,
11861
+ children: [
11862
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Select.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_lucide_react24.CheckIcon, { className: "size-4" }) }) }),
11863
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Select.ItemText, { children })
11864
+ ]
11865
+ }
11866
+ );
11867
+ }
11868
+ function SelectSeparator({
11869
+ className,
11870
+ ...props
11871
+ }) {
11872
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
11873
+ import_radix_ui8.Select.Separator,
11874
+ {
11875
+ "data-slot": "select-separator",
11876
+ className: cn("-mx-1 my-1 h-px bg-border", className),
11877
+ ...props
11878
+ }
11879
+ );
11880
+ }
11881
+ function SelectScrollUpButton({
11882
+ className,
11883
+ ...props
11884
+ }) {
11885
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
11886
+ import_radix_ui8.Select.ScrollUpButton,
11887
+ {
11888
+ "data-slot": "select-scroll-up-button",
11889
+ className: cn("flex cursor-default items-center justify-center py-1", className),
11890
+ ...props,
11891
+ children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_lucide_react24.ChevronUpIcon, { className: "size-4" })
11892
+ }
11893
+ );
11894
+ }
11895
+ function SelectScrollDownButton({
11896
+ className,
11897
+ ...props
11898
+ }) {
11899
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
11900
+ import_radix_ui8.Select.ScrollDownButton,
11901
+ {
11902
+ "data-slot": "select-scroll-down-button",
11903
+ className: cn("flex cursor-default items-center justify-center py-1", className),
11904
+ ...props,
11905
+ children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_lucide_react24.ChevronDownIcon, { className: "size-4" })
11906
+ }
11907
+ );
11908
+ }
11909
+
11910
+ // src/ui/popover.tsx
11911
+ var import_radix_ui9 = require("radix-ui");
11912
+ var import_jsx_runtime106 = require("react/jsx-runtime");
11631
11913
  function Popover({
11632
11914
  ...props
11633
11915
  }) {
11634
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Popover.Root, { "data-slot": "popover", ...props });
11916
+ return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_radix_ui9.Popover.Root, { "data-slot": "popover", ...props });
11635
11917
  }
11636
11918
  function PopoverTrigger({
11637
11919
  ...props
11638
11920
  }) {
11639
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
11921
+ return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_radix_ui9.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
11640
11922
  }
11641
11923
  function PopoverAnchor({
11642
11924
  ...props
11643
11925
  }) {
11644
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Popover.Anchor, { "data-slot": "popover-anchor", ...props });
11926
+ return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_radix_ui9.Popover.Anchor, { "data-slot": "popover-anchor", ...props });
11645
11927
  }
11646
11928
  function PopoverContent({
11647
11929
  className,
@@ -11650,8 +11932,8 @@ function PopoverContent({
11650
11932
  variant = "default",
11651
11933
  ...props
11652
11934
  }) {
11653
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(import_radix_ui8.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
11654
- import_radix_ui8.Popover.Content,
11935
+ return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_radix_ui9.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11936
+ import_radix_ui9.Popover.Content,
11655
11937
  {
11656
11938
  "data-slot": "popover-content",
11657
11939
  "data-variant": variant,
@@ -11663,7 +11945,7 @@ function PopoverContent({
11663
11945
  "min-w-[8rem] origin-[var(--radix-popover-content-transform-origin)]"
11664
11946
  ) : cn(
11665
11947
  overlaySurfaceClass,
11666
- "w-72 origin-[var(--radix-popover-content-transform-origin)] rounded-xl p-4 outline-hidden"
11948
+ "w-72 origin-[var(--radix-popover-content-transform-origin)] rounded-xl p-3 outline-hidden"
11667
11949
  ),
11668
11950
  className
11669
11951
  ),
@@ -11673,499 +11955,471 @@ function PopoverContent({
11673
11955
  }
11674
11956
 
11675
11957
  // src/app/data/FilterDropdown.tsx
11676
- var import_jsx_runtime106 = require("react/jsx-runtime");
11677
- var DEFAULT_CONTACTS = [
11678
- { id: "1", name: "Pedro Olivares Sanchez", email: "polivares@timbal.ai", initials: "PE" },
11679
- { id: "2", name: "John Doe", email: "john@example.com", initials: "JD" },
11680
- { id: "3", name: "Sarah Smith", email: "sarah@example.com", initials: "SS" }
11958
+ var import_jsx_runtime107 = require("react/jsx-runtime");
11959
+ var DEFAULT_PRESETS = [
11960
+ { id: "last_7_days", label: "Last 7 days" },
11961
+ { id: "last_30_days", label: "Last 30 days" },
11962
+ { id: "last_90_days", label: "Last 90 days" },
11963
+ { id: "this_month", label: "This month" },
11964
+ { id: "this_year", label: "This year" },
11965
+ { id: "custom", label: "Custom range" }
11681
11966
  ];
11682
- var OPERATORS = [
11683
- { id: "greater_than", label: "Greater than..." },
11684
- { id: "less_than", label: "Less than..." },
11685
- { id: "equals", label: "Equals..." }
11967
+ var DEFAULT_OPERATORS = [
11968
+ { id: "gt", label: "Greater than" },
11969
+ { id: "lt", label: "Less than" },
11970
+ { id: "eq", label: "Equals" }
11686
11971
  ];
11972
+ function asArray(v) {
11973
+ return Array.isArray(v) ? v : [];
11974
+ }
11975
+ function asText(v) {
11976
+ return typeof v === "string" ? v : "";
11977
+ }
11978
+ function asDate(v) {
11979
+ return v && !Array.isArray(v) && typeof v === "object" && "preset" in v ? v : { preset: null };
11980
+ }
11981
+ function asNumeric(v) {
11982
+ return v && !Array.isArray(v) && typeof v === "object" && "operator" in v ? v : { operator: "gt", value: "" };
11983
+ }
11984
+ var OPERATOR_SYMBOL = {
11985
+ gt: ">",
11986
+ lt: "<",
11987
+ eq: "="
11988
+ };
11687
11989
  function FilterDropdown({
11688
- filters,
11689
- onFiltersChange,
11690
- initialFilters,
11691
- contacts = DEFAULT_CONTACTS,
11990
+ fields,
11991
+ value,
11992
+ defaultValue,
11993
+ onChange,
11994
+ label = "Filter",
11995
+ align = "start",
11996
+ showActiveChips = true,
11692
11997
  className
11693
11998
  }) {
11694
11999
  const [isOpen, setIsOpen] = (0, import_react73.useState)(false);
11695
- const [activeMenu, setActiveMenu] = (0, import_react73.useState)("contact");
12000
+ const [activeId, setActiveId] = (0, import_react73.useState)(fields[0]?.id ?? null);
11696
12001
  const [isMobile, setIsMobile] = (0, import_react73.useState)(false);
12002
+ const isControlled = value !== void 0;
12003
+ const [internal, setInternal] = (0, import_react73.useState)(defaultValue ?? {});
12004
+ const values = isControlled ? value : internal;
11697
12005
  (0, import_react73.useEffect)(() => {
11698
12006
  const checkMobile = () => setIsMobile(window.innerWidth < 768);
11699
12007
  checkMobile();
11700
12008
  window.addEventListener("resize", checkMobile);
11701
12009
  return () => window.removeEventListener("resize", checkMobile);
11702
12010
  }, []);
11703
- const [selectedContacts, setSelectedContacts] = (0, import_react73.useState)(
11704
- filters?.contacts ?? initialFilters?.contacts ?? []
11705
- );
11706
- const [walletInput, setWalletInput] = (0, import_react73.useState)(filters?.walletAddress ?? initialFilters?.walletAddress ?? "");
11707
- const [appliedWallet, setAppliedWallet] = (0, import_react73.useState)(filters?.walletAddress ?? initialFilters?.walletAddress ?? "");
11708
- const [selectedDatePreset, setSelectedDatePreset] = (0, import_react73.useState)(
11709
- filters?.lastInvoiceDate ?? initialFilters?.lastInvoiceDate ?? null
11710
- );
11711
- const [customDateFrom, setCustomDateFrom] = (0, import_react73.useState)(
11712
- filters?.customDateRange?.from ?? initialFilters?.customDateRange?.from ?? ""
11713
- );
11714
- const [customDateTo, setCustomDateTo] = (0, import_react73.useState)(
11715
- filters?.customDateRange?.to ?? initialFilters?.customDateRange?.to ?? ""
11716
- );
11717
- const [ltvOperator, setLtvOperator] = (0, import_react73.useState)(
11718
- filters?.lifetimeValue?.operator ?? initialFilters?.lifetimeValue?.operator ?? "greater_than"
11719
- );
11720
- const [ltvValue, setLtvValue] = (0, import_react73.useState)(filters?.lifetimeValue?.value ?? initialFilters?.lifetimeValue?.value ?? "");
11721
- const [isLtvOperatorOpen, setLtvOperatorOpen] = (0, import_react73.useState)(false);
11722
- const [outstandingOperator, setOutstandingOperator] = (0, import_react73.useState)(
11723
- filters?.outstanding?.operator ?? initialFilters?.outstanding?.operator ?? "greater_than"
11724
- );
11725
- const [outstandingValue, setOutstandingValue] = (0, import_react73.useState)(filters?.outstanding?.value ?? initialFilters?.outstanding?.value ?? "");
11726
- const [isOutstandingOperatorOpen, setOutstandingOperatorOpen] = (0, import_react73.useState)(false);
11727
12011
  (0, import_react73.useEffect)(() => {
11728
- if (filters) {
11729
- setSelectedContacts(filters.contacts ?? []);
11730
- setWalletInput(filters.walletAddress ?? "");
11731
- setAppliedWallet(filters.walletAddress ?? "");
11732
- setSelectedDatePreset(filters.lastInvoiceDate ?? null);
11733
- setCustomDateFrom(filters.customDateRange?.from ?? "");
11734
- setCustomDateTo(filters.customDateRange?.to ?? "");
11735
- setLtvOperator(filters.lifetimeValue?.operator ?? "greater_than");
11736
- setLtvValue(filters.lifetimeValue?.value ?? "");
11737
- setOutstandingOperator(filters.outstanding?.operator ?? "greater_than");
11738
- setOutstandingValue(filters.outstanding?.value ?? "");
11739
- }
11740
- }, [filters]);
11741
- const [contactSearch, setContactSearch] = (0, import_react73.useState)("");
11742
- const [walletSearch, setWalletSearch] = (0, import_react73.useState)("");
11743
- const refDate = (0, import_react73.useMemo)(() => new Date(2026, 5, 26), []);
11744
- const presets = (0, import_react73.useMemo)(() => {
11745
- const year = refDate.getFullYear();
11746
- const month = refDate.getMonth();
11747
- const lastMonthDate = new Date(year, month - 1, 1);
11748
- const lastMonthLabel = lastMonthDate.toLocaleDateString("en-US", { month: "short", year: "numeric" });
11749
- const thisMonthLabel = refDate.toLocaleDateString("en-US", { month: "short", year: "numeric" });
11750
- const thisQuarter = Math.floor(month / 3) + 1;
11751
- const thisQuarterLabel = `Q${thisQuarter} ${year}`;
11752
- const lastQuarter = thisQuarter === 1 ? 4 : thisQuarter - 1;
11753
- const lastQuarterYear = thisQuarter === 1 ? year - 1 : year;
11754
- const lastQuarterLabel = `Q${lastQuarter} ${lastQuarterYear}`;
11755
- const thisYearLabel = `${year}`;
11756
- const last30 = new Date(refDate);
11757
- last30.setDate(refDate.getDate() - 30);
11758
- const formatDate = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
11759
- const last30Label = `${formatDate(last30)} - ${formatDate(refDate)}`;
11760
- const last90 = new Date(refDate);
11761
- last90.setDate(refDate.getDate() - 90);
11762
- const last90Label = `${formatDate(last90)} - ${formatDate(refDate)}`;
11763
- return [
11764
- { id: "last_month", label: "Last month", date: lastMonthLabel },
11765
- { id: "this_month", label: "This month", date: thisMonthLabel },
11766
- { id: "this_quarter", label: "This quarter", date: thisQuarterLabel },
11767
- { id: "last_quarter", label: "Last quarter", date: lastQuarterLabel },
11768
- { id: "this_year", label: "This year", date: thisYearLabel },
11769
- { id: "last_30_days", label: "Last 30 days", date: last30Label },
11770
- { id: "last_90_days", label: "Last 90 days", date: last90Label },
11771
- { id: "custom", label: "Custom range", date: "" }
11772
- ];
11773
- }, [refDate]);
11774
- const filteredContacts = (0, import_react73.useMemo)(() => {
11775
- if (!contactSearch) return contacts;
11776
- const query = contactSearch.toLowerCase();
11777
- return contacts.filter(
11778
- (c) => c.name.toLowerCase().includes(query) || c.email.toLowerCase().includes(query)
11779
- );
11780
- }, [contacts, contactSearch]);
11781
- const handleContactToggle = (contactName) => {
11782
- const next = selectedContacts.includes(contactName) ? selectedContacts.filter((name) => name !== contactName) : [...selectedContacts, contactName];
11783
- setSelectedContacts(next);
11784
- notifyChanges({ contacts: next });
11785
- setIsOpen(false);
12012
+ if (!fields.some((f) => f.id === activeId)) {
12013
+ setActiveId(fields[0]?.id ?? null);
12014
+ }
12015
+ }, [fields, activeId]);
12016
+ const commit = (id, next) => {
12017
+ const merged = { ...values, [id]: next };
12018
+ if (!isControlled) setInternal(merged);
12019
+ onChange?.(merged);
11786
12020
  };
11787
- const handleWalletApply = () => {
11788
- setAppliedWallet(walletInput);
11789
- notifyChanges({ walletAddress: walletInput });
11790
- setIsOpen(false);
12021
+ const clearAll = () => {
12022
+ if (!isControlled) setInternal({});
12023
+ onChange?.({});
11791
12024
  };
11792
- const handleWalletClear = () => {
11793
- setWalletInput("");
11794
- setAppliedWallet("");
11795
- notifyChanges({ walletAddress: "" });
11796
- setIsOpen(false);
11797
- };
11798
- const handleDatePresetSelect = (presetId) => {
11799
- setSelectedDatePreset(presetId);
11800
- if (presetId !== "custom") {
11801
- notifyChanges({ lastInvoiceDate: presetId, customDateRange: void 0 });
11802
- setIsOpen(false);
12025
+ const activeIdx = fields.findIndex((f) => f.id === activeId);
12026
+ const activeField = activeIdx >= 0 ? fields[activeIdx] : void 0;
12027
+ const chips = [];
12028
+ for (const field of fields) {
12029
+ const v = values[field.id];
12030
+ if (field.type === "multiselect") {
12031
+ const selected = asArray(v);
12032
+ for (const optionValue of selected) {
12033
+ const opt = field.options?.find((o) => o.value === optionValue);
12034
+ chips.push({
12035
+ id: `${field.id}:${optionValue}`,
12036
+ label: `${field.label}: ${opt?.label ?? optionValue}`,
12037
+ remove: () => commit(field.id, selected.filter((x) => x !== optionValue))
12038
+ });
12039
+ }
12040
+ } else if (field.type === "text") {
12041
+ const text = asText(v);
12042
+ if (text) {
12043
+ chips.push({
12044
+ id: field.id,
12045
+ label: `${field.label}: ${text}`,
12046
+ remove: () => commit(field.id, "")
12047
+ });
12048
+ }
12049
+ } else if (field.type === "numeric") {
12050
+ const n = asNumeric(v);
12051
+ if (n.value) {
12052
+ chips.push({
12053
+ id: field.id,
12054
+ label: `${field.label} ${OPERATOR_SYMBOL[n.operator]} ${n.value}`,
12055
+ remove: () => commit(field.id, null)
12056
+ });
12057
+ }
12058
+ } else if (field.type === "daterange") {
12059
+ const d = asDate(v);
12060
+ if (d.preset) {
12061
+ const presetLabel = d.preset === "custom" ? `${d.from || "\u2026"} \u2013 ${d.to || "\u2026"}` : (field.presets ?? DEFAULT_PRESETS).find((p) => p.id === d.preset)?.label ?? d.preset;
12062
+ chips.push({
12063
+ id: field.id,
12064
+ label: `${field.label}: ${presetLabel}`,
12065
+ remove: () => commit(field.id, { preset: null })
12066
+ });
12067
+ }
11803
12068
  }
11804
- };
11805
- const handleCustomDateApply = () => {
11806
- notifyChanges({
11807
- lastInvoiceDate: "custom",
11808
- customDateRange: { from: customDateFrom, to: customDateTo }
11809
- });
11810
- setIsOpen(false);
11811
- };
11812
- const handleLtvApply = () => {
11813
- notifyChanges({
11814
- lifetimeValue: ltvValue ? { operator: ltvOperator, value: ltvValue } : null
11815
- });
11816
- setIsOpen(false);
11817
- };
11818
- const handleLtvClear = () => {
11819
- setLtvValue("");
11820
- notifyChanges({ lifetimeValue: null });
11821
- setIsOpen(false);
11822
- };
11823
- const handleOutstandingApply = () => {
11824
- notifyChanges({
11825
- outstanding: outstandingValue ? { operator: outstandingOperator, value: outstandingValue } : null
11826
- });
11827
- setIsOpen(false);
11828
- };
11829
- const handleOutstandingClear = () => {
11830
- setOutstandingValue("");
11831
- notifyChanges({ outstanding: null });
11832
- setIsOpen(false);
11833
- };
11834
- const notifyChanges = (overrides) => {
11835
- const current = {
11836
- contacts: selectedContacts,
11837
- walletAddress: appliedWallet,
11838
- lastInvoiceDate: selectedDatePreset,
11839
- customDateRange: customDateFrom || customDateTo ? { from: customDateFrom, to: customDateTo } : void 0,
11840
- lifetimeValue: ltvValue ? { operator: ltvOperator, value: ltvValue } : null,
11841
- outstanding: outstandingValue ? { operator: outstandingOperator, value: outstandingValue } : null,
11842
- ...overrides
11843
- };
11844
- onFiltersChange?.(current);
11845
- };
11846
- const menuItems = [
11847
- { id: "contact", label: "Contact", icon: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.UserIcon, { className: "size-4" }) },
11848
- { id: "wallet", label: "Wallet address", icon: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.WalletIcon, { className: "size-4" }) },
11849
- { id: "date", label: "Last invoice date", icon: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.CalendarIcon, { className: "size-4" }) },
11850
- { id: "ltv", label: "Lifetime value", icon: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.TrendingUpIcon, { className: "size-4" }) },
11851
- { id: "outstanding", label: "Outstanding", icon: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.CircleDollarSignIcon, { className: "size-4" }) }
11852
- ];
11853
- const activeIdx = menuItems.findIndex((item) => item.id === activeMenu);
11854
- return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: cn("inline-block", className), children: /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
11855
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11856
- Button,
12069
+ }
12070
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: cn("flex flex-wrap items-center gap-2", className), children: [
12071
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
12072
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12073
+ Button,
12074
+ {
12075
+ variant: "outline",
12076
+ size: "sm",
12077
+ className: "border-dashed font-medium text-muted-foreground hover:text-foreground",
12078
+ iconLeading: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(import_lucide_react25.ListFilterIcon, { className: "size-4" }),
12079
+ children: label
12080
+ }
12081
+ ) }),
12082
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12083
+ PopoverContent,
12084
+ {
12085
+ variant: "list",
12086
+ align,
12087
+ className: "overflow-visible border-none bg-transparent p-0 shadow-none max-w-[calc(100vw-32px)] md:max-w-none",
12088
+ children: /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "relative flex flex-col md:flex-row items-stretch md:items-start w-[calc(100vw-32px)] max-w-[340px] md:w-auto md:max-w-none", children: [
12089
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("div", { className: "w-full md:w-56 rounded-xl border border-border bg-popover p-1.5 shadow-lg", children: fields.map((field) => {
12090
+ const isActive = activeId === field.id;
12091
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(
12092
+ "button",
12093
+ {
12094
+ type: "button",
12095
+ className: cn(
12096
+ "flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm text-left transition-colors outline-none",
12097
+ isActive ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
12098
+ ),
12099
+ onMouseEnter: () => !isMobile && setActiveId(field.id),
12100
+ onClick: () => setActiveId(field.id),
12101
+ children: [
12102
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("span", { className: "flex items-center gap-2", children: [
12103
+ field.icon,
12104
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { children: field.label })
12105
+ ] }),
12106
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(import_lucide_react25.ChevronRightIcon, { className: "size-4 text-muted-foreground/50" })
12107
+ ]
12108
+ },
12109
+ field.id
12110
+ );
12111
+ }) }),
12112
+ activeField && /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12113
+ "div",
12114
+ {
12115
+ className: "relative left-0 mt-2 w-full md:absolute md:left-[calc(100%+6px)] md:w-80 rounded-xl border border-border bg-popover p-3 shadow-lg transition-all duration-150 md:mt-0",
12116
+ style: isMobile ? {} : { top: `${activeIdx * 36 + 6}px` },
12117
+ children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12118
+ FilterFieldControl,
12119
+ {
12120
+ field: activeField,
12121
+ value: values[activeField.id],
12122
+ onChange: (next) => commit(activeField.id, next),
12123
+ onClose: () => setIsOpen(false)
12124
+ }
12125
+ )
12126
+ }
12127
+ )
12128
+ ] })
12129
+ }
12130
+ )
12131
+ ] }),
12132
+ showActiveChips && chips.map((chip) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(FilterChip, { label: chip.label, onRemove: chip.remove }, chip.id)),
12133
+ showActiveChips && chips.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12134
+ "button",
11857
12135
  {
11858
- variant: "outline",
11859
- size: "sm",
11860
- shape: "pill",
11861
- className: "border-dashed font-medium text-muted-foreground hover:text-foreground",
11862
- iconLeading: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.ListFilterIcon, { className: "size-4" }),
11863
- children: "Filter"
12136
+ type: "button",
12137
+ onClick: clearAll,
12138
+ className: "rounded-full px-3 py-1 text-sm font-medium text-muted-foreground outline-none transition-colors hover:text-foreground",
12139
+ children: "Clear all"
11864
12140
  }
11865
- ) }),
11866
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11867
- PopoverContent,
11868
- {
11869
- variant: "list",
11870
- align: "start",
11871
- className: "overflow-visible border-none bg-transparent p-0 shadow-none max-w-[calc(100vw-32px)] md:max-w-none",
11872
- children: /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "relative flex flex-col md:flex-row items-stretch md:items-start w-[calc(100vw-32px)] max-w-[340px] md:w-auto md:max-w-none", children: [
11873
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "w-full md:w-56 rounded-xl border border-border bg-popover p-1.5 shadow-lg", children: menuItems.map((item) => {
11874
- const isActive = activeMenu === item.id;
11875
- return /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(
11876
- "button",
11877
- {
11878
- type: "button",
11879
- className: cn(
11880
- "flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm text-left transition-colors outline-none",
11881
- isActive ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
11882
- ),
11883
- onMouseEnter: () => !isMobile && setActiveMenu(item.id),
11884
- onClick: () => setActiveMenu(item.id),
11885
- children: [
11886
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("span", { className: "flex items-center gap-2", children: [
11887
- item.icon,
11888
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { children: item.label })
11889
- ] }),
11890
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.ChevronRightIcon, { className: "size-4 text-muted-foreground/50" })
11891
- ]
11892
- },
11893
- item.id
11894
- );
11895
- }) }),
11896
- activeMenu && /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(
11897
- "div",
12141
+ )
12142
+ ] });
12143
+ }
12144
+ function FilterChip({ label, onRemove }) {
12145
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("span", { className: "inline-flex h-9 items-center gap-1.5 rounded-full border border-border bg-muted/40 pl-3 pr-1.5 text-sm font-medium text-foreground", children: [
12146
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "truncate", children: label }),
12147
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12148
+ "button",
12149
+ {
12150
+ type: "button",
12151
+ onClick: onRemove,
12152
+ "aria-label": `Remove ${label}`,
12153
+ className: "flex size-5 items-center justify-center rounded-full text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground",
12154
+ children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(import_lucide_react25.XIcon, { className: "size-3.5" })
12155
+ }
12156
+ )
12157
+ ] });
12158
+ }
12159
+ function FilterFieldControl({
12160
+ field,
12161
+ value,
12162
+ onChange,
12163
+ onClose
12164
+ }) {
12165
+ switch (field.type) {
12166
+ case "multiselect":
12167
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(MultiSelectControl, { field, value: asArray(value), onChange });
12168
+ case "text":
12169
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(TextControl, { field, value: asText(value), onChange, onClose });
12170
+ case "daterange":
12171
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(DateRangeControl, { field, value: asDate(value), onChange, onClose });
12172
+ case "numeric":
12173
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(NumericControl, { field, value: asNumeric(value), onChange, onClose });
12174
+ default:
12175
+ return null;
12176
+ }
12177
+ }
12178
+ function MultiSelectControl({
12179
+ field,
12180
+ value,
12181
+ onChange
12182
+ }) {
12183
+ const options = field.options ?? [];
12184
+ const [search, setSearch] = (0, import_react73.useState)("");
12185
+ const searchable = field.searchable ?? options.length > 8;
12186
+ const filtered = (0, import_react73.useMemo)(() => {
12187
+ if (!search) return options;
12188
+ const q = search.toLowerCase();
12189
+ return options.filter(
12190
+ (o) => o.label.toLowerCase().includes(q) || o.hint?.toLowerCase().includes(q)
12191
+ );
12192
+ }, [options, search]);
12193
+ const toggle = (optionValue) => {
12194
+ onChange(
12195
+ value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue]
12196
+ );
12197
+ };
12198
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
12199
+ searchable && /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12200
+ SearchInput,
12201
+ {
12202
+ placeholder: field.searchPlaceholder ?? "Search\u2026",
12203
+ value: search,
12204
+ onChange: (e) => setSearch(e.target.value),
12205
+ className: "w-full min-w-0"
12206
+ }
12207
+ ),
12208
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("div", { className: "flex max-h-48 flex-col gap-1 overflow-y-auto pr-1", children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("p", { className: "py-4 text-center text-xs text-muted-foreground", children: "No options found" }) : filtered.map((option) => /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(
12209
+ "label",
12210
+ {
12211
+ className: "flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 transition-colors hover:bg-muted/50",
12212
+ children: [
12213
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12214
+ Checkbox,
11898
12215
  {
11899
- className: "relative left-0 mt-2 w-full md:absolute md:left-[calc(100%+6px)] md:w-80 rounded-xl border border-border bg-popover p-3 shadow-lg transition-all duration-150 md:mt-0",
11900
- style: isMobile ? {} : { top: `${activeIdx * 36 + 6}px` },
11901
- children: [
11902
- activeMenu === "contact" && /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
11903
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "relative flex items-center", children: [
11904
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.SearchIcon, { className: "absolute left-2.5 size-4 text-muted-foreground/60" }),
11905
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11906
- "input",
11907
- {
11908
- type: "text",
11909
- placeholder: "Search by name or email...",
11910
- value: contactSearch,
11911
- onChange: (e) => setContactSearch(e.target.value),
11912
- className: "w-full rounded-lg border border-border bg-background py-1.5 pl-8 pr-3 text-sm outline-none placeholder:text-muted-foreground/60 focus:border-border"
11913
- }
11914
- )
11915
- ] }),
11916
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "max-h-48 overflow-y-auto flex flex-col gap-1 pr-1", children: filteredContacts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("p", { className: "py-4 text-center text-xs text-muted-foreground", children: "No contacts found" }) : filteredContacts.map((contact) => {
11917
- const isChecked = selectedContacts.includes(contact.name);
11918
- return /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(
11919
- "label",
11920
- {
11921
- className: "flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 hover:bg-muted/50 transition-colors",
11922
- children: [
11923
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11924
- Checkbox,
11925
- {
11926
- checked: isChecked,
11927
- onCheckedChange: () => handleContactToggle(contact.name)
11928
- }
11929
- ),
11930
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(Avatar, { variant: "secondary", children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(AvatarFallback, { children: contact.initials }) }),
11931
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { className: "text-sm font-medium text-foreground", children: contact.name })
11932
- ]
11933
- },
11934
- contact.id
11935
- );
11936
- }) })
11937
- ] }),
11938
- activeMenu === "wallet" && /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
11939
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "relative flex items-center", children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11940
- "input",
11941
- {
11942
- type: "text",
11943
- placeholder: "Search by wallet...",
11944
- value: walletInput,
11945
- onChange: (e) => setWalletInput(e.target.value),
11946
- className: "w-full rounded-lg border border-border bg-background px-3 py-1.5 text-sm outline-none placeholder:text-muted-foreground/60"
11947
- }
11948
- ) }),
11949
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
11950
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11951
- Button,
11952
- {
11953
- variant: "ghost",
11954
- size: "sm",
11955
- onClick: handleWalletClear,
11956
- className: "text-muted-foreground hover:text-foreground h-8 px-3",
11957
- children: "Clear"
11958
- }
11959
- ),
11960
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11961
- Button,
11962
- {
11963
- color: "primary",
11964
- size: "sm",
11965
- onClick: handleWalletApply,
11966
- className: "h-8 px-3",
11967
- children: "Apply"
11968
- }
11969
- )
11970
- ] })
11971
- ] }),
11972
- activeMenu === "date" && /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex flex-col gap-1", children: [
11973
- presets.map((preset) => {
11974
- const isSelected = selectedDatePreset === preset.id;
11975
- return /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(
11976
- "button",
11977
- {
11978
- type: "button",
11979
- onClick: () => handleDatePresetSelect(preset.id),
11980
- className: cn(
11981
- "flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-sm text-left transition-colors outline-none",
11982
- isSelected ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
11983
- ),
11984
- children: [
11985
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { children: preset.label }),
11986
- preset.date && /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { className: "text-xs text-muted-foreground/70", children: preset.date })
11987
- ]
11988
- },
11989
- preset.id
11990
- );
11991
- }),
11992
- selectedDatePreset === "custom" && /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex flex-col gap-2 mt-2 pt-2 border-t border-border/40", children: [
11993
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex items-center gap-2", children: [
11994
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
11995
- "input",
11996
- {
11997
- type: "date",
11998
- value: customDateFrom,
11999
- onChange: (e) => setCustomDateFrom(e.target.value),
12000
- className: "w-full rounded-lg border border-border bg-background px-2 py-1 text-xs outline-none"
12001
- }
12002
- ),
12003
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { className: "text-xs text-muted-foreground", children: "to" }),
12004
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12005
- "input",
12006
- {
12007
- type: "date",
12008
- value: customDateTo,
12009
- onChange: (e) => setCustomDateTo(e.target.value),
12010
- className: "w-full rounded-lg border border-border bg-background px-2 py-1 text-xs outline-none"
12011
- }
12012
- )
12013
- ] }),
12014
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "flex justify-end gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12015
- Button,
12016
- {
12017
- color: "primary",
12018
- size: "sm",
12019
- onClick: handleCustomDateApply,
12020
- className: "h-7 text-xs px-2.5",
12021
- children: "Apply"
12022
- }
12023
- ) })
12024
- ] })
12025
- ] }),
12026
- activeMenu === "ltv" && /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
12027
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex items-center gap-2", children: [
12028
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "relative shrink-0", children: [
12029
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(
12030
- "button",
12031
- {
12032
- type: "button",
12033
- onClick: () => setLtvOperatorOpen(!isLtvOperatorOpen),
12034
- className: "flex h-9 items-center gap-1 rounded-lg border border-border bg-background px-2.5 text-xs font-normal text-muted-foreground hover:bg-muted/50 hover:text-foreground outline-none whitespace-nowrap",
12035
- children: [
12036
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { children: OPERATORS.find((op) => op.id === ltvOperator)?.label.replace("...", "") }),
12037
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.ChevronDownIcon, { className: "size-3" })
12038
- ]
12039
- }
12040
- ),
12041
- isLtvOperatorOpen && /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "absolute left-0 top-full z-50 mt-1 w-32 rounded-lg border border-border bg-popover p-1 shadow-md", children: OPERATORS.map((op) => /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12042
- "button",
12043
- {
12044
- type: "button",
12045
- onClick: () => {
12046
- setLtvOperator(op.id);
12047
- setLtvOperatorOpen(false);
12048
- },
12049
- className: "w-full rounded-md px-2 py-1 text-left text-xs text-foreground hover:bg-muted outline-none",
12050
- children: op.label
12051
- },
12052
- op.id
12053
- )) })
12054
- ] }),
12055
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12056
- "input",
12057
- {
12058
- type: "text",
12059
- placeholder: "0.00",
12060
- value: ltvValue,
12061
- onChange: (e) => setLtvValue(e.target.value),
12062
- className: "h-9 flex-1 min-w-0 rounded-lg border border-border bg-background px-3 py-1 text-sm outline-none placeholder:text-muted-foreground/60"
12063
- }
12064
- )
12065
- ] }),
12066
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
12067
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12068
- Button,
12069
- {
12070
- variant: "ghost",
12071
- size: "sm",
12072
- onClick: handleLtvClear,
12073
- className: "text-muted-foreground hover:text-foreground h-8 px-3",
12074
- children: "Clear"
12075
- }
12076
- ),
12077
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12078
- Button,
12079
- {
12080
- color: "primary",
12081
- size: "sm",
12082
- onClick: handleLtvApply,
12083
- className: "h-8 px-3",
12084
- children: "Apply"
12085
- }
12086
- )
12087
- ] })
12088
- ] }),
12089
- activeMenu === "outstanding" && /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
12090
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex items-center gap-2", children: [
12091
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "relative shrink-0", children: [
12092
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(
12093
- "button",
12094
- {
12095
- type: "button",
12096
- onClick: () => setOutstandingOperatorOpen(!isOutstandingOperatorOpen),
12097
- className: "flex h-9 items-center gap-1 rounded-lg border border-border bg-background px-2.5 text-xs font-normal text-muted-foreground hover:bg-muted/50 hover:text-foreground outline-none whitespace-nowrap",
12098
- children: [
12099
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { children: OPERATORS.find((op) => op.id === outstandingOperator)?.label.replace("...", "") }),
12100
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(import_lucide_react24.ChevronDownIcon, { className: "size-3" })
12101
- ]
12102
- }
12103
- ),
12104
- isOutstandingOperatorOpen && /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "absolute left-0 top-full z-50 mt-1 w-32 rounded-lg border border-border bg-popover p-1 shadow-md", children: OPERATORS.map((op) => /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12105
- "button",
12106
- {
12107
- type: "button",
12108
- onClick: () => {
12109
- setOutstandingOperator(op.id);
12110
- setOutstandingOperatorOpen(false);
12111
- },
12112
- className: "w-full rounded-md px-2 py-1 text-left text-xs text-foreground hover:bg-muted outline-none",
12113
- children: op.label
12114
- },
12115
- op.id
12116
- )) })
12117
- ] }),
12118
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12119
- "input",
12120
- {
12121
- type: "text",
12122
- placeholder: "0.00",
12123
- value: outstandingValue,
12124
- onChange: (e) => setOutstandingValue(e.target.value),
12125
- className: "h-9 flex-1 min-w-0 rounded-lg border border-border bg-background px-3 py-1 text-sm outline-none placeholder:text-muted-foreground/60"
12126
- }
12127
- )
12128
- ] }),
12129
- /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
12130
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12131
- Button,
12132
- {
12133
- variant: "ghost",
12134
- size: "sm",
12135
- onClick: handleOutstandingClear,
12136
- className: "text-muted-foreground hover:text-foreground h-8 px-3",
12137
- children: "Clear"
12138
- }
12139
- ),
12140
- /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
12141
- Button,
12142
- {
12143
- color: "primary",
12144
- size: "sm",
12145
- onClick: handleOutstandingApply,
12146
- className: "h-8 px-3",
12147
- children: "Apply"
12148
- }
12149
- )
12150
- ] })
12151
- ] })
12152
- ]
12216
+ checked: value.includes(option.value),
12217
+ onCheckedChange: () => toggle(option.value)
12153
12218
  }
12154
- )
12155
- ] })
12219
+ ),
12220
+ option.icon,
12221
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("span", { className: "flex min-w-0 flex-col", children: [
12222
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "truncate text-sm font-medium text-foreground", children: option.label }),
12223
+ option.hint && /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: option.hint })
12224
+ ] })
12225
+ ]
12226
+ },
12227
+ option.value
12228
+ )) })
12229
+ ] });
12230
+ }
12231
+ function TextControl({
12232
+ field,
12233
+ value,
12234
+ onChange,
12235
+ onClose
12236
+ }) {
12237
+ const [draft, setDraft] = (0, import_react73.useState)(value);
12238
+ (0, import_react73.useEffect)(() => setDraft(value), [value]);
12239
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
12240
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12241
+ "input",
12242
+ {
12243
+ type: "text",
12244
+ placeholder: field.placeholder ?? "Type a value\u2026",
12245
+ value: draft,
12246
+ onChange: (e) => setDraft(e.target.value),
12247
+ onKeyDown: (e) => {
12248
+ if (e.key === "Enter") {
12249
+ onChange(draft);
12250
+ onClose();
12251
+ }
12252
+ },
12253
+ className: controlClass({ size: "sm" }, "w-full")
12254
+ }
12255
+ ),
12256
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12257
+ ApplyClear,
12258
+ {
12259
+ onClear: () => {
12260
+ setDraft("");
12261
+ onChange("");
12262
+ onClose();
12263
+ },
12264
+ onApply: () => {
12265
+ onChange(draft);
12266
+ onClose();
12267
+ }
12156
12268
  }
12157
12269
  )
12158
- ] }) });
12270
+ ] });
12271
+ }
12272
+ function DateRangeControl({
12273
+ field,
12274
+ value,
12275
+ onChange,
12276
+ onClose
12277
+ }) {
12278
+ const presets = field.presets ?? DEFAULT_PRESETS;
12279
+ const [from, setFrom] = (0, import_react73.useState)(value.from ?? "");
12280
+ const [to, setTo] = (0, import_react73.useState)(value.to ?? "");
12281
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex flex-col gap-1", children: [
12282
+ presets.map((preset) => {
12283
+ const isSelected = value.preset === preset.id;
12284
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(
12285
+ "button",
12286
+ {
12287
+ type: "button",
12288
+ onClick: () => {
12289
+ if (preset.id === "custom") {
12290
+ onChange({ preset: "custom", from, to });
12291
+ } else {
12292
+ onChange({ preset: preset.id });
12293
+ onClose();
12294
+ }
12295
+ },
12296
+ className: cn(
12297
+ "flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-left text-sm transition-colors outline-none",
12298
+ isSelected ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
12299
+ ),
12300
+ children: [
12301
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { children: preset.label }),
12302
+ preset.hint && /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "text-xs text-muted-foreground/70", children: preset.hint })
12303
+ ]
12304
+ },
12305
+ preset.id
12306
+ );
12307
+ }),
12308
+ value.preset === "custom" && /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "mt-2 flex flex-col gap-2 border-t border-border/40 pt-2", children: [
12309
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex items-center gap-2", children: [
12310
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12311
+ "input",
12312
+ {
12313
+ type: "date",
12314
+ value: from,
12315
+ onChange: (e) => setFrom(e.target.value),
12316
+ className: controlClass({ size: "sm" }, "w-full text-xs")
12317
+ }
12318
+ ),
12319
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "text-xs text-muted-foreground", children: "to" }),
12320
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12321
+ "input",
12322
+ {
12323
+ type: "date",
12324
+ value: to,
12325
+ onChange: (e) => setTo(e.target.value),
12326
+ className: controlClass({ size: "sm" }, "w-full text-xs")
12327
+ }
12328
+ )
12329
+ ] }),
12330
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12331
+ Button,
12332
+ {
12333
+ color: "primary",
12334
+ size: "sm",
12335
+ className: "h-8 px-3",
12336
+ onClick: () => {
12337
+ onChange({ preset: "custom", from, to });
12338
+ onClose();
12339
+ },
12340
+ children: "Apply"
12341
+ }
12342
+ ) })
12343
+ ] })
12344
+ ] });
12345
+ }
12346
+ function NumericControl({
12347
+ field,
12348
+ value,
12349
+ onChange,
12350
+ onClose
12351
+ }) {
12352
+ const operators = field.operators ?? DEFAULT_OPERATORS;
12353
+ const [operator, setOperator] = (0, import_react73.useState)(value.operator);
12354
+ const [draft, setDraft] = (0, import_react73.useState)(value.value);
12355
+ (0, import_react73.useEffect)(() => {
12356
+ setOperator(value.operator);
12357
+ setDraft(value.value);
12358
+ }, [value.operator, value.value]);
12359
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
12360
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex items-center gap-2", children: [
12361
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(Select, { value: operator, onValueChange: (v) => setOperator(v), children: [
12362
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(SelectTrigger, { size: "sm", className: "shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(SelectValue, {}) }),
12363
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(SelectContent, { children: operators.map((op) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(SelectItem, { value: op.id, children: op.label }, op.id)) })
12364
+ ] }),
12365
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12366
+ "input",
12367
+ {
12368
+ type: "text",
12369
+ inputMode: "decimal",
12370
+ placeholder: field.placeholder ?? "0.00",
12371
+ value: draft,
12372
+ onChange: (e) => setDraft(e.target.value),
12373
+ onKeyDown: (e) => {
12374
+ if (e.key === "Enter") {
12375
+ onChange(draft ? { operator, value: draft } : null);
12376
+ onClose();
12377
+ }
12378
+ },
12379
+ className: controlClass({ size: "sm" }, "min-w-0 flex-1")
12380
+ }
12381
+ )
12382
+ ] }),
12383
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12384
+ ApplyClear,
12385
+ {
12386
+ onClear: () => {
12387
+ setDraft("");
12388
+ onChange(null);
12389
+ onClose();
12390
+ },
12391
+ onApply: () => {
12392
+ onChange(draft ? { operator, value: draft } : null);
12393
+ onClose();
12394
+ }
12395
+ }
12396
+ )
12397
+ ] });
12398
+ }
12399
+ function ApplyClear({ onClear, onApply }) {
12400
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "flex items-center justify-end gap-2 border-t border-border/40 pt-1", children: [
12401
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12402
+ Button,
12403
+ {
12404
+ variant: "ghost",
12405
+ size: "sm",
12406
+ onClick: onClear,
12407
+ className: "h-8 px-3 text-muted-foreground hover:text-foreground",
12408
+ children: "Clear"
12409
+ }
12410
+ ),
12411
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { color: "primary", size: "sm", onClick: onApply, className: "h-8 px-3", children: "Apply" })
12412
+ ] });
12159
12413
  }
12160
12414
 
12161
12415
  // src/app/data/DataTable.tsx
12162
12416
  var import_react74 = require("react");
12163
- var import_lucide_react25 = require("lucide-react");
12417
+ var import_lucide_react26 = require("lucide-react");
12164
12418
 
12165
12419
  // src/ui/skeleton.tsx
12166
- var import_jsx_runtime107 = require("react/jsx-runtime");
12420
+ var import_jsx_runtime108 = require("react/jsx-runtime");
12167
12421
  function Skeleton({ className, ...props }) {
12168
- return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
12422
+ return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12169
12423
  "div",
12170
12424
  {
12171
12425
  "data-slot": "skeleton",
@@ -12176,7 +12430,7 @@ function Skeleton({ className, ...props }) {
12176
12430
  }
12177
12431
 
12178
12432
  // src/app/data/DataTable.tsx
12179
- var import_jsx_runtime108 = require("react/jsx-runtime");
12433
+ var import_jsx_runtime109 = require("react/jsx-runtime");
12180
12434
  var shellClass2 = "w-full";
12181
12435
  var tableClass = "w-full border-separate border-spacing-0 bg-transparent text-sm";
12182
12436
  var headRowClass = "";
@@ -12219,12 +12473,12 @@ function SortIndicator({
12219
12473
  }) {
12220
12474
  const iconClass = "size-3.5 shrink-0 opacity-60 group-hover:opacity-100";
12221
12475
  if (!active) {
12222
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(import_lucide_react25.ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
12476
+ return /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(import_lucide_react26.ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
12223
12477
  }
12224
12478
  if (direction === "desc") {
12225
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(import_lucide_react25.ArrowDownIcon, { className: iconClass, "aria-hidden": true });
12479
+ return /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(import_lucide_react26.ArrowDownIcon, { className: iconClass, "aria-hidden": true });
12226
12480
  }
12227
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(import_lucide_react25.ArrowUpIcon, { className: iconClass, "aria-hidden": true });
12481
+ return /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(import_lucide_react26.ArrowUpIcon, { className: iconClass, "aria-hidden": true });
12228
12482
  }
12229
12483
  function DataTable({
12230
12484
  columns,
@@ -12322,7 +12576,7 @@ function DataTable({
12322
12576
  const headPad = dense ? "px-3 py-2" : void 0;
12323
12577
  const colSpan = columns.length + (selectable ? 1 : 0);
12324
12578
  if (!loading && rows.length === 0 && emptyMode === "replace") {
12325
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(EmptyState, { title: emptyTitle, description: emptyDescription, className });
12579
+ return /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(EmptyState, { title: emptyTitle, description: emptyDescription, className });
12326
12580
  }
12327
12581
  const allKeys = sortedRows.map(getRowKey);
12328
12582
  const allSelected = allKeys.length > 0 && allKeys.every((k) => selectedSet.has(k));
@@ -12347,10 +12601,10 @@ function DataTable({
12347
12601
  const hasPager = paginated && !loading && sortedRows.length > 0;
12348
12602
  const hasFoot = (showRowCount || footer || hasPager) && (loading || sortedRows.length > 0);
12349
12603
  const skeletonCount = loadingRows ?? pageSize ?? 5;
12350
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("table", { className: tableClass, children: [
12351
- caption ? /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("caption", { className: "sr-only", children: caption }) : null,
12352
- /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("thead", { className: cn(headRowClass, stickyHeader && stickyHeadClass), children: /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("tr", { children: [
12353
- selectable ? /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("th", { scope: "col", className: cn(selectCellClass, headPad), children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12604
+ return /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("table", { className: tableClass, children: [
12605
+ caption ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("caption", { className: "sr-only", children: caption }) : null,
12606
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("thead", { className: cn(headRowClass, stickyHeader && stickyHeadClass), children: /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("tr", { children: [
12607
+ selectable ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("th", { scope: "col", className: cn(selectCellClass, headPad), children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12354
12608
  Checkbox,
12355
12609
  {
12356
12610
  checked: headerCheckedState,
@@ -12362,19 +12616,19 @@ function DataTable({
12362
12616
  columns.map((col) => {
12363
12617
  const isSorted = sort?.columnId === col.id;
12364
12618
  const ariaSort = col.sortable ? isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none" : void 0;
12365
- const headerContent = col.sortable ? /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)(
12619
+ const headerContent = col.sortable ? /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)(
12366
12620
  "button",
12367
12621
  {
12368
12622
  type: "button",
12369
12623
  className: sortButtonClass,
12370
12624
  onClick: () => setSort(nextSort(sort, col.id)),
12371
12625
  children: [
12372
- /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("span", { className: "truncate", children: col.header }),
12373
- /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
12626
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("span", { className: "truncate", children: col.header }),
12627
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
12374
12628
  ]
12375
12629
  }
12376
12630
  ) : col.header;
12377
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12631
+ return /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12378
12632
  "th",
12379
12633
  {
12380
12634
  scope: "col",
@@ -12391,9 +12645,9 @@ function DataTable({
12391
12645
  );
12392
12646
  })
12393
12647
  ] }) }),
12394
- /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: loading ? Array.from({ length: skeletonCount }).map((_, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("tr", { className: rowClass, "aria-hidden": true, children: [
12395
- selectable ? /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("td", { className: cn(selectCellClass, cellPad), children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(Skeleton, { className: "size-4 rounded-[4px]" }) }) : null,
12396
- columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12648
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: loading ? Array.from({ length: skeletonCount }).map((_, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("tr", { className: rowClass, "aria-hidden": true, children: [
12649
+ selectable ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("td", { className: cn(selectCellClass, cellPad), children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(Skeleton, { className: "size-4 rounded-[4px]" }) }) : null,
12650
+ columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12397
12651
  "td",
12398
12652
  {
12399
12653
  className: cn(
@@ -12402,17 +12656,17 @@ function DataTable({
12402
12656
  col.align && alignClass[col.align],
12403
12657
  col.className
12404
12658
  ),
12405
- children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(Skeleton, { className: "h-4 w-[60%]" })
12659
+ children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(Skeleton, { className: "h-4 w-[60%]" })
12406
12660
  },
12407
12661
  col.id
12408
12662
  ))
12409
- ] }, `skeleton-${rowIdx}`)) : visibleRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("td", { colSpan, className: emptyCellClass, children: /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("div", { className: "flex flex-col items-center gap-1", children: [
12410
- /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("p", { className: "font-medium text-foreground", children: emptyTitle }),
12411
- emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
12663
+ ] }, `skeleton-${rowIdx}`)) : visibleRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("td", { colSpan, className: emptyCellClass, children: /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("div", { className: "flex flex-col items-center gap-1", children: [
12664
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("p", { className: "font-medium text-foreground", children: emptyTitle }),
12665
+ emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
12412
12666
  ] }) }) }) : visibleRows.map((row) => {
12413
12667
  const key = getRowKey(row);
12414
12668
  const isSelected = selectedSet.has(key);
12415
- return /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)(
12669
+ return /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)(
12416
12670
  "tr",
12417
12671
  {
12418
12672
  className: rowClass,
@@ -12428,12 +12682,12 @@ function DataTable({
12428
12682
  tabIndex: onRowClick ? 0 : void 0,
12429
12683
  role: onRowClick ? "button" : void 0,
12430
12684
  children: [
12431
- selectable ? /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12685
+ selectable ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12432
12686
  "td",
12433
12687
  {
12434
12688
  className: cn(selectCellClass, cellPad),
12435
12689
  onClick: (event) => event.stopPropagation(),
12436
- children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12690
+ children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12437
12691
  Checkbox,
12438
12692
  {
12439
12693
  checked: isSelected,
@@ -12443,7 +12697,7 @@ function DataTable({
12443
12697
  )
12444
12698
  }
12445
12699
  ) : null,
12446
- columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12700
+ columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12447
12701
  "td",
12448
12702
  {
12449
12703
  className: cn(
@@ -12453,7 +12707,7 @@ function DataTable({
12453
12707
  col.align && alignClass[col.align],
12454
12708
  col.className
12455
12709
  ),
12456
- children: col.truncate ? /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("div", { className: "truncate", children: col.cell(row) }) : col.cell(row)
12710
+ children: col.truncate ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("div", { className: "truncate", children: col.cell(row) }) : col.cell(row)
12457
12711
  },
12458
12712
  col.id
12459
12713
  ))
@@ -12462,7 +12716,7 @@ function DataTable({
12462
12716
  key
12463
12717
  );
12464
12718
  }) }),
12465
- hasFoot ? /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("tfoot", { children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)("td", { colSpan, className: footCellClass, children: /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)(
12719
+ hasFoot ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("tfoot", { children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)("td", { colSpan, className: footCellClass, children: /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)(
12466
12720
  "div",
12467
12721
  {
12468
12722
  className: cn(
@@ -12470,18 +12724,18 @@ function DataTable({
12470
12724
  (showRowCount || footer || hasPager) && "justify-between"
12471
12725
  ),
12472
12726
  children: [
12473
- /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("div", { className: footInnerClass, children: [
12474
- showRowCount ? /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("span", { children: [
12727
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("div", { className: footInnerClass, children: [
12728
+ showRowCount ? /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("span", { children: [
12475
12729
  rowCountText,
12476
12730
  selectable && selectedSet.size > 0 ? ` \xB7 ${selectedSet.size} selected` : null
12477
- ] }) : selectable && selectedSet.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("span", { children: [
12731
+ ] }) : selectable && selectedSet.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("span", { children: [
12478
12732
  selectedSet.size,
12479
12733
  " selected"
12480
12734
  ] }) : null,
12481
12735
  footer
12482
12736
  ] }),
12483
- hasPager ? /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("div", { className: "flex items-center gap-2", children: [
12484
- /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("span", { className: "tabular-nums", children: [
12737
+ hasPager ? /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("div", { className: "flex items-center gap-2", children: [
12738
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("span", { className: "tabular-nums", children: [
12485
12739
  pageIndex * pageSize + 1,
12486
12740
  "\u2013",
12487
12741
  Math.min(
@@ -12492,8 +12746,8 @@ function DataTable({
12492
12746
  "of ",
12493
12747
  sortedRows.length
12494
12748
  ] }),
12495
- /* @__PURE__ */ (0, import_jsx_runtime108.jsxs)("div", { className: "flex items-center gap-1", children: [
12496
- /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12749
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)("div", { className: "flex items-center gap-1", children: [
12750
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12497
12751
  "button",
12498
12752
  {
12499
12753
  type: "button",
@@ -12501,10 +12755,10 @@ function DataTable({
12501
12755
  onClick: () => setPage(pageIndex - 1),
12502
12756
  disabled: pageIndex <= 0,
12503
12757
  "aria-label": "Previous page",
12504
- children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(import_lucide_react25.ChevronLeftIcon, { className: "size-4", "aria-hidden": true })
12758
+ children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(import_lucide_react26.ChevronLeftIcon, { className: "size-4", "aria-hidden": true })
12505
12759
  }
12506
12760
  ),
12507
- /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(
12761
+ /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12508
12762
  "button",
12509
12763
  {
12510
12764
  type: "button",
@@ -12512,7 +12766,7 @@ function DataTable({
12512
12766
  onClick: () => setPage(pageIndex + 1),
12513
12767
  disabled: pageIndex >= pageCount - 1,
12514
12768
  "aria-label": "Next page",
12515
- children: /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(import_lucide_react25.ChevronRightIcon, { className: "size-4", "aria-hidden": true })
12769
+ children: /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(import_lucide_react26.ChevronRightIcon, { className: "size-4", "aria-hidden": true })
12516
12770
  }
12517
12771
  )
12518
12772
  ] })
@@ -12525,7 +12779,7 @@ function DataTable({
12525
12779
 
12526
12780
  // src/app/data/ChartPanel.tsx
12527
12781
  var import_react75 = require("react");
12528
- var import_jsx_runtime109 = require("react/jsx-runtime");
12782
+ var import_jsx_runtime110 = require("react/jsx-runtime");
12529
12783
  var ChartPanel = ({
12530
12784
  title,
12531
12785
  description,
@@ -12543,14 +12797,14 @@ var ChartPanel = ({
12543
12797
  const titleId = (0, import_react75.useId)();
12544
12798
  const resolvedTitle = title ?? artifact?.title;
12545
12799
  const hasHeader = Boolean(resolvedTitle || description || actions);
12546
- const body = loading ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(Skeleton, { className: "w-full rounded-lg", style: { height }, "aria-hidden": true }) : children ?? (artifact ? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(ChartArtifactView, { artifact, embedded: true, height }) : null);
12547
- return /* @__PURE__ */ (0, import_jsx_runtime109.jsxs)(
12800
+ const body = loading ? /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(Skeleton, { className: "w-full rounded-lg", style: { height }, "aria-hidden": true }) : children ?? (artifact ? /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(ChartArtifactView, { artifact, embedded: true, height }) : null);
12801
+ return /* @__PURE__ */ (0, import_jsx_runtime110.jsxs)(
12548
12802
  "section",
12549
12803
  {
12550
12804
  className: cn(metricCardShellClass, "aui-app-chart-panel", className),
12551
12805
  "aria-labelledby": resolvedTitle ? titleId : void 0,
12552
12806
  children: [
12553
- /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12807
+ /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(
12554
12808
  MetricCardHeader,
12555
12809
  {
12556
12810
  title: resolvedTitle,
@@ -12559,14 +12813,14 @@ var ChartPanel = ({
12559
12813
  actions
12560
12814
  }
12561
12815
  ),
12562
- /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12816
+ /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(
12563
12817
  "div",
12564
12818
  {
12565
12819
  className: cn(
12566
12820
  "relative min-h-0 w-full",
12567
12821
  hasHeader ? metricChartPlotRegionClass : chartPanelBodyClass
12568
12822
  ),
12569
- children: body ?? /* @__PURE__ */ (0, import_jsx_runtime109.jsx)(
12823
+ children: body ?? /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(
12570
12824
  "div",
12571
12825
  {
12572
12826
  className: "flex items-center justify-center text-sm font-normal text-muted-foreground",
@@ -12584,7 +12838,7 @@ var ChartPanel = ({
12584
12838
 
12585
12839
  // src/app/data/MetricRow.tsx
12586
12840
  var import_react76 = require("react");
12587
- var import_jsx_runtime110 = require("react/jsx-runtime");
12841
+ var import_jsx_runtime111 = require("react/jsx-runtime");
12588
12842
  var MetricRow = ({
12589
12843
  title,
12590
12844
  titleTag,
@@ -12610,13 +12864,13 @@ var MetricRow = ({
12610
12864
  onMetricChange?.(id);
12611
12865
  };
12612
12866
  const hasHeader = Boolean(title || titleTag || description || actions);
12613
- return /* @__PURE__ */ (0, import_jsx_runtime110.jsxs)(
12867
+ return /* @__PURE__ */ (0, import_jsx_runtime111.jsxs)(
12614
12868
  "section",
12615
12869
  {
12616
12870
  className: cn(metricCardShellClass, className),
12617
12871
  "aria-labelledby": title ? titleId : void 0,
12618
12872
  children: [
12619
- /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(
12873
+ /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
12620
12874
  MetricCardHeader,
12621
12875
  {
12622
12876
  title,
@@ -12626,7 +12880,7 @@ var MetricRow = ({
12626
12880
  actions
12627
12881
  }
12628
12882
  ),
12629
- /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(
12883
+ /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
12630
12884
  "div",
12631
12885
  {
12632
12886
  role: selectable ? "group" : void 0,
@@ -12637,18 +12891,18 @@ var MetricRow = ({
12637
12891
  metricTilesGridColsClass(loading ? metrics.length || 4 : metrics.length),
12638
12892
  hasHeader && "mt-3.5 border-t border-border/40"
12639
12893
  ),
12640
- children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime110.jsxs)(
12894
+ children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime111.jsxs)(
12641
12895
  "div",
12642
12896
  {
12643
12897
  className: cn("flex min-w-0 flex-1 flex-col gap-2", metricTileClass),
12644
12898
  "aria-hidden": true,
12645
12899
  children: [
12646
- /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(Skeleton, { className: "h-3 w-20" }),
12647
- /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(Skeleton, { className: "h-7 w-24" })
12900
+ /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(Skeleton, { className: "h-3 w-20" }),
12901
+ /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(Skeleton, { className: "h-7 w-24" })
12648
12902
  ]
12649
12903
  },
12650
12904
  `skeleton-${index}`
12651
- )) : metrics.map((m, index) => /* @__PURE__ */ (0, import_jsx_runtime110.jsx)(
12905
+ )) : metrics.map((m, index) => /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
12652
12906
  MetricTile,
12653
12907
  {
12654
12908
  label: m.label,
@@ -12676,7 +12930,7 @@ var MetricRow = ({
12676
12930
 
12677
12931
  // src/app/data/MetricChartCard.tsx
12678
12932
  var import_react77 = require("react");
12679
- var import_jsx_runtime111 = require("react/jsx-runtime");
12933
+ var import_jsx_runtime112 = require("react/jsx-runtime");
12680
12934
  var MetricChartCard = ({
12681
12935
  title,
12682
12936
  titleTag,
@@ -12712,13 +12966,13 @@ var MetricChartCard = ({
12712
12966
  };
12713
12967
  const hasHeader = Boolean(title || titleTag || description || actions);
12714
12968
  const chartAriaLabel = typeof active?.label === "string" ? `${active.label} over time` : "Metric chart";
12715
- return /* @__PURE__ */ (0, import_jsx_runtime111.jsxs)(
12969
+ return /* @__PURE__ */ (0, import_jsx_runtime112.jsxs)(
12716
12970
  "section",
12717
12971
  {
12718
12972
  className: cn(metricCardShellClass, className),
12719
12973
  "aria-labelledby": title ? titleId : void 0,
12720
12974
  children: [
12721
- /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
12975
+ /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(
12722
12976
  MetricCardHeader,
12723
12977
  {
12724
12978
  title,
@@ -12728,7 +12982,7 @@ var MetricChartCard = ({
12728
12982
  titleId
12729
12983
  }
12730
12984
  ),
12731
- /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
12985
+ /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(
12732
12986
  "div",
12733
12987
  {
12734
12988
  role: "group",
@@ -12739,18 +12993,18 @@ var MetricChartCard = ({
12739
12993
  metricTilesGridColsClass(loading ? metrics.length || 4 : metrics.length),
12740
12994
  hasHeader && "mt-3.5 border-t border-border/40"
12741
12995
  ),
12742
- children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime111.jsxs)(
12996
+ children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime112.jsxs)(
12743
12997
  "div",
12744
12998
  {
12745
12999
  className: cn("flex min-w-0 flex-1 flex-col gap-2", metricTileClass),
12746
13000
  "aria-hidden": true,
12747
13001
  children: [
12748
- /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(Skeleton, { className: "h-3 w-20" }),
12749
- /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(Skeleton, { className: "h-7 w-24" })
13002
+ /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(Skeleton, { className: "h-3 w-20" }),
13003
+ /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(Skeleton, { className: "h-7 w-24" })
12750
13004
  ]
12751
13005
  },
12752
13006
  `skeleton-${index}`
12753
- )) : metrics.map((m, index) => /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
13007
+ )) : metrics.map((m, index) => /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(
12754
13008
  MetricTile,
12755
13009
  {
12756
13010
  label: m.label,
@@ -12771,14 +13025,14 @@ var MetricChartCard = ({
12771
13025
  ))
12772
13026
  }
12773
13027
  ),
12774
- /* @__PURE__ */ (0, import_jsx_runtime111.jsx)("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
13028
+ /* @__PURE__ */ (0, import_jsx_runtime112.jsx)("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(
12775
13029
  Skeleton,
12776
13030
  {
12777
13031
  className: "w-full rounded-lg",
12778
13032
  style: { height },
12779
13033
  "aria-hidden": true
12780
13034
  }
12781
- ) : active?.data && active.data.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
13035
+ ) : active?.data && active.data.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(
12782
13036
  LineAreaChart,
12783
13037
  {
12784
13038
  data: active.data,
@@ -12798,7 +13052,7 @@ var MetricChartCard = ({
12798
13052
  ariaLabel: chartAriaLabel
12799
13053
  },
12800
13054
  active.id
12801
- ) : /* @__PURE__ */ (0, import_jsx_runtime111.jsx)(
13055
+ ) : /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(
12802
13056
  "div",
12803
13057
  {
12804
13058
  className: "flex w-full items-center justify-center text-sm font-normal text-muted-foreground",
@@ -12904,8 +13158,8 @@ function useLiveQuery(fetcher, options = {}) {
12904
13158
 
12905
13159
  // src/ui/untitled-button.tsx
12906
13160
  var import_class_variance_authority2 = require("class-variance-authority");
12907
- var import_radix_ui9 = require("radix-ui");
12908
- var import_jsx_runtime112 = require("react/jsx-runtime");
13161
+ var import_radix_ui10 = require("radix-ui");
13162
+ var import_jsx_runtime113 = require("react/jsx-runtime");
12909
13163
  var SOLID_SKEUOMORPHIC_SHADOW2 = "shadow-skeuomorphic-solid";
12910
13164
  var BORDERED_SKEUOMORPHIC_SHADOW2 = "shadow-skeuomorphic-bordered";
12911
13165
  var untitledButtonVariants = (0, import_class_variance_authority2.cva)(
@@ -12988,10 +13242,10 @@ var untitledButtonVariants = (0, import_class_variance_authority2.cva)(
12988
13242
  )
12989
13243
  },
12990
13244
  size: {
12991
- sm: "h-9 gap-1.5 rounded-lg px-3 text-sm",
12992
- md: "h-10 gap-1.5 rounded-lg px-3.5 text-sm",
12993
- lg: "h-11 gap-2 rounded-lg px-4 text-base",
12994
- xl: "h-12 gap-2 rounded-lg px-5 text-base"
13245
+ sm: "h-8 gap-1 rounded-md px-2.5 text-xs",
13246
+ md: "h-9 gap-1.5 rounded-lg px-3 text-sm",
13247
+ lg: "h-10 gap-1.5 rounded-lg px-3.5 text-sm",
13248
+ xl: "h-11 gap-2 rounded-lg px-4 text-base"
12995
13249
  }
12996
13250
  },
12997
13251
  defaultVariants: {
@@ -13016,8 +13270,8 @@ function UntitledButton({
13016
13270
  const isDisabled = disabled || isLoading;
13017
13271
  const classes = cn(untitledButtonVariants({ color, size }), className);
13018
13272
  if (asChild) {
13019
- return /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(
13020
- import_radix_ui9.Slot.Root,
13273
+ return /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
13274
+ import_radix_ui10.Slot.Root,
13021
13275
  {
13022
13276
  className: classes,
13023
13277
  "aria-disabled": isDisabled ? true : void 0,
@@ -13027,7 +13281,7 @@ function UntitledButton({
13027
13281
  }
13028
13282
  );
13029
13283
  }
13030
- return /* @__PURE__ */ (0, import_jsx_runtime112.jsxs)(
13284
+ return /* @__PURE__ */ (0, import_jsx_runtime113.jsxs)(
13031
13285
  "button",
13032
13286
  {
13033
13287
  type,
@@ -13036,7 +13290,7 @@ function UntitledButton({
13036
13290
  className: classes,
13037
13291
  ...props,
13038
13292
  children: [
13039
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime112.jsx)(
13293
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
13040
13294
  "span",
13041
13295
  {
13042
13296
  "aria-hidden": true,
@@ -13051,8 +13305,8 @@ function UntitledButton({
13051
13305
  }
13052
13306
 
13053
13307
  // src/ui/banner.tsx
13054
- var import_lucide_react26 = require("lucide-react");
13055
- var import_jsx_runtime113 = require("react/jsx-runtime");
13308
+ var import_lucide_react27 = require("lucide-react");
13309
+ var import_jsx_runtime114 = require("react/jsx-runtime");
13056
13310
  var bannerSoftClass = {
13057
13311
  default: "border-border/50 bg-muted/30 text-foreground/90 dark:bg-muted/15",
13058
13312
  primary: "border-primary/15 bg-primary/5 text-primary-800 dark:text-primary-200 [&_[data-banner-icon]]:text-primary",
@@ -13097,7 +13351,7 @@ function Banner({
13097
13351
  }) {
13098
13352
  const isSolid = variant === "solid";
13099
13353
  const isSingleLine = !title;
13100
- return /* @__PURE__ */ (0, import_jsx_runtime113.jsxs)(
13354
+ return /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(
13101
13355
  "div",
13102
13356
  {
13103
13357
  "data-slot": "banner",
@@ -13112,7 +13366,7 @@ function Banner({
13112
13366
  ),
13113
13367
  ...props,
13114
13368
  children: [
13115
- icon ? /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
13369
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
13116
13370
  "span",
13117
13371
  {
13118
13372
  "data-banner-icon": true,
@@ -13123,9 +13377,9 @@ function Banner({
13123
13377
  children: icon
13124
13378
  }
13125
13379
  ) : null,
13126
- /* @__PURE__ */ (0, import_jsx_runtime113.jsxs)("div", { className: "min-w-0 flex-1", children: [
13127
- title ? /* @__PURE__ */ (0, import_jsx_runtime113.jsx)("p", { className: "font-medium tracking-tight", children: title }) : null,
13128
- children ? /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
13380
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)("div", { className: "min-w-0 flex-1", children: [
13381
+ title ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)("p", { className: "font-medium tracking-tight", children: title }) : null,
13382
+ children ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
13129
13383
  "div",
13130
13384
  {
13131
13385
  className: cn(
@@ -13136,8 +13390,8 @@ function Banner({
13136
13390
  }
13137
13391
  ) : null
13138
13392
  ] }),
13139
- actions ? /* @__PURE__ */ (0, import_jsx_runtime113.jsx)("div", { className: "flex shrink-0 items-center gap-2", children: actions }) : null,
13140
- onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
13393
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)("div", { className: "flex shrink-0 items-center gap-2", children: actions }) : null,
13394
+ onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
13141
13395
  "button",
13142
13396
  {
13143
13397
  type: "button",
@@ -13148,7 +13402,7 @@ function Banner({
13148
13402
  isSingleLine ? "self-center" : "-mt-0.5",
13149
13403
  isSolid ? "opacity-80 hover:bg-background/15 hover:opacity-100" : "text-muted-foreground hover:bg-foreground/10 hover:text-foreground"
13150
13404
  ),
13151
- children: /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(import_lucide_react26.XIcon, { className: "size-4", "aria-hidden": true })
13405
+ children: /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(import_lucide_react27.XIcon, { className: "size-4", "aria-hidden": true })
13152
13406
  }
13153
13407
  ) : null
13154
13408
  ]
@@ -13157,7 +13411,7 @@ function Banner({
13157
13411
  }
13158
13412
 
13159
13413
  // src/ui/timeline.tsx
13160
- var import_jsx_runtime114 = require("react/jsx-runtime");
13414
+ var import_jsx_runtime115 = require("react/jsx-runtime");
13161
13415
  var timelineRowGap = {
13162
13416
  sm: "pb-4",
13163
13417
  default: "pb-6"
@@ -13190,16 +13444,16 @@ var toneStyles = {
13190
13444
  }
13191
13445
  };
13192
13446
  function Timeline({ items, size = "default", className, ...props }) {
13193
- return /* @__PURE__ */ (0, import_jsx_runtime114.jsx)("ol", { "data-slot": "timeline", className: cn("flex flex-col", className), ...props, children: items.map((item, index) => {
13447
+ return /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("ol", { "data-slot": "timeline", className: cn("flex flex-col", className), ...props, children: items.map((item, index) => {
13194
13448
  const last = index === items.length - 1;
13195
13449
  const tone = item.tone ?? "default";
13196
13450
  const styles = toneStyles[tone];
13197
- return /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(
13451
+ return /* @__PURE__ */ (0, import_jsx_runtime115.jsxs)(
13198
13452
  "li",
13199
13453
  {
13200
13454
  className: cn("relative flex gap-3.5 last:pb-0", timelineRowGap[size]),
13201
13455
  children: [
13202
- !last ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
13456
+ !last ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13203
13457
  "span",
13204
13458
  {
13205
13459
  "aria-hidden": true,
@@ -13209,7 +13463,7 @@ function Timeline({ items, size = "default", className, ...props }) {
13209
13463
  )
13210
13464
  }
13211
13465
  ) : null,
13212
- /* @__PURE__ */ (0, import_jsx_runtime114.jsx)("div", { className: "relative flex w-5 shrink-0 justify-center pt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
13466
+ /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("div", { className: "relative flex w-5 shrink-0 justify-center pt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13213
13467
  "span",
13214
13468
  {
13215
13469
  className: cn(
@@ -13217,7 +13471,7 @@ function Timeline({ items, size = "default", className, ...props }) {
13217
13471
  styles.border,
13218
13472
  item.icon ? "size-6" : "size-4"
13219
13473
  ),
13220
- children: item.icon ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)("div", { className: cn("text-xs", styles.icon), children: item.icon }) : /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
13474
+ children: item.icon ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("div", { className: cn("text-xs", styles.icon), children: item.icon }) : /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13221
13475
  "span",
13222
13476
  {
13223
13477
  className: cn(
@@ -13228,12 +13482,12 @@ function Timeline({ items, size = "default", className, ...props }) {
13228
13482
  )
13229
13483
  }
13230
13484
  ) }),
13231
- /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)("div", { className: "min-w-0 flex-1 pb-0.5", children: [
13232
- /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
13233
- /* @__PURE__ */ (0, import_jsx_runtime114.jsx)("p", { className: "text-sm font-normal text-foreground", children: item.title }),
13234
- item.meta ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground tabular-nums", children: item.meta }) : null
13485
+ /* @__PURE__ */ (0, import_jsx_runtime115.jsxs)("div", { className: "min-w-0 flex-1 pb-0.5", children: [
13486
+ /* @__PURE__ */ (0, import_jsx_runtime115.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
13487
+ /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("p", { className: "text-sm font-normal text-foreground", children: item.title }),
13488
+ item.meta ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground tabular-nums", children: item.meta }) : null
13235
13489
  ] }),
13236
- item.description ? /* @__PURE__ */ (0, import_jsx_runtime114.jsx)("p", { className: "mt-0.5 text-[13px] leading-relaxed text-muted-foreground", children: item.description }) : null
13490
+ item.description ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("p", { className: "mt-0.5 text-[13px] leading-relaxed text-muted-foreground", children: item.description }) : null
13237
13491
  ] })
13238
13492
  ]
13239
13493
  },
@@ -13247,8 +13501,8 @@ var React6 = __toESM(require("react"), 1);
13247
13501
  var import_core2 = require("@dnd-kit/core");
13248
13502
  var import_sortable = require("@dnd-kit/sortable");
13249
13503
  var import_utilities = require("@dnd-kit/utilities");
13250
- var import_lucide_react27 = require("lucide-react");
13251
- var import_jsx_runtime115 = require("react/jsx-runtime");
13504
+ var import_lucide_react28 = require("lucide-react");
13505
+ var import_jsx_runtime116 = require("react/jsx-runtime");
13252
13506
  var columnTitleToneClass = {
13253
13507
  default: "text-foreground",
13254
13508
  primary: "text-blue-600 dark:text-blue-400",
@@ -13310,7 +13564,7 @@ function SortableCard({
13310
13564
  transition
13311
13565
  };
13312
13566
  const dragHandleProps = disabled ? void 0 : { ...attributes, ...listeners2 };
13313
- return /* @__PURE__ */ (0, import_jsx_runtime115.jsxs)(
13567
+ return /* @__PURE__ */ (0, import_jsx_runtime116.jsxs)(
13314
13568
  "div",
13315
13569
  {
13316
13570
  ref: setNodeRef,
@@ -13325,7 +13579,7 @@ function SortableCard({
13325
13579
  className
13326
13580
  ),
13327
13581
  children: [
13328
- !disabled && dragHandle === "auto" ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13582
+ !disabled && dragHandle === "auto" ? /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(
13329
13583
  "button",
13330
13584
  {
13331
13585
  type: "button",
@@ -13333,7 +13587,7 @@ function SortableCard({
13333
13587
  className: "absolute right-1.5 top-1.5 z-10 grid size-6 cursor-grab touch-none place-items-center rounded-md text-muted-foreground/40 opacity-0 transition hover:bg-foreground/5 hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 group-hover/kanban-card:opacity-100 active:cursor-grabbing",
13334
13588
  ...attributes,
13335
13589
  ...listeners2,
13336
- children: /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(import_lucide_react27.GripVerticalIcon, { className: "size-4", "aria-hidden": true })
13590
+ children: /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(import_lucide_react28.GripVerticalIcon, { className: "size-4", "aria-hidden": true })
13337
13591
  }
13338
13592
  ) : null,
13339
13593
  renderCard(card, { column, isDragging, isOverlay: false, dragHandleProps })
@@ -13357,7 +13611,7 @@ function KanbanColumnView({
13357
13611
  }) {
13358
13612
  const tone = column.tone ?? "default";
13359
13613
  const { setNodeRef, isOver } = (0, import_core2.useDroppable)({ id: column.id, disabled });
13360
- return /* @__PURE__ */ (0, import_jsx_runtime115.jsxs)(
13614
+ return /* @__PURE__ */ (0, import_jsx_runtime116.jsxs)(
13361
13615
  "div",
13362
13616
  {
13363
13617
  "data-slot": "kanban-column",
@@ -13367,9 +13621,9 @@ function KanbanColumnView({
13367
13621
  className
13368
13622
  ),
13369
13623
  children: [
13370
- renderColumnHeader ? renderColumnHeader(column) : /* @__PURE__ */ (0, import_jsx_runtime115.jsxs)("div", { className: "flex flex-col gap-0.5 px-1 pb-0.5", children: [
13371
- /* @__PURE__ */ (0, import_jsx_runtime115.jsxs)("div", { className: "flex items-center gap-2", children: [
13372
- /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13624
+ renderColumnHeader ? renderColumnHeader(column) : /* @__PURE__ */ (0, import_jsx_runtime116.jsxs)("div", { className: "flex flex-col gap-0.5 px-1 pb-0.5", children: [
13625
+ /* @__PURE__ */ (0, import_jsx_runtime116.jsxs)("div", { className: "flex items-center gap-2", children: [
13626
+ /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(
13373
13627
  "h3",
13374
13628
  {
13375
13629
  className: cn(
@@ -13379,12 +13633,12 @@ function KanbanColumnView({
13379
13633
  children: column.title
13380
13634
  }
13381
13635
  ),
13382
- /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("span", { className: "shrink-0 text-xs font-normal tabular-nums text-muted-foreground/60", children: column.cards.length }),
13383
- column.action ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("div", { className: "shrink-0", children: column.action }) : null
13636
+ /* @__PURE__ */ (0, import_jsx_runtime116.jsx)("span", { className: "shrink-0 text-xs font-normal tabular-nums text-muted-foreground/60", children: column.cards.length }),
13637
+ column.action ? /* @__PURE__ */ (0, import_jsx_runtime116.jsx)("div", { className: "shrink-0", children: column.action }) : null
13384
13638
  ] }),
13385
- column.description ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("p", { className: "truncate text-xs text-muted-foreground", children: column.description }) : null
13639
+ column.description ? /* @__PURE__ */ (0, import_jsx_runtime116.jsx)("p", { className: "truncate text-xs text-muted-foreground", children: column.description }) : null
13386
13640
  ] }),
13387
- /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(import_sortable.SortableContext, { items: cardIds, strategy: import_sortable.verticalListSortingStrategy, children: /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13641
+ /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(import_sortable.SortableContext, { items: cardIds, strategy: import_sortable.verticalListSortingStrategy, children: /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(
13388
13642
  "div",
13389
13643
  {
13390
13644
  ref: setNodeRef,
@@ -13394,9 +13648,9 @@ function KanbanColumnView({
13394
13648
  densityListClass[density],
13395
13649
  isOver && "bg-muted/50"
13396
13650
  ),
13397
- children: column.cards.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("div", { className: "flex flex-1 items-center justify-center rounded-xl border border-dashed border-border/60 px-2 py-8 text-center text-xs text-muted-foreground/70", children: emptyColumnLabel ?? "Drop here" }) : column.cards.map((card) => {
13651
+ children: column.cards.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime116.jsx)("div", { className: "flex flex-1 items-center justify-center rounded-xl border border-dashed border-border/60 px-2 py-8 text-center text-xs text-muted-foreground/70", children: emptyColumnLabel ?? "Drop here" }) : column.cards.map((card) => {
13398
13652
  const id = getCardId(card);
13399
- return /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13653
+ return /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(
13400
13654
  SortableCard,
13401
13655
  {
13402
13656
  card,
@@ -13414,7 +13668,7 @@ function KanbanColumnView({
13414
13668
  })
13415
13669
  }
13416
13670
  ) }),
13417
- column.footer ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)("div", { className: "px-0.5 pt-0.5", children: column.footer }) : null
13671
+ column.footer ? /* @__PURE__ */ (0, import_jsx_runtime116.jsx)("div", { className: "px-0.5 pt-0.5", children: column.footer }) : null
13418
13672
  ]
13419
13673
  }
13420
13674
  );
@@ -13553,7 +13807,7 @@ function Kanban({
13553
13807
  onColumnsChange?.(next);
13554
13808
  }
13555
13809
  };
13556
- return /* @__PURE__ */ (0, import_jsx_runtime115.jsxs)(
13810
+ return /* @__PURE__ */ (0, import_jsx_runtime116.jsxs)(
13557
13811
  import_core2.DndContext,
13558
13812
  {
13559
13813
  sensors,
@@ -13567,7 +13821,7 @@ function Kanban({
13567
13821
  if (isControlled) setInternal(cloneColumns(columnsProp));
13568
13822
  },
13569
13823
  children: [
13570
- /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13824
+ /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(
13571
13825
  "div",
13572
13826
  {
13573
13827
  "data-slot": "kanban",
@@ -13578,7 +13832,7 @@ function Kanban({
13578
13832
  density === "compact" ? "gap-3" : "gap-4",
13579
13833
  className
13580
13834
  ),
13581
- children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13835
+ children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(
13582
13836
  KanbanColumnView,
13583
13837
  {
13584
13838
  column,
@@ -13598,7 +13852,7 @@ function Kanban({
13598
13852
  ))
13599
13853
  }
13600
13854
  ),
13601
- /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(import_core2.DragOverlay, { children: activeCard ? /* @__PURE__ */ (0, import_jsx_runtime115.jsx)(
13855
+ /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(import_core2.DragOverlay, { children: activeCard ? /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(
13602
13856
  "div",
13603
13857
  {
13604
13858
  "data-slot": "kanban-card-overlay",
@@ -13747,8 +14001,8 @@ When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`,
13747
14001
  `.trim();
13748
14002
 
13749
14003
  // src/auth/guard.tsx
13750
- var import_lucide_react28 = require("lucide-react");
13751
- var import_jsx_runtime116 = require("react/jsx-runtime");
14004
+ var import_lucide_react29 = require("lucide-react");
14005
+ var import_jsx_runtime117 = require("react/jsx-runtime");
13752
14006
  var AuthGuard = ({
13753
14007
  children,
13754
14008
  requireAuth = false,
@@ -13759,7 +14013,7 @@ var AuthGuard = ({
13759
14013
  return children;
13760
14014
  }
13761
14015
  if (loading) {
13762
- return /* @__PURE__ */ (0, import_jsx_runtime116.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime116.jsx)(import_lucide_react28.Loader2, { className: "w-8 h-8 animate-spin" }) });
14016
+ return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_lucide_react29.Loader2, { className: "w-8 h-8 animate-spin" }) });
13763
14017
  }
13764
14018
  if (requireAuth && !isAuthenticated && !isEmbedded) {
13765
14019
  const returnTo = encodeURIComponent(
@@ -13772,162 +14026,7 @@ var AuthGuard = ({
13772
14026
  };
13773
14027
 
13774
14028
  // src/index.ts
13775
- var import_react79 = require("@assistant-ui/react");
13776
-
13777
- // src/ui/select.tsx
13778
- var import_radix_ui10 = require("radix-ui");
13779
- var import_lucide_react29 = require("lucide-react");
13780
- var import_jsx_runtime117 = require("react/jsx-runtime");
13781
- function Select({
13782
- ...props
13783
- }) {
13784
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_radix_ui10.Select.Root, { "data-slot": "select", ...props });
13785
- }
13786
- function SelectGroup({
13787
- ...props
13788
- }) {
13789
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_radix_ui10.Select.Group, { "data-slot": "select-group", ...props });
13790
- }
13791
- function SelectValue({
13792
- ...props
13793
- }) {
13794
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_radix_ui10.Select.Value, { "data-slot": "select-value", ...props });
13795
- }
13796
- function SelectTrigger({
13797
- className,
13798
- size = "default",
13799
- children,
13800
- ...props
13801
- }) {
13802
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsxs)(
13803
- import_radix_ui10.Select.Trigger,
13804
- {
13805
- "data-slot": "select-trigger",
13806
- "data-size": size,
13807
- className: cn(
13808
- controlClass({ size }),
13809
- "flex w-fit items-center justify-between gap-2 whitespace-nowrap *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
13810
- className
13811
- ),
13812
- ...props,
13813
- children: [
13814
- children,
13815
- /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_radix_ui10.Select.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_lucide_react29.ChevronDownIcon, { className: "size-4 opacity-50" }) })
13816
- ]
13817
- }
13818
- );
13819
- }
13820
- function SelectContent({
13821
- className,
13822
- children,
13823
- position = "popper",
13824
- ...props
13825
- }) {
13826
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_radix_ui10.Select.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime117.jsxs)(
13827
- import_radix_ui10.Select.Content,
13828
- {
13829
- "data-slot": "select-content",
13830
- className: cn(
13831
- overlayListPanelClass,
13832
- "relative max-h-[var(--radix-select-content-available-height)] min-w-[8rem] origin-[var(--radix-select-content-transform-origin)] overflow-x-hidden overflow-y-auto",
13833
- position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
13834
- className
13835
- ),
13836
- position,
13837
- ...props,
13838
- children: [
13839
- /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(SelectScrollUpButton, {}),
13840
- /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(
13841
- import_radix_ui10.Select.Viewport,
13842
- {
13843
- className: cn(
13844
- "p-1",
13845
- position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
13846
- ),
13847
- children
13848
- }
13849
- ),
13850
- /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(SelectScrollDownButton, {})
13851
- ]
13852
- }
13853
- ) });
13854
- }
13855
- function SelectLabel({
13856
- className,
13857
- ...props
13858
- }) {
13859
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(
13860
- import_radix_ui10.Select.Label,
13861
- {
13862
- "data-slot": "select-label",
13863
- className: cn("px-2 py-1.5 text-xs font-medium text-muted-foreground", className),
13864
- ...props
13865
- }
13866
- );
13867
- }
13868
- function SelectItem({
13869
- className,
13870
- children,
13871
- ...props
13872
- }) {
13873
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsxs)(
13874
- import_radix_ui10.Select.Item,
13875
- {
13876
- "data-slot": "select-item",
13877
- className: cn(
13878
- overlayItemClass,
13879
- "w-full py-1.5 pr-8 pl-2 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
13880
- className
13881
- ),
13882
- ...props,
13883
- children: [
13884
- /* @__PURE__ */ (0, import_jsx_runtime117.jsx)("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_radix_ui10.Select.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_lucide_react29.CheckIcon, { className: "size-4" }) }) }),
13885
- /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_radix_ui10.Select.ItemText, { children })
13886
- ]
13887
- }
13888
- );
13889
- }
13890
- function SelectSeparator({
13891
- className,
13892
- ...props
13893
- }) {
13894
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(
13895
- import_radix_ui10.Select.Separator,
13896
- {
13897
- "data-slot": "select-separator",
13898
- className: cn("-mx-1 my-1 h-px bg-border", className),
13899
- ...props
13900
- }
13901
- );
13902
- }
13903
- function SelectScrollUpButton({
13904
- className,
13905
- ...props
13906
- }) {
13907
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(
13908
- import_radix_ui10.Select.ScrollUpButton,
13909
- {
13910
- "data-slot": "select-scroll-up-button",
13911
- className: cn("flex cursor-default items-center justify-center py-1", className),
13912
- ...props,
13913
- children: /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_lucide_react29.ChevronUpIcon, { className: "size-4" })
13914
- }
13915
- );
13916
- }
13917
- function SelectScrollDownButton({
13918
- className,
13919
- ...props
13920
- }) {
13921
- return /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(
13922
- import_radix_ui10.Select.ScrollDownButton,
13923
- {
13924
- "data-slot": "select-scroll-down-button",
13925
- className: cn("flex cursor-default items-center justify-center py-1", className),
13926
- ...props,
13927
- children: /* @__PURE__ */ (0, import_jsx_runtime117.jsx)(import_lucide_react29.ChevronDownIcon, { className: "size-4" })
13928
- }
13929
- );
13930
- }
14029
+ var import_react84 = require("@assistant-ui/react");
13931
14030
 
13932
14031
  // src/ui/input.tsx
13933
14032
  var import_jsx_runtime118 = require("react/jsx-runtime");
@@ -13961,7 +14060,7 @@ function Textarea({ className, ...props }) {
13961
14060
  "data-slot": "textarea",
13962
14061
  className: cn(
13963
14062
  controlSurfaceClass,
13964
- "min-h-16 w-full resize-y rounded-lg px-3 py-2 leading-relaxed",
14063
+ "min-h-16 w-full resize-y rounded-lg px-2.5 py-1.5 leading-relaxed",
13965
14064
  className
13966
14065
  ),
13967
14066
  ...props
@@ -14220,7 +14319,7 @@ function BreadcrumbEllipsis({
14220
14319
  "data-slot": "breadcrumb-ellipsis",
14221
14320
  role: "presentation",
14222
14321
  "aria-hidden": "true",
14223
- className: cn("flex size-9 items-center justify-center", className),
14322
+ className: cn("flex size-8 items-center justify-center", className),
14224
14323
  ...props,
14225
14324
  children: [
14226
14325
  /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_lucide_react31.MoreHorizontalIcon, { className: "size-4" }),
@@ -14356,7 +14455,7 @@ function ToolbarButton({
14356
14455
  {
14357
14456
  "data-slot": "toolbar-button",
14358
14457
  className: cn(
14359
- "inline-flex h-8 min-w-8 items-center justify-center rounded-md px-2 text-sm font-medium text-foreground outline-none transition-colors",
14458
+ "inline-flex h-7 min-w-7 items-center justify-center rounded-md px-1.5 text-sm font-medium text-foreground outline-none transition-colors",
14360
14459
  "hover:bg-muted focus-visible:ring-2 focus-visible:ring-foreground/10 disabled:pointer-events-none disabled:opacity-50",
14361
14460
  className
14362
14461
  ),
@@ -14399,7 +14498,7 @@ function ToolbarToggleItem({
14399
14498
  {
14400
14499
  "data-slot": "toolbar-toggle-item",
14401
14500
  className: cn(
14402
- "inline-flex h-8 min-w-8 items-center justify-center rounded-md px-2 text-sm outline-none transition-colors",
14501
+ "inline-flex h-7 min-w-7 items-center justify-center rounded-md px-1.5 text-sm outline-none transition-colors",
14403
14502
  "hover:bg-muted focus-visible:ring-2 focus-visible:ring-foreground/10",
14404
14503
  "data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
14405
14504
  className
@@ -14417,7 +14516,7 @@ function ToolbarLink({
14417
14516
  {
14418
14517
  "data-slot": "toolbar-link",
14419
14518
  className: cn(
14420
- "inline-flex h-8 items-center rounded-md px-2 text-sm text-foreground outline-none transition-colors hover:bg-muted focus-visible:ring-2 focus-visible:ring-foreground/10",
14519
+ "inline-flex h-7 items-center rounded-md px-1.5 text-sm text-foreground outline-none transition-colors hover:bg-muted focus-visible:ring-2 focus-visible:ring-foreground/10",
14421
14520
  className
14422
14521
  ),
14423
14522
  ...props
@@ -14438,7 +14537,7 @@ function Menubar({
14438
14537
  {
14439
14538
  "data-slot": "menubar",
14440
14539
  className: cn(
14441
- "flex h-9 items-center gap-1 rounded-lg border border-border bg-gradient-to-b from-elevated-from to-elevated-to p-1 shadow-card",
14540
+ "flex h-8 items-center gap-1 rounded-lg border border-border bg-gradient-to-b from-elevated-from to-elevated-to p-1 shadow-card",
14442
14541
  className
14443
14542
  ),
14444
14543
  ...props
@@ -14459,7 +14558,7 @@ function MenubarTrigger({
14459
14558
  {
14460
14559
  "data-slot": "menubar-trigger",
14461
14560
  className: cn(
14462
- "flex cursor-default items-center rounded-md px-2 py-1 text-sm font-medium outline-none select-none",
14561
+ "flex cursor-default items-center rounded-md px-2 py-0.5 text-sm font-medium outline-none select-none",
14463
14562
  "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
14464
14563
  className
14465
14564
  ),
@@ -14521,7 +14620,7 @@ function MenubarCheckboxItem({
14521
14620
  import_radix_ui18.Menubar.CheckboxItem,
14522
14621
  {
14523
14622
  "data-slot": "menubar-checkbox-item",
14524
- className: cn(overlayItemClass, "py-1.5 pr-2 pl-8", className),
14623
+ className: cn(overlayItemClass, "py-1 pr-2 pl-8", className),
14525
14624
  checked,
14526
14625
  ...props,
14527
14626
  children: [
@@ -14545,7 +14644,7 @@ function MenubarRadioItem({
14545
14644
  import_radix_ui18.Menubar.RadioItem,
14546
14645
  {
14547
14646
  "data-slot": "menubar-radio-item",
14548
- className: cn(overlayItemClass, "py-1.5 pr-2 pl-8", className),
14647
+ className: cn(overlayItemClass, "py-1 pr-2 pl-8", className),
14549
14648
  ...props,
14550
14649
  children: [
14551
14650
  /* @__PURE__ */ (0, import_jsx_runtime128.jsx)("span", { className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime128.jsx)(import_radix_ui18.Menubar.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime128.jsx)(import_lucide_react33.CircleIcon, { className: "size-2 fill-current" }) }) }),
@@ -14831,7 +14930,7 @@ function CommandDialog({
14831
14930
  {
14832
14931
  className: cn("overflow-hidden p-0", className),
14833
14932
  showCloseButton,
14834
- children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(Command, { className: "[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:size-4 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:size-4", children })
14933
+ children: /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(Command, { className: "[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:size-4 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-1.5 [&_[cmdk-item]_svg]:size-4", children })
14835
14934
  }
14836
14935
  )
14837
14936
  ] });
@@ -14844,7 +14943,7 @@ function CommandInput({
14844
14943
  "div",
14845
14944
  {
14846
14945
  "data-slot": "command-input-wrapper",
14847
- className: "flex h-10 items-center gap-2 border-b border-border px-3",
14946
+ className: "flex h-9 items-center gap-2 border-b border-border px-2.5",
14848
14947
  children: [
14849
14948
  /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(import_lucide_react35.SearchIcon, { className: "size-4 shrink-0 text-muted-foreground" }),
14850
14949
  /* @__PURE__ */ (0, import_jsx_runtime130.jsx)(
@@ -14852,7 +14951,7 @@ function CommandInput({
14852
14951
  {
14853
14952
  "data-slot": "command-input",
14854
14953
  className: cn(
14855
- "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground/70 disabled:cursor-not-allowed disabled:opacity-50",
14954
+ "flex h-9 w-full rounded-md bg-transparent py-2 text-sm outline-none placeholder:text-muted-foreground/70 disabled:cursor-not-allowed disabled:opacity-50",
14856
14955
  className
14857
14956
  ),
14858
14957
  ...props
@@ -14882,7 +14981,7 @@ function CommandEmpty({
14882
14981
  import_cmdk.Command.Empty,
14883
14982
  {
14884
14983
  "data-slot": "command-empty",
14885
- className: "py-6 text-center text-sm text-muted-foreground",
14984
+ className: "py-4 text-center text-sm text-muted-foreground",
14886
14985
  ...props
14887
14986
  }
14888
14987
  );
@@ -14896,7 +14995,7 @@ function CommandGroup({
14896
14995
  {
14897
14996
  "data-slot": "command-group",
14898
14997
  className: cn(
14899
- "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
14998
+ "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
14900
14999
  className
14901
15000
  ),
14902
15001
  ...props
@@ -14978,12 +15077,12 @@ function Calendar({
14978
15077
  button_previous: cn(navButtonClass, defaults.button_previous),
14979
15078
  button_next: cn(navButtonClass, defaults.button_next),
14980
15079
  month_caption: cn(
14981
- "flex h-10 items-center justify-center",
15080
+ "flex h-9 items-center justify-center",
14982
15081
  defaults.month_caption
14983
15082
  ),
14984
15083
  caption_label: cn("text-sm font-semibold", defaults.caption_label),
14985
15084
  dropdowns: cn(
14986
- "flex h-10 items-center justify-center gap-1.5 text-sm font-semibold",
15085
+ "flex h-9 items-center justify-center gap-1.5 text-sm font-semibold",
14987
15086
  defaults.dropdowns
14988
15087
  ),
14989
15088
  dropdown_root: cn(
@@ -14994,17 +15093,17 @@ function Calendar({
14994
15093
  month_grid: cn("border-separate border-spacing-y-1", defaults.month_grid),
14995
15094
  weekdays: cn(defaults.weekdays),
14996
15095
  weekday: cn(
14997
- "size-10 pb-2 text-xs font-medium text-muted-foreground",
15096
+ "size-9 pb-2 text-xs font-medium text-muted-foreground",
14998
15097
  defaults.weekday
14999
15098
  ),
15000
15099
  week: cn(defaults.week),
15001
- week_number_header: cn("size-10", defaults.week_number_header),
15100
+ week_number_header: cn("size-9", defaults.week_number_header),
15002
15101
  week_number: cn(
15003
15102
  "text-xs text-muted-foreground",
15004
15103
  defaults.week_number
15005
15104
  ),
15006
15105
  day: cn(
15007
- "relative size-10 p-0 text-center text-sm focus-within:relative focus-within:z-10",
15106
+ "relative size-9 p-0 text-center text-sm focus-within:relative focus-within:z-10",
15008
15107
  defaults.day
15009
15108
  ),
15010
15109
  range_start: cn("rounded-l-md", defaults.range_start),
@@ -15302,7 +15401,7 @@ function InputOTPSlot({
15302
15401
  "data-slot": "input-otp-slot",
15303
15402
  className: cn(
15304
15403
  controlSurfaceClass,
15305
- "relative size-9 rounded-none text-center text-sm tabular-nums",
15404
+ "relative size-8 rounded-none text-center text-sm tabular-nums",
15306
15405
  "-ms-px first:ms-0 first:rounded-s-lg last:rounded-e-lg",
15307
15406
  "focus-visible:z-10",
15308
15407
  className
@@ -15503,7 +15602,7 @@ function AccordionTrigger({
15503
15602
  {
15504
15603
  "data-slot": "accordion-trigger",
15505
15604
  className: cn(
15506
- "flex flex-1 items-center justify-between gap-4 rounded-md py-4 text-left text-sm font-medium outline-none transition-all",
15605
+ "flex flex-1 items-center justify-between gap-4 rounded-md py-3 text-left text-sm font-medium outline-none transition-all",
15507
15606
  "focus-visible:ring-2 focus-visible:ring-foreground/10 disabled:pointer-events-none disabled:opacity-50",
15508
15607
  "hover:underline [&[data-state=open]>svg]:rotate-180",
15509
15608
  className
@@ -15527,7 +15626,7 @@ function AccordionContent({
15527
15626
  "data-slot": "accordion-content",
15528
15627
  className: "overflow-hidden text-sm text-muted-foreground data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
15529
15628
  ...props,
15530
- children: /* @__PURE__ */ (0, import_jsx_runtime138.jsx)("div", { className: cn("pt-0 pb-4", className), children })
15629
+ children: /* @__PURE__ */ (0, import_jsx_runtime138.jsx)("div", { className: cn("pt-0 pb-3", className), children })
15531
15630
  }
15532
15631
  );
15533
15632
  }
@@ -15728,10 +15827,10 @@ var sheetContentVariants = (0, import_class_variance_authority5.cva)(
15728
15827
  {
15729
15828
  variants: {
15730
15829
  side: {
15731
- top: "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top fixed top-4 inset-x-4 mx-auto w-[calc(100vw-2rem)] sm:max-w-lg rounded-2xl p-6",
15732
- bottom: "data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom fixed bottom-4 inset-x-4 mx-auto w-[calc(100vw-2rem)] sm:max-w-lg rounded-2xl p-6",
15733
- left: "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left fixed top-4 bottom-4 left-4 w-[calc(100vw-2rem)] rounded-2xl p-6",
15734
- right: "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right fixed top-4 bottom-4 right-4 w-[calc(100vw-2rem)] rounded-2xl p-6"
15830
+ top: "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top fixed top-4 inset-x-4 mx-auto w-[calc(100vw-2rem)] sm:max-w-lg rounded-2xl p-5",
15831
+ bottom: "data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom fixed bottom-4 inset-x-4 mx-auto w-[calc(100vw-2rem)] sm:max-w-lg rounded-2xl p-5",
15832
+ left: "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left fixed top-4 bottom-4 left-4 w-[calc(100vw-2rem)] rounded-2xl p-5",
15833
+ right: "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right fixed top-4 bottom-4 right-4 w-[calc(100vw-2rem)] rounded-2xl p-5"
15735
15834
  },
15736
15835
  size: {
15737
15836
  default: "",
@@ -16375,7 +16474,7 @@ function ContextMenuSubContent({
16375
16474
  var import_class_variance_authority7 = require("class-variance-authority");
16376
16475
  var import_jsx_runtime151 = require("react/jsx-runtime");
16377
16476
  var alertVariants = (0, import_class_variance_authority7.cva)(
16378
- "relative grid w-full gap-1 rounded-xl border px-4 py-3 text-sm [&>svg]:absolute [&>svg]:top-3.5 [&>svg]:left-4 [&>svg]:size-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11",
16477
+ "relative grid w-full gap-1 rounded-xl border px-3.5 py-2.5 text-sm [&>svg]:absolute [&>svg]:top-3 [&>svg]:left-3.5 [&>svg]:size-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-10",
16379
16478
  {
16380
16479
  variants: {
16381
16480
  variant: {
@@ -16433,7 +16532,7 @@ function Card({ className, ...props }) {
16433
16532
  "data-slot": "card",
16434
16533
  className: cn(
16435
16534
  TIMBAL_V2_ELEVATED_SURFACE,
16436
- "flex flex-col gap-4 rounded-xl py-4 text-card-foreground",
16535
+ "flex flex-col gap-3 rounded-xl py-3 text-card-foreground",
16437
16536
  className
16438
16537
  ),
16439
16538
  ...props
@@ -16445,7 +16544,7 @@ function CardHeader({ className, ...props }) {
16445
16544
  "div",
16446
16545
  {
16447
16546
  "data-slot": "card-header",
16448
- className: cn("flex flex-col gap-1.5 px-4", className),
16547
+ className: cn("flex flex-col gap-1.5 px-3.5", className),
16449
16548
  ...props
16450
16549
  }
16451
16550
  );
@@ -16471,14 +16570,14 @@ function CardDescription({ className, ...props }) {
16471
16570
  );
16472
16571
  }
16473
16572
  function CardContent({ className, ...props }) {
16474
- return /* @__PURE__ */ (0, import_jsx_runtime152.jsx)("div", { "data-slot": "card-content", className: cn("px-4", className), ...props });
16573
+ return /* @__PURE__ */ (0, import_jsx_runtime152.jsx)("div", { "data-slot": "card-content", className: cn("px-3.5", className), ...props });
16475
16574
  }
16476
16575
  function CardFooter({ className, ...props }) {
16477
16576
  return /* @__PURE__ */ (0, import_jsx_runtime152.jsx)(
16478
16577
  "div",
16479
16578
  {
16480
16579
  "data-slot": "card-footer",
16481
- className: cn("flex items-center px-4", className),
16580
+ className: cn("flex items-center px-3.5", className),
16482
16581
  ...props
16483
16582
  }
16484
16583
  );
@@ -16548,7 +16647,7 @@ function TableHead({ className, ...props }) {
16548
16647
  {
16549
16648
  "data-slot": "table-head",
16550
16649
  className: cn(
16551
- "h-10 px-3 text-left align-middle text-xs font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
16650
+ "h-8 px-2.5 text-left align-middle text-xs font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
16552
16651
  className
16553
16652
  ),
16554
16653
  ...props
@@ -16561,7 +16660,7 @@ function TableCell({ className, ...props }) {
16561
16660
  {
16562
16661
  "data-slot": "table-cell",
16563
16662
  className: cn(
16564
- "p-3 align-middle text-sm [&:has([role=checkbox])]:pr-0",
16663
+ "py-2 px-2.5 align-middle text-sm [&:has([role=checkbox])]:pr-0",
16565
16664
  className
16566
16665
  ),
16567
16666
  ...props
@@ -16615,7 +16714,7 @@ function Toast({
16615
16714
  "data-slot": "toast",
16616
16715
  className: cn(
16617
16716
  TIMBAL_V2_ELEVATED_SURFACE,
16618
- "group pointer-events-auto relative flex w-full items-center justify-between gap-3 overflow-hidden rounded-xl p-4 pr-8 shadow-card-elevated transition-all",
16717
+ "group pointer-events-auto relative flex w-full items-center justify-between gap-3 overflow-hidden rounded-xl p-3 pr-7 shadow-card-elevated transition-all",
16619
16718
  "data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-80 data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full data-[state=closed]:slide-out-to-right-full",
16620
16719
  variant === "destructive" && "border-destructive/45 bg-destructive/10 text-destructive",
16621
16720
  className
@@ -16936,7 +17035,7 @@ function Rating({
16936
17035
  const value = isControlled ? valueProp : uncontrolled;
16937
17036
  const [hover, setHover] = React11.useState(null);
16938
17037
  const interactive = !readOnly && !disabled;
16939
- const shown = hover ?? value;
17038
+ const shown2 = hover ?? value;
16940
17039
  const set = (next) => {
16941
17040
  if (!interactive) return;
16942
17041
  if (!isControlled) setUncontrolled(next);
@@ -16974,7 +17073,7 @@ function Rating({
16974
17073
  onMouseLeave: () => setHover(null),
16975
17074
  children: Array.from({ length: max }, (_, i) => {
16976
17075
  const unit = i + 1;
16977
- const filled = unit <= shown;
17076
+ const filled = unit <= shown2;
16978
17077
  return /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
16979
17078
  "button",
16980
17079
  {
@@ -17107,8 +17206,8 @@ var React13 = __toESM(require("react"), 1);
17107
17206
  var import_lucide_react47 = require("lucide-react");
17108
17207
  var import_jsx_runtime160 = require("react/jsx-runtime");
17109
17208
  var tagInputSizeClass = {
17110
- sm: "min-h-9 gap-1 px-1.5 py-1",
17111
- default: "min-h-10 gap-1.5 px-2 py-1.5"
17209
+ sm: "min-h-8 gap-1 px-1.5 py-0.5",
17210
+ default: "min-h-9 gap-1 px-2 py-1"
17112
17211
  };
17113
17212
  function TagInput({
17114
17213
  value: valueProp,
@@ -17216,8 +17315,8 @@ var snippetVariantClass = {
17216
17315
  ghost: "border-transparent bg-foreground/[0.04]"
17217
17316
  };
17218
17317
  var snippetSizeClass = {
17219
- sm: "gap-1.5 py-1 pl-2.5 pr-1 text-xs",
17220
- default: "gap-2 py-1.5 pl-3 pr-1.5 text-sm"
17318
+ sm: "gap-1.5 py-0.5 pl-2 pr-0.5 text-xs",
17319
+ default: "gap-2 py-1 pl-2.5 pr-1 text-sm"
17221
17320
  };
17222
17321
  function Snippet({
17223
17322
  children,
@@ -17333,6 +17432,373 @@ function CircularProgress({
17333
17432
  }
17334
17433
  );
17335
17434
  }
17435
+
17436
+ // src/site/Reveal.tsx
17437
+ var React14 = __toESM(require("react"), 1);
17438
+ var import_react79 = require("motion/react");
17439
+
17440
+ // src/site/easing.ts
17441
+ var EASE = {
17442
+ /** Strong slow-out — the workhorse for entrances and reveals. */
17443
+ out: [0.16, 1, 0.3, 1],
17444
+ /** Symmetric in-out for loops and continuous motion. */
17445
+ inOut: [0.65, 0, 0.35, 1],
17446
+ /** Gentle in-out, good for parallax / large translations. */
17447
+ soft: [0.4, 0, 0.2, 1]
17448
+ };
17449
+ var DURATION = {
17450
+ fast: 0.4,
17451
+ base: 0.7,
17452
+ slow: 1.1
17453
+ };
17454
+ var SPRING = {
17455
+ /** Tight, responsive follow. */
17456
+ snappy: { stiffness: 350, damping: 30, mass: 0.4 },
17457
+ /** Looser, more elastic follow. */
17458
+ smooth: { stiffness: 150, damping: 20, mass: 0.6 }
17459
+ };
17460
+
17461
+ // src/site/Reveal.tsx
17462
+ var import_jsx_runtime163 = require("react/jsx-runtime");
17463
+ function hidden(variant, distance) {
17464
+ switch (variant) {
17465
+ case "fade":
17466
+ return { opacity: 0 };
17467
+ case "fade-up":
17468
+ return { opacity: 0, y: distance };
17469
+ case "fade-down":
17470
+ return { opacity: 0, y: -distance };
17471
+ case "fade-left":
17472
+ return { opacity: 0, x: distance };
17473
+ case "fade-right":
17474
+ return { opacity: 0, x: -distance };
17475
+ case "blur":
17476
+ return { opacity: 0, filter: "blur(12px)" };
17477
+ case "scale":
17478
+ return { opacity: 0, scale: 0.94 };
17479
+ case "mask-up":
17480
+ return { y: "110%" };
17481
+ }
17482
+ }
17483
+ function shown(variant) {
17484
+ if (variant === "mask-up") return { y: "0%" };
17485
+ if (variant === "blur") return { opacity: 1, filter: "blur(0px)" };
17486
+ if (variant === "scale") return { opacity: 1, scale: 1 };
17487
+ return { opacity: 1, x: 0, y: 0 };
17488
+ }
17489
+ var Reveal = React14.forwardRef(function Reveal2({
17490
+ variant = "fade-up",
17491
+ delay = 0,
17492
+ duration = DURATION.base,
17493
+ distance = 28,
17494
+ amount = 0.3,
17495
+ repeat = false,
17496
+ as = "div",
17497
+ className,
17498
+ children,
17499
+ ...rest
17500
+ }, ref) {
17501
+ const reduce = (0, import_react79.useReducedMotion)();
17502
+ const isMask = variant === "mask-up";
17503
+ if (reduce) {
17504
+ const Tag = as;
17505
+ return /* @__PURE__ */ (0, import_jsx_runtime163.jsx)(Tag, { ref, className: cn(isMask && "overflow-hidden", className), ...rest, children });
17506
+ }
17507
+ const variants = {
17508
+ hidden: hidden(variant, distance),
17509
+ shown: shown(variant)
17510
+ };
17511
+ const MotionTag = import_react79.motion[as] ?? import_react79.motion.div;
17512
+ const inner = /* @__PURE__ */ (0, import_jsx_runtime163.jsx)(
17513
+ MotionTag,
17514
+ {
17515
+ ref,
17516
+ className,
17517
+ variants,
17518
+ initial: "hidden",
17519
+ whileInView: "shown",
17520
+ viewport: { once: !repeat, amount },
17521
+ transition: { duration, delay, ease: EASE.out },
17522
+ ...rest,
17523
+ children
17524
+ }
17525
+ );
17526
+ if (isMask) {
17527
+ return /* @__PURE__ */ (0, import_jsx_runtime163.jsx)("span", { className: "block overflow-hidden", children: inner });
17528
+ }
17529
+ return inner;
17530
+ });
17531
+
17532
+ // src/site/TextReveal.tsx
17533
+ var React15 = __toESM(require("react"), 1);
17534
+ var import_react80 = require("motion/react");
17535
+ var import_jsx_runtime164 = require("react/jsx-runtime");
17536
+ var tokenVariants = {
17537
+ hidden: { y: "115%" },
17538
+ shown: { y: "0%" }
17539
+ };
17540
+ function TextReveal({
17541
+ children,
17542
+ splitBy = "words",
17543
+ stagger = 0.06,
17544
+ delay = 0,
17545
+ duration = DURATION.base,
17546
+ repeat = false,
17547
+ amount = 0.4,
17548
+ as = "span",
17549
+ className,
17550
+ ...rest
17551
+ }) {
17552
+ const reduce = (0, import_react80.useReducedMotion)();
17553
+ const Tag = as;
17554
+ const tokens = React15.useMemo(() => {
17555
+ if (splitBy === "lines") return children.split("\n");
17556
+ return children.split(/(\s+)/).filter((t) => t.length > 0);
17557
+ }, [children, splitBy]);
17558
+ if (reduce) {
17559
+ return /* @__PURE__ */ (0, import_jsx_runtime164.jsx)(Tag, { className, ...rest, children });
17560
+ }
17561
+ const containerVariants = {
17562
+ hidden: {},
17563
+ shown: { transition: { staggerChildren: stagger, delayChildren: delay } }
17564
+ };
17565
+ return /* @__PURE__ */ (0, import_jsx_runtime164.jsx)(
17566
+ import_react80.motion.span,
17567
+ {
17568
+ variants: containerVariants,
17569
+ initial: "hidden",
17570
+ whileInView: "shown",
17571
+ viewport: { once: !repeat, amount },
17572
+ className: cn(as === "span" ? "inline" : "block", className),
17573
+ ...rest,
17574
+ children: /* @__PURE__ */ (0, import_jsx_runtime164.jsx)(Tag, { className: as === "span" ? "inline" : "block", children: tokens.map(
17575
+ (token, i) => /^\s+$/.test(token) && splitBy === "words" ? /* @__PURE__ */ (0, import_jsx_runtime164.jsx)("span", { children: " " }, i) : /* @__PURE__ */ (0, import_jsx_runtime164.jsx)(
17576
+ "span",
17577
+ {
17578
+ className: cn(
17579
+ "overflow-hidden",
17580
+ splitBy === "lines" ? "block" : "inline-block align-bottom"
17581
+ ),
17582
+ children: /* @__PURE__ */ (0, import_jsx_runtime164.jsx)(
17583
+ import_react80.motion.span,
17584
+ {
17585
+ className: "inline-block",
17586
+ variants: tokenVariants,
17587
+ transition: { duration, ease: EASE.out },
17588
+ children: token
17589
+ }
17590
+ )
17591
+ },
17592
+ i
17593
+ )
17594
+ ) })
17595
+ }
17596
+ );
17597
+ }
17598
+
17599
+ // src/site/Parallax.tsx
17600
+ var React16 = __toESM(require("react"), 1);
17601
+ var import_react81 = require("motion/react");
17602
+ var import_jsx_runtime165 = require("react/jsx-runtime");
17603
+ var Parallax = React16.forwardRef(function Parallax2({ speed = 0.2, axis = "y", smooth = true, className, children, style, ...rest }, forwardedRef) {
17604
+ const reduce = (0, import_react81.useReducedMotion)();
17605
+ const innerRef = React16.useRef(null);
17606
+ React16.useImperativeHandle(forwardedRef, () => innerRef.current);
17607
+ const { scrollYProgress } = (0, import_react81.useScroll)({
17608
+ target: innerRef,
17609
+ offset: ["start end", "end start"]
17610
+ });
17611
+ const range = 100 * speed;
17612
+ const raw = (0, import_react81.useTransform)(scrollYProgress, [0, 1], [range, -range]);
17613
+ const smoothed = (0, import_react81.useSpring)(raw, { stiffness: 120, damping: 30, mass: 0.4 });
17614
+ const value = smooth ? smoothed : raw;
17615
+ if (reduce) {
17616
+ return /* @__PURE__ */ (0, import_jsx_runtime165.jsx)("div", { ref: innerRef, className, style, ...rest, children });
17617
+ }
17618
+ return /* @__PURE__ */ (0, import_jsx_runtime165.jsx)(
17619
+ import_react81.motion.div,
17620
+ {
17621
+ ref: innerRef,
17622
+ className: cn("will-change-transform", className),
17623
+ style: { ...style, [axis]: value },
17624
+ ...rest,
17625
+ children
17626
+ }
17627
+ );
17628
+ });
17629
+
17630
+ // src/site/Marquee.tsx
17631
+ var React17 = __toESM(require("react"), 1);
17632
+ var import_react82 = require("motion/react");
17633
+ var import_jsx_runtime166 = require("react/jsx-runtime");
17634
+ var Marquee = React17.forwardRef(function Marquee2({ speed = 60, direction = "left", pauseOnHover = true, gap = "3rem", className, children, ...rest }, ref) {
17635
+ const reduce = (0, import_react82.useReducedMotion)();
17636
+ const x = (0, import_react82.useMotionValue)(0);
17637
+ const setWidthRef = React17.useRef(0);
17638
+ const groupRef = React17.useRef(null);
17639
+ const [paused, setPaused] = React17.useState(false);
17640
+ React17.useEffect(() => {
17641
+ const el = groupRef.current;
17642
+ if (!el) return;
17643
+ const measure = () => {
17644
+ const gapPx = parseFloat(getComputedStyle(el.parentElement).columnGap || "0") || 0;
17645
+ setWidthRef.current = el.offsetWidth + gapPx;
17646
+ };
17647
+ measure();
17648
+ const ro = new ResizeObserver(measure);
17649
+ ro.observe(el);
17650
+ return () => ro.disconnect();
17651
+ }, []);
17652
+ (0, import_react82.useAnimationFrame)((_, delta) => {
17653
+ if (reduce || paused || setWidthRef.current === 0) return;
17654
+ const dir = direction === "left" ? -1 : 1;
17655
+ const moveBy = speed * delta / 1e3;
17656
+ let next = x.get() + dir * moveBy;
17657
+ const w = setWidthRef.current;
17658
+ if (next <= -w) next += w;
17659
+ else if (next >= w) next -= w;
17660
+ x.set(next);
17661
+ });
17662
+ if (reduce) {
17663
+ return /* @__PURE__ */ (0, import_jsx_runtime166.jsx)(
17664
+ "div",
17665
+ {
17666
+ ref,
17667
+ className: cn("flex w-full items-center overflow-x-auto", className),
17668
+ style: { columnGap: gap },
17669
+ ...rest,
17670
+ children
17671
+ }
17672
+ );
17673
+ }
17674
+ return /* @__PURE__ */ (0, import_jsx_runtime166.jsx)(
17675
+ "div",
17676
+ {
17677
+ ref,
17678
+ className: cn("w-full overflow-hidden", className),
17679
+ onMouseEnter: pauseOnHover ? () => setPaused(true) : void 0,
17680
+ onMouseLeave: pauseOnHover ? () => setPaused(false) : void 0,
17681
+ ...rest,
17682
+ children: /* @__PURE__ */ (0, import_jsx_runtime166.jsxs)(import_react82.motion.div, { className: "flex w-max flex-nowrap items-center", style: { x, columnGap: gap }, children: [
17683
+ /* @__PURE__ */ (0, import_jsx_runtime166.jsx)("div", { ref: groupRef, className: "flex flex-nowrap items-center", style: { columnGap: gap }, children }),
17684
+ /* @__PURE__ */ (0, import_jsx_runtime166.jsx)("div", { className: "flex flex-nowrap items-center", style: { columnGap: gap }, "aria-hidden": true, children })
17685
+ ] })
17686
+ }
17687
+ );
17688
+ });
17689
+
17690
+ // src/site/Magnetic.tsx
17691
+ var React18 = __toESM(require("react"), 1);
17692
+ var import_react83 = require("motion/react");
17693
+ var import_jsx_runtime167 = require("react/jsx-runtime");
17694
+ var Magnetic = React18.forwardRef(function Magnetic2({ strength = 0.35, max = 24, spring = "snappy", className, children, ...rest }, forwardedRef) {
17695
+ const reduce = (0, import_react83.useReducedMotion)();
17696
+ const innerRef = React18.useRef(null);
17697
+ React18.useImperativeHandle(forwardedRef, () => innerRef.current);
17698
+ const mvx = (0, import_react83.useMotionValue)(0);
17699
+ const mvy = (0, import_react83.useMotionValue)(0);
17700
+ const x = (0, import_react83.useSpring)(mvx, SPRING[spring]);
17701
+ const y = (0, import_react83.useSpring)(mvy, SPRING[spring]);
17702
+ const clamp3 = (v) => Math.max(-max, Math.min(max, v));
17703
+ function handleMove(e) {
17704
+ if (reduce) return;
17705
+ const el = innerRef.current;
17706
+ if (!el) return;
17707
+ const rect = el.getBoundingClientRect();
17708
+ const cx = rect.left + rect.width / 2;
17709
+ const cy = rect.top + rect.height / 2;
17710
+ mvx.set(clamp3((e.clientX - cx) * strength));
17711
+ mvy.set(clamp3((e.clientY - cy) * strength));
17712
+ }
17713
+ function reset() {
17714
+ mvx.set(0);
17715
+ mvy.set(0);
17716
+ }
17717
+ if (reduce) {
17718
+ return /* @__PURE__ */ (0, import_jsx_runtime167.jsx)("div", { ref: innerRef, className: cn("inline-block", className), ...rest, children });
17719
+ }
17720
+ return /* @__PURE__ */ (0, import_jsx_runtime167.jsx)(
17721
+ import_react83.motion.div,
17722
+ {
17723
+ ref: innerRef,
17724
+ className: cn("inline-block", className),
17725
+ style: { x, y },
17726
+ onMouseMove: handleMove,
17727
+ onMouseLeave: reset,
17728
+ ...rest,
17729
+ children
17730
+ }
17731
+ );
17732
+ });
17733
+
17734
+ // src/site/agent-instructions.ts
17735
+ var SITE_AGENT_INSTRUCTIONS = `
17736
+ ## Site kit (@timbal-ai/timbal-react/site)
17737
+
17738
+ Expressive **motion & interaction primitives** for marketing, brand, landing, and editorial pages \u2014 the counterpart to \`/app\` (which is for dashboards and operations UIs). Import from \`@timbal-ai/timbal-react/site\` (or the package root).
17739
+
17740
+ These are **mechanics, not art direction**: they animate whatever you put inside them. Compose them under a chosen aesthetic; they do not impose colors, type, or layout.
17741
+
17742
+ ### When to use \`/site\` (and when not to)
17743
+
17744
+ - **Do** use \`/site\` for landing pages, hero sections, feature walkthroughs, logo walls, pricing pages, and editorial/brand storytelling.
17745
+ - **Do not** use \`/site\` inside dashboards, settings, tables, or in-thread chat artifacts \u2014 those stay on \`/app\` and \`/artifacts\`. Animated dashboard chrome reads as slop.
17746
+ - Every primitive is **reduced-motion-aware** (collapses to static, no-transform output under \`prefers-reduced-motion\`) and **SSR-safe** (no layout shift \u2014 elements occupy their space from first paint). You never need to guard them yourself.
17747
+ - Built on the \`motion\` engine the package already bundles \u2014 **no extra dependencies**.
17748
+
17749
+ ### Dosing (anti-overuse \u2014 read this)
17750
+
17751
+ The failure mode is animating *everything*. Restraint is the brand signal.
17752
+
17753
+ - Pick **one** signature motion per section (e.g. a \`TextReveal\` headline **or** a \`Parallax\` hero image, not both stacked).
17754
+ - Stagger entrances down the page; do not fire ten reveals at once on first paint.
17755
+ - Reserve \`Magnetic\` for **primary** CTAs / nav, not every button.
17756
+ - Keep \`Parallax\` \`speed\` subtle (\`0.15\`\u2013\`0.35\`); large values look gimmicky.
17757
+ - Default durations are intentionally slow and weighted (\`DURATION.base\` = 0.7s) \u2014 that confident pacing is the point. Don't speed everything up to app-kit's 150ms.
17758
+
17759
+ ### Component menu
17760
+
17761
+ | Component | Use for | Key props |
17762
+ |-----------|---------|-----------|
17763
+ | \`Reveal\` | Fade/slide a block in as it scrolls into view (headings, cards, images, list items). | \`variant\` (\`fade\` \\| \`fade-up\` \\| \`fade-down\` \\| \`fade-left\` \\| \`fade-right\` \\| \`blur\` \\| \`scale\` \\| \`mask-up\`, default \`fade-up\`), \`delay\`, \`duration\`, \`distance\` (px, default 28), \`amount\` (visibility fraction 0\u20131 / \`"some"\` / \`"all"\`, default 0.3), \`repeat\` (replay on re-enter), \`as\` (render element, e.g. \`"section"\`/\`"li"\`). |
17764
+ | \`TextReveal\` | Signature editorial headline entrance \u2014 text rides up token-by-token from a clip on a stagger. | \`children\` (**plain string only**), \`splitBy\` (\`words\` default \\| \`lines\`), \`stagger\` (default 0.06), \`delay\`, \`duration\`, \`amount\` (default 0.4), \`repeat\`, \`as\` (\`span\` default \\| \`h1\`\u2013\`h4\` \\| \`p\`). |
17765
+ | \`Parallax\` | Depth \u2014 translate a layer relative to scroll (hero images, background art). | \`speed\` (-0.6\u20260.6, positive = lags behind scroll, default 0.2), \`axis\` (\`y\` default \\| \`x\`), \`smooth\` (spring-damped, default true). |
17766
+ | \`Marquee\` | Seamless infinite scrolling row (logo walls, testimonials, ticker). Duplicates children internally \u2014 no visible seam. | \`speed\` (px/s, default 60), \`direction\` (\`left\` default \\| \`right\`), \`pauseOnHover\` (default true), \`gap\` (CSS length, default \`"3rem"\`). |
17767
+ | \`Magnetic\` | Pointer-following "magnetic" affordance for a **single** interactive child (primary CTA, nav link). | \`strength\` (fraction of cursor offset, default 0.35), \`max\` (px clamp, default 24), \`spring\` (\`"snappy"\` default \\| \`"smooth"\`). Wrap one button/link. |
17768
+
17769
+ ### Motion tokens
17770
+
17771
+ \`EASE\` (cubic-bezier tuples: \`out\` / \`inOut\` / \`soft\`), \`DURATION\` (\`fast\` 0.4s / \`base\` 0.7s / \`slow\` 1.1s), and \`SPRING\` (\`snappy\` / \`smooth\`) are exported for custom \`motion\` work that should match the kit's feel. Prefer the component defaults; reach for tokens only when hand-rolling a bespoke animation.
17772
+
17773
+ ### Example imports
17774
+
17775
+ \`\`\`tsx
17776
+ import { Reveal, TextReveal, Parallax, Marquee, Magnetic } from "@timbal-ai/timbal-react/site";
17777
+ \`\`\`
17778
+
17779
+ \`\`\`tsx
17780
+ <Reveal variant="fade-up" delay={0.1}>
17781
+ <TextReveal as="h1" className="text-6xl font-semibold">
17782
+ Built for the long run
17783
+ </TextReveal>
17784
+ </Reveal>
17785
+
17786
+ <Parallax speed={0.3}>
17787
+ <img src={hero} alt="" className="h-full w-full object-cover" />
17788
+ </Parallax>
17789
+
17790
+ <Magnetic strength={0.4}>
17791
+ <Button>Get started</Button>
17792
+ </Magnetic>
17793
+ \`\`\`
17794
+
17795
+ ### Rules
17796
+
17797
+ - \`/site\` is for the **marketing/brand surface**, not the product app shell (\`/app\`) or in-chat widgets (\`/artifacts\`).
17798
+ - \`TextReveal\` takes a **string** child only \u2014 it splits internally; do not pass JSX.
17799
+ - \`Magnetic\` wraps a **single** interactive child; don't wrap whole layouts.
17800
+ - Trust the reduced-motion / SSR handling \u2014 never add your own \`prefers-reduced-motion\` guards around these.
17801
+ `.trim();
17336
17802
  // Annotate the CommonJS export names for ESM import in node:
17337
17803
  0 && (module.exports = {
17338
17804
  APP_KIT_AGENT_INSTRUCTIONS,
@@ -17445,6 +17911,7 @@ function CircularProgress({
17445
17911
  ContextMenuTrigger,
17446
17912
  CopyButton,
17447
17913
  DEFAULT_UPLOAD_ACCEPT,
17914
+ DURATION,
17448
17915
  DangerZone,
17449
17916
  DangerZoneAction,
17450
17917
  DataTable,
@@ -17478,6 +17945,7 @@ function CircularProgress({
17478
17945
  DropdownMenuSubContent,
17479
17946
  DropdownMenuSubTrigger,
17480
17947
  DropdownMenuTrigger,
17948
+ EASE,
17481
17949
  EmptyState,
17482
17950
  ExpandableSection,
17483
17951
  Field,
@@ -17523,7 +17991,9 @@ function CircularProgress({
17523
17991
  KbdGroup,
17524
17992
  Label,
17525
17993
  LineAreaChart,
17994
+ Magnetic,
17526
17995
  MarkdownText,
17996
+ Marquee,
17527
17997
  MemoPillSegmentedTabs,
17528
17998
  Menubar,
17529
17999
  MenubarCheckboxItem,
@@ -17562,6 +18032,7 @@ function CircularProgress({
17562
18032
  PaginationLink,
17563
18033
  PaginationNext,
17564
18034
  PaginationPrevious,
18035
+ Parallax,
17565
18036
  PieChart,
17566
18037
  PillSegmentedTabs,
17567
18038
  PlanBadge,
@@ -17578,8 +18049,11 @@ function CircularProgress({
17578
18049
  RadioGroupItem,
17579
18050
  Rating,
17580
18051
  ResourceCard,
18052
+ Reveal,
17581
18053
  SEMANTIC_COLOR_TOKENS,
18054
+ SITE_AGENT_INSTRUCTIONS,
17582
18055
  SLOP_BUDGETS,
18056
+ SPRING,
17583
18057
  STUDIO_NAV_MODE,
17584
18058
  ScrollArea,
17585
18059
  ScrollBar,
@@ -17639,6 +18113,7 @@ function CircularProgress({
17639
18113
  TableHeader,
17640
18114
  TableRow,
17641
18115
  TagInput,
18116
+ TextReveal,
17642
18117
  Textarea,
17643
18118
  Thread,
17644
18119
  ThreadPrimitive,