@nocoo/basalt 3.1.0 → 3.2.1

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 (133) hide show
  1. package/ai/DESIGN.md +128 -55
  2. package/ai/INTEGRATION.md +9 -9
  3. package/ai/USAGE.md +1 -1
  4. package/ai/registry.json +166 -124
  5. package/dist/charts/config.d.ts +1 -1
  6. package/dist/charts/config.js +1 -1
  7. package/dist/charts/config.js.map +1 -1
  8. package/dist/charts/frame.js +2 -2
  9. package/dist/charts/frame.js.map +1 -1
  10. package/dist/charts/heatmap-calendar.js +4 -4
  11. package/dist/charts/heatmap-calendar.js.map +1 -1
  12. package/dist/charts/heatmap-matrix.js +5 -5
  13. package/dist/charts/heatmap-matrix.js.map +1 -1
  14. package/dist/charts/sparkline.js +1 -1
  15. package/dist/charts/sparkline.js.map +1 -1
  16. package/dist/charts/stat-card.js +1 -1
  17. package/dist/charts/stat-card.js.map +1 -1
  18. package/dist/components/alert-dialog.js +4 -4
  19. package/dist/components/alert-dialog.js.map +1 -1
  20. package/dist/components/app-header.js +1 -1
  21. package/dist/components/app-header.js.map +1 -1
  22. package/dist/components/app-shell.js +1 -1
  23. package/dist/components/app-shell.js.map +1 -1
  24. package/dist/components/approval-card.js +5 -6
  25. package/dist/components/approval-card.js.map +1 -1
  26. package/dist/components/avatar.js +1 -1
  27. package/dist/components/avatar.js.map +1 -1
  28. package/dist/components/chat-bubble.js +1 -1
  29. package/dist/components/chat-bubble.js.map +1 -1
  30. package/dist/components/chat-composer.js +1 -1
  31. package/dist/components/chat-composer.js.map +1 -1
  32. package/dist/components/chat-header.js +1 -1
  33. package/dist/components/chat-header.js.map +1 -1
  34. package/dist/components/chat-inbox.js +1 -1
  35. package/dist/components/chat-inbox.js.map +1 -1
  36. package/dist/components/chat-markdown.js +1 -1
  37. package/dist/components/chat-markdown.js.map +1 -1
  38. package/dist/components/chat-message.js +2 -2
  39. package/dist/components/chat-message.js.map +1 -1
  40. package/dist/components/code.js +5 -4
  41. package/dist/components/code.js.map +1 -1
  42. package/dist/components/command-palette.js +2 -2
  43. package/dist/components/command-palette.js.map +1 -1
  44. package/dist/components/context-cards.js +6 -6
  45. package/dist/components/context-cards.js.map +1 -1
  46. package/dist/components/context-menu.js +1 -1
  47. package/dist/components/context-menu.js.map +1 -1
  48. package/dist/components/data-table.js +127 -124
  49. package/dist/components/data-table.js.map +1 -1
  50. package/dist/components/dialog.js +2 -2
  51. package/dist/components/dialog.js.map +1 -1
  52. package/dist/components/diff-table.js +3 -3
  53. package/dist/components/diff-table.js.map +1 -1
  54. package/dist/components/dropdown-menu.js +1 -1
  55. package/dist/components/dropdown-menu.js.map +1 -1
  56. package/dist/components/editable-nav-item.js +2 -2
  57. package/dist/components/editable-nav-item.js.map +1 -1
  58. package/dist/components/file-dropzone.js +1 -1
  59. package/dist/components/file-dropzone.js.map +1 -1
  60. package/dist/components/filter-bar.js +1 -1
  61. package/dist/components/filter-bar.js.map +1 -1
  62. package/dist/components/icon-picker.js +3 -3
  63. package/dist/components/icon-picker.js.map +1 -1
  64. package/dist/components/inline-editable.js +1 -1
  65. package/dist/components/inline-editable.js.map +1 -1
  66. package/dist/components/input-area.js +1 -1
  67. package/dist/components/input-area.js.map +1 -1
  68. package/dist/components/input-group.js +2 -2
  69. package/dist/components/input-group.js.map +1 -1
  70. package/dist/components/layer-card.d.ts +6 -4
  71. package/dist/components/layer-card.js +61 -71
  72. package/dist/components/layer-card.js.map +1 -1
  73. package/dist/components/link.js +1 -1
  74. package/dist/components/link.js.map +1 -1
  75. package/dist/components/loader.js +1 -1
  76. package/dist/components/loader.js.map +1 -1
  77. package/dist/components/menu-bar.js +2 -2
  78. package/dist/components/menu-bar.js.map +1 -1
  79. package/dist/components/multi-select.js +1 -1
  80. package/dist/components/multi-select.js.map +1 -1
  81. package/dist/components/overlay.d.ts +3 -6
  82. package/dist/components/overlay.js +3 -3
  83. package/dist/components/overlay.js.map +1 -1
  84. package/dist/components/page-header.d.ts +2 -2
  85. package/dist/components/page-header.js +7 -7
  86. package/dist/components/page-header.js.map +1 -1
  87. package/dist/components/recommendation-card.js +2 -2
  88. package/dist/components/recommendation-card.js.map +1 -1
  89. package/dist/components/responsive-master-detail.js +2 -2
  90. package/dist/components/responsive-master-detail.js.map +1 -1
  91. package/dist/components/scroll-area.js +1 -1
  92. package/dist/components/scroll-area.js.map +1 -1
  93. package/dist/components/section-rule.js +1 -1
  94. package/dist/components/section-rule.js.map +1 -1
  95. package/dist/components/segment-control.js +1 -1
  96. package/dist/components/segment-control.js.map +1 -1
  97. package/dist/components/select.js +2 -2
  98. package/dist/components/select.js.map +1 -1
  99. package/dist/components/sensitive-input.js +1 -1
  100. package/dist/components/sensitive-input.js.map +1 -1
  101. package/dist/components/sheet.js +3 -3
  102. package/dist/components/sheet.js.map +1 -1
  103. package/dist/components/sidebar.js +3 -3
  104. package/dist/components/sidebar.js.map +1 -1
  105. package/dist/components/skeleton-line.js +1 -1
  106. package/dist/components/skeleton-line.js.map +1 -1
  107. package/dist/components/stat-strip.js +1 -1
  108. package/dist/components/stat-strip.js.map +1 -1
  109. package/dist/components/table.d.ts +2 -0
  110. package/dist/components/table.js +10 -12
  111. package/dist/components/table.js.map +1 -1
  112. package/dist/components/tabs.js +2 -2
  113. package/dist/components/tabs.js.map +1 -1
  114. package/dist/components/tag-badge.js +1 -1
  115. package/dist/components/tag-badge.js.map +1 -1
  116. package/dist/components/tag-color-picker.js +2 -2
  117. package/dist/components/tag-color-picker.js.map +1 -1
  118. package/dist/components/text.js +2 -2
  119. package/dist/components/text.js.map +1 -1
  120. package/dist/components/thinking.js +1 -1
  121. package/dist/components/thinking.js.map +1 -1
  122. package/dist/components/toast.js +1 -1
  123. package/dist/components/toast.js.map +1 -1
  124. package/dist/components/tool-chips.js +2 -2
  125. package/dist/components/tool-chips.js.map +1 -1
  126. package/dist/components/toolbar.js +8 -8
  127. package/dist/components/toolbar.js.map +1 -1
  128. package/dist/styles/base.css +71 -0
  129. package/dist/styles/standalone.css +187 -168
  130. package/dist/styles/tailwind.css +9 -2
  131. package/dist/styles/tokens.css +86 -40
  132. package/dist/utils/navigation.d.ts +1 -1
  133. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.js","names":["hasSlotContent","slot","StatCard","Icon","heading","title","label","hasStatus","status","hasTrendContent","trendContent","hasAction","action","hasChildren","children","isInteractive","display","value","isPositiveTrend","trend","isNegativeTrend","named","ariaLabel","subtitle","LayerCard","cn","className","iconColor","StatGrid","columns"],"sources":["../../src/charts/stat-card.tsx"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { LayerCard } from \"../components/layer-card\";\nimport { cn } from \"../utils/cn\";\n\nexport type StatCardProps = {\n\t/**\n\t * Secondary heading label for the metric card (overridden by title).\n\t */\n\tlabel?: string;\n\t/**\n\t * Primary heading title for the metric card (takes precedence over label).\n\t */\n\ttitle?: string;\n\t/**\n\t * Metric value, formatted via toLocaleString() if a number is provided.\n\t * Overridden by the status slot if provided.\n\t */\n\tvalue: string | number;\n\t/**\n\t * Supporting descriptive subtitle text rendered below value.\n\t */\n\tsubtitle?: string;\n\t/**\n\t * Optional decorative Lucide icon component.\n\t */\n\ticon?: LucideIcon;\n\t/**\n\t * Color class applied to the decorative icon.\n\t * @default \"text-basalt-muted-foreground\"\n\t */\n\ticonColor?: string;\n\t/**\n\t * Structured percentage trend value and optional label.\n\t * Overridden by the trendContent slot if provided.\n\t */\n\ttrend?: { value: number; label?: string };\n\t/**\n\t * Optional header action or interactive element (e.g. tooltip trigger or button).\n\t * Renders alongside the title/icon. Switches card role to group for accessible descendants.\n\t */\n\taction?: ReactNode;\n\t/**\n\t * Optional custom status replacement slot (e.g. loading skeleton, error state, or empty state).\n\t * Takes precedence over the default value display and excludes value from accessible name.\n\t * Subtitle and trend remain caller-managed; when error/empty state is shown, callers should omit trend.\n\t */\n\tstatus?: ReactNode;\n\t/**\n\t * Optional custom trend replacement slot (e.g. custom badge, sparkline, or localized trend indicator).\n\t * Takes precedence over the default trend calculation and excludes default trend from accessible name.\n\t */\n\ttrendContent?: ReactNode;\n\t/**\n\t * Optional supporting content rendered below the value, subtitle, and trend in the same surface.\n\t */\n\tchildren?: ReactNode;\n\t/**\n\t * Explicit accessible label overriding automatic accessible name calculation.\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Additional CSS class names for styling the card root.\n\t */\n\tclassName?: string;\n};\n\nfunction hasSlotContent(slot: ReactNode | undefined): boolean {\n\treturn slot !== undefined && slot !== null && slot !== false;\n}\n\nexport function StatCard({\n\tlabel,\n\ttitle,\n\tvalue,\n\tsubtitle,\n\ticon: Icon,\n\ticonColor = \"text-basalt-muted-foreground\",\n\ttrend,\n\taction,\n\tstatus,\n\ttrendContent,\n\tchildren,\n\tariaLabel,\n\tclassName,\n}: StatCardProps) {\n\tconst heading = title ?? label;\n\tconst hasStatus = hasSlotContent(status);\n\tconst hasTrendContent = hasSlotContent(trendContent);\n\tconst hasAction = hasSlotContent(action);\n\tconst hasChildren = hasSlotContent(children);\n\tconst isInteractive = hasAction || hasStatus || hasTrendContent || hasChildren;\n\n\tconst display = typeof value === \"number\" ? value.toLocaleString() : value;\n\tconst isPositiveTrend = trend && trend.value > 0;\n\tconst isNegativeTrend = trend && trend.value < 0;\n\n\t// Accessible name: If custom status or custom trendContent is provided, do not report\n\t// the overridden hidden default value or default trend to assistive technology.\n\tconst named =\n\t\tariaLabel ??\n\t\t[\n\t\t\theading,\n\t\t\t!hasStatus ? display : null,\n\t\t\tsubtitle,\n\t\t\t!hasTrendContent && trend\n\t\t\t\t? `${isPositiveTrend ? \"+\" : \"\"}${trend.value}% ${trend.label ?? \"\"}`\n\t\t\t\t: null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \")\n\t\t\t.trim();\n\n\treturn (\n\t\t<LayerCard\n\t\t\tdata-slot=\"stat-card\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex min-w-0 flex-col gap-basalt-card-sm overflow-visible [overflow-wrap:anywhere]\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\trole={isInteractive ? \"group\" : \"img\"}\n\t\t\taria-label={named}\n\t\t>\n\t\t\t{heading || Icon || hasAction ? (\n\t\t\t\t<div\n\t\t\t\t\tdata-slot=\"stat-card-heading\"\n\t\t\t\t\tclassName=\"flex items-center justify-between gap-basalt-space-lg\"\n\t\t\t\t>\n\t\t\t\t\t<div className=\"flex min-w-0 items-start gap-basalt-space-lg\">\n\t\t\t\t\t\t{Icon ? (\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclassName={cn(\"mt-basalt-space-xs size-basalt-icon-lg shrink-0\", iconColor)}\n\t\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<p className=\"min-w-0 text-basalt-base font-medium text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t{heading}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t{hasAction ? <div className=\"flex shrink-0 items-center\">{action}</div> : null}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<div data-slot=\"stat-card-metric\" className=\"min-w-0 space-y-basalt-space-sm\">\n\t\t\t\t{hasStatus ? (\n\t\t\t\t\t<div>{status}</div>\n\t\t\t\t) : (\n\t\t\t\t\t<p\n\t\t\t\t\t\tdata-slot=\"stat-card-value\"\n\t\t\t\t\t\tclassName=\"font-basalt-display text-basalt-4xl leading-basalt-tight font-semibold tracking-tight tabular-nums text-basalt-foreground\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{display}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t\t{subtitle ? (\n\t\t\t\t\t<p className=\"text-basalt-sm text-basalt-muted-foreground\">{subtitle}</p>\n\t\t\t\t) : null}\n\t\t\t\t{hasTrendContent ? (\n\t\t\t\t\t<div\n\t\t\t\t\t\tdata-slot=\"stat-card-trend\"\n\t\t\t\t\t\tclassName=\"flex flex-wrap items-baseline gap-x-basalt-space-md gap-y-basalt-space-xs text-basalt-sm\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{trendContent}\n\t\t\t\t\t</div>\n\t\t\t\t) : trend ? (\n\t\t\t\t\t<div\n\t\t\t\t\t\tdata-slot=\"stat-card-trend\"\n\t\t\t\t\t\tclassName=\"flex flex-wrap items-baseline gap-x-basalt-space-md gap-y-basalt-space-xs text-basalt-sm\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"font-medium tabular-nums\",\n\t\t\t\t\t\t\t\tisPositiveTrend && \"text-basalt-tag-success-foreground\",\n\t\t\t\t\t\t\t\tisNegativeTrend && \"text-basalt-destructive\",\n\t\t\t\t\t\t\t\t!isPositiveTrend && !isNegativeTrend && \"text-basalt-muted-foreground\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{`${isPositiveTrend ? \"+\" : \"\"}${trend.value}%`}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t{trend.label ? (\n\t\t\t\t\t\t\t<span className=\"text-basalt-muted-foreground\">{trend.label}</span>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t\t{hasChildren ? (\n\t\t\t\t<div data-slot=\"stat-card-content\" className=\"mt-auto min-w-0\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</LayerCard>\n\t);\n}\n\nexport type StatGridProps = {\n\tchildren: ReactNode;\n\tcolumns?: 2 | 3 | 4;\n\tclassName?: string;\n};\n\nexport function StatGrid({ children, columns = 4, className }: StatGridProps) {\n\tconst gridCols = {\n\t\t2: \"grid-cols-1 sm:grid-cols-2\",\n\t\t3: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\",\n\t\t4: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-4\",\n\t};\n\treturn (\n\t\t<div className={cn(\"grid gap-basalt-layout\", gridCols[columns], className)}>{children}</div>\n\t);\n}\n"],"mappings":";;;;;AAmEA,SAASA,EAAe,GAAsC;CAC7D,OAAOC,KAA+B,QAAQA,MAAS;AACxD;AAEA,SAAgBC,EAAS,EACxB,UACA,UACA,UACA,aACA,MAAMC,GACN,eAAY,gCACZ,UACA,WACA,WACA,iBACA,aACA,cACA,gBACiB;CACjB,IAAMC,IAAUC,KAASC,GACnBC,IAAYP,EAAeQ,CAAM,GACjCC,IAAkBT,EAAeU,CAAY,GAC7CC,IAAYX,EAAeY,CAAM,GACjCC,IAAcb,EAAec,CAAQ,GACrCC,IAAgBJ,KAAaJ,KAAaE,KAAmBI,GAE7DG,IAAU,OAAOC,KAAU,WAAWA,EAAM,eAAe,IAAIA,GAC/DC,IAAkBC,KAASA,EAAM,QAAQ,GACzCC,IAAkBD,KAASA,EAAM,QAAQ,GAIzCE,IACLC,KACA;EACClB;EACCG,IAAsB,OAAVS;EACbO;EACA,CAACd,KAAmBU,IACjB,GAAGD,IAAkB,MAAM,KAAKC,EAAM,MAAM,IAAIA,EAAM,SAAS,OAC/D;CACJ,CAAC,CACC,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,CAAC,CACT,KAAK;CAER,OACC,kBAACK,GAAD;EACC,aAAU;EACV,WAAWC,EACV,sFACAC,CACD;EACA,MAAMX,IAAgB,UAAU;EAChC,cAAYM;EAPb,UAAA;GASEjB,KAAWD,KAAQQ,IACnB,kBAAC,OAAD;IACC,aAAU;IACV,WAAU;IAFX,UAAA,CAIC,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACER,IACA,kBAACA,GAAD;MACC,eAAY;MACZ,WAAWsB,EAAG,mDAAmDE,CAAS;MAC1E,aAAa;KACb,CAAA,IACE,MACJ,kBAAC,KAAD;MAAG,WAAU;MACX,UAAAvB;KACC,CAAA,CACC;IACJ,CAAA,GAAAO,IAAY,kBAAC,OAAD;KAAK,WAAU;KAA8B,UAAAC;IAAY,CAAA,IAAI,IACtE;GACF,CAAA,IAAA;GACJ,kBAAC,OAAD;IAAK,aAAU;IAAmB,WAAU;IAA5C,UAAA;KACEL,IACA,kBAAC,OAAD,EAAA,UAAMC,EAAY,CAAA,IAElB,kBAAC,KAAD;MACC,aAAU;MACV,WAAU;MAET,UAAAQ;KACC,CAAA;KAEHO,IACA,kBAAC,KAAD;MAAG,WAAU;MAA+C,UAAAA;KAAY,CAAA,IACrE;KACHd,IACA,kBAAC,OAAD;MACC,aAAU;MACV,WAAU;MAET,UAAAC;KACG,CAAA,IACFS,IACH,kBAAC,OAAD;MACC,aAAU;MACV,WAAU;MAFX,UAAA,CAIC,kBAAC,QAAD;OACC,WAAWM,EACV,4BACAP,KAAmB,sCACnBE,KAAmB,2BACnB,CAACF,KAAmB,CAACE,KAAmB,8BACzC;OAEC,UAAA,GAAGF,IAAkB,MAAM,KAAKC,EAAM,MAAM;MACxC,CAAA,GACLA,EAAM,QACN,kBAAC,QAAD;OAAM,WAAU;OAAgC,UAAAA,EAAM;MAAY,CAAA,IAC/D,IACA;KACF,CAAA,IAAA;IACA;;GACJN,IACA,kBAAC,OAAD;IAAK,aAAU;IAAoB,WAAU;IAC3C;GACG,CAAA,IACF;EACM;;AAEb;AAQA,SAAgBe,EAAS,EAAE,aAAU,aAAU,GAAG,gBAA4B;CAM7E,OACC,kBAAC,OAAD;EAAK,WAAWH,EAAG,0BAA0B;GAL7C,GAAG;GACH,GAAG;GACH,GAAG;EAG0C,EAASI,IAAUH,CAAS;EAAI;CAAc,CAAA;AAE7F"}
1
+ {"version":3,"file":"stat-card.js","names":["hasSlotContent","slot","StatCard","Icon","heading","title","label","hasStatus","status","hasTrendContent","trendContent","hasAction","action","hasChildren","children","isInteractive","display","value","isPositiveTrend","trend","isNegativeTrend","named","ariaLabel","subtitle","LayerCard","cn","className","iconColor","StatGrid","columns"],"sources":["../../src/charts/stat-card.tsx"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { LayerCard } from \"../components/layer-card\";\nimport { cn } from \"../utils/cn\";\n\nexport type StatCardProps = {\n\t/**\n\t * Secondary heading label for the metric card (overridden by title).\n\t */\n\tlabel?: string;\n\t/**\n\t * Primary heading title for the metric card (takes precedence over label).\n\t */\n\ttitle?: string;\n\t/**\n\t * Metric value, formatted via toLocaleString() if a number is provided.\n\t * Overridden by the status slot if provided.\n\t */\n\tvalue: string | number;\n\t/**\n\t * Supporting descriptive subtitle text rendered below value.\n\t */\n\tsubtitle?: string;\n\t/**\n\t * Optional decorative Lucide icon component.\n\t */\n\ticon?: LucideIcon;\n\t/**\n\t * Color class applied to the decorative icon.\n\t * @default \"text-basalt-muted-foreground\"\n\t */\n\ticonColor?: string;\n\t/**\n\t * Structured percentage trend value and optional label.\n\t * Overridden by the trendContent slot if provided.\n\t */\n\ttrend?: { value: number; label?: string };\n\t/**\n\t * Optional header action or interactive element (e.g. tooltip trigger or button).\n\t * Renders alongside the title/icon. Switches card role to group for accessible descendants.\n\t */\n\taction?: ReactNode;\n\t/**\n\t * Optional custom status replacement slot (e.g. loading skeleton, error state, or empty state).\n\t * Takes precedence over the default value display and excludes value from accessible name.\n\t * Subtitle and trend remain caller-managed; when error/empty state is shown, callers should omit trend.\n\t */\n\tstatus?: ReactNode;\n\t/**\n\t * Optional custom trend replacement slot (e.g. custom badge, sparkline, or localized trend indicator).\n\t * Takes precedence over the default trend calculation and excludes default trend from accessible name.\n\t */\n\ttrendContent?: ReactNode;\n\t/**\n\t * Optional supporting content rendered below the value, subtitle, and trend in the same surface.\n\t */\n\tchildren?: ReactNode;\n\t/**\n\t * Explicit accessible label overriding automatic accessible name calculation.\n\t */\n\tariaLabel?: string;\n\t/**\n\t * Additional CSS class names for styling the card root.\n\t */\n\tclassName?: string;\n};\n\nfunction hasSlotContent(slot: ReactNode | undefined): boolean {\n\treturn slot !== undefined && slot !== null && slot !== false;\n}\n\nexport function StatCard({\n\tlabel,\n\ttitle,\n\tvalue,\n\tsubtitle,\n\ticon: Icon,\n\ticonColor = \"text-basalt-muted-foreground\",\n\ttrend,\n\taction,\n\tstatus,\n\ttrendContent,\n\tchildren,\n\tariaLabel,\n\tclassName,\n}: StatCardProps) {\n\tconst heading = title ?? label;\n\tconst hasStatus = hasSlotContent(status);\n\tconst hasTrendContent = hasSlotContent(trendContent);\n\tconst hasAction = hasSlotContent(action);\n\tconst hasChildren = hasSlotContent(children);\n\tconst isInteractive = hasAction || hasStatus || hasTrendContent || hasChildren;\n\n\tconst display = typeof value === \"number\" ? value.toLocaleString() : value;\n\tconst isPositiveTrend = trend && trend.value > 0;\n\tconst isNegativeTrend = trend && trend.value < 0;\n\n\t// Accessible name: If custom status or custom trendContent is provided, do not report\n\t// the overridden hidden default value or default trend to assistive technology.\n\tconst named =\n\t\tariaLabel ??\n\t\t[\n\t\t\theading,\n\t\t\t!hasStatus ? display : null,\n\t\t\tsubtitle,\n\t\t\t!hasTrendContent && trend\n\t\t\t\t? `${isPositiveTrend ? \"+\" : \"\"}${trend.value}% ${trend.label ?? \"\"}`\n\t\t\t\t: null,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \")\n\t\t\t.trim();\n\n\treturn (\n\t\t<LayerCard\n\t\t\tdata-slot=\"stat-card\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex min-w-0 flex-col gap-basalt-card-sm overflow-visible [overflow-wrap:anywhere]\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\trole={isInteractive ? \"group\" : \"img\"}\n\t\t\taria-label={named}\n\t\t>\n\t\t\t{heading || Icon || hasAction ? (\n\t\t\t\t<div\n\t\t\t\t\tdata-slot=\"stat-card-heading\"\n\t\t\t\t\tclassName=\"flex items-center justify-between gap-basalt-space-lg\"\n\t\t\t\t>\n\t\t\t\t\t<div className=\"flex min-w-0 items-start gap-basalt-space-lg\">\n\t\t\t\t\t\t{Icon ? (\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclassName={cn(\"mt-basalt-space-xs size-basalt-icon-lg shrink-0\", iconColor)}\n\t\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<p className=\"min-w-0 text-basalt-base font-medium text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t{heading}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t{hasAction ? <div className=\"flex shrink-0 items-center\">{action}</div> : null}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<div data-slot=\"stat-card-metric\" className=\"min-w-0 space-y-basalt-space-sm\">\n\t\t\t\t{hasStatus ? (\n\t\t\t\t\t<div>{status}</div>\n\t\t\t\t) : (\n\t\t\t\t\t<p\n\t\t\t\t\t\tdata-slot=\"stat-card-value\"\n\t\t\t\t\t\tclassName=\"font-basalt-display text-basalt-3xl leading-basalt-tight font-semibold tracking-tight tabular-nums text-basalt-foreground\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{display}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t\t{subtitle ? (\n\t\t\t\t\t<p className=\"text-basalt-sm text-basalt-muted-foreground\">{subtitle}</p>\n\t\t\t\t) : null}\n\t\t\t\t{hasTrendContent ? (\n\t\t\t\t\t<div\n\t\t\t\t\t\tdata-slot=\"stat-card-trend\"\n\t\t\t\t\t\tclassName=\"flex flex-wrap items-baseline gap-x-basalt-space-md gap-y-basalt-space-xs text-basalt-sm\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{trendContent}\n\t\t\t\t\t</div>\n\t\t\t\t) : trend ? (\n\t\t\t\t\t<div\n\t\t\t\t\t\tdata-slot=\"stat-card-trend\"\n\t\t\t\t\t\tclassName=\"flex flex-wrap items-baseline gap-x-basalt-space-md gap-y-basalt-space-xs text-basalt-sm\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"font-medium tabular-nums\",\n\t\t\t\t\t\t\t\tisPositiveTrend && \"text-basalt-tag-success-foreground\",\n\t\t\t\t\t\t\t\tisNegativeTrend && \"text-basalt-destructive\",\n\t\t\t\t\t\t\t\t!isPositiveTrend && !isNegativeTrend && \"text-basalt-muted-foreground\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{`${isPositiveTrend ? \"+\" : \"\"}${trend.value}%`}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t{trend.label ? (\n\t\t\t\t\t\t\t<span className=\"text-basalt-muted-foreground\">{trend.label}</span>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t\t{hasChildren ? (\n\t\t\t\t<div data-slot=\"stat-card-content\" className=\"mt-auto min-w-0\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</LayerCard>\n\t);\n}\n\nexport type StatGridProps = {\n\tchildren: ReactNode;\n\tcolumns?: 2 | 3 | 4;\n\tclassName?: string;\n};\n\nexport function StatGrid({ children, columns = 4, className }: StatGridProps) {\n\tconst gridCols = {\n\t\t2: \"grid-cols-1 sm:grid-cols-2\",\n\t\t3: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\",\n\t\t4: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-4\",\n\t};\n\treturn (\n\t\t<div className={cn(\"grid gap-basalt-layout\", gridCols[columns], className)}>{children}</div>\n\t);\n}\n"],"mappings":";;;;;AAmEA,SAASA,EAAe,GAAsC;CAC7D,OAAOC,KAA+B,QAAQA,MAAS;AACxD;AAEA,SAAgBC,EAAS,EACxB,UACA,UACA,UACA,aACA,MAAMC,GACN,eAAY,gCACZ,UACA,WACA,WACA,iBACA,aACA,cACA,gBACiB;CACjB,IAAMC,IAAUC,KAASC,GACnBC,IAAYP,EAAeQ,CAAM,GACjCC,IAAkBT,EAAeU,CAAY,GAC7CC,IAAYX,EAAeY,CAAM,GACjCC,IAAcb,EAAec,CAAQ,GACrCC,IAAgBJ,KAAaJ,KAAaE,KAAmBI,GAE7DG,IAAU,OAAOC,KAAU,WAAWA,EAAM,eAAe,IAAIA,GAC/DC,IAAkBC,KAASA,EAAM,QAAQ,GACzCC,IAAkBD,KAASA,EAAM,QAAQ,GAIzCE,IACLC,KACA;EACClB;EACCG,IAAsB,OAAVS;EACbO;EACA,CAACd,KAAmBU,IACjB,GAAGD,IAAkB,MAAM,KAAKC,EAAM,MAAM,IAAIA,EAAM,SAAS,OAC/D;CACJ,CAAC,CACC,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,CAAC,CACT,KAAK;CAER,OACC,kBAACK,GAAD;EACC,aAAU;EACV,WAAWC,EACV,sFACAC,CACD;EACA,MAAMX,IAAgB,UAAU;EAChC,cAAYM;EAPb,UAAA;GASEjB,KAAWD,KAAQQ,IACnB,kBAAC,OAAD;IACC,aAAU;IACV,WAAU;IAFX,UAAA,CAIC,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACER,IACA,kBAACA,GAAD;MACC,eAAY;MACZ,WAAWsB,EAAG,mDAAmDE,CAAS;MAC1E,aAAa;KACb,CAAA,IACE,MACJ,kBAAC,KAAD;MAAG,WAAU;MACX,UAAAvB;KACC,CAAA,CACC;IACJ,CAAA,GAAAO,IAAY,kBAAC,OAAD;KAAK,WAAU;KAA8B,UAAAC;IAAY,CAAA,IAAI,IACtE;GACF,CAAA,IAAA;GACJ,kBAAC,OAAD;IAAK,aAAU;IAAmB,WAAU;IAA5C,UAAA;KACEL,IACA,kBAAC,OAAD,EAAA,UAAMC,EAAY,CAAA,IAElB,kBAAC,KAAD;MACC,aAAU;MACV,WAAU;MAET,UAAAQ;KACC,CAAA;KAEHO,IACA,kBAAC,KAAD;MAAG,WAAU;MAA+C,UAAAA;KAAY,CAAA,IACrE;KACHd,IACA,kBAAC,OAAD;MACC,aAAU;MACV,WAAU;MAET,UAAAC;KACG,CAAA,IACFS,IACH,kBAAC,OAAD;MACC,aAAU;MACV,WAAU;MAFX,UAAA,CAIC,kBAAC,QAAD;OACC,WAAWM,EACV,4BACAP,KAAmB,sCACnBE,KAAmB,2BACnB,CAACF,KAAmB,CAACE,KAAmB,8BACzC;OAEC,UAAA,GAAGF,IAAkB,MAAM,KAAKC,EAAM,MAAM;MACxC,CAAA,GACLA,EAAM,QACN,kBAAC,QAAD;OAAM,WAAU;OAAgC,UAAAA,EAAM;MAAY,CAAA,IAC/D,IACA;KACF,CAAA,IAAA;IACA;;GACJN,IACA,kBAAC,OAAD;IAAK,aAAU;IAAoB,WAAU;IAC3C;GACG,CAAA,IACF;EACM;;AAEb;AAQA,SAAgBe,EAAS,EAAE,aAAU,aAAU,GAAG,gBAA4B;CAM7E,OACC,kBAAC,OAAD;EAAK,WAAWH,EAAG,0BAA0B;GAL7C,GAAG;GACH,GAAG;GACH,GAAG;EAG0C,EAASI,IAAUH,CAAS;EAAI;CAAc,CAAA;AAE7F"}
@@ -27,13 +27,13 @@ var f = a.forwardRef(({ className: e, size: t = "base", ...n }, a) => /* @__PURE
27
27
  f.displayName = i.Content.displayName;
28
28
  var p = a.forwardRef(({ className: t, ...n }, r) => /* @__PURE__ */ o(i.Title, {
29
29
  ref: r,
30
- className: e("min-w-0 text-basalt-3xl font-semibold tracking-tight wrap-anywhere", t),
30
+ className: e("min-w-0 text-basalt-xl font-semibold leading-basalt-tight tracking-tight wrap-anywhere", t),
31
31
  ...n
32
32
  }));
33
33
  p.displayName = i.Title.displayName;
34
34
  var m = a.forwardRef(({ className: t, ...n }, r) => /* @__PURE__ */ o(i.Description, {
35
35
  ref: r,
36
- className: e("text-basalt-lg text-basalt-muted-foreground", t),
36
+ className: e("text-basalt-base leading-[var(--basalt-line-relaxed)] text-basalt-muted-foreground", t),
37
37
  ...n
38
38
  }));
39
39
  m.displayName = i.Description.displayName;
@@ -50,12 +50,12 @@ var g = a.forwardRef(({ className: n, ...r }, a) => /* @__PURE__ */ o(i.Action,
50
50
  }));
51
51
  g.displayName = i.Action.displayName;
52
52
  var _ = ({ className: t, ...n }) => /* @__PURE__ */ o("div", {
53
- className: e("flex flex-col space-y-basalt-space-lg text-left", t),
53
+ className: e("flex flex-col space-y-basalt-space-md text-left", t),
54
54
  ...n
55
55
  });
56
56
  _.displayName = "AlertDialogHeader";
57
57
  var v = ({ className: t, ...n }) => /* @__PURE__ */ o("div", {
58
- className: e("mt-basalt-space-lg flex flex-col-reverse gap-basalt-space-lg sm:flex-row sm:justify-end", t),
58
+ className: e("mt-basalt-layout flex flex-col-reverse gap-basalt-space-lg sm:flex-row sm:justify-end", t),
59
59
  ...n
60
60
  });
61
61
  v.displayName = "AlertDialogFooter";
@@ -1 +1 @@
1
- {"version":3,"file":"alert-dialog.js","names":["AlertDialogPrimitive","React","AlertDialog","AlertDialogTrigger","AlertDialogPortal","AlertDialogOverlay","props","dialogOverlayClass","className","AlertDialogContent","dialogPanelClass","AlertDialogTitle","cn","AlertDialogDescription","AlertDialogCancel","buttonVariants","AlertDialogAction","AlertDialogHeader","AlertDialogFooter"],"sources":["../../src/components/alert-dialog.tsx"],"sourcesContent":["import * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { buttonVariants } from \"./button\";\nimport { type DialogSize, dialogOverlayClass, dialogPanelClass } from \"./dialog\";\n\ntype RadixAlertDialogProps = React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Root>;\ntype RadixAlertDialogTriggerProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Trigger\n>;\ntype RadixAlertDialogPortalProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Portal\n>;\ntype RadixAlertDialogOverlayProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Overlay\n>;\ntype RadixAlertDialogContentProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Content\n>;\ntype RadixAlertDialogTitleProps = React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>;\ntype RadixAlertDialogDescriptionProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Description\n>;\ntype RadixAlertDialogActionProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Action\n>;\ntype RadixAlertDialogCancelProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Cancel\n>;\n\nexport interface AlertDialogProps\n\textends Omit<RadixAlertDialogProps, \"open\" | \"defaultOpen\" | \"onOpenChange\"> {\n\t/**\n\t * Controlled open state of the alert dialog.\n\t */\n\topen?: RadixAlertDialogProps[\"open\"];\n\t/**\n\t * Uncontrolled default open state of the alert dialog on initial render.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixAlertDialogProps[\"defaultOpen\"];\n\t/**\n\t * Callback invoked when the open state changes.\n\t */\n\tonOpenChange?: RadixAlertDialogProps[\"onOpenChange\"];\n}\n\nexport const AlertDialog: React.FC<AlertDialogProps> = AlertDialogPrimitive.Root;\n\nexport interface AlertDialogTriggerProps extends Omit<RadixAlertDialogTriggerProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * Trigger forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogTriggerProps[\"asChild\"];\n}\n\nexport const AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nexport interface AlertDialogPortalProps\n\textends Omit<RadixAlertDialogPortalProps, \"container\" | \"forceMount\"> {\n\t/**\n\t * Target container element where the alert dialog overlay and content portal should mount.\n\t */\n\tcontainer?: RadixAlertDialogPortalProps[\"container\"];\n\t/**\n\t * Used to force mounting when controlling transition animations externally.\n\t */\n\tforceMount?: RadixAlertDialogPortalProps[\"forceMount\"];\n}\n\nexport const AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nexport interface AlertDialogOverlayProps\n\textends Omit<RadixAlertDialogOverlayProps, \"asChild\" | \"forceMount\"> {\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * Overlay forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogOverlayProps[\"asChild\"];\n\t/**\n\t * Used to force mounting when controlling transition animations externally.\n\t */\n\tforceMount?: RadixAlertDialogOverlayProps[\"forceMount\"];\n}\n\nexport const AlertDialogOverlay = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n\tAlertDialogOverlayProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Overlay ref={ref} className={dialogOverlayClass(className)} {...props} />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nexport interface AlertDialogContentProps\n\textends Omit<\n\t\tRadixAlertDialogContentProps,\n\t\t| \"size\"\n\t\t| \"asChild\"\n\t\t| \"forceMount\"\n\t\t| \"trapFocus\"\n\t\t| \"onOpenAutoFocus\"\n\t\t| \"onCloseAutoFocus\"\n\t\t| \"onEscapeKeyDown\"\n\t> {\n\t/**\n\t * Fixed desktop width preset, shared with Dialog. Content scrolls vertically when overflowing available height.\n\t * @default \"base\"\n\t */\n\tsize?: DialogSize;\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * Content forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogContentProps[\"asChild\"];\n\t/**\n\t * Force mounting content in DOM for external animation controls.\n\t * When forceMount is true, the content remains mounted even when closed.\n\t * The caller is responsible for visibility transitions and unmounting after animation completes.\n\t * Note: Keeping modal content forceMounted may isolate background interactions until unmounted.\n\t */\n\tforceMount?: RadixAlertDialogContentProps[\"forceMount\"];\n\t/**\n\t * Event handler called when auto-focusing on open. Defaults to focusing the cancel button. Can be prevented with event.preventDefault().\n\t */\n\tonOpenAutoFocus?: RadixAlertDialogContentProps[\"onOpenAutoFocus\"];\n\t/**\n\t * Event handler called when restoring focus on close. Can be prevented with event.preventDefault().\n\t */\n\tonCloseAutoFocus?: RadixAlertDialogContentProps[\"onCloseAutoFocus\"];\n\t/**\n\t * Event handler called when the Escape key is pressed. Can be prevented with event.preventDefault().\n\t */\n\tonEscapeKeyDown?: RadixAlertDialogContentProps[\"onEscapeKeyDown\"];\n}\n\nexport const AlertDialogContent = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Content>,\n\tAlertDialogContentProps\n>(({ className, size = \"base\", ...props }, ref) => (\n\t<AlertDialogPortal forceMount={props.forceMount}>\n\t\t<AlertDialogOverlay forceMount={props.forceMount} />\n\t\t<AlertDialogPrimitive.Content\n\t\t\tref={ref}\n\t\t\tdata-basalt-surface-root=\"\"\n\t\t\tclassName={dialogPanelClass({ size, className })}\n\t\t\t{...props}\n\t\t/>\n\t</AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nexport interface AlertDialogTitleProps extends Omit<RadixAlertDialogTitleProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered heading element to the child element, merging props and behavior.\n\t * Title forwards ref to HTMLHeadingElement and inherits native h2 attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogTitleProps[\"asChild\"];\n}\n\nexport const AlertDialogTitle = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Title>,\n\tAlertDialogTitleProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Title\n\t\tref={ref}\n\t\tclassName={cn(\"min-w-0 text-basalt-3xl font-semibold tracking-tight wrap-anywhere\", className)}\n\t\t{...props}\n\t/>\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nexport interface AlertDialogDescriptionProps\n\textends Omit<RadixAlertDialogDescriptionProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered paragraph element to the child element, merging props and behavior.\n\t * Description forwards ref to HTMLParagraphElement and inherits native p attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogDescriptionProps[\"asChild\"];\n}\n\nexport const AlertDialogDescription = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Description>,\n\tAlertDialogDescriptionProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Description\n\t\tref={ref}\n\t\tclassName={cn(\"text-basalt-lg text-basalt-muted-foreground\", className)}\n\t\t{...props}\n\t/>\n));\nAlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;\n\nexport interface AlertDialogCancelProps extends Omit<RadixAlertDialogCancelProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * Cancel forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogCancelProps[\"asChild\"];\n}\n\nexport const AlertDialogCancel = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n\tAlertDialogCancelProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Cancel\n\t\tref={ref}\n\t\tclassName={cn(buttonVariants({ variant: \"outline\" }), className)}\n\t\t{...props}\n\t/>\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport interface AlertDialogActionProps extends Omit<RadixAlertDialogActionProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * Action forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogActionProps[\"asChild\"];\n}\n\nexport const AlertDialogAction = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Action>,\n\tAlertDialogActionProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Action\n\t\tref={ref}\n\t\tclassName={cn(buttonVariants({ variant: \"destructive\" }), className)}\n\t\t{...props}\n\t/>\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nexport interface AlertDialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const AlertDialogHeader = ({ className, ...props }: AlertDialogHeaderProps) => (\n\t<div className={cn(\"flex flex-col space-y-basalt-space-lg text-left\", className)} {...props} />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nexport interface AlertDialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const AlertDialogFooter = ({ className, ...props }: AlertDialogFooterProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t\"mt-basalt-space-lg flex flex-col-reverse gap-basalt-space-lg sm:flex-row sm:justify-end\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n"],"mappings":";;;;;;;;AA+CA,IAAaE,IAA0CF,EAAqB,MAW/DG,IAAqBH,EAAqB,SAc1CI,IAAoBJ,EAAqB,QAgBzCK,IAAqBJ,EAAM,YAGrC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,SAAtB;CAAmC;CAAK,WAAWO,EAAmBC,CAAS;CAAG,GAAIF;AAAQ,CAAA,CAC9F;AACD,EAAmB,cAAcN,EAAqB,QAAQ;AA6C9D,IAAaS,IAAqBR,EAAM,YAGrC,EAAE,cAAW,UAAO,QAAQ,GAAGK,KAAS,MAC1C,kBAACF,GAAD;CAAmB,YAAYE,EAAM;CAArC,UAAA,CACC,kBAACD,GAAD,EAAoB,YAAYC,EAAM,WAAa,CAAA,GACnD,kBAACN,EAAqB,SAAtB;EACM;EACL,4BAAyB;EACzB,WAAWU,EAAiB;GAAE;GAAM;EAAU,CAAC;EAC/C,GAAIJ;CACJ,CAAA,CACiB;AACnB,CAAA,CAAA;AACD,EAAmB,cAAcN,EAAqB,QAAQ;AAW9D,IAAaW,IAAmBV,EAAM,YAGnC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,OAAtB;CACM;CACL,WAAWY,EAAG,sEAAsEJ,CAAS;CAC7F,GAAIF;AACJ,CAAA,CACD;AACD,EAAiB,cAAcN,EAAqB,MAAM;AAY1D,IAAaa,IAAyBZ,EAAM,YAGzC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,aAAtB;CACM;CACL,WAAWY,EAAG,+CAA+CJ,CAAS;CACtE,GAAIF;AACJ,CAAA,CACD;AACD,EAAuB,cAAcN,EAAqB,YAAY;AAWtE,IAAac,IAAoBb,EAAM,YAGpC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,QAAtB;CACM;CACL,WAAWY,EAAGG,EAAe,EAAE,SAAS,UAAU,CAAC,GAAGP,CAAS;CAC/D,GAAIF;AACJ,CAAA,CACD;AACD,EAAkB,cAAcN,EAAqB,OAAO;AAW5D,IAAagB,IAAoBf,EAAM,YAGpC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,QAAtB;CACM;CACL,WAAWY,EAAGG,EAAe,EAAE,SAAS,cAAc,CAAC,GAAGP,CAAS;CACnE,GAAIF;AACJ,CAAA,CACD;AACD,EAAkB,cAAcN,EAAqB,OAAO;AAI5D,IAAaiB,KAAqB,EAAE,cAAW,GAAGX,QACjD,kBAAC,OAAD;CAAK,WAAWM,EAAG,mDAAmDJ,CAAS;CAAG,GAAIF;AAAQ,CAAA;AAE/F,EAAkB,cAAc;AAIhC,IAAaY,KAAqB,EAAE,cAAW,GAAGZ,QACjD,kBAAC,OAAD;CACC,WAAWM,EACV,2FACAJ,CACD;CACA,GAAIF;AACJ,CAAA;AAEF,EAAkB,cAAc"}
1
+ {"version":3,"file":"alert-dialog.js","names":["AlertDialogPrimitive","React","AlertDialog","AlertDialogTrigger","AlertDialogPortal","AlertDialogOverlay","props","dialogOverlayClass","className","AlertDialogContent","dialogPanelClass","AlertDialogTitle","cn","AlertDialogDescription","AlertDialogCancel","buttonVariants","AlertDialogAction","AlertDialogHeader","AlertDialogFooter"],"sources":["../../src/components/alert-dialog.tsx"],"sourcesContent":["import * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { buttonVariants } from \"./button\";\nimport { type DialogSize, dialogOverlayClass, dialogPanelClass } from \"./dialog\";\n\ntype RadixAlertDialogProps = React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Root>;\ntype RadixAlertDialogTriggerProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Trigger\n>;\ntype RadixAlertDialogPortalProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Portal\n>;\ntype RadixAlertDialogOverlayProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Overlay\n>;\ntype RadixAlertDialogContentProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Content\n>;\ntype RadixAlertDialogTitleProps = React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>;\ntype RadixAlertDialogDescriptionProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Description\n>;\ntype RadixAlertDialogActionProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Action\n>;\ntype RadixAlertDialogCancelProps = React.ComponentPropsWithoutRef<\n\ttypeof AlertDialogPrimitive.Cancel\n>;\n\nexport interface AlertDialogProps\n\textends Omit<RadixAlertDialogProps, \"open\" | \"defaultOpen\" | \"onOpenChange\"> {\n\t/**\n\t * Controlled open state of the alert dialog.\n\t */\n\topen?: RadixAlertDialogProps[\"open\"];\n\t/**\n\t * Uncontrolled default open state of the alert dialog on initial render.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixAlertDialogProps[\"defaultOpen\"];\n\t/**\n\t * Callback invoked when the open state changes.\n\t */\n\tonOpenChange?: RadixAlertDialogProps[\"onOpenChange\"];\n}\n\nexport const AlertDialog: React.FC<AlertDialogProps> = AlertDialogPrimitive.Root;\n\nexport interface AlertDialogTriggerProps extends Omit<RadixAlertDialogTriggerProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * Trigger forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogTriggerProps[\"asChild\"];\n}\n\nexport const AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nexport interface AlertDialogPortalProps\n\textends Omit<RadixAlertDialogPortalProps, \"container\" | \"forceMount\"> {\n\t/**\n\t * Target container element where the alert dialog overlay and content portal should mount.\n\t */\n\tcontainer?: RadixAlertDialogPortalProps[\"container\"];\n\t/**\n\t * Used to force mounting when controlling transition animations externally.\n\t */\n\tforceMount?: RadixAlertDialogPortalProps[\"forceMount\"];\n}\n\nexport const AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nexport interface AlertDialogOverlayProps\n\textends Omit<RadixAlertDialogOverlayProps, \"asChild\" | \"forceMount\"> {\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * Overlay forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogOverlayProps[\"asChild\"];\n\t/**\n\t * Used to force mounting when controlling transition animations externally.\n\t */\n\tforceMount?: RadixAlertDialogOverlayProps[\"forceMount\"];\n}\n\nexport const AlertDialogOverlay = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n\tAlertDialogOverlayProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Overlay ref={ref} className={dialogOverlayClass(className)} {...props} />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nexport interface AlertDialogContentProps\n\textends Omit<\n\t\tRadixAlertDialogContentProps,\n\t\t| \"size\"\n\t\t| \"asChild\"\n\t\t| \"forceMount\"\n\t\t| \"trapFocus\"\n\t\t| \"onOpenAutoFocus\"\n\t\t| \"onCloseAutoFocus\"\n\t\t| \"onEscapeKeyDown\"\n\t> {\n\t/**\n\t * Fixed desktop width preset, shared with Dialog. Content scrolls vertically when overflowing available height.\n\t * @default \"base\"\n\t */\n\tsize?: DialogSize;\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * Content forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogContentProps[\"asChild\"];\n\t/**\n\t * Force mounting content in DOM for external animation controls.\n\t * When forceMount is true, the content remains mounted even when closed.\n\t * The caller is responsible for visibility transitions and unmounting after animation completes.\n\t * Note: Keeping modal content forceMounted may isolate background interactions until unmounted.\n\t */\n\tforceMount?: RadixAlertDialogContentProps[\"forceMount\"];\n\t/**\n\t * Event handler called when auto-focusing on open. Defaults to focusing the cancel button. Can be prevented with event.preventDefault().\n\t */\n\tonOpenAutoFocus?: RadixAlertDialogContentProps[\"onOpenAutoFocus\"];\n\t/**\n\t * Event handler called when restoring focus on close. Can be prevented with event.preventDefault().\n\t */\n\tonCloseAutoFocus?: RadixAlertDialogContentProps[\"onCloseAutoFocus\"];\n\t/**\n\t * Event handler called when the Escape key is pressed. Can be prevented with event.preventDefault().\n\t */\n\tonEscapeKeyDown?: RadixAlertDialogContentProps[\"onEscapeKeyDown\"];\n}\n\nexport const AlertDialogContent = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Content>,\n\tAlertDialogContentProps\n>(({ className, size = \"base\", ...props }, ref) => (\n\t<AlertDialogPortal forceMount={props.forceMount}>\n\t\t<AlertDialogOverlay forceMount={props.forceMount} />\n\t\t<AlertDialogPrimitive.Content\n\t\t\tref={ref}\n\t\t\tdata-basalt-surface-root=\"\"\n\t\t\tclassName={dialogPanelClass({ size, className })}\n\t\t\t{...props}\n\t\t/>\n\t</AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nexport interface AlertDialogTitleProps extends Omit<RadixAlertDialogTitleProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered heading element to the child element, merging props and behavior.\n\t * Title forwards ref to HTMLHeadingElement and inherits native h2 attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogTitleProps[\"asChild\"];\n}\n\nexport const AlertDialogTitle = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Title>,\n\tAlertDialogTitleProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Title\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"min-w-0 text-basalt-xl font-semibold leading-basalt-tight tracking-tight wrap-anywhere\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nexport interface AlertDialogDescriptionProps\n\textends Omit<RadixAlertDialogDescriptionProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered paragraph element to the child element, merging props and behavior.\n\t * Description forwards ref to HTMLParagraphElement and inherits native p attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogDescriptionProps[\"asChild\"];\n}\n\nexport const AlertDialogDescription = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Description>,\n\tAlertDialogDescriptionProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Description\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"text-basalt-base leading-[var(--basalt-line-relaxed)] text-basalt-muted-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nAlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;\n\nexport interface AlertDialogCancelProps extends Omit<RadixAlertDialogCancelProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * Cancel forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogCancelProps[\"asChild\"];\n}\n\nexport const AlertDialogCancel = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n\tAlertDialogCancelProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Cancel\n\t\tref={ref}\n\t\tclassName={cn(buttonVariants({ variant: \"outline\" }), className)}\n\t\t{...props}\n\t/>\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport interface AlertDialogActionProps extends Omit<RadixAlertDialogActionProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * Action forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixAlertDialogActionProps[\"asChild\"];\n}\n\nexport const AlertDialogAction = React.forwardRef<\n\tReact.ElementRef<typeof AlertDialogPrimitive.Action>,\n\tAlertDialogActionProps\n>(({ className, ...props }, ref) => (\n\t<AlertDialogPrimitive.Action\n\t\tref={ref}\n\t\tclassName={cn(buttonVariants({ variant: \"destructive\" }), className)}\n\t\t{...props}\n\t/>\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nexport interface AlertDialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const AlertDialogHeader = ({ className, ...props }: AlertDialogHeaderProps) => (\n\t<div className={cn(\"flex flex-col space-y-basalt-space-md text-left\", className)} {...props} />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nexport interface AlertDialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const AlertDialogFooter = ({ className, ...props }: AlertDialogFooterProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t\"mt-basalt-layout flex flex-col-reverse gap-basalt-space-lg sm:flex-row sm:justify-end\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n"],"mappings":";;;;;;;;AA+CA,IAAaE,IAA0CF,EAAqB,MAW/DG,IAAqBH,EAAqB,SAc1CI,IAAoBJ,EAAqB,QAgBzCK,IAAqBJ,EAAM,YAGrC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,SAAtB;CAAmC;CAAK,WAAWO,EAAmBC,CAAS;CAAG,GAAIF;AAAQ,CAAA,CAC9F;AACD,EAAmB,cAAcN,EAAqB,QAAQ;AA6C9D,IAAaS,IAAqBR,EAAM,YAGrC,EAAE,cAAW,UAAO,QAAQ,GAAGK,KAAS,MAC1C,kBAACF,GAAD;CAAmB,YAAYE,EAAM;CAArC,UAAA,CACC,kBAACD,GAAD,EAAoB,YAAYC,EAAM,WAAa,CAAA,GACnD,kBAACN,EAAqB,SAAtB;EACM;EACL,4BAAyB;EACzB,WAAWU,EAAiB;GAAE;GAAM;EAAU,CAAC;EAC/C,GAAIJ;CACJ,CAAA,CACiB;AACnB,CAAA,CAAA;AACD,EAAmB,cAAcN,EAAqB,QAAQ;AAW9D,IAAaW,IAAmBV,EAAM,YAGnC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,OAAtB;CACM;CACL,WAAWY,EACV,0FACAJ,CACD;CACA,GAAIF;AACJ,CAAA,CACD;AACD,EAAiB,cAAcN,EAAqB,MAAM;AAY1D,IAAaa,IAAyBZ,EAAM,YAGzC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,aAAtB;CACM;CACL,WAAWY,EACV,sFACAJ,CACD;CACA,GAAIF;AACJ,CAAA,CACD;AACD,EAAuB,cAAcN,EAAqB,YAAY;AAWtE,IAAac,IAAoBb,EAAM,YAGpC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,QAAtB;CACM;CACL,WAAWY,EAAGG,EAAe,EAAE,SAAS,UAAU,CAAC,GAAGP,CAAS;CAC/D,GAAIF;AACJ,CAAA,CACD;AACD,EAAkB,cAAcN,EAAqB,OAAO;AAW5D,IAAagB,IAAoBf,EAAM,YAGpC,EAAE,cAAW,GAAGK,KAAS,MAC3B,kBAACN,EAAqB,QAAtB;CACM;CACL,WAAWY,EAAGG,EAAe,EAAE,SAAS,cAAc,CAAC,GAAGP,CAAS;CACnE,GAAIF;AACJ,CAAA,CACD;AACD,EAAkB,cAAcN,EAAqB,OAAO;AAI5D,IAAaiB,KAAqB,EAAE,cAAW,GAAGX,QACjD,kBAAC,OAAD;CAAK,WAAWM,EAAG,mDAAmDJ,CAAS;CAAG,GAAIF;AAAQ,CAAA;AAE/F,EAAkB,cAAc;AAIhC,IAAaY,KAAqB,EAAE,cAAW,GAAGZ,QACjD,kBAAC,OAAD;CACC,WAAWM,EACV,yFACAJ,CACD;CACA,GAAIF;AACJ,CAAA;AAEF,EAAkB,cAAc"}
@@ -10,7 +10,7 @@ function s({ leading: s, breadcrumbs: c, title: l, actions: u, sticky: d = !1, d
10
10
  "data-basalt-header": "",
11
11
  "data-sticky": d || void 0,
12
12
  "data-density": f,
13
- className: e(t, "flex shrink-0 items-center justify-between gap-basalt-space-lg px-basalt-space-lg md:px-basalt-space-lg", f === "compact" ? "h-[3.25rem]" : "h-basalt-14", p),
13
+ className: e(t, "flex shrink-0 items-center justify-between gap-basalt-space-lg px-basalt-space-lg md:px-basalt-layout-sm", f === "compact" ? "h-[3.25rem]" : "h-basalt-14", p),
14
14
  ...m,
15
15
  children: [/* @__PURE__ */ o("div", {
16
16
  className: "flex min-w-0 items-center gap-basalt-space-lg",
@@ -1 +1 @@
1
- {"version":3,"file":"app-header.js","names":["_Fragment","AppHeader","props","sticky","density","cn","BASALT_UI_CLASS","className","leading","breadcrumbs","Fragment","Breadcrumbs","title","ChevronRight","actions"],"sources":["../../src/components/app-header.tsx"],"sourcesContent":["import { ChevronRight } from \"lucide-react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Breadcrumbs } from \"./breadcrumbs\";\n\nexport function AppHeader({\n\tleading,\n\tbreadcrumbs,\n\ttitle,\n\tactions,\n\tsticky = false,\n\tdensity = \"comfortable\",\n\tclassName,\n\t...props\n}: HTMLAttributes<HTMLElement> & {\n\tleading?: ReactNode;\n\tbreadcrumbs?: { href?: string; label: ReactNode }[];\n\ttitle?: ReactNode;\n\tactions?: ReactNode;\n\t/** Keep this row visible in its current scroll owner, including the shell safe area. */\n\tsticky?: boolean;\n\t/** Compact is a 52px row; comfortable is 56px. */\n\tdensity?: \"comfortable\" | \"compact\";\n}) {\n\treturn (\n\t\t<header\n\t\t\tdata-basalt-header=\"\"\n\t\t\tdata-sticky={sticky || undefined}\n\t\t\tdata-density={density}\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"flex shrink-0 items-center justify-between gap-basalt-space-lg px-basalt-space-lg md:px-basalt-space-lg\",\n\t\t\t\tdensity === \"compact\" ? \"h-[3.25rem]\" : \"h-basalt-14\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"flex min-w-0 items-center gap-basalt-space-lg\">\n\t\t\t\t{leading ? (\n\t\t\t\t\t<div data-basalt-header-leading=\"\" className=\"flex shrink-0 items-center\">\n\t\t\t\t\t\t{leading}\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t\t<div className=\"flex min-w-0 items-center gap-basalt-space-sm\">\n\t\t\t\t\t{breadcrumbs && breadcrumbs.length > 0 ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<Breadcrumbs items={breadcrumbs} className=\"min-w-0\" />\n\t\t\t\t\t\t\t{title ? (\n\t\t\t\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\t\t\t\tclassName=\"size-basalt-icon-sm shrink-0 text-basalt-muted-foreground\"\n\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{title ? (\n\t\t\t\t\t\t<h1 className=\"truncate text-basalt-base font-normal text-basalt-foreground\">\n\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t</h1>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t{actions ? (\n\t\t\t\t<div\n\t\t\t\t\tdata-basalt-header-actions=\"\"\n\t\t\t\t\tclassName=\"flex shrink-0 items-center gap-basalt-space-sm\"\n\t\t\t\t>\n\t\t\t\t\t{actions}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</header>\n\t);\n}\n"],"mappings":";;;;;;;AAMA,SAAgBC,EAAU,EACzB,YACA,gBACA,UACA,YACA,YAAS,IACT,aAAU,eACV,cACA,GAAGC,KAUD;CACF,OACC,kBAAC,UAAD;EACC,sBAAmB;EACnB,eAAaC,KAAU,KAAA;EACvB,gBAAcC;EACd,WAAWC,EACVC,GACA,2GACAF,MAAY,YAAY,gBAAgB,eACxCG,CACD;EACA,GAAIL;EAVL,UAAA,CAYC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACEM,IACA,kBAAC,OAAD;IAAK,8BAA2B;IAAG,WAAU;IAC3C,UAAAA;GACG,CAAA,IACF,MACJ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACEC,KAAeA,EAAY,SAAS,IACpC,kBAAAT,GAAA,EAAA,UAAA,CACC,kBAACW,GAAD;KAAa,OAAOF;KAAa,WAAU;IAAW,CAAA,GACrDG,IACA,kBAACC,GAAD;KACC,WAAU;KACV,eAAY;IACZ,CAAA,IACE,IACH,EAAA,CAAA,IACC,MACHD,IACA,kBAAC,MAAD;KAAI,WAAU;KACZ,UAAAA;IACE,CAAA,IACD,IACA;GACD,CAAA,CAAA;EACJ,CAAA,GAAAE,IACA,kBAAC,OAAD;GACC,8BAA2B;GAC3B,WAAU;GAET,UAAAA;EACG,CAAA,IACF,IACG;;AAEV"}
1
+ {"version":3,"file":"app-header.js","names":["_Fragment","AppHeader","props","sticky","density","cn","BASALT_UI_CLASS","className","leading","breadcrumbs","Fragment","Breadcrumbs","title","ChevronRight","actions"],"sources":["../../src/components/app-header.tsx"],"sourcesContent":["import { ChevronRight } from \"lucide-react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Breadcrumbs } from \"./breadcrumbs\";\n\nexport function AppHeader({\n\tleading,\n\tbreadcrumbs,\n\ttitle,\n\tactions,\n\tsticky = false,\n\tdensity = \"comfortable\",\n\tclassName,\n\t...props\n}: HTMLAttributes<HTMLElement> & {\n\tleading?: ReactNode;\n\tbreadcrumbs?: { href?: string; label: ReactNode }[];\n\ttitle?: ReactNode;\n\tactions?: ReactNode;\n\t/** Keep this row visible in its current scroll owner, including the shell safe area. */\n\tsticky?: boolean;\n\t/** Compact is a 52px row; comfortable is 56px. */\n\tdensity?: \"comfortable\" | \"compact\";\n}) {\n\treturn (\n\t\t<header\n\t\t\tdata-basalt-header=\"\"\n\t\t\tdata-sticky={sticky || undefined}\n\t\t\tdata-density={density}\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"flex shrink-0 items-center justify-between gap-basalt-space-lg px-basalt-space-lg md:px-basalt-layout-sm\",\n\t\t\t\tdensity === \"compact\" ? \"h-[3.25rem]\" : \"h-basalt-14\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"flex min-w-0 items-center gap-basalt-space-lg\">\n\t\t\t\t{leading ? (\n\t\t\t\t\t<div data-basalt-header-leading=\"\" className=\"flex shrink-0 items-center\">\n\t\t\t\t\t\t{leading}\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t\t<div className=\"flex min-w-0 items-center gap-basalt-space-sm\">\n\t\t\t\t\t{breadcrumbs && breadcrumbs.length > 0 ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<Breadcrumbs items={breadcrumbs} className=\"min-w-0\" />\n\t\t\t\t\t\t\t{title ? (\n\t\t\t\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\t\t\t\tclassName=\"size-basalt-icon-sm shrink-0 text-basalt-muted-foreground\"\n\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{title ? (\n\t\t\t\t\t\t<h1 className=\"truncate text-basalt-base font-normal text-basalt-foreground\">\n\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t</h1>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t{actions ? (\n\t\t\t\t<div\n\t\t\t\t\tdata-basalt-header-actions=\"\"\n\t\t\t\t\tclassName=\"flex shrink-0 items-center gap-basalt-space-sm\"\n\t\t\t\t>\n\t\t\t\t\t{actions}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</header>\n\t);\n}\n"],"mappings":";;;;;;;AAMA,SAAgBC,EAAU,EACzB,YACA,gBACA,UACA,YACA,YAAS,IACT,aAAU,eACV,cACA,GAAGC,KAUD;CACF,OACC,kBAAC,UAAD;EACC,sBAAmB;EACnB,eAAaC,KAAU,KAAA;EACvB,gBAAcC;EACd,WAAWC,EACVC,GACA,4GACAF,MAAY,YAAY,gBAAgB,eACxCG,CACD;EACA,GAAIL;EAVL,UAAA,CAYC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACEM,IACA,kBAAC,OAAD;IAAK,8BAA2B;IAAG,WAAU;IAC3C,UAAAA;GACG,CAAA,IACF,MACJ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACEC,KAAeA,EAAY,SAAS,IACpC,kBAAAT,GAAA,EAAA,UAAA,CACC,kBAACW,GAAD;KAAa,OAAOF;KAAa,WAAU;IAAW,CAAA,GACrDG,IACA,kBAACC,GAAD;KACC,WAAU;KACV,eAAY;IACZ,CAAA,IACE,IACH,EAAA,CAAA,IACC,MACHD,IACA,kBAAC,MAAD;KAAI,WAAU;KACZ,UAAAA;IACE,CAAA,IACD,IACA;GACD,CAAA,CAAA;EACJ,CAAA,GAAAE,IACA,kBAAC,OAAD;GACC,8BAA2B;GAC3B,WAAU;GAET,UAAAA;EACG,CAAA,IACF,IACG;;AAEV"}
@@ -6,7 +6,7 @@ import { jsx as n } from "react/jsx-runtime";
6
6
  function r({ href: r = "#main-content", className: i, children: a, ...o }) {
7
7
  return /* @__PURE__ */ n("a", {
8
8
  href: r,
9
- className: e(t, "sr-only focus:not-sr-only focus:absolute focus:top-basalt-2 focus:left-basalt-2 focus:z-[100] focus:rounded-basalt-md focus:bg-basalt-primary focus:px-basalt-space-lg focus:py-basalt-space-lg focus:text-basalt-base focus:font-medium focus:text-basalt-primary-foreground", i),
9
+ className: e(t, "basalt-focus", "sr-only focus:not-sr-only focus:absolute focus:top-basalt-2 focus:left-basalt-2 focus:z-[100] focus:rounded-basalt-md focus:bg-basalt-primary focus:px-basalt-space-lg focus:py-basalt-space-lg focus:text-basalt-base focus:font-medium focus:text-basalt-primary-foreground", i),
10
10
  ...o,
11
11
  children: a
12
12
  });
@@ -1 +1 @@
1
- {"version":3,"file":"app-shell.js","names":["AppSkipLink","props","cn","BASALT_UI_CLASS","className","AppShell","layout","AppMain"],"sources":["../../src/components/app-shell.tsx"],"sourcesContent":["import type { AnchorHTMLAttributes, HTMLAttributes } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport function AppSkipLink({\n\thref = \"#main-content\",\n\tclassName,\n\tchildren,\n\t...props\n}: AnchorHTMLAttributes<HTMLAnchorElement>) {\n\treturn (\n\t\t<a\n\t\t\thref={href}\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"sr-only focus:not-sr-only focus:absolute focus:top-basalt-2 focus:left-basalt-2 focus:z-[100] focus:rounded-basalt-md focus:bg-basalt-primary focus:px-basalt-space-lg focus:py-basalt-space-lg focus:text-basalt-base focus:font-medium focus:text-basalt-primary-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</a>\n\t);\n}\n\nexport function AppShell({\n\tlayout = \"workspace\",\n\tclassName,\n\t...props\n}: HTMLAttributes<HTMLDivElement> & {\n\t/** Scroll owner: bounded panes, document, or document below 768px. */\n\tlayout?: \"workspace\" | \"document\" | \"responsive\";\n}) {\n\treturn (\n\t\t<div\n\t\t\tdata-basalt-shell={layout}\n\t\t\tclassName={cn(\"flex w-full bg-basalt-background\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport function AppMain({ className, ...props }: HTMLAttributes<HTMLElement>) {\n\treturn (\n\t\t<main\n\t\t\tid=\"main-content\"\n\t\t\ttabIndex={-1}\n\t\t\tdata-basalt-main=\"\"\n\t\t\tclassName={cn(\"flex min-h-0 min-w-0 flex-1 flex-col\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;;AAIA,SAAgBA,EAAY,EAC3B,UAAO,iBACP,cACA,aACA,GAAGC,KACwC;CAC3C,OACC,kBAAC,KAAD;EACO;EACN,WAAWC,EACVC,GACA,iRACAC,CACD;EACA,GAAIH;EAEH;CACC,CAAA;AAEL;AAEA,SAAgBI,EAAS,EACxB,YAAS,aACT,cACA,GAAGJ,KAID;CACF,OACC,kBAAC,OAAD;EACC,qBAAmBK;EACnB,WAAWJ,EAAG,oCAAoCE,CAAS;EAC3D,GAAIH;CACJ,CAAA;AAEH;AAEA,SAAgBM,EAAQ,EAAE,cAAW,GAAGN,KAAsC;CAC7E,OACC,kBAAC,QAAD;EACC,IAAG;EACH,UAAU;EACV,oBAAiB;EACjB,WAAWC,EAAG,wCAAwCE,CAAS;EAC/D,GAAIH;CACJ,CAAA;AAEH"}
1
+ {"version":3,"file":"app-shell.js","names":["AppSkipLink","props","cn","BASALT_UI_CLASS","className","AppShell","layout","AppMain"],"sources":["../../src/components/app-shell.tsx"],"sourcesContent":["import type { AnchorHTMLAttributes, HTMLAttributes } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport function AppSkipLink({\n\thref = \"#main-content\",\n\tclassName,\n\tchildren,\n\t...props\n}: AnchorHTMLAttributes<HTMLAnchorElement>) {\n\treturn (\n\t\t<a\n\t\t\thref={href}\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"basalt-focus\",\n\t\t\t\t\"sr-only focus:not-sr-only focus:absolute focus:top-basalt-2 focus:left-basalt-2 focus:z-[100] focus:rounded-basalt-md focus:bg-basalt-primary focus:px-basalt-space-lg focus:py-basalt-space-lg focus:text-basalt-base focus:font-medium focus:text-basalt-primary-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</a>\n\t);\n}\n\nexport function AppShell({\n\tlayout = \"workspace\",\n\tclassName,\n\t...props\n}: HTMLAttributes<HTMLDivElement> & {\n\t/** Scroll owner: bounded panes, document, or document below 768px. */\n\tlayout?: \"workspace\" | \"document\" | \"responsive\";\n}) {\n\treturn (\n\t\t<div\n\t\t\tdata-basalt-shell={layout}\n\t\t\tclassName={cn(\"flex w-full bg-basalt-background\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport function AppMain({ className, ...props }: HTMLAttributes<HTMLElement>) {\n\treturn (\n\t\t<main\n\t\t\tid=\"main-content\"\n\t\t\ttabIndex={-1}\n\t\t\tdata-basalt-main=\"\"\n\t\t\tclassName={cn(\"flex min-h-0 min-w-0 flex-1 flex-col\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;;AAIA,SAAgBA,EAAY,EAC3B,UAAO,iBACP,cACA,aACA,GAAGC,KACwC;CAC3C,OACC,kBAAC,KAAD;EACO;EACN,WAAWC,EACVC,GACA,gBACA,iRACAC,CACD;EACA,GAAIH;EAEH;CACC,CAAA;AAEL;AAEA,SAAgBI,EAAS,EACxB,YAAS,aACT,cACA,GAAGJ,KAID;CACF,OACC,kBAAC,OAAD;EACC,qBAAmBK;EACnB,WAAWJ,EAAG,oCAAoCE,CAAS;EAC3D,GAAIH;CACJ,CAAA;AAEH;AAEA,SAAgBM,EAAQ,EAAE,cAAW,GAAGN,KAAsC;CAC7E,OACC,kBAAC,QAAD;EACC,IAAG;EACH,UAAU;EACV,oBAAiB;EACjB,WAAWC,EAAG,wCAAwCE,CAAS;EAC/D,GAAIH;CACJ,CAAA;AAEH"}
@@ -43,7 +43,7 @@ function h({ className: h, onDismiss: g, ..._ }) {
43
43
  let T = v.status === "submitting";
44
44
  return /* @__PURE__ */ m(a, {
45
45
  padding: "sm",
46
- className: e("w-full space-y-basalt-content-gap px-basalt-panel-x py-basalt-panel-y leading-[var(--basalt-line-body)]", h),
46
+ className: e("w-full space-y-basalt-card-sm px-basalt-panel-x py-basalt-panel-y leading-[var(--basalt-line-body)]", h),
47
47
  children: [
48
48
  /* @__PURE__ */ m("div", {
49
49
  className: "flex items-center justify-between gap-basalt-content-gap",
@@ -57,6 +57,7 @@ function h({ className: h, onDismiss: g, ..._ }) {
57
57
  }), g && /* @__PURE__ */ p(t, {
58
58
  variant: "ghost",
59
59
  size: "icon",
60
+ className: "-my-basalt-space-sm -mr-basalt-space-sm",
60
61
  "aria-label": "Dismiss approval",
61
62
  disabled: T,
62
63
  onClick: g,
@@ -77,7 +78,7 @@ function h({ className: h, onDismiss: g, ..._ }) {
77
78
  "data-hover-selected": v.answer?.selected.includes(e.id),
78
79
  "data-disabled": e.disabled || T ? "" : void 0,
79
80
  htmlFor: `${y}-${e.id}`,
80
- className: "flex cursor-pointer items-center gap-basalt-row-gap rounded-basalt-sm px-basalt-row-x py-basalt-row-y text-basalt-code leading-basalt-row",
81
+ className: "flex cursor-pointer items-center gap-basalt-row-gap rounded-basalt-sm px-basalt-row-x py-basalt-row-y text-basalt-base leading-basalt-row",
81
82
  children: [/* @__PURE__ */ p(s.Item, {
82
83
  id: `${y}-${e.id}`,
83
84
  value: e.id,
@@ -93,7 +94,7 @@ function h({ className: h, onDismiss: g, ..._ }) {
93
94
  "data-hover-selected": v.answer?.selected.includes(e.id),
94
95
  "data-disabled": e.disabled || T ? "" : void 0,
95
96
  htmlFor: `${y}-${e.id}`,
96
- className: "flex cursor-pointer items-center gap-basalt-row-gap rounded-basalt-sm px-basalt-row-x py-basalt-row-y text-basalt-code leading-basalt-row",
97
+ className: "flex cursor-pointer items-center gap-basalt-row-gap rounded-basalt-sm px-basalt-row-x py-basalt-row-y text-basalt-base leading-basalt-row",
97
98
  children: [/* @__PURE__ */ p(n, {
98
99
  id: `${y}-${e.id}`,
99
100
  checked: v.answer?.selected.includes(e.id) ?? !1,
@@ -116,7 +117,7 @@ function h({ className: h, onDismiss: g, ..._ }) {
116
117
  children: v.error
117
118
  }),
118
119
  /* @__PURE__ */ m("div", {
119
- className: "flex items-center justify-between gap-basalt-content-gap border-t border-basalt-border pt-basalt-space-lg",
120
+ className: "flex items-center justify-between gap-basalt-content-gap border-t border-basalt-border pt-basalt-card-sm",
120
121
  children: [/* @__PURE__ */ m("div", {
121
122
  className: "flex items-center gap-basalt-content-gap",
122
123
  children: [/* @__PURE__ */ p(t, {
@@ -139,12 +140,10 @@ function h({ className: h, onDismiss: g, ..._ }) {
139
140
  className: "flex gap-basalt-content-gap",
140
141
  children: [w.required === !1 && /* @__PURE__ */ p(t, {
141
142
  variant: "ghost",
142
- size: "sm",
143
143
  disabled: T,
144
144
  onClick: v.skip,
145
145
  children: "Skip"
146
146
  }), /* @__PURE__ */ p(t, {
147
- size: "sm",
148
147
  loading: T,
149
148
  disabled: !v.canContinue || T,
150
149
  onClick: v.continue,
@@ -1 +1 @@
1
- {"version":3,"file":"approval-card.js","names":["ApprovalCard","props","vm","useApprovalCardViewModel","id","useId","options","useRef","heading","submitted","highlightRef","useHoverHighlight","useEffect","active","question","LayerCard","busy","cn","className","onDismiss","Button","X","Radio","option","Checkbox","Input","event","ChevronLeft"],"sources":["../../src/components/approval-card.tsx"],"sourcesContent":["import { ChevronLeft, X } from \"lucide-react\";\nimport { useEffect, useId, useRef } from \"react\";\nimport type { ApprovalAnswers, ApprovalQuestion } from \"../models/agent-feedback\";\nimport { cn } from \"../utils/cn\";\nimport { useHoverHighlight } from \"../utils/use-hover-highlight\";\nimport { useApprovalCardViewModel } from \"../viewmodels/use-approval-card\";\nimport { Button } from \"./button\";\nimport { Checkbox } from \"./checkbox\";\nimport { Input } from \"./input\";\nimport { LayerCard } from \"./layer-card\";\nimport { Radio } from \"./radio\";\n\nexport type { ApprovalAnswer, ApprovalAnswers, ApprovalQuestion } from \"../models/agent-feedback\";\nexport interface ApprovalCardProps {\n\t/** Stable question and option IDs. Remount with a new key for a new request. */\n\tquestions: readonly ApprovalQuestion[];\n\t/** Submit answers; a rejected promise keeps answers and shows retry feedback. */\n\tonSubmit: (answers: ApprovalAnswers) => void | Promise<void>;\n\t/** Enable automatic progression after a single selection. Never auto-submits. @default true */\n\tautoAdvance?: boolean;\n\tonDismiss?: () => void;\n\tclassName?: string;\n}\n\nexport function ApprovalCard({ className, onDismiss, ...props }: ApprovalCardProps) {\n\tconst vm = useApprovalCardViewModel(props);\n\tconst id = useId();\n\tconst options = useRef<HTMLDivElement | null>(null);\n\tconst heading = useRef<HTMLHeadingElement | null>(null);\n\tconst submitted = useRef<HTMLParagraphElement | null>(null);\n\tconst highlightRef = useHoverHighlight(options);\n\tuseEffect(() => {\n\t\tif (!vm.focusToken) return;\n\t\tconst active = document.activeElement;\n\t\t// A control the user is still holding stays put; a removed or disabled one hands off to the question.\n\t\tif (\n\t\t\tactive instanceof HTMLElement &&\n\t\t\tactive !== document.body &&\n\t\t\tactive.isConnected &&\n\t\t\t!active.matches(\":disabled, [aria-disabled='true']\")\n\t\t)\n\t\t\treturn;\n\t\tconst answer = options.current?.querySelector<HTMLElement>(\n\t\t\t':is([role=\"radio\"], [role=\"checkbox\"], input):not(:disabled):not([aria-disabled=\"true\"])',\n\t\t);\n\t\t(answer ?? heading.current)?.focus();\n\t}, [vm.focusToken]);\n\tuseEffect(() => {\n\t\tif (vm.status === \"submitted\") submitted.current?.focus();\n\t}, [vm.status]);\n\tconst question = vm.question;\n\tif (!question)\n\t\treturn (\n\t\t\t<LayerCard padding=\"sm\" className={className}>\n\t\t\t\t<p className=\"text-basalt-base text-basalt-muted-foreground\">No approval questions</p>\n\t\t\t</LayerCard>\n\t\t);\n\tif (vm.status === \"submitted\")\n\t\treturn (\n\t\t\t<LayerCard padding=\"sm\" className={className}>\n\t\t\t\t<p ref={submitted} tabIndex={-1} role=\"status\" className=\"text-basalt-base\">\n\t\t\t\t\tAnswers submitted\n\t\t\t\t</p>\n\t\t\t</LayerCard>\n\t\t);\n\tconst busy = vm.status === \"submitting\";\n\treturn (\n\t\t<LayerCard\n\t\t\tpadding=\"sm\"\n\t\t\tclassName={cn(\n\t\t\t\t\"w-full space-y-basalt-content-gap px-basalt-panel-x py-basalt-panel-y leading-[var(--basalt-line-body)]\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<div className=\"flex items-center justify-between gap-basalt-content-gap\">\n\t\t\t\t<h3\n\t\t\t\t\tref={heading}\n\t\t\t\t\tid={id}\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tclassName=\"text-basalt-base font-medium\"\n\t\t\t\t\taria-live=\"polite\"\n\t\t\t\t>\n\t\t\t\t\t{question.label}\n\t\t\t\t</h3>\n\t\t\t\t{onDismiss && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\taria-label=\"Dismiss approval\"\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\tonClick={onDismiss}\n\t\t\t\t\t>\n\t\t\t\t\t\t<X />\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tkey={question.id}\n\t\t\t\tref={highlightRef}\n\t\t\t\tclassName=\"basalt-agent-reveal basalt-hover-list -mx-basalt-row-x space-y-basalt-content-gap\"\n\t\t\t>\n\t\t\t\t{question.type === \"single\" ? (\n\t\t\t\t\t<Radio.Group\n\t\t\t\t\t\tvalue={vm.answer?.selected[0] ?? \"\"}\n\t\t\t\t\t\tonValueChange={vm.choose}\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\taria-labelledby={id}\n\t\t\t\t\t\tclassName=\"gap-basalt-space-xs\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{question.options.map((option) => (\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\tkey={option.id}\n\t\t\t\t\t\t\t\tdata-basalt-hover-item=\"\"\n\t\t\t\t\t\t\t\tdata-hover-selected={vm.answer?.selected.includes(option.id)}\n\t\t\t\t\t\t\t\tdata-disabled={option.disabled || busy ? \"\" : undefined}\n\t\t\t\t\t\t\t\thtmlFor={`${id}-${option.id}`}\n\t\t\t\t\t\t\t\tclassName=\"flex cursor-pointer items-center gap-basalt-row-gap rounded-basalt-sm px-basalt-row-x py-basalt-row-y text-basalt-code leading-basalt-row\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Radio.Item\n\t\t\t\t\t\t\t\t\tid={`${id}-${option.id}`}\n\t\t\t\t\t\t\t\t\tvalue={option.id}\n\t\t\t\t\t\t\t\t\tdisabled={option.disabled}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Radio.Group>\n\t\t\t\t) : (\n\t\t\t\t\t<fieldset disabled={busy} aria-labelledby={id} className=\"space-y-basalt-space-xs\">\n\t\t\t\t\t\t{question.options.map((option) => (\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\tkey={option.id}\n\t\t\t\t\t\t\t\tdata-basalt-hover-item=\"\"\n\t\t\t\t\t\t\t\tdata-hover-selected={vm.answer?.selected.includes(option.id)}\n\t\t\t\t\t\t\t\tdata-disabled={option.disabled || busy ? \"\" : undefined}\n\t\t\t\t\t\t\t\thtmlFor={`${id}-${option.id}`}\n\t\t\t\t\t\t\t\tclassName=\"flex cursor-pointer items-center gap-basalt-row-gap rounded-basalt-sm px-basalt-row-x py-basalt-row-y text-basalt-code leading-basalt-row\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\tid={`${id}-${option.id}`}\n\t\t\t\t\t\t\t\t\tchecked={vm.answer?.selected.includes(option.id) ?? false}\n\t\t\t\t\t\t\t\t\tonCheckedChange={() => vm.choose(option.id)}\n\t\t\t\t\t\t\t\t\tdisabled={option.disabled}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</fieldset>\n\t\t\t\t)}\n\t\t\t\t{question.allowCustom && (\n\t\t\t\t\t<Input\n\t\t\t\t\t\taria-label=\"Custom answer\"\n\t\t\t\t\t\tplaceholder=\"Something else...\"\n\t\t\t\t\t\tclassName=\"ml-basalt-row-x w-[calc(100%-2*var(--basalt-space-row-x))]\"\n\t\t\t\t\t\tvalue={vm.answer?.custom ?? \"\"}\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\tonChange={(event) => vm.setCustom(event.target.value)}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t{vm.error && (\n\t\t\t\t<p role=\"alert\" className=\"text-basalt-sm text-basalt-danger\">\n\t\t\t\t\t{vm.error}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className=\"flex items-center justify-between gap-basalt-content-gap border-t border-basalt-border pt-basalt-space-lg\">\n\t\t\t\t<div className=\"flex items-center gap-basalt-content-gap\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\tclassName=\"-ml-[calc((var(--basalt-size-action)-var(--basalt-size-icon))/2)]\"\n\t\t\t\t\t\taria-label=\"Previous question\"\n\t\t\t\t\t\tdisabled={busy || vm.position === 0}\n\t\t\t\t\t\tonClick={() => vm.move(vm.position - 1)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ChevronLeft />\n\t\t\t\t\t</Button>\n\t\t\t\t\t<span className=\"text-basalt-sm tabular-nums text-basalt-muted-foreground\">\n\t\t\t\t\t\t{vm.position + 1} / {props.questions.length}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex gap-basalt-content-gap\">\n\t\t\t\t\t{question.required === false && (\n\t\t\t\t\t\t<Button variant=\"ghost\" size=\"sm\" disabled={busy} onClick={vm.skip}>\n\t\t\t\t\t\t\tSkip\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t\t<Button size=\"sm\" loading={busy} disabled={!vm.canContinue || busy} onClick={vm.continue}>\n\t\t\t\t\t\t{vm.last ? \"Submit\" : \"Continue\"}\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</LayerCard>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;AAwBA,SAAgBA,EAAa,EAAE,cAAW,cAAW,GAAGC,KAA4B;CACnF,IAAMC,IAAKC,EAAyBF,CAAK,GACnCG,IAAKC,EAAM,GACXC,IAAUC,EAA8B,IAAI,GAC5CC,IAAUD,EAAkC,IAAI,GAChDE,IAAYF,EAAoC,IAAI,GACpDG,IAAeC,EAAkBL,CAAO;CAiB9C,AAhBAM,QAAgB;EACf,IAAI,CAACV,EAAG,YAAY;EACpB,IAAMW,IAAS,SAAS;EAExB,AACCA,aAAkB,eAClBA,MAAW,SAAS,QACpBA,EAAO,eACP,CAACA,EAAO,QAAQ,mCAAmC,MAGrCP,EAAQ,SAAS,cAC/B,gGACD,KACWE,EAAQ,QAAA,EAAU,MAAM;CACpC,GAAG,CAACN,EAAG,UAAU,CAAC,GAClBU,QAAgB;EACf,AAAIV,EAAG,WAAW,eAAaO,EAAU,SAAS,MAAM;CACzD,GAAG,CAACP,EAAG,MAAM,CAAC;CACd,IAAMY,IAAWZ,EAAG;CACpB,IAAI,CAACY,GACJ,OACC,kBAACC,GAAD;EAAW,SAAQ;EAAgB;EAClC,UAAA,kBAAC,KAAD;GAAG,WAAU;GAAgD,UAAA;EAAwB,CAAA;CAC3E,CAAA;CAEb,IAAIb,EAAG,WAAW,aACjB,OACC,kBAACa,GAAD;EAAW,SAAQ;EAAgB;EAClC,UAAA,kBAAC,KAAD;GAAG,KAAKN;GAAW,UAAU;GAAI,MAAK;GAAS,WAAU;GAAmB,UAAA;EAEzE,CAAA;CACO,CAAA;CAEb,IAAMO,IAAOd,EAAG,WAAW;CAC3B,OACC,kBAACa,GAAD;EACC,SAAQ;EACR,WAAWE,EACV,2GACAC,CACD;EALD,UAAA;GAOC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACC,kBAAC,MAAD;KACC,KAAKV;KACD;KACJ,UAAU;KACV,WAAU;KACV,aAAU;KAET,UAAAM,EAAS;IACP,CAAA,GACHK,KACA,kBAACC,GAAD;KACC,SAAQ;KACR,MAAK;KACL,cAAW;KACX,UAAUJ;KACV,SAASG;KAET,UAAA,kBAACE,GAAD,CAAI,CAAA;IACG,CAAA,CAEL;;GACL,kBAAC,OAAD;IAEC,KAAKX;IACL,WAAU;IAHX,UAAA,CAKEI,EAAS,SAAS,WAClB,kBAACQ,EAAM,OAAP;KACC,OAAOpB,EAAG,QAAQ,SAAS,MAAM;KACjC,eAAeA,EAAG;KAClB,UAAUc;KACV,mBAAiBZ;KACjB,WAAU;KAET,UAAAU,EAAS,QAAQ,KAAK,MACtB,kBAAC,SAAD;MAEC,0BAAuB;MACvB,uBAAqBZ,EAAG,QAAQ,SAAS,SAASqB,EAAO,EAAE;MAC3D,iBAAeA,EAAO,YAAYP,IAAO,KAAK,KAAA;MAC9C,SAAS,GAAGZ,EAAG,GAAGmB,EAAO;MACzB,WAAU;MANX,UAAA,CAQC,kBAACD,EAAM,MAAP;OACC,IAAI,GAAGlB,EAAG,GAAGmB,EAAO;OACpB,OAAOA,EAAO;OACd,UAAUA,EAAO;MACjB,CAAA,GACAA,EAAO,KACF;KAbD,GAAAA,EAAO,EAaN,CACP;IACW,CAAA,IAEb,kBAAC,YAAD;KAAU,UAAUP;KAAM,mBAAiBZ;KAAI,WAAU;KACvD,UAAAU,EAAS,QAAQ,KAAK,MACtB,kBAAC,SAAD;MAEC,0BAAuB;MACvB,uBAAqBZ,EAAG,QAAQ,SAAS,SAASqB,EAAO,EAAE;MAC3D,iBAAeA,EAAO,YAAYP,IAAO,KAAK,KAAA;MAC9C,SAAS,GAAGZ,EAAG,GAAGmB,EAAO;MACzB,WAAU;MANX,UAAA,CAQC,kBAACC,GAAD;OACC,IAAI,GAAGpB,EAAG,GAAGmB,EAAO;OACpB,SAASrB,EAAG,QAAQ,SAAS,SAASqB,EAAO,EAAE,KAAK;OACpD,uBAAuBrB,EAAG,OAAOqB,EAAO,EAAE;OAC1C,UAAUA,EAAO;MACjB,CAAA,GACAA,EAAO,KACF;KAdD,GAAAA,EAAO,EAcN,CACP;IACQ,CAAA,GAEVT,EAAS,eACT,kBAACW,GAAD;KACC,cAAW;KACX,aAAY;KACZ,WAAU;KACV,OAAOvB,EAAG,QAAQ,UAAU;KAC5B,UAAUc;KACV,WAAW,MAAUd,EAAG,UAAUwB,EAAM,OAAO,KAAK;IACpD,CAAA,CAEE;GA9DC,GAAAZ,EAAS,EA8DV;GACJZ,EAAG,SACH,kBAAC,KAAD;IAAG,MAAK;IAAQ,WAAU;IACxB,UAAAA,EAAG;GACF,CAAA;GAEJ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACC,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACC,kBAACkB,GAAD;MACC,SAAQ;MACR,MAAK;MACL,WAAU;MACV,cAAW;MACX,UAAUJ,KAAQd,EAAG,aAAa;MAClC,eAAeA,EAAG,KAAKA,EAAG,WAAW,CAAC;MAEtC,UAAA,kBAACyB,GAAD,CAAc,CAAA;KACP,CAAA,GACR,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OACEzB,EAAG,WAAW;OAAE;OAAID,EAAM,UAAU;MAChC;KACF,CAAA,CAAA;IACL,CAAA,GAAA,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACEa,EAAS,aAAa,MACtB,kBAACM,GAAD;MAAQ,SAAQ;MAAQ,MAAK;MAAK,UAAUJ;MAAM,SAASd,EAAG;MAAM,UAAA;KAE5D,CAAA,GAET,kBAACkB,GAAD;MAAQ,MAAK;MAAK,SAASJ;MAAM,UAAU,CAACd,EAAG,eAAec;MAAM,SAASd,EAAG;MAC9E,UAAAA,EAAG,OAAO,WAAW;KACf,CAAA,CACJ;IACD,CAAA,CAAA;;EACK;;AAEb"}
1
+ {"version":3,"file":"approval-card.js","names":["ApprovalCard","props","vm","useApprovalCardViewModel","id","useId","options","useRef","heading","submitted","highlightRef","useHoverHighlight","useEffect","active","question","LayerCard","busy","cn","className","onDismiss","Button","X","Radio","option","Checkbox","Input","event","ChevronLeft"],"sources":["../../src/components/approval-card.tsx"],"sourcesContent":["import { ChevronLeft, X } from \"lucide-react\";\nimport { useEffect, useId, useRef } from \"react\";\nimport type { ApprovalAnswers, ApprovalQuestion } from \"../models/agent-feedback\";\nimport { cn } from \"../utils/cn\";\nimport { useHoverHighlight } from \"../utils/use-hover-highlight\";\nimport { useApprovalCardViewModel } from \"../viewmodels/use-approval-card\";\nimport { Button } from \"./button\";\nimport { Checkbox } from \"./checkbox\";\nimport { Input } from \"./input\";\nimport { LayerCard } from \"./layer-card\";\nimport { Radio } from \"./radio\";\n\nexport type { ApprovalAnswer, ApprovalAnswers, ApprovalQuestion } from \"../models/agent-feedback\";\nexport interface ApprovalCardProps {\n\t/** Stable question and option IDs. Remount with a new key for a new request. */\n\tquestions: readonly ApprovalQuestion[];\n\t/** Submit answers; a rejected promise keeps answers and shows retry feedback. */\n\tonSubmit: (answers: ApprovalAnswers) => void | Promise<void>;\n\t/** Enable automatic progression after a single selection. Never auto-submits. @default true */\n\tautoAdvance?: boolean;\n\tonDismiss?: () => void;\n\tclassName?: string;\n}\n\nexport function ApprovalCard({ className, onDismiss, ...props }: ApprovalCardProps) {\n\tconst vm = useApprovalCardViewModel(props);\n\tconst id = useId();\n\tconst options = useRef<HTMLDivElement | null>(null);\n\tconst heading = useRef<HTMLHeadingElement | null>(null);\n\tconst submitted = useRef<HTMLParagraphElement | null>(null);\n\tconst highlightRef = useHoverHighlight(options);\n\tuseEffect(() => {\n\t\tif (!vm.focusToken) return;\n\t\tconst active = document.activeElement;\n\t\t// A control the user is still holding stays put; a removed or disabled one hands off to the question.\n\t\tif (\n\t\t\tactive instanceof HTMLElement &&\n\t\t\tactive !== document.body &&\n\t\t\tactive.isConnected &&\n\t\t\t!active.matches(\":disabled, [aria-disabled='true']\")\n\t\t)\n\t\t\treturn;\n\t\tconst answer = options.current?.querySelector<HTMLElement>(\n\t\t\t':is([role=\"radio\"], [role=\"checkbox\"], input):not(:disabled):not([aria-disabled=\"true\"])',\n\t\t);\n\t\t(answer ?? heading.current)?.focus();\n\t}, [vm.focusToken]);\n\tuseEffect(() => {\n\t\tif (vm.status === \"submitted\") submitted.current?.focus();\n\t}, [vm.status]);\n\tconst question = vm.question;\n\tif (!question)\n\t\treturn (\n\t\t\t<LayerCard padding=\"sm\" className={className}>\n\t\t\t\t<p className=\"text-basalt-base text-basalt-muted-foreground\">No approval questions</p>\n\t\t\t</LayerCard>\n\t\t);\n\tif (vm.status === \"submitted\")\n\t\treturn (\n\t\t\t<LayerCard padding=\"sm\" className={className}>\n\t\t\t\t<p ref={submitted} tabIndex={-1} role=\"status\" className=\"text-basalt-base\">\n\t\t\t\t\tAnswers submitted\n\t\t\t\t</p>\n\t\t\t</LayerCard>\n\t\t);\n\tconst busy = vm.status === \"submitting\";\n\treturn (\n\t\t<LayerCard\n\t\t\tpadding=\"sm\"\n\t\t\tclassName={cn(\n\t\t\t\t\"w-full space-y-basalt-card-sm px-basalt-panel-x py-basalt-panel-y leading-[var(--basalt-line-body)]\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<div className=\"flex items-center justify-between gap-basalt-content-gap\">\n\t\t\t\t<h3\n\t\t\t\t\tref={heading}\n\t\t\t\t\tid={id}\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tclassName=\"text-basalt-base font-medium\"\n\t\t\t\t\taria-live=\"polite\"\n\t\t\t\t>\n\t\t\t\t\t{question.label}\n\t\t\t\t</h3>\n\t\t\t\t{onDismiss && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\tclassName=\"-my-basalt-space-sm -mr-basalt-space-sm\"\n\t\t\t\t\t\taria-label=\"Dismiss approval\"\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\tonClick={onDismiss}\n\t\t\t\t\t>\n\t\t\t\t\t\t<X />\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tkey={question.id}\n\t\t\t\tref={highlightRef}\n\t\t\t\tclassName=\"basalt-agent-reveal basalt-hover-list -mx-basalt-row-x space-y-basalt-content-gap\"\n\t\t\t>\n\t\t\t\t{question.type === \"single\" ? (\n\t\t\t\t\t<Radio.Group\n\t\t\t\t\t\tvalue={vm.answer?.selected[0] ?? \"\"}\n\t\t\t\t\t\tonValueChange={vm.choose}\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\taria-labelledby={id}\n\t\t\t\t\t\tclassName=\"gap-basalt-space-xs\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{question.options.map((option) => (\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\tkey={option.id}\n\t\t\t\t\t\t\t\tdata-basalt-hover-item=\"\"\n\t\t\t\t\t\t\t\tdata-hover-selected={vm.answer?.selected.includes(option.id)}\n\t\t\t\t\t\t\t\tdata-disabled={option.disabled || busy ? \"\" : undefined}\n\t\t\t\t\t\t\t\thtmlFor={`${id}-${option.id}`}\n\t\t\t\t\t\t\t\tclassName=\"flex cursor-pointer items-center gap-basalt-row-gap rounded-basalt-sm px-basalt-row-x py-basalt-row-y text-basalt-base leading-basalt-row\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Radio.Item\n\t\t\t\t\t\t\t\t\tid={`${id}-${option.id}`}\n\t\t\t\t\t\t\t\t\tvalue={option.id}\n\t\t\t\t\t\t\t\t\tdisabled={option.disabled}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Radio.Group>\n\t\t\t\t) : (\n\t\t\t\t\t<fieldset disabled={busy} aria-labelledby={id} className=\"space-y-basalt-space-xs\">\n\t\t\t\t\t\t{question.options.map((option) => (\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\tkey={option.id}\n\t\t\t\t\t\t\t\tdata-basalt-hover-item=\"\"\n\t\t\t\t\t\t\t\tdata-hover-selected={vm.answer?.selected.includes(option.id)}\n\t\t\t\t\t\t\t\tdata-disabled={option.disabled || busy ? \"\" : undefined}\n\t\t\t\t\t\t\t\thtmlFor={`${id}-${option.id}`}\n\t\t\t\t\t\t\t\tclassName=\"flex cursor-pointer items-center gap-basalt-row-gap rounded-basalt-sm px-basalt-row-x py-basalt-row-y text-basalt-base leading-basalt-row\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\tid={`${id}-${option.id}`}\n\t\t\t\t\t\t\t\t\tchecked={vm.answer?.selected.includes(option.id) ?? false}\n\t\t\t\t\t\t\t\t\tonCheckedChange={() => vm.choose(option.id)}\n\t\t\t\t\t\t\t\t\tdisabled={option.disabled}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</fieldset>\n\t\t\t\t)}\n\t\t\t\t{question.allowCustom && (\n\t\t\t\t\t<Input\n\t\t\t\t\t\taria-label=\"Custom answer\"\n\t\t\t\t\t\tplaceholder=\"Something else...\"\n\t\t\t\t\t\tclassName=\"ml-basalt-row-x w-[calc(100%-2*var(--basalt-space-row-x))]\"\n\t\t\t\t\t\tvalue={vm.answer?.custom ?? \"\"}\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\tonChange={(event) => vm.setCustom(event.target.value)}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t{vm.error && (\n\t\t\t\t<p role=\"alert\" className=\"text-basalt-sm text-basalt-danger\">\n\t\t\t\t\t{vm.error}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className=\"flex items-center justify-between gap-basalt-content-gap border-t border-basalt-border pt-basalt-card-sm\">\n\t\t\t\t<div className=\"flex items-center gap-basalt-content-gap\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\tclassName=\"-ml-[calc((var(--basalt-size-action)-var(--basalt-size-icon))/2)]\"\n\t\t\t\t\t\taria-label=\"Previous question\"\n\t\t\t\t\t\tdisabled={busy || vm.position === 0}\n\t\t\t\t\t\tonClick={() => vm.move(vm.position - 1)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ChevronLeft />\n\t\t\t\t\t</Button>\n\t\t\t\t\t<span className=\"text-basalt-sm tabular-nums text-basalt-muted-foreground\">\n\t\t\t\t\t\t{vm.position + 1} / {props.questions.length}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex gap-basalt-content-gap\">\n\t\t\t\t\t{question.required === false && (\n\t\t\t\t\t\t<Button variant=\"ghost\" disabled={busy} onClick={vm.skip}>\n\t\t\t\t\t\t\tSkip\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t\t<Button loading={busy} disabled={!vm.canContinue || busy} onClick={vm.continue}>\n\t\t\t\t\t\t{vm.last ? \"Submit\" : \"Continue\"}\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</LayerCard>\n\t);\n}\n"],"mappings":"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"}
@@ -38,7 +38,7 @@ function d({ name: r, colorKey: i, initials: o, size: c = "default", className:
38
38
  "aria-label": r,
39
39
  className: e(c === "sm" && "size-basalt-6", d),
40
40
  children: /* @__PURE__ */ a(l, {
41
- className: e("font-medium", c === "sm" ? "text-basalt-xs" : "text-basalt-sm", u[t(i ?? r)]),
41
+ className: e("font-medium text-basalt-sm", u[t(i ?? r)]),
42
42
  children: o?.trim() ? Array.from(o.trim().toLocaleUpperCase("en-US")).slice(0, 2).join("") : n(r)
43
43
  })
44
44
  });
@@ -1 +1 @@
1
- {"version":3,"file":"avatar.js","names":["React","AvatarPrimitive","Avatar","props","cn","className","AvatarImage","AvatarFallback","AVATAR_TONES","TAG_COLORS","AvatarInitials","name","size","avatarColorIndex","colorKey","initials","avatarInitials"],"sources":["../../src/components/avatar.tsx"],"sourcesContent":["import * as AvatarPrimitive from \"@radix-ui/react-avatar\";\nimport * as React from \"react\";\nimport { avatarColorIndex, avatarInitials } from \"../models/avatar\";\nimport { cn } from \"../utils/cn\";\nimport { TAG_COLORS } from \"./tag-badge\";\n\nexport type AvatarProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,\n\t\"asChild\"\n> & {\n\t/**\n\t * Change the default rendered element for the one passed as a child, merging their props and behavior.\n\t * @default false\n\t */\n\tasChild?: boolean;\n};\n\nexport const Avatar = React.forwardRef<React.ElementRef<typeof AvatarPrimitive.Root>, AvatarProps>(\n\t({ className, ...props }, ref) => (\n\t\t<AvatarPrimitive.Root\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"relative flex h-basalt-9 w-basalt-9 shrink-0 overflow-hidden rounded-basalt-full\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nAvatar.displayName = AvatarPrimitive.Root.displayName;\n\nexport type AvatarImageProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>,\n\t\"asChild\" | \"onLoadingStatusChange\" | \"src\" | \"alt\"\n> & {\n\t/**\n\t * Change the default rendered element for the one passed as a child, merging their props and behavior.\n\t * @default false\n\t */\n\tasChild?: boolean;\n\t/**\n\t * Image source URL for the avatar image.\n\t */\n\tsrc?: React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>[\"src\"];\n\t/**\n\t * Text description of the image for accessibility and screen readers.\n\t */\n\talt?: React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>[\"alt\"];\n\t/**\n\t * A callback providing the current loading status of the image ('idle' | 'loading' | 'loaded' | 'error').\n\t */\n\tonLoadingStatusChange?: React.ComponentPropsWithoutRef<\n\t\ttypeof AvatarPrimitive.Image\n\t>[\"onLoadingStatusChange\"];\n};\n\nexport const AvatarImage = React.forwardRef<\n\tReact.ElementRef<typeof AvatarPrimitive.Image>,\n\tAvatarImageProps\n>(({ className, ...props }, ref) => (\n\t<AvatarPrimitive.Image\n\t\tref={ref}\n\t\tclassName={cn(\"aspect-square h-full w-full\", className)}\n\t\t{...props}\n\t/>\n));\nAvatarImage.displayName = AvatarPrimitive.Image.displayName;\n\nexport type AvatarFallbackProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>,\n\t\"asChild\" | \"delayMs\"\n> & {\n\t/**\n\t * Change the default rendered element for the one passed as a child, merging their props and behavior.\n\t * @default false\n\t */\n\tasChild?: boolean;\n\t/**\n\t * Useful for delaying rendering so it only appears for those with slower connections.\n\t * Unset by default, rendering immediately without delay.\n\t */\n\tdelayMs?: number;\n};\n\nexport const AvatarFallback = React.forwardRef<\n\tReact.ElementRef<typeof AvatarPrimitive.Fallback>,\n\tAvatarFallbackProps\n>(({ className, ...props }, ref) => (\n\t<AvatarPrimitive.Fallback\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex h-full w-full items-center justify-center rounded-basalt-full bg-basalt-muted text-basalt-sm\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nAvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;\n\nconst AVATAR_TONES = [\n\tTAG_COLORS.blue.className,\n\tTAG_COLORS.amber.className,\n\tTAG_COLORS.rose.className,\n\tTAG_COLORS.teal.className,\n\tTAG_COLORS.violet.className,\n\tTAG_COLORS.success.className,\n] as const;\n\nexport interface AvatarInitialsProps {\n\t/** Person or organization name; initials are derived from its first two words. */\n\tname: string;\n\t/** Stable color identity, independent of display name changes. */\n\tcolorKey?: string;\n\t/** Two-letter override for application-specific abbreviations. */\n\tinitials?: string;\n\t/** Avatar diameter. @default \"default\" */\n\tsize?: \"sm\" | \"default\";\n\tclassName?: string;\n}\n\nexport function AvatarInitials({\n\tname,\n\tcolorKey,\n\tinitials,\n\tsize = \"default\",\n\tclassName,\n}: AvatarInitialsProps) {\n\treturn (\n\t\t<Avatar\n\t\t\trole=\"img\"\n\t\t\taria-label={name}\n\t\t\tclassName={cn(size === \"sm\" && \"size-basalt-6\", className)}\n\t\t>\n\t\t\t<AvatarFallback\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"font-medium\",\n\t\t\t\t\tsize === \"sm\" ? \"text-basalt-xs\" : \"text-basalt-sm\",\n\t\t\t\t\tAVATAR_TONES[avatarColorIndex(colorKey ?? name)],\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{initials?.trim()\n\t\t\t\t\t? Array.from(initials.trim().toLocaleUpperCase(\"en-US\")).slice(0, 2).join(\"\")\n\t\t\t\t\t: avatarInitials(name)}\n\t\t\t</AvatarFallback>\n\t\t</Avatar>\n\t);\n}\n"],"mappings":";;;;;;;;AAiBA,IAAaE,IAASF,EAAM,YAC1B,EAAE,cAAW,GAAGG,KAAS,MACzB,kBAACF,EAAgB,MAAjB;CACM;CACL,WAAWG,EACV,oFACAC,CACD;CACA,GAAIF;AACJ,CAAA,CAEH;AACA,EAAO,cAAcF,EAAgB,KAAK;AA2B1C,IAAaK,IAAcN,EAAM,YAG9B,EAAE,cAAW,GAAGG,KAAS,MAC3B,kBAACF,EAAgB,OAAjB;CACM;CACL,WAAWG,EAAG,+BAA+BC,CAAS;CACtD,GAAIF;AACJ,CAAA,CACD;AACD,EAAY,cAAcF,EAAgB,MAAM;AAkBhD,IAAaM,IAAiBP,EAAM,YAGjC,EAAE,cAAW,GAAGG,KAAS,MAC3B,kBAACF,EAAgB,UAAjB;CACM;CACL,WAAWG,EACV,qGACAC,CACD;CACA,GAAIF;AACJ,CAAA,CACD;AACD,EAAe,cAAcF,EAAgB,SAAS;AAEtD,IAAMO,IAAe;CACpBC,EAAW,KAAK;CAChBA,EAAW,MAAM;CACjBA,EAAW,KAAK;CAChBA,EAAW,KAAK;CAChBA,EAAW,OAAO;CAClBA,EAAW,QAAQ;AACpB;AAcA,SAAgBC,EAAe,EAC9B,SACA,aACA,aACA,UAAO,WACP,gBACuB;CACvB,OACC,kBAACR,GAAD;EACC,MAAK;EACL,cAAYS;EACZ,WAAWP,EAAGQ,MAAS,QAAQ,iBAAiBP,CAAS;EAEzD,UAAA,kBAACE,GAAD;GACC,WAAWH,EACV,eACAQ,MAAS,OAAO,mBAAmB,kBACnCJ,EAAaK,EAAiBC,KAAYH,CAAI,EAC/C;GAEC,UAAAI,GAAU,KAAK,IACb,MAAM,KAAKA,EAAS,KAAK,CAAC,CAAC,kBAAkB,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAC1EC,EAAeL,CAAI;EACP,CAAA;CACT,CAAA;AAEV"}
1
+ {"version":3,"file":"avatar.js","names":["React","AvatarPrimitive","Avatar","props","cn","className","AvatarImage","AvatarFallback","AVATAR_TONES","TAG_COLORS","AvatarInitials","name","size","avatarColorIndex","colorKey","initials","avatarInitials"],"sources":["../../src/components/avatar.tsx"],"sourcesContent":["import * as AvatarPrimitive from \"@radix-ui/react-avatar\";\nimport * as React from \"react\";\nimport { avatarColorIndex, avatarInitials } from \"../models/avatar\";\nimport { cn } from \"../utils/cn\";\nimport { TAG_COLORS } from \"./tag-badge\";\n\nexport type AvatarProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,\n\t\"asChild\"\n> & {\n\t/**\n\t * Change the default rendered element for the one passed as a child, merging their props and behavior.\n\t * @default false\n\t */\n\tasChild?: boolean;\n};\n\nexport const Avatar = React.forwardRef<React.ElementRef<typeof AvatarPrimitive.Root>, AvatarProps>(\n\t({ className, ...props }, ref) => (\n\t\t<AvatarPrimitive.Root\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"relative flex h-basalt-9 w-basalt-9 shrink-0 overflow-hidden rounded-basalt-full\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t),\n);\nAvatar.displayName = AvatarPrimitive.Root.displayName;\n\nexport type AvatarImageProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>,\n\t\"asChild\" | \"onLoadingStatusChange\" | \"src\" | \"alt\"\n> & {\n\t/**\n\t * Change the default rendered element for the one passed as a child, merging their props and behavior.\n\t * @default false\n\t */\n\tasChild?: boolean;\n\t/**\n\t * Image source URL for the avatar image.\n\t */\n\tsrc?: React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>[\"src\"];\n\t/**\n\t * Text description of the image for accessibility and screen readers.\n\t */\n\talt?: React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>[\"alt\"];\n\t/**\n\t * A callback providing the current loading status of the image ('idle' | 'loading' | 'loaded' | 'error').\n\t */\n\tonLoadingStatusChange?: React.ComponentPropsWithoutRef<\n\t\ttypeof AvatarPrimitive.Image\n\t>[\"onLoadingStatusChange\"];\n};\n\nexport const AvatarImage = React.forwardRef<\n\tReact.ElementRef<typeof AvatarPrimitive.Image>,\n\tAvatarImageProps\n>(({ className, ...props }, ref) => (\n\t<AvatarPrimitive.Image\n\t\tref={ref}\n\t\tclassName={cn(\"aspect-square h-full w-full\", className)}\n\t\t{...props}\n\t/>\n));\nAvatarImage.displayName = AvatarPrimitive.Image.displayName;\n\nexport type AvatarFallbackProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>,\n\t\"asChild\" | \"delayMs\"\n> & {\n\t/**\n\t * Change the default rendered element for the one passed as a child, merging their props and behavior.\n\t * @default false\n\t */\n\tasChild?: boolean;\n\t/**\n\t * Useful for delaying rendering so it only appears for those with slower connections.\n\t * Unset by default, rendering immediately without delay.\n\t */\n\tdelayMs?: number;\n};\n\nexport const AvatarFallback = React.forwardRef<\n\tReact.ElementRef<typeof AvatarPrimitive.Fallback>,\n\tAvatarFallbackProps\n>(({ className, ...props }, ref) => (\n\t<AvatarPrimitive.Fallback\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex h-full w-full items-center justify-center rounded-basalt-full bg-basalt-muted text-basalt-sm\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nAvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;\n\nconst AVATAR_TONES = [\n\tTAG_COLORS.blue.className,\n\tTAG_COLORS.amber.className,\n\tTAG_COLORS.rose.className,\n\tTAG_COLORS.teal.className,\n\tTAG_COLORS.violet.className,\n\tTAG_COLORS.success.className,\n] as const;\n\nexport interface AvatarInitialsProps {\n\t/** Person or organization name; initials are derived from its first two words. */\n\tname: string;\n\t/** Stable color identity, independent of display name changes. */\n\tcolorKey?: string;\n\t/** Two-letter override for application-specific abbreviations. */\n\tinitials?: string;\n\t/** Avatar diameter. @default \"default\" */\n\tsize?: \"sm\" | \"default\";\n\tclassName?: string;\n}\n\nexport function AvatarInitials({\n\tname,\n\tcolorKey,\n\tinitials,\n\tsize = \"default\",\n\tclassName,\n}: AvatarInitialsProps) {\n\treturn (\n\t\t<Avatar\n\t\t\trole=\"img\"\n\t\t\taria-label={name}\n\t\t\tclassName={cn(size === \"sm\" && \"size-basalt-6\", className)}\n\t\t>\n\t\t\t<AvatarFallback\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"font-medium text-basalt-sm\",\n\t\t\t\t\tAVATAR_TONES[avatarColorIndex(colorKey ?? name)],\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{initials?.trim()\n\t\t\t\t\t? Array.from(initials.trim().toLocaleUpperCase(\"en-US\")).slice(0, 2).join(\"\")\n\t\t\t\t\t: avatarInitials(name)}\n\t\t\t</AvatarFallback>\n\t\t</Avatar>\n\t);\n}\n"],"mappings":";;;;;;;;AAiBA,IAAaE,IAASF,EAAM,YAC1B,EAAE,cAAW,GAAGG,KAAS,MACzB,kBAACF,EAAgB,MAAjB;CACM;CACL,WAAWG,EACV,oFACAC,CACD;CACA,GAAIF;AACJ,CAAA,CAEH;AACA,EAAO,cAAcF,EAAgB,KAAK;AA2B1C,IAAaK,IAAcN,EAAM,YAG9B,EAAE,cAAW,GAAGG,KAAS,MAC3B,kBAACF,EAAgB,OAAjB;CACM;CACL,WAAWG,EAAG,+BAA+BC,CAAS;CACtD,GAAIF;AACJ,CAAA,CACD;AACD,EAAY,cAAcF,EAAgB,MAAM;AAkBhD,IAAaM,IAAiBP,EAAM,YAGjC,EAAE,cAAW,GAAGG,KAAS,MAC3B,kBAACF,EAAgB,UAAjB;CACM;CACL,WAAWG,EACV,qGACAC,CACD;CACA,GAAIF;AACJ,CAAA,CACD;AACD,EAAe,cAAcF,EAAgB,SAAS;AAEtD,IAAMO,IAAe;CACpBC,EAAW,KAAK;CAChBA,EAAW,MAAM;CACjBA,EAAW,KAAK;CAChBA,EAAW,KAAK;CAChBA,EAAW,OAAO;CAClBA,EAAW,QAAQ;AACpB;AAcA,SAAgBC,EAAe,EAC9B,SACA,aACA,aACA,UAAO,WACP,gBACuB;CACvB,OACC,kBAACR,GAAD;EACC,MAAK;EACL,cAAYS;EACZ,WAAWP,EAAGQ,MAAS,QAAQ,iBAAiBP,CAAS;EAEzD,UAAA,kBAACE,GAAD;GACC,WAAWH,EACV,8BACAI,EAAaK,EAAiBC,KAAYH,CAAI,EAC/C;GAEC,UAAAI,GAAU,KAAK,IACb,MAAM,KAAKA,EAAS,KAAK,CAAC,CAAC,kBAAkB,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAC1EC,EAAeL,CAAI;EACP,CAAA;CACT,CAAA;AAEV"}
@@ -5,7 +5,7 @@ import { jsx as n, jsxs as r } from "react/jsx-runtime";
5
5
  //#region src/components/chat-bubble.tsx
6
6
  function i({ variant: i = "assistant", streaming: a = !1, className: o, children: s }) {
7
7
  if (i === "system") return /* @__PURE__ */ n("p", {
8
- className: e(t, "px-basalt-space-sm text-center text-basalt-xs text-basalt-muted-foreground", o),
8
+ className: e(t, "px-basalt-space-sm text-center text-basalt-sm text-basalt-muted-foreground", o),
9
9
  children: s
10
10
  });
11
11
  let c = i === "user";
@@ -1 +1 @@
1
- {"version":3,"file":"chat-bubble.js","names":["ChatBubble","variant","cn","BASALT_UI_CLASS","className","user","children","streaming"],"sources":["../../src/components/chat-bubble.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport type ChatBubbleVariant = \"assistant\" | \"system\" | \"user\";\n\nexport interface ChatBubbleProps {\n\t/**\n\t * Alignment and fill.\n\t * @default \"assistant\"\n\t */\n\tvariant?: ChatBubbleVariant;\n\t/**\n\t * Show a streaming caret after the body.\n\t * @default false\n\t */\n\tstreaming?: boolean;\n\t/**\n\t * Optional class name applied to the message bubble.\n\t * Component only accepts variant, streaming, className, and children without native HTML rest forwarding or forwarded ref.\n\t */\n\tclassName?: string;\n\t/**\n\t * Message content.\n\t */\n\tchildren: ReactNode;\n}\n\nexport function ChatBubble({\n\tvariant = \"assistant\",\n\tstreaming = false,\n\tclassName,\n\tchildren,\n}: ChatBubbleProps) {\n\tif (variant === \"system\") {\n\t\treturn (\n\t\t\t<p\n\t\t\t\tclassName={cn(\n\t\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\t\"px-basalt-space-sm text-center text-basalt-xs text-basalt-muted-foreground\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</p>\n\t\t);\n\t}\n\tconst user = variant === \"user\";\n\treturn (\n\t\t<div className={cn(BASALT_UI_CLASS, \"flex w-full\", user ? \"justify-end\" : \"justify-start\")}>\n\t\t\t<div\n\t\t\t\tdata-basalt-surface={user ? undefined : \"\"}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"max-w-[92%] px-basalt-panel-x py-basalt-panel-y text-basalt-base leading-[var(--basalt-line-body)] shadow-sm\",\n\t\t\t\t\tuser\n\t\t\t\t\t\t? \"rounded-basalt-lg rounded-br-basalt-md bg-basalt-primary text-basalt-primary-foreground\"\n\t\t\t\t\t\t: \"rounded-basalt-lg rounded-bl-basalt-md text-basalt-foreground ring-1 ring-basalt-border/50\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t{streaming ? (\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName=\"mt-basalt-space-sm inline-block h-basalt-3 w-basalt-1_5 animate-pulse rounded-basalt-sm bg-basalt-primary/70 align-middle motion-reduce:animate-none\"\n\t\t\t\t\t\taria-hidden\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;AA4BA,SAAgBA,EAAW,EAC1B,aAAU,aACV,eAAY,IACZ,cACA,eACmB;CACnB,IAAIC,MAAY,UACf,OACC,kBAAC,KAAD;EACC,WAAWC,EACVC,GACA,8EACAC,CACD;EAEC;CACC,CAAA;CAGL,IAAMC,IAAOJ,MAAY;CACzB,OACC,kBAAC,OAAD;EAAK,WAAWC,EAAGC,GAAiB,eAAeE,IAAO,gBAAgB,eAAe;EACxF,UAAA,kBAAC,OAAD;GACC,uBAAqBA,IAAO,KAAA,IAAY;GACxC,WAAWH,EACV,gHACAG,IACG,4FACA,8FACHD,CACD;GARD,UAAA,CAUEE,GACAC,IACA,kBAAC,QAAD;IACC,WAAU;IACV,eAAA;GACA,CAAA,IACE,IACA;;CACD,CAAA;AAEP"}
1
+ {"version":3,"file":"chat-bubble.js","names":["ChatBubble","variant","cn","BASALT_UI_CLASS","className","user","children","streaming"],"sources":["../../src/components/chat-bubble.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport type ChatBubbleVariant = \"assistant\" | \"system\" | \"user\";\n\nexport interface ChatBubbleProps {\n\t/**\n\t * Alignment and fill.\n\t * @default \"assistant\"\n\t */\n\tvariant?: ChatBubbleVariant;\n\t/**\n\t * Show a streaming caret after the body.\n\t * @default false\n\t */\n\tstreaming?: boolean;\n\t/**\n\t * Optional class name applied to the message bubble.\n\t * Component only accepts variant, streaming, className, and children without native HTML rest forwarding or forwarded ref.\n\t */\n\tclassName?: string;\n\t/**\n\t * Message content.\n\t */\n\tchildren: ReactNode;\n}\n\nexport function ChatBubble({\n\tvariant = \"assistant\",\n\tstreaming = false,\n\tclassName,\n\tchildren,\n}: ChatBubbleProps) {\n\tif (variant === \"system\") {\n\t\treturn (\n\t\t\t<p\n\t\t\t\tclassName={cn(\n\t\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\t\"px-basalt-space-sm text-center text-basalt-sm text-basalt-muted-foreground\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</p>\n\t\t);\n\t}\n\tconst user = variant === \"user\";\n\treturn (\n\t\t<div className={cn(BASALT_UI_CLASS, \"flex w-full\", user ? \"justify-end\" : \"justify-start\")}>\n\t\t\t<div\n\t\t\t\tdata-basalt-surface={user ? undefined : \"\"}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"max-w-[92%] px-basalt-panel-x py-basalt-panel-y text-basalt-base leading-[var(--basalt-line-body)] shadow-sm\",\n\t\t\t\t\tuser\n\t\t\t\t\t\t? \"rounded-basalt-lg rounded-br-basalt-md bg-basalt-primary text-basalt-primary-foreground\"\n\t\t\t\t\t\t: \"rounded-basalt-lg rounded-bl-basalt-md text-basalt-foreground ring-1 ring-basalt-border/50\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t{streaming ? (\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName=\"mt-basalt-space-sm inline-block h-basalt-3 w-basalt-1_5 animate-pulse rounded-basalt-sm bg-basalt-primary/70 align-middle motion-reduce:animate-none\"\n\t\t\t\t\t\taria-hidden\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;AA4BA,SAAgBA,EAAW,EAC1B,aAAU,aACV,eAAY,IACZ,cACA,eACmB;CACnB,IAAIC,MAAY,UACf,OACC,kBAAC,KAAD;EACC,WAAWC,EACVC,GACA,8EACAC,CACD;EAEC;CACC,CAAA;CAGL,IAAMC,IAAOJ,MAAY;CACzB,OACC,kBAAC,OAAD;EAAK,WAAWC,EAAGC,GAAiB,eAAeE,IAAO,gBAAgB,eAAe;EACxF,UAAA,kBAAC,OAAD;GACC,uBAAqBA,IAAO,KAAA,IAAY;GACxC,WAAWH,EACV,gHACAG,IACG,4FACA,8FACHD,CACD;GARD,UAAA,CAUEE,GACAC,IACA,kBAAC,QAAD;IACC,WAAU;IACV,eAAA;GACA,CAAA,IACE,IACA;;CACD,CAAA;AAEP"}
@@ -25,7 +25,7 @@ function p({ disabled: p = !1, streaming: m = !1, label: h = "Message", placehol
25
25
  e.preventDefault(), F();
26
26
  },
27
27
  children: [/* @__PURE__ */ f("div", {
28
- className: "rounded-basalt-lg bg-basalt-control p-basalt-space-lg ring-1 ring-basalt-border focus-within:ring-basalt-ring",
28
+ className: "basalt-focus-group rounded-basalt-lg bg-basalt-control p-basalt-space-lg ring-1 ring-basalt-border",
29
29
  children: [
30
30
  E.length > 0 && /* @__PURE__ */ d("ul", {
31
31
  "aria-label": "Attachments",
@@ -1 +1 @@
1
- {"version":3,"file":"chat-composer.js","names":["_Fragment","Fragment$1","ChatComposer","vm","useChatComposer","attachments","ref","useRef","fileInput","errorId","useId","composingRef","submit","cn","className","event","Paperclip","file","onRemoveAttachment","Button","disabled","streaming","X","InputArea","label","onFilesSelect","toolbar","onCancel","cancelLabel","Square","sendLabel","ArrowUp"],"sources":["../../src/components/chat-composer.tsx"],"sourcesContent":["import { ArrowUp, Paperclip, Square, X } from \"lucide-react\";\nimport { type FormEvent, type KeyboardEvent, type ReactNode, useId, useRef } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { useChatComposer } from \"../viewmodels/use-chat-composer\";\nimport { Button } from \"./button\";\nimport { InputArea } from \"./input-area\";\n\nexport interface ChatComposerProps {\n\t/** Controlled draft; keep one draft per conversation in the application. */\n\tvalue?: string;\n\t/** Initial draft when uncontrolled. */\n\tdefaultValue?: string;\n\tonValueChange?: (value: string) => void;\n\t/** Model, tool and context controls arranged before Send. */\n\ttoolbar?: ReactNode;\n\t/** Caller-owned attachments; this component never uploads files. */\n\tattachments?: readonly ChatComposerAttachment[];\n\tonRemoveAttachment?: (id: string) => void;\n\t/** Local file selection callback. File validation/upload belong to the application. */\n\tonFilesSelect?: (files: File[]) => void;\n\taccept?: string;\n\t/**\n\t * Disable the field and send.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n\t/**\n\t * Replace send with stop. When streaming is true, the stop button renders and triggers onCancel.\n\t * @default false\n\t */\n\tstreaming?: boolean;\n\t/**\n\t * Field accessible name.\n\t * @default \"Message\"\n\t */\n\tlabel?: string;\n\t/**\n\t * Placeholder when empty.\n\t */\n\tplaceholder?: string;\n\t/**\n\t * Called with trimmed text. Async failure preserves draft and attachments for retry.\n\t */\n\tonSend: (text: string) => void | Promise<void>;\n\t/**\n\t * Called when the stop control is pressed while streaming is active.\n\t */\n\tonCancel?: () => void;\n\t/**\n\t * Send control accessible name.\n\t * @default \"Send message\"\n\t */\n\tsendLabel?: string;\n\t/**\n\t * Stop control accessible name.\n\t * @default \"Stop generating\"\n\t */\n\tcancelLabel?: string;\n\t/**\n\t * Optional class name applied to the form container.\n\t * Component manages internal draft/height state and does not forward native form rest attributes or ref.\n\t */\n\tclassName?: string;\n}\n\nexport type ChatComposerAttachment = { id: string; name: string };\n\nexport function ChatComposer({\n\tdisabled = false,\n\tstreaming = false,\n\tlabel = \"Message\",\n\tplaceholder,\n\tonSend,\n\tonCancel,\n\tsendLabel = \"Send message\",\n\tcancelLabel = \"Stop generating\",\n\tclassName,\n\tvalue,\n\tdefaultValue,\n\tonValueChange,\n\ttoolbar,\n\tattachments = [],\n\tonRemoveAttachment,\n\tonFilesSelect,\n\taccept,\n}: ChatComposerProps) {\n\tconst vm = useChatComposer({\n\t\tvalue,\n\t\tdefaultValue,\n\t\tonValueChange,\n\t\tonSend,\n\t\tdisabled,\n\t\tstreaming,\n\t\thasAttachments: attachments.length > 0,\n\t});\n\tconst ref = useRef<HTMLTextAreaElement>(null);\n\tconst fileInput = useRef<HTMLInputElement>(null);\n\tconst errorId = useId();\n\tconst composingRef = useRef(false);\n\tconst submit = async () => {\n\t\tif (await vm.send()) ref.current?.focus();\n\t};\n\n\tconst onSubmit = (event: FormEvent) => {\n\t\tevent.preventDefault();\n\t\tvoid submit();\n\t};\n\n\tconst onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n\t\tif (composingRef.current || event.nativeEvent.isComposing || event.keyCode === 229) {\n\t\t\treturn;\n\t\t}\n\t\tif (event.key !== \"Enter\" || event.shiftKey) {\n\t\t\treturn;\n\t\t}\n\t\tevent.preventDefault();\n\t\tvoid submit();\n\t};\n\n\treturn (\n\t\t<form className={cn(\"basalt-ui shrink-0\", className)} onSubmit={onSubmit}>\n\t\t\t<div className=\"rounded-basalt-lg bg-basalt-control p-basalt-space-lg ring-1 ring-basalt-border focus-within:ring-basalt-ring\">\n\t\t\t\t{attachments.length > 0 && (\n\t\t\t\t\t<ul\n\t\t\t\t\t\taria-label=\"Attachments\"\n\t\t\t\t\t\tclassName=\"mb-basalt-space-lg flex flex-wrap gap-basalt-space-md\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{attachments.map((file) => (\n\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\tkey={file.id}\n\t\t\t\t\t\t\t\tclassName=\"flex min-w-0 max-w-full items-center gap-basalt-space-sm rounded-basalt-md bg-basalt-secondary py-basalt-space-sm pl-basalt-space-lg pr-basalt-space-sm text-basalt-sm\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Paperclip aria-hidden=\"true\" className=\"size-basalt-icon shrink-0\" />\n\t\t\t\t\t\t\t\t<span className=\"truncate\">{file.name}</span>\n\t\t\t\t\t\t\t\t{onRemoveAttachment && (\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\t\tdisabled={disabled || vm.pending || streaming}\n\t\t\t\t\t\t\t\t\t\tclassName=\"size-basalt-5\"\n\t\t\t\t\t\t\t\t\t\taria-label={`Remove ${file.name}`}\n\t\t\t\t\t\t\t\t\t\tonClick={() => onRemoveAttachment(file.id)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<X />\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t)}\n\t\t\t\t<InputArea\n\t\t\t\t\tref={ref}\n\t\t\t\t\tvalue={vm.value}\n\t\t\t\t\tonChange={(event) => vm.update(event.target.value)}\n\t\t\t\t\tonCompositionStart={() => {\n\t\t\t\t\t\tcomposingRef.current = true;\n\t\t\t\t\t}}\n\t\t\t\t\tonCompositionEnd={() => {\n\t\t\t\t\t\tcomposingRef.current = false;\n\t\t\t\t\t}}\n\t\t\t\t\tonKeyDown={onKeyDown}\n\t\t\t\t\trows={1}\n\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\tdisabled={disabled || vm.pending}\n\t\t\t\t\taria-label={label}\n\t\t\t\t\taria-describedby={vm.error ? errorId : undefined}\n\t\t\t\t\taria-description=\"Enter to send, Shift+Enter for a new line\"\n\t\t\t\t\tclassName=\"basalt-chat-input min-h-[calc(1lh+var(--basalt-space-2))] resize-none overflow-y-auto border-0 bg-transparent px-basalt-space-sm py-basalt-space-sm text-basalt-base leading-[var(--basalt-line-body)] shadow-none ring-0 outline-none\"\n\t\t\t\t/>\n\t\t\t\t<div className=\"mt-basalt-content-gap flex items-center justify-between gap-basalt-content-gap\">\n\t\t\t\t\t<div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-basalt-space-sm\">\n\t\t\t\t\t\t{onFilesSelect && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\tref={fileInput}\n\t\t\t\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\t\taccept={accept}\n\t\t\t\t\t\t\t\t\thidden\n\t\t\t\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\t\t\t\tonFilesSelect(Array.from(event.target.files ?? []));\n\t\t\t\t\t\t\t\t\t\tevent.target.value = \"\";\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\taria-label=\"Attach files\"\n\t\t\t\t\t\t\t\t\tdisabled={disabled || vm.pending || streaming}\n\t\t\t\t\t\t\t\t\tonClick={() => fileInput.current?.click()}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Paperclip />\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<fieldset disabled={disabled || streaming || vm.pending} className=\"contents\">\n\t\t\t\t\t\t\t{toolbar}\n\t\t\t\t\t\t</fieldset>\n\t\t\t\t\t</div>\n\t\t\t\t\t{streaming ? (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\tonClick={onCancel}\n\t\t\t\t\t\t\tdisabled={disabled || !onCancel}\n\t\t\t\t\t\t\taria-label={cancelLabel}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Square className=\"h-basalt-3_5 w-basalt-3_5 fill-current\" strokeWidth={0} />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\tdisabled={!vm.canSend}\n\t\t\t\t\t\t\tloading={vm.pending}\n\t\t\t\t\t\t\taria-label={sendLabel}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<ArrowUp className=\"h-basalt-4 w-basalt-4\" strokeWidth={2.25} />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t{vm.error && (\n\t\t\t\t<p\n\t\t\t\t\tid={errorId}\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tclassName=\"mt-basalt-content-gap text-basalt-sm text-basalt-danger\"\n\t\t\t\t>\n\t\t\t\t\t{vm.error}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t</form>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat-composer.js","names":["_Fragment","Fragment$1","ChatComposer","vm","useChatComposer","attachments","ref","useRef","fileInput","errorId","useId","composingRef","submit","cn","className","event","Paperclip","file","onRemoveAttachment","Button","disabled","streaming","X","InputArea","label","onFilesSelect","toolbar","onCancel","cancelLabel","Square","sendLabel","ArrowUp"],"sources":["../../src/components/chat-composer.tsx"],"sourcesContent":["import { ArrowUp, Paperclip, Square, X } from \"lucide-react\";\nimport { type FormEvent, type KeyboardEvent, type ReactNode, useId, useRef } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { useChatComposer } from \"../viewmodels/use-chat-composer\";\nimport { Button } from \"./button\";\nimport { InputArea } from \"./input-area\";\n\nexport interface ChatComposerProps {\n\t/** Controlled draft; keep one draft per conversation in the application. */\n\tvalue?: string;\n\t/** Initial draft when uncontrolled. */\n\tdefaultValue?: string;\n\tonValueChange?: (value: string) => void;\n\t/** Model, tool and context controls arranged before Send. */\n\ttoolbar?: ReactNode;\n\t/** Caller-owned attachments; this component never uploads files. */\n\tattachments?: readonly ChatComposerAttachment[];\n\tonRemoveAttachment?: (id: string) => void;\n\t/** Local file selection callback. File validation/upload belong to the application. */\n\tonFilesSelect?: (files: File[]) => void;\n\taccept?: string;\n\t/**\n\t * Disable the field and send.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n\t/**\n\t * Replace send with stop. When streaming is true, the stop button renders and triggers onCancel.\n\t * @default false\n\t */\n\tstreaming?: boolean;\n\t/**\n\t * Field accessible name.\n\t * @default \"Message\"\n\t */\n\tlabel?: string;\n\t/**\n\t * Placeholder when empty.\n\t */\n\tplaceholder?: string;\n\t/**\n\t * Called with trimmed text. Async failure preserves draft and attachments for retry.\n\t */\n\tonSend: (text: string) => void | Promise<void>;\n\t/**\n\t * Called when the stop control is pressed while streaming is active.\n\t */\n\tonCancel?: () => void;\n\t/**\n\t * Send control accessible name.\n\t * @default \"Send message\"\n\t */\n\tsendLabel?: string;\n\t/**\n\t * Stop control accessible name.\n\t * @default \"Stop generating\"\n\t */\n\tcancelLabel?: string;\n\t/**\n\t * Optional class name applied to the form container.\n\t * Component manages internal draft/height state and does not forward native form rest attributes or ref.\n\t */\n\tclassName?: string;\n}\n\nexport type ChatComposerAttachment = { id: string; name: string };\n\nexport function ChatComposer({\n\tdisabled = false,\n\tstreaming = false,\n\tlabel = \"Message\",\n\tplaceholder,\n\tonSend,\n\tonCancel,\n\tsendLabel = \"Send message\",\n\tcancelLabel = \"Stop generating\",\n\tclassName,\n\tvalue,\n\tdefaultValue,\n\tonValueChange,\n\ttoolbar,\n\tattachments = [],\n\tonRemoveAttachment,\n\tonFilesSelect,\n\taccept,\n}: ChatComposerProps) {\n\tconst vm = useChatComposer({\n\t\tvalue,\n\t\tdefaultValue,\n\t\tonValueChange,\n\t\tonSend,\n\t\tdisabled,\n\t\tstreaming,\n\t\thasAttachments: attachments.length > 0,\n\t});\n\tconst ref = useRef<HTMLTextAreaElement>(null);\n\tconst fileInput = useRef<HTMLInputElement>(null);\n\tconst errorId = useId();\n\tconst composingRef = useRef(false);\n\tconst submit = async () => {\n\t\tif (await vm.send()) ref.current?.focus();\n\t};\n\n\tconst onSubmit = (event: FormEvent) => {\n\t\tevent.preventDefault();\n\t\tvoid submit();\n\t};\n\n\tconst onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n\t\tif (composingRef.current || event.nativeEvent.isComposing || event.keyCode === 229) {\n\t\t\treturn;\n\t\t}\n\t\tif (event.key !== \"Enter\" || event.shiftKey) {\n\t\t\treturn;\n\t\t}\n\t\tevent.preventDefault();\n\t\tvoid submit();\n\t};\n\n\treturn (\n\t\t<form className={cn(\"basalt-ui shrink-0\", className)} onSubmit={onSubmit}>\n\t\t\t<div className=\"basalt-focus-group rounded-basalt-lg bg-basalt-control p-basalt-space-lg ring-1 ring-basalt-border\">\n\t\t\t\t{attachments.length > 0 && (\n\t\t\t\t\t<ul\n\t\t\t\t\t\taria-label=\"Attachments\"\n\t\t\t\t\t\tclassName=\"mb-basalt-space-lg flex flex-wrap gap-basalt-space-md\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{attachments.map((file) => (\n\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\tkey={file.id}\n\t\t\t\t\t\t\t\tclassName=\"flex min-w-0 max-w-full items-center gap-basalt-space-sm rounded-basalt-md bg-basalt-secondary py-basalt-space-sm pl-basalt-space-lg pr-basalt-space-sm text-basalt-sm\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Paperclip aria-hidden=\"true\" className=\"size-basalt-icon shrink-0\" />\n\t\t\t\t\t\t\t\t<span className=\"truncate\">{file.name}</span>\n\t\t\t\t\t\t\t\t{onRemoveAttachment && (\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\t\tdisabled={disabled || vm.pending || streaming}\n\t\t\t\t\t\t\t\t\t\tclassName=\"size-basalt-5\"\n\t\t\t\t\t\t\t\t\t\taria-label={`Remove ${file.name}`}\n\t\t\t\t\t\t\t\t\t\tonClick={() => onRemoveAttachment(file.id)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<X />\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t)}\n\t\t\t\t<InputArea\n\t\t\t\t\tref={ref}\n\t\t\t\t\tvalue={vm.value}\n\t\t\t\t\tonChange={(event) => vm.update(event.target.value)}\n\t\t\t\t\tonCompositionStart={() => {\n\t\t\t\t\t\tcomposingRef.current = true;\n\t\t\t\t\t}}\n\t\t\t\t\tonCompositionEnd={() => {\n\t\t\t\t\t\tcomposingRef.current = false;\n\t\t\t\t\t}}\n\t\t\t\t\tonKeyDown={onKeyDown}\n\t\t\t\t\trows={1}\n\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\tdisabled={disabled || vm.pending}\n\t\t\t\t\taria-label={label}\n\t\t\t\t\taria-describedby={vm.error ? errorId : undefined}\n\t\t\t\t\taria-description=\"Enter to send, Shift+Enter for a new line\"\n\t\t\t\t\tclassName=\"basalt-chat-input min-h-[calc(1lh+var(--basalt-space-2))] resize-none overflow-y-auto border-0 bg-transparent px-basalt-space-sm py-basalt-space-sm text-basalt-base leading-[var(--basalt-line-body)] shadow-none ring-0 outline-none\"\n\t\t\t\t/>\n\t\t\t\t<div className=\"mt-basalt-content-gap flex items-center justify-between gap-basalt-content-gap\">\n\t\t\t\t\t<div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-basalt-space-sm\">\n\t\t\t\t\t\t{onFilesSelect && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\tref={fileInput}\n\t\t\t\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\t\taccept={accept}\n\t\t\t\t\t\t\t\t\thidden\n\t\t\t\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\t\t\t\tonFilesSelect(Array.from(event.target.files ?? []));\n\t\t\t\t\t\t\t\t\t\tevent.target.value = \"\";\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\taria-label=\"Attach files\"\n\t\t\t\t\t\t\t\t\tdisabled={disabled || vm.pending || streaming}\n\t\t\t\t\t\t\t\t\tonClick={() => fileInput.current?.click()}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Paperclip />\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<fieldset disabled={disabled || streaming || vm.pending} className=\"contents\">\n\t\t\t\t\t\t\t{toolbar}\n\t\t\t\t\t\t</fieldset>\n\t\t\t\t\t</div>\n\t\t\t\t\t{streaming ? (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\tonClick={onCancel}\n\t\t\t\t\t\t\tdisabled={disabled || !onCancel}\n\t\t\t\t\t\t\taria-label={cancelLabel}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Square className=\"h-basalt-3_5 w-basalt-3_5 fill-current\" strokeWidth={0} />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\tdisabled={!vm.canSend}\n\t\t\t\t\t\t\tloading={vm.pending}\n\t\t\t\t\t\t\taria-label={sendLabel}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<ArrowUp className=\"h-basalt-4 w-basalt-4\" strokeWidth={2.25} />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t{vm.error && (\n\t\t\t\t<p\n\t\t\t\t\tid={errorId}\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tclassName=\"mt-basalt-content-gap text-basalt-sm text-basalt-danger\"\n\t\t\t\t>\n\t\t\t\t\t{vm.error}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t</form>\n\t);\n}\n"],"mappings":"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"}
@@ -18,7 +18,7 @@ function i({ title: i, subtitle: a, leading: o, children: s, className: c, ...l
18
18
  className: "truncate text-basalt-base font-semibold tracking-tight",
19
19
  children: i
20
20
  }), a ? /* @__PURE__ */ n("p", {
21
- className: "truncate text-basalt-xs text-basalt-muted-foreground",
21
+ className: "truncate text-basalt-sm text-basalt-muted-foreground",
22
22
  children: a
23
23
  }) : null]
24
24
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"chat-header.js","names":["ChatHeader","props","cn","BASALT_UI_CLASS","className","leading","title","subtitle","children"],"sources":["../../src/components/chat-header.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport interface ChatHeaderProps\n\textends Omit<HTMLAttributes<HTMLElement>, \"title\" | \"children\" | \"className\"> {\n\t/**\n\t * Conversation title.\n\t */\n\ttitle: ReactNode;\n\t/**\n\t * Secondary line under the title.\n\t */\n\tsubtitle?: ReactNode;\n\t/**\n\t * Leading mark, usually an icon.\n\t */\n\tleading?: ReactNode;\n\t/**\n\t * Trailing actions.\n\t */\n\tchildren?: ReactNode;\n\t/**\n\t * Optional class name applied to the header element.\n\t * Component inherits native header HTMLAttributes on the root element but does not forward ref.\n\t */\n\tclassName?: string;\n}\n\nexport function ChatHeader({\n\ttitle,\n\tsubtitle,\n\tleading,\n\tchildren,\n\tclassName,\n\t...props\n}: ChatHeaderProps) {\n\treturn (\n\t\t<header\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"flex items-center justify-between gap-basalt-content-gap border-b border-basalt-border/50 px-basalt-panel-x py-basalt-panel-y leading-[var(--basalt-line-body)]\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"flex min-w-0 items-center gap-basalt-content-gap\">\n\t\t\t\t{leading ? (\n\t\t\t\t\t<span className=\"flex h-basalt-8 w-basalt-8 items-center justify-center\">{leading}</span>\n\t\t\t\t) : null}\n\t\t\t\t<div className=\"min-w-0\">\n\t\t\t\t\t<p className=\"truncate text-basalt-base font-semibold tracking-tight\">{title}</p>\n\t\t\t\t\t{subtitle ? (\n\t\t\t\t\t\t<p className=\"truncate text-basalt-xs text-basalt-muted-foreground\">{subtitle}</p>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t{children ? <div className=\"flex items-center gap-basalt-space-sm\">{children}</div> : null}\n\t\t</header>\n\t);\n}\n"],"mappings":";;;;;AA6BA,SAAgBA,EAAW,EAC1B,UACA,aACA,YACA,aACA,cACA,GAAGC,KACgB;CACnB,OACC,kBAAC,UAAD;EACC,WAAWC,EACVC,GACA,mKACAC,CACD;EACA,GAAIH;EANL,UAAA,CAQC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACEI,IACA,kBAAC,QAAD;IAAM,WAAU;IAA0D,UAAAA;GAAc,CAAA,IACrF,MACJ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACC,kBAAC,KAAD;KAAG,WAAU;KAA0D,UAAAC;IAAS,CAAA,GAC/EC,IACA,kBAAC,KAAD;KAAG,WAAU;KAAwD,UAAAA;IAAY,CAAA,IAC9E,IACA;GACD,CAAA,CAAA;EACJ,CAAA,GAAAC,IAAW,kBAAC,OAAD;GAAK,WAAU;GAAyC;EAAc,CAAA,IAAI,IAC/E;;AAEV"}
1
+ {"version":3,"file":"chat-header.js","names":["ChatHeader","props","cn","BASALT_UI_CLASS","className","leading","title","subtitle","children"],"sources":["../../src/components/chat-header.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport interface ChatHeaderProps\n\textends Omit<HTMLAttributes<HTMLElement>, \"title\" | \"children\" | \"className\"> {\n\t/**\n\t * Conversation title.\n\t */\n\ttitle: ReactNode;\n\t/**\n\t * Secondary line under the title.\n\t */\n\tsubtitle?: ReactNode;\n\t/**\n\t * Leading mark, usually an icon.\n\t */\n\tleading?: ReactNode;\n\t/**\n\t * Trailing actions.\n\t */\n\tchildren?: ReactNode;\n\t/**\n\t * Optional class name applied to the header element.\n\t * Component inherits native header HTMLAttributes on the root element but does not forward ref.\n\t */\n\tclassName?: string;\n}\n\nexport function ChatHeader({\n\ttitle,\n\tsubtitle,\n\tleading,\n\tchildren,\n\tclassName,\n\t...props\n}: ChatHeaderProps) {\n\treturn (\n\t\t<header\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"flex items-center justify-between gap-basalt-content-gap border-b border-basalt-border/50 px-basalt-panel-x py-basalt-panel-y leading-[var(--basalt-line-body)]\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"flex min-w-0 items-center gap-basalt-content-gap\">\n\t\t\t\t{leading ? (\n\t\t\t\t\t<span className=\"flex h-basalt-8 w-basalt-8 items-center justify-center\">{leading}</span>\n\t\t\t\t) : null}\n\t\t\t\t<div className=\"min-w-0\">\n\t\t\t\t\t<p className=\"truncate text-basalt-base font-semibold tracking-tight\">{title}</p>\n\t\t\t\t\t{subtitle ? (\n\t\t\t\t\t\t<p className=\"truncate text-basalt-sm text-basalt-muted-foreground\">{subtitle}</p>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t{children ? <div className=\"flex items-center gap-basalt-space-sm\">{children}</div> : null}\n\t\t</header>\n\t);\n}\n"],"mappings":";;;;;AA6BA,SAAgBA,EAAW,EAC1B,UACA,aACA,YACA,aACA,cACA,GAAGC,KACgB;CACnB,OACC,kBAAC,UAAD;EACC,WAAWC,EACVC,GACA,mKACAC,CACD;EACA,GAAIH;EANL,UAAA,CAQC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACEI,IACA,kBAAC,QAAD;IAAM,WAAU;IAA0D,UAAAA;GAAc,CAAA,IACrF,MACJ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACC,kBAAC,KAAD;KAAG,WAAU;KAA0D,UAAAC;IAAS,CAAA,GAC/EC,IACA,kBAAC,KAAD;KAAG,WAAU;KAAwD,UAAAA;IAAY,CAAA,IAC9E,IACA;GACD,CAAA,CAAA;EACJ,CAAA,GAAAC,IAAW,kBAAC,OAAD;GAAK,WAAU;GAAyC;EAAc,CAAA,IAAI,IAC/E;;AAEV"}
@@ -30,7 +30,7 @@ function o({ items: o, activeId: s, onSelect: c, className: l, ...u }) {
30
30
  className: "truncate text-basalt-base font-medium text-basalt-foreground",
31
31
  children: t.title
32
32
  }), t.time ? /* @__PURE__ */ i("span", {
33
- className: "shrink-0 text-basalt-xs text-basalt-muted-foreground",
33
+ className: "shrink-0 text-basalt-sm text-basalt-muted-foreground",
34
34
  children: t.time
35
35
  }) : null]
36
36
  }), t.preview ? /* @__PURE__ */ i("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"chat-inbox.js","names":["ChatInbox","props","highlightRef","useHoverHighlight","cn","NAV_LIST_CLASS","className","items","active","item","activeId","onSelect","NAV_ITEM_CLASS"],"sources":["../../src/components/chat-inbox.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { NAV_ITEM_CLASS, NAV_LIST_CLASS } from \"../utils/navigation\";\nimport { useHoverHighlight } from \"../utils/use-hover-highlight\";\n\nexport interface ChatInboxItem {\n\t/** Stable id for selection. */\n\tid: string;\n\t/** Thread title. */\n\ttitle: string;\n\t/** Last-message preview. */\n\tpreview?: string;\n\t/** Timestamp label. */\n\ttime?: string;\n\t/** Optional leading mark. */\n\tleading?: ReactNode;\n}\n\nexport interface ChatInboxProps\n\textends Omit<HTMLAttributes<HTMLElement>, \"onSelect\" | \"className\"> {\n\t/**\n\t * Threads to list ({ id: string, title: string, preview?: string, time?: string, leading?: ReactNode }[]).\n\t */\n\titems: readonly ChatInboxItem[];\n\t/**\n\t * Selected thread id.\n\t */\n\tactiveId?: string;\n\t/**\n\t * Called when a thread is chosen.\n\t */\n\tonSelect: (id: string) => void;\n\t/**\n\t * Optional class name applied to the navigation element.\n\t * Component inherits native nav HTMLAttributes on the root element but does not forward ref.\n\t */\n\tclassName?: string;\n}\n\nexport function ChatInbox({ items, activeId, onSelect, className, ...props }: ChatInboxProps) {\n\tconst highlightRef = useHoverHighlight();\n\treturn (\n\t\t<nav\n\t\t\tref={highlightRef}\n\t\t\tclassName={cn(\n\t\t\t\tNAV_LIST_CLASS,\n\t\t\t\t\"min-h-0 flex-col overflow-y-auto overscroll-y-contain\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{items.map((item) => {\n\t\t\t\tconst active = item.id === activeId;\n\t\t\t\treturn (\n\t\t\t\t\t<button\n\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-current={active ? \"true\" : undefined}\n\t\t\t\t\t\tdata-basalt-hover-item=\"\"\n\t\t\t\t\t\tdata-hover-selected={active}\n\t\t\t\t\t\tonClick={() => onSelect(item.id)}\n\t\t\t\t\t\tclassName={cn(NAV_ITEM_CLASS, \"w-full justify-start\")}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.leading ? (\n\t\t\t\t\t\t\t<span className=\"flex h-basalt-8 w-basalt-8 shrink-0 items-center justify-center\">\n\t\t\t\t\t\t\t\t{item.leading}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<span className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t<span className=\"flex items-baseline justify-between gap-basalt-row-gap\">\n\t\t\t\t\t\t\t\t<span className=\"truncate text-basalt-base font-medium text-basalt-foreground\">\n\t\t\t\t\t\t\t\t\t{item.title}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{item.time ? (\n\t\t\t\t\t\t\t\t\t<span className=\"shrink-0 text-basalt-xs text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t{item.time}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{item.preview ? (\n\t\t\t\t\t\t\t\t<span className=\"mt-basalt-space-xs block truncate text-basalt-sm text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t{item.preview}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</button>\n\t\t\t\t);\n\t\t\t})}\n\t\t</nav>\n\t);\n}\n"],"mappings":";;;;;;AAuCA,SAAgBA,EAAU,EAAE,UAAO,aAAU,aAAU,cAAW,GAAGC,KAAyB;CAC7F,IAAMC,IAAeC,EAAkB;CACvC,OACC,kBAAC,OAAD;EACC,KAAKD;EACL,WAAWE,EACVC,GACA,yDACAC,CACD;EACA,GAAIL;EAEH,UAAAM,EAAM,KAAK,MAAS;GACpB,IAAMC,IAASC,EAAK,OAAOC;GAC3B,OACC,kBAAC,UAAD;IAEC,MAAK;IACL,gBAAcF,IAAS,SAAS,KAAA;IAChC,0BAAuB;IACvB,uBAAqBA;IACrB,eAAeG,EAASF,EAAK,EAAE;IAC/B,WAAWL,EAAGQ,GAAgB,sBAAsB;IAPrD,UAAA,CASEH,EAAK,UACL,kBAAC,QAAD;KAAM,WAAU;KACd,UAAAA,EAAK;IACD,CAAA,IACH,MACJ,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACC,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA,CACC,kBAAC,QAAD;OAAM,WAAU;OACd,UAAAA,EAAK;MACD,CAAA,GACLA,EAAK,OACL,kBAAC,QAAD;OAAM,WAAU;OACd,UAAAA,EAAK;MACD,CAAA,IACH,IACC;KACL,CAAA,GAAAA,EAAK,UACL,kBAAC,QAAD;MAAM,WAAU;MACd,UAAAA,EAAK;KACD,CAAA,IACH,IACC;IACC,CAAA,CAAA;GA9BF,GAAAA,EAAK,EA8BH;EAEV,CAAC;CACG,CAAA;AAEP"}
1
+ {"version":3,"file":"chat-inbox.js","names":["ChatInbox","props","highlightRef","useHoverHighlight","cn","NAV_LIST_CLASS","className","items","active","item","activeId","onSelect","NAV_ITEM_CLASS"],"sources":["../../src/components/chat-inbox.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { NAV_ITEM_CLASS, NAV_LIST_CLASS } from \"../utils/navigation\";\nimport { useHoverHighlight } from \"../utils/use-hover-highlight\";\n\nexport interface ChatInboxItem {\n\t/** Stable id for selection. */\n\tid: string;\n\t/** Thread title. */\n\ttitle: string;\n\t/** Last-message preview. */\n\tpreview?: string;\n\t/** Timestamp label. */\n\ttime?: string;\n\t/** Optional leading mark. */\n\tleading?: ReactNode;\n}\n\nexport interface ChatInboxProps\n\textends Omit<HTMLAttributes<HTMLElement>, \"onSelect\" | \"className\"> {\n\t/**\n\t * Threads to list ({ id: string, title: string, preview?: string, time?: string, leading?: ReactNode }[]).\n\t */\n\titems: readonly ChatInboxItem[];\n\t/**\n\t * Selected thread id.\n\t */\n\tactiveId?: string;\n\t/**\n\t * Called when a thread is chosen.\n\t */\n\tonSelect: (id: string) => void;\n\t/**\n\t * Optional class name applied to the navigation element.\n\t * Component inherits native nav HTMLAttributes on the root element but does not forward ref.\n\t */\n\tclassName?: string;\n}\n\nexport function ChatInbox({ items, activeId, onSelect, className, ...props }: ChatInboxProps) {\n\tconst highlightRef = useHoverHighlight();\n\treturn (\n\t\t<nav\n\t\t\tref={highlightRef}\n\t\t\tclassName={cn(\n\t\t\t\tNAV_LIST_CLASS,\n\t\t\t\t\"min-h-0 flex-col overflow-y-auto overscroll-y-contain\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{items.map((item) => {\n\t\t\t\tconst active = item.id === activeId;\n\t\t\t\treturn (\n\t\t\t\t\t<button\n\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-current={active ? \"true\" : undefined}\n\t\t\t\t\t\tdata-basalt-hover-item=\"\"\n\t\t\t\t\t\tdata-hover-selected={active}\n\t\t\t\t\t\tonClick={() => onSelect(item.id)}\n\t\t\t\t\t\tclassName={cn(NAV_ITEM_CLASS, \"w-full justify-start\")}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.leading ? (\n\t\t\t\t\t\t\t<span className=\"flex h-basalt-8 w-basalt-8 shrink-0 items-center justify-center\">\n\t\t\t\t\t\t\t\t{item.leading}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<span className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t\t<span className=\"flex items-baseline justify-between gap-basalt-row-gap\">\n\t\t\t\t\t\t\t\t<span className=\"truncate text-basalt-base font-medium text-basalt-foreground\">\n\t\t\t\t\t\t\t\t\t{item.title}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{item.time ? (\n\t\t\t\t\t\t\t\t\t<span className=\"shrink-0 text-basalt-sm text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t{item.time}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{item.preview ? (\n\t\t\t\t\t\t\t\t<span className=\"mt-basalt-space-xs block truncate text-basalt-sm text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t{item.preview}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</button>\n\t\t\t\t);\n\t\t\t})}\n\t\t</nav>\n\t);\n}\n"],"mappings":";;;;;;AAuCA,SAAgBA,EAAU,EAAE,UAAO,aAAU,aAAU,cAAW,GAAGC,KAAyB;CAC7F,IAAMC,IAAeC,EAAkB;CACvC,OACC,kBAAC,OAAD;EACC,KAAKD;EACL,WAAWE,EACVC,GACA,yDACAC,CACD;EACA,GAAIL;EAEH,UAAAM,EAAM,KAAK,MAAS;GACpB,IAAMC,IAASC,EAAK,OAAOC;GAC3B,OACC,kBAAC,UAAD;IAEC,MAAK;IACL,gBAAcF,IAAS,SAAS,KAAA;IAChC,0BAAuB;IACvB,uBAAqBA;IACrB,eAAeG,EAASF,EAAK,EAAE;IAC/B,WAAWL,EAAGQ,GAAgB,sBAAsB;IAPrD,UAAA,CASEH,EAAK,UACL,kBAAC,QAAD;KAAM,WAAU;KACd,UAAAA,EAAK;IACD,CAAA,IACH,MACJ,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACC,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA,CACC,kBAAC,QAAD;OAAM,WAAU;OACd,UAAAA,EAAK;MACD,CAAA,GACLA,EAAK,OACL,kBAAC,QAAD;OAAM,WAAU;OACd,UAAAA,EAAK;MACD,CAAA,IACH,IACC;KACL,CAAA,GAAAA,EAAK,UACL,kBAAC,QAAD;MAAM,WAAU;MACd,UAAAA,EAAK;KACD,CAAA,IACH,IACC;IACC,CAAA,CAAA;GA9BF,GAAAA,EAAK,EA8BH;EAEV,CAAC;CACG,CAAA;AAEP"}
@@ -16,7 +16,7 @@ function l(i, c = !1) {
16
16
  case "heading": {
17
17
  let e = `h${Math.min(6, d.depth + 1)}`;
18
18
  f = /* @__PURE__ */ a(e, {
19
- className: "font-semibold text-basalt-lg",
19
+ className: "font-semibold text-basalt-xl",
20
20
  children: l(d.tokens, c)
21
21
  });
22
22
  break;
@@ -1 +1 @@
1
- {"version":3,"file":"chat-markdown.js","names":["nodes","tokens","token","raw","node","Heading","streaming","decodeHTML","word","i","CodeHighlighted","List","cn","item","index","href","contextSourceHref","text","cell","row","j","Fragment","ChatMarkdown","rendered","useMemo","marked","content","className"],"sources":["../../src/components/chat-markdown.tsx"],"sourcesContent":["import { decodeHTML } from \"entities\";\nimport { type MarkedToken, marked, type Token } from \"marked\";\nimport { Fragment, type ReactNode, useMemo } from \"react\";\nimport { contextSourceHref } from \"../models/context-cards\";\nimport { cn } from \"../utils/cn\";\nimport { CodeHighlighted } from \"./code\";\n\nexport interface ChatMarkdownProps {\n\t/** Untrusted Markdown. Raw HTML is rendered as text, never injected. */\n\tcontent: string;\n\t/** Animate newly appended prose words; disable for static output. */\n\tstreaming?: boolean;\n\tclassName?: string;\n}\n\nfunction nodes(tokens: readonly Token[], streaming = false): ReactNode {\n\treturn tokens.map((raw, index) => {\n\t\tconst token = raw as MarkedToken;\n\t\tlet node: ReactNode;\n\t\tswitch (token.type) {\n\t\t\tcase \"space\":\n\t\t\tcase \"def\":\n\t\t\t\treturn null;\n\t\t\tcase \"heading\": {\n\t\t\t\tconst Heading = `h${Math.min(6, token.depth + 1)}` as \"h2\";\n\t\t\t\tnode = (\n\t\t\t\t\t<Heading className=\"font-semibold text-basalt-lg\">\n\t\t\t\t\t\t{nodes(token.tokens, streaming)}\n\t\t\t\t\t</Heading>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"paragraph\":\n\t\t\t\tnode = <p>{nodes(token.tokens, streaming)}</p>;\n\t\t\t\tbreak;\n\t\t\tcase \"text\":\n\t\t\t\tnode = token.tokens\n\t\t\t\t\t? nodes(token.tokens, streaming)\n\t\t\t\t\t: streaming\n\t\t\t\t\t\t? decodeHTML(token.text)\n\t\t\t\t\t\t\t\t.split(/(\\s+)/)\n\t\t\t\t\t\t\t\t.map((word, i) =>\n\t\t\t\t\t\t\t\t\t/\\S/.test(word) ? (\n\t\t\t\t\t\t\t\t\t\t<span key={i} className=\"basalt-chat-word\">\n\t\t\t\t\t\t\t\t\t\t\t{word}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\tword\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: decodeHTML(token.text);\n\t\t\t\tbreak;\n\t\t\tcase \"strong\":\n\t\t\t\tnode = <strong>{nodes(token.tokens, streaming)}</strong>;\n\t\t\t\tbreak;\n\t\t\tcase \"em\":\n\t\t\t\tnode = <em>{nodes(token.tokens, streaming)}</em>;\n\t\t\t\tbreak;\n\t\t\tcase \"del\":\n\t\t\t\tnode = <del>{nodes(token.tokens, streaming)}</del>;\n\t\t\t\tbreak;\n\t\t\tcase \"codespan\":\n\t\t\t\tnode = (\n\t\t\t\t\t<code className=\"rounded-basalt-sm bg-basalt-accent px-basalt-space-sm py-basalt-space-xs font-mono text-basalt-sm\">\n\t\t\t\t\t\t{token.text}\n\t\t\t\t\t</code>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"code\":\n\t\t\t\tnode = <CodeHighlighted code={token.text} title={token.lang || \"text\"} lineNumbers />;\n\t\t\t\tbreak;\n\t\t\tcase \"blockquote\":\n\t\t\t\tnode = (\n\t\t\t\t\t<blockquote className=\"border-l-2 border-basalt-border pl-basalt-space-lg text-basalt-muted-foreground\">\n\t\t\t\t\t\t{nodes(token.tokens, streaming)}\n\t\t\t\t\t</blockquote>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"list\": {\n\t\t\t\tconst List = token.ordered ? \"ol\" : \"ul\";\n\t\t\t\tnode = (\n\t\t\t\t\t<List\n\t\t\t\t\t\tstart={token.ordered ? Number(token.start) || 1 : undefined}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"space-y-basalt-space-sm pl-basalt-space-lg\",\n\t\t\t\t\t\t\ttoken.ordered ? \"list-decimal\" : \"list-disc\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{token.items.map((item, i) => (\n\t\t\t\t\t\t\t<li key={`${index}-${i}`}>\n\t\t\t\t\t\t\t\t{item.task && (\n\t\t\t\t\t\t\t\t\t<span aria-label={item.checked ? \"Complete\" : \"Incomplete\"} role=\"img\">\n\t\t\t\t\t\t\t\t\t\t{item.checked ? \"☑ \" : \"☐ \"}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{nodes(item.tokens, streaming)}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</List>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"link\":\n\t\t\tcase \"image\": {\n\t\t\t\tconst href = contextSourceHref(decodeHTML(token.href));\n\t\t\t\tconst text =\n\t\t\t\t\ttoken.type === \"link\" ? nodes(token.tokens, streaming) : decodeHTML(token.text);\n\t\t\t\tnode = href ? (\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={href}\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\tclassName=\"text-basalt-primary underline underline-offset-4\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{text}\n\t\t\t\t\t</a>\n\t\t\t\t) : (\n\t\t\t\t\ttext\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"table\":\n\t\t\t\tnode = (\n\t\t\t\t\t<div className=\"max-w-full overflow-x-auto\">\n\t\t\t\t\t\t<table className=\"w-full border-collapse text-left text-basalt-sm\">\n\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t{token.header.map((cell, i) => (\n\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"whitespace-nowrap border-b border-basalt-border px-basalt-space-lg py-basalt-space-md\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{nodes(cell.tokens, streaming)}\n\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t{token.rows.map((row, i) => (\n\t\t\t\t\t\t\t\t\t<tr key={i}>\n\t\t\t\t\t\t\t\t\t\t{row.map((cell, j) => (\n\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\tkey={j}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-b border-basalt-border px-basalt-space-lg py-basalt-space-md\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{nodes(cell.tokens, streaming)}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t</div>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"br\":\n\t\t\t\tnode = <br />;\n\t\t\t\tbreak;\n\t\t\tcase \"hr\":\n\t\t\t\tnode = <hr className=\"border-basalt-border\" />;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tnode = \"text\" in token ? String(token.text) : token.raw;\n\t\t}\n\t\treturn <Fragment key={index}>{node}</Fragment>;\n\t});\n}\n\nexport function ChatMarkdown({ content, streaming = false, className }: ChatMarkdownProps) {\n\tconst rendered = useMemo(\n\t\t() => nodes(marked.lexer(content, { gfm: true }), streaming),\n\t\t[content, streaming],\n\t);\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"basalt-ui min-w-0 space-y-basalt-space-lg break-words text-basalt-base leading-[var(--basalt-line-relaxed)] [&_p]:whitespace-pre-wrap\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{rendered}\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat-markdown.js","names":["nodes","tokens","token","raw","node","Heading","streaming","decodeHTML","word","i","CodeHighlighted","List","cn","item","index","href","contextSourceHref","text","cell","row","j","Fragment","ChatMarkdown","rendered","useMemo","marked","content","className"],"sources":["../../src/components/chat-markdown.tsx"],"sourcesContent":["import { decodeHTML } from \"entities\";\nimport { type MarkedToken, marked, type Token } from \"marked\";\nimport { Fragment, type ReactNode, useMemo } from \"react\";\nimport { contextSourceHref } from \"../models/context-cards\";\nimport { cn } from \"../utils/cn\";\nimport { CodeHighlighted } from \"./code\";\n\nexport interface ChatMarkdownProps {\n\t/** Untrusted Markdown. Raw HTML is rendered as text, never injected. */\n\tcontent: string;\n\t/** Animate newly appended prose words; disable for static output. */\n\tstreaming?: boolean;\n\tclassName?: string;\n}\n\nfunction nodes(tokens: readonly Token[], streaming = false): ReactNode {\n\treturn tokens.map((raw, index) => {\n\t\tconst token = raw as MarkedToken;\n\t\tlet node: ReactNode;\n\t\tswitch (token.type) {\n\t\t\tcase \"space\":\n\t\t\tcase \"def\":\n\t\t\t\treturn null;\n\t\t\tcase \"heading\": {\n\t\t\t\tconst Heading = `h${Math.min(6, token.depth + 1)}` as \"h2\";\n\t\t\t\tnode = (\n\t\t\t\t\t<Heading className=\"font-semibold text-basalt-xl\">\n\t\t\t\t\t\t{nodes(token.tokens, streaming)}\n\t\t\t\t\t</Heading>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"paragraph\":\n\t\t\t\tnode = <p>{nodes(token.tokens, streaming)}</p>;\n\t\t\t\tbreak;\n\t\t\tcase \"text\":\n\t\t\t\tnode = token.tokens\n\t\t\t\t\t? nodes(token.tokens, streaming)\n\t\t\t\t\t: streaming\n\t\t\t\t\t\t? decodeHTML(token.text)\n\t\t\t\t\t\t\t\t.split(/(\\s+)/)\n\t\t\t\t\t\t\t\t.map((word, i) =>\n\t\t\t\t\t\t\t\t\t/\\S/.test(word) ? (\n\t\t\t\t\t\t\t\t\t\t<span key={i} className=\"basalt-chat-word\">\n\t\t\t\t\t\t\t\t\t\t\t{word}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\tword\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: decodeHTML(token.text);\n\t\t\t\tbreak;\n\t\t\tcase \"strong\":\n\t\t\t\tnode = <strong>{nodes(token.tokens, streaming)}</strong>;\n\t\t\t\tbreak;\n\t\t\tcase \"em\":\n\t\t\t\tnode = <em>{nodes(token.tokens, streaming)}</em>;\n\t\t\t\tbreak;\n\t\t\tcase \"del\":\n\t\t\t\tnode = <del>{nodes(token.tokens, streaming)}</del>;\n\t\t\t\tbreak;\n\t\t\tcase \"codespan\":\n\t\t\t\tnode = (\n\t\t\t\t\t<code className=\"rounded-basalt-sm bg-basalt-accent px-basalt-space-sm py-basalt-space-xs font-mono text-basalt-sm\">\n\t\t\t\t\t\t{token.text}\n\t\t\t\t\t</code>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"code\":\n\t\t\t\tnode = <CodeHighlighted code={token.text} title={token.lang || \"text\"} lineNumbers />;\n\t\t\t\tbreak;\n\t\t\tcase \"blockquote\":\n\t\t\t\tnode = (\n\t\t\t\t\t<blockquote className=\"border-l-2 border-basalt-border pl-basalt-space-lg text-basalt-muted-foreground\">\n\t\t\t\t\t\t{nodes(token.tokens, streaming)}\n\t\t\t\t\t</blockquote>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"list\": {\n\t\t\t\tconst List = token.ordered ? \"ol\" : \"ul\";\n\t\t\t\tnode = (\n\t\t\t\t\t<List\n\t\t\t\t\t\tstart={token.ordered ? Number(token.start) || 1 : undefined}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"space-y-basalt-space-sm pl-basalt-space-lg\",\n\t\t\t\t\t\t\ttoken.ordered ? \"list-decimal\" : \"list-disc\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{token.items.map((item, i) => (\n\t\t\t\t\t\t\t<li key={`${index}-${i}`}>\n\t\t\t\t\t\t\t\t{item.task && (\n\t\t\t\t\t\t\t\t\t<span aria-label={item.checked ? \"Complete\" : \"Incomplete\"} role=\"img\">\n\t\t\t\t\t\t\t\t\t\t{item.checked ? \"☑ \" : \"☐ \"}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{nodes(item.tokens, streaming)}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</List>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"link\":\n\t\t\tcase \"image\": {\n\t\t\t\tconst href = contextSourceHref(decodeHTML(token.href));\n\t\t\t\tconst text =\n\t\t\t\t\ttoken.type === \"link\" ? nodes(token.tokens, streaming) : decodeHTML(token.text);\n\t\t\t\tnode = href ? (\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={href}\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\tclassName=\"text-basalt-primary underline underline-offset-4\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{text}\n\t\t\t\t\t</a>\n\t\t\t\t) : (\n\t\t\t\t\ttext\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"table\":\n\t\t\t\tnode = (\n\t\t\t\t\t<div className=\"max-w-full overflow-x-auto\">\n\t\t\t\t\t\t<table className=\"w-full border-collapse text-left text-basalt-sm\">\n\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t{token.header.map((cell, i) => (\n\t\t\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"whitespace-nowrap border-b border-basalt-border px-basalt-space-lg py-basalt-space-md\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{nodes(cell.tokens, streaming)}\n\t\t\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t{token.rows.map((row, i) => (\n\t\t\t\t\t\t\t\t\t<tr key={i}>\n\t\t\t\t\t\t\t\t\t\t{row.map((cell, j) => (\n\t\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\t\tkey={j}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-b border-basalt-border px-basalt-space-lg py-basalt-space-md\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{nodes(cell.tokens, streaming)}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t</div>\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"br\":\n\t\t\t\tnode = <br />;\n\t\t\t\tbreak;\n\t\t\tcase \"hr\":\n\t\t\t\tnode = <hr className=\"border-basalt-border\" />;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tnode = \"text\" in token ? String(token.text) : token.raw;\n\t\t}\n\t\treturn <Fragment key={index}>{node}</Fragment>;\n\t});\n}\n\nexport function ChatMarkdown({ content, streaming = false, className }: ChatMarkdownProps) {\n\tconst rendered = useMemo(\n\t\t() => nodes(marked.lexer(content, { gfm: true }), streaming),\n\t\t[content, streaming],\n\t);\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"basalt-ui min-w-0 space-y-basalt-space-lg break-words text-basalt-base leading-[var(--basalt-line-relaxed)] [&_p]:whitespace-pre-wrap\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{rendered}\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}