@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":"diff-table.js","names":["_Fragment","Fragment$1","DiffTable","props","vm","useDiffTableViewModel","id","useId","LayerCard","cn","className","title","Table","TableHeader","TableRow","TableHead","columns","column","TableBody","included","row","event","TableCell","Plus","Minus","Checkbox","Check","Button"],"sources":["../../src/components/diff-table.tsx"],"sourcesContent":["import { Check, Minus, Plus } from \"lucide-react\";\nimport { useId } from \"react\";\nimport type { DiffTableColumn, DiffTableRow } from \"../models/diff-table\";\nimport { cn } from \"../utils/cn\";\nimport { useDiffTableViewModel } from \"../viewmodels/use-diff-table\";\nimport { Button } from \"./button\";\nimport { Checkbox } from \"./checkbox\";\nimport { LayerCard } from \"./layer-card\";\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from \"./table\";\n\nexport type { DiffTableColumn, DiffTableRow } from \"../models/diff-table\";\n\nexport interface DiffTableProps {\n\t/** Stable columns and text/number cells. */\n\tcolumns: readonly DiffTableColumn[];\n\t/** Proposed rows; remount with a new key for a different proposal. */\n\trows: readonly DiffTableRow[];\n\t/** Heading and accessible table name. @default \"Proposed changes\" */\n\ttitle?: string;\n\t/** Explicitly apply only selected changes; rejection keeps the selection for retry. */\n\tonApply: (changes: readonly DiffTableRow[]) => void | Promise<void>;\n\tdisabled?: boolean;\n\tclassName?: string;\n}\n\nexport function DiffTable({\n\ttitle = \"Proposed changes\",\n\tcolumns,\n\tclassName,\n\t...props\n}: DiffTableProps) {\n\tconst vm = useDiffTableViewModel(props);\n\tconst id = useId();\n\treturn (\n\t\t<LayerCard\n\t\t\tpadding=\"none\"\n\t\t\taria-labelledby={id}\n\t\t\tclassName={cn(\"min-w-0 overflow-hidden leading-[var(--basalt-line-body)]\", className)}\n\t\t>\n\t\t\t<header className=\"flex flex-wrap items-center justify-between gap-basalt-content-gap border-b border-basalt-border px-basalt-panel-x py-basalt-panel-y\">\n\t\t\t\t<h3 id={id} className=\"text-basalt-code font-medium\">\n\t\t\t\t\t{title}\n\t\t\t\t</h3>\n\t\t\t\t<span className=\"text-basalt-sm text-basalt-muted-foreground\">Select changes to apply</span>\n\t\t\t</header>\n\t\t\t<div\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={`${title} scroll area`}\n\t\t\t\t// biome-ignore lint/a11y/noNoninteractiveTabindex: Named overflow region supports keyboard scrolling.\n\t\t\t\ttabIndex={0}\n\t\t\t\tclassName=\"overflow-x-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-basalt-ring\"\n\t\t\t>\n\t\t\t\t<Table aria-label={title} aria-busy={vm.status === \"applying\" || undefined}>\n\t\t\t\t\t<TableHeader>\n\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t<TableHead scope=\"col\" className=\"ps-basalt-table-edge\">\n\t\t\t\t\t\t\t\tChange\n\t\t\t\t\t\t\t</TableHead>\n\t\t\t\t\t\t\t{columns.map((column) => (\n\t\t\t\t\t\t\t\t<TableHead key={column.id} scope=\"col\" style={{ minWidth: column.width }}>\n\t\t\t\t\t\t\t\t\t{column.label}\n\t\t\t\t\t\t\t\t</TableHead>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t<TableHead scope=\"col\" className=\"pe-basalt-table-edge\">\n\t\t\t\t\t\t\t\t<span className=\"sr-only\">Include change</span>\n\t\t\t\t\t\t\t</TableHead>\n\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t</TableHeader>\n\t\t\t\t\t<TableBody>\n\t\t\t\t\t\t{props.rows.map((row) => {\n\t\t\t\t\t\t\tconst included = row.change !== \"unchanged\" && !vm.excluded.includes(row.id);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<TableRow\n\t\t\t\t\t\t\t\t\tkey={row.id}\n\t\t\t\t\t\t\t\t\tdata-diff-change={row.change}\n\t\t\t\t\t\t\t\t\tdata-included={included}\n\t\t\t\t\t\t\t\t\taria-selected={row.change !== \"unchanged\" ? included : undefined}\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"basalt-agent-reveal\",\n\t\t\t\t\t\t\t\t\t\trow.change !== \"unchanged\" && !vm.blocked && \"cursor-pointer\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\t\t\t\tif (event.target instanceof Element && event.target.closest(\"button, a, input\"))\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\tvm.toggle(row.id);\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\t<TableCell className=\"whitespace-nowrap ps-basalt-table-edge text-basalt-sm\">\n\t\t\t\t\t\t\t\t\t\t<span className=\"inline-flex items-center gap-basalt-control-gap leading-[var(--basalt-line-body)]\">\n\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\tdata-diff-marker=\"\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"inline-flex size-basalt-icon-sm shrink-0 items-center justify-center\"\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{row.change === \"add\" ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Plus className=\"size-basalt-icon-sm\" />\n\t\t\t\t\t\t\t\t\t\t\t\t) : row.change === \"remove\" ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Minus className=\"size-basalt-icon-sm\" />\n\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t{row.change === \"unchanged\"\n\t\t\t\t\t\t\t\t\t\t\t\t? \"Keep\"\n\t\t\t\t\t\t\t\t\t\t\t\t: row.change === \"add\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t? \"Add\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t: \"Remove\"}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t\t{columns.map((column) => (\n\t\t\t\t\t\t\t\t\t\t<TableCell\n\t\t\t\t\t\t\t\t\t\t\tkey={column.id}\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\"whitespace-nowrap\",\n\t\t\t\t\t\t\t\t\t\t\t\tincluded && row.change === \"remove\" && \"line-through\",\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\tstyle={{ minWidth: column.width }}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{row.values[column.id] ?? \"—\"}\n\t\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t<TableCell className=\"pe-basalt-table-edge\">\n\t\t\t\t\t\t\t\t\t\t{row.change !== \"unchanged\" && (\n\t\t\t\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\t\t\t\tdisabled={vm.blocked}\n\t\t\t\t\t\t\t\t\t\t\t\tchecked={included}\n\t\t\t\t\t\t\t\t\t\t\t\taria-label={`Include ${row.change === \"add\" ? \"addition\" : \"removal\"} ${row.label}`}\n\t\t\t\t\t\t\t\t\t\t\t\tonCheckedChange={() => vm.toggle(row.id)}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t\t{props.rows.length === 0 && (\n\t\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t\t<TableCell\n\t\t\t\t\t\t\t\t\tcolSpan={columns.length + 2}\n\t\t\t\t\t\t\t\t\tclassName=\"ps-basalt-table-edge pe-basalt-table-edge\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<p role=\"status\" className=\"text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\tNo proposed changes\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</TableBody>\n\t\t\t\t</Table>\n\t\t\t</div>\n\t\t\t{vm.error && (\n\t\t\t\t<p\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tclassName=\"px-basalt-panel-x py-basalt-panel-y 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\t<footer className=\"flex flex-wrap items-center justify-between gap-basalt-content-gap border-t border-basalt-border px-basalt-panel-x py-basalt-panel-y\">\n\t\t\t\t{vm.status === \"applied\" ? (\n\t\t\t\t\t<p\n\t\t\t\t\t\trole=\"status\"\n\t\t\t\t\t\tclassName=\"inline-flex items-center gap-basalt-space-md text-basalt-base\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Check aria-hidden=\"true\" className=\"size-basalt-icon\" />\n\t\t\t\t\t\t{vm.selected.length} changes applied\n\t\t\t\t\t</p>\n\t\t\t\t) : (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<span className=\"text-basalt-sm tabular-nums text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t{vm.removals} removals · {vm.additions} additions\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\tloading={vm.status === \"applying\"}\n\t\t\t\t\t\t\tdisabled={vm.blocked || vm.selected.length === 0}\n\t\t\t\t\t\t\tonClick={() => void vm.apply()}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tApply {vm.selected.length} changes\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</footer>\n\t\t</LayerCard>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"diff-table.js","names":["_Fragment","Fragment$1","DiffTable","props","vm","useDiffTableViewModel","id","useId","LayerCard","cn","className","title","Table","TableHeader","TableRow","TableHead","columns","column","TableBody","included","row","event","TableCell","Plus","Minus","Checkbox","Check","Button"],"sources":["../../src/components/diff-table.tsx"],"sourcesContent":["import { Check, Minus, Plus } from \"lucide-react\";\nimport { useId } from \"react\";\nimport type { DiffTableColumn, DiffTableRow } from \"../models/diff-table\";\nimport { cn } from \"../utils/cn\";\nimport { useDiffTableViewModel } from \"../viewmodels/use-diff-table\";\nimport { Button } from \"./button\";\nimport { Checkbox } from \"./checkbox\";\nimport { LayerCard } from \"./layer-card\";\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from \"./table\";\n\nexport type { DiffTableColumn, DiffTableRow } from \"../models/diff-table\";\n\nexport interface DiffTableProps {\n\t/** Stable columns and text/number cells. */\n\tcolumns: readonly DiffTableColumn[];\n\t/** Proposed rows; remount with a new key for a different proposal. */\n\trows: readonly DiffTableRow[];\n\t/** Heading and accessible table name. @default \"Proposed changes\" */\n\ttitle?: string;\n\t/** Explicitly apply only selected changes; rejection keeps the selection for retry. */\n\tonApply: (changes: readonly DiffTableRow[]) => void | Promise<void>;\n\tdisabled?: boolean;\n\tclassName?: string;\n}\n\nexport function DiffTable({\n\ttitle = \"Proposed changes\",\n\tcolumns,\n\tclassName,\n\t...props\n}: DiffTableProps) {\n\tconst vm = useDiffTableViewModel(props);\n\tconst id = useId();\n\treturn (\n\t\t<LayerCard\n\t\t\tpadding=\"none\"\n\t\t\taria-labelledby={id}\n\t\t\tclassName={cn(\"min-w-0 overflow-hidden leading-[var(--basalt-line-body)]\", className)}\n\t\t>\n\t\t\t<header className=\"flex flex-wrap items-center justify-between gap-basalt-content-gap border-b border-basalt-border px-basalt-panel-x py-basalt-panel-y\">\n\t\t\t\t<h3 id={id} className=\"text-basalt-base font-medium\">\n\t\t\t\t\t{title}\n\t\t\t\t</h3>\n\t\t\t\t<span className=\"text-basalt-sm text-basalt-muted-foreground\">Select changes to apply</span>\n\t\t\t</header>\n\t\t\t<div\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={`${title} scroll area`}\n\t\t\t\t// biome-ignore lint/a11y/noNoninteractiveTabindex: Named overflow region supports keyboard scrolling.\n\t\t\t\ttabIndex={0}\n\t\t\t\tclassName=\"basalt-focus basalt-focus-inset overflow-x-auto\"\n\t\t\t>\n\t\t\t\t<Table aria-label={title} aria-busy={vm.status === \"applying\" || undefined}>\n\t\t\t\t\t<TableHeader>\n\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t<TableHead scope=\"col\" className=\"ps-basalt-table-edge\">\n\t\t\t\t\t\t\t\tChange\n\t\t\t\t\t\t\t</TableHead>\n\t\t\t\t\t\t\t{columns.map((column) => (\n\t\t\t\t\t\t\t\t<TableHead key={column.id} scope=\"col\" style={{ minWidth: column.width }}>\n\t\t\t\t\t\t\t\t\t{column.label}\n\t\t\t\t\t\t\t\t</TableHead>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t<TableHead scope=\"col\" className=\"pe-basalt-table-edge\">\n\t\t\t\t\t\t\t\t<span className=\"sr-only\">Include change</span>\n\t\t\t\t\t\t\t</TableHead>\n\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t</TableHeader>\n\t\t\t\t\t<TableBody>\n\t\t\t\t\t\t{props.rows.map((row) => {\n\t\t\t\t\t\t\tconst included = row.change !== \"unchanged\" && !vm.excluded.includes(row.id);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<TableRow\n\t\t\t\t\t\t\t\t\tkey={row.id}\n\t\t\t\t\t\t\t\t\tdata-diff-change={row.change}\n\t\t\t\t\t\t\t\t\tdata-included={included}\n\t\t\t\t\t\t\t\t\taria-selected={row.change !== \"unchanged\" ? included : undefined}\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"basalt-agent-reveal\",\n\t\t\t\t\t\t\t\t\t\trow.change !== \"unchanged\" && !vm.blocked && \"cursor-pointer\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\t\t\t\tif (event.target instanceof Element && event.target.closest(\"button, a, input\"))\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\tvm.toggle(row.id);\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\t<TableCell className=\"whitespace-nowrap ps-basalt-table-edge text-basalt-sm\">\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\"inline-flex items-center gap-basalt-control-gap leading-[var(--basalt-line-body)]\",\n\t\t\t\t\t\t\t\t\t\t\t\trow.change === \"add\" && \"text-basalt-success\",\n\t\t\t\t\t\t\t\t\t\t\t\trow.change === \"remove\" && \"text-basalt-destructive\",\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\tdata-diff-marker=\"\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"inline-flex size-basalt-icon-sm shrink-0 items-center justify-center\"\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{row.change === \"add\" ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Plus className=\"size-basalt-icon-sm\" />\n\t\t\t\t\t\t\t\t\t\t\t\t) : row.change === \"remove\" ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Minus className=\"size-basalt-icon-sm\" />\n\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t{row.change === \"unchanged\"\n\t\t\t\t\t\t\t\t\t\t\t\t? \"Keep\"\n\t\t\t\t\t\t\t\t\t\t\t\t: row.change === \"add\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t? \"Add\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t: \"Remove\"}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t\t{columns.map((column) => (\n\t\t\t\t\t\t\t\t\t\t<TableCell\n\t\t\t\t\t\t\t\t\t\t\tkey={column.id}\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\"whitespace-nowrap\",\n\t\t\t\t\t\t\t\t\t\t\t\tincluded && row.change === \"remove\" && \"line-through\",\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\tstyle={{ minWidth: column.width }}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{row.values[column.id] ?? \"—\"}\n\t\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t<TableCell className=\"pe-basalt-table-edge\">\n\t\t\t\t\t\t\t\t\t\t{row.change !== \"unchanged\" && (\n\t\t\t\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\t\t\t\tdisabled={vm.blocked}\n\t\t\t\t\t\t\t\t\t\t\t\tchecked={included}\n\t\t\t\t\t\t\t\t\t\t\t\taria-label={`Include ${row.change === \"add\" ? \"addition\" : \"removal\"} ${row.label}`}\n\t\t\t\t\t\t\t\t\t\t\t\tonCheckedChange={() => vm.toggle(row.id)}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t\t{props.rows.length === 0 && (\n\t\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t\t<TableCell\n\t\t\t\t\t\t\t\t\tcolSpan={columns.length + 2}\n\t\t\t\t\t\t\t\t\tclassName=\"ps-basalt-table-edge pe-basalt-table-edge\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<p role=\"status\" className=\"text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\tNo proposed changes\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</TableBody>\n\t\t\t\t</Table>\n\t\t\t</div>\n\t\t\t{vm.error && (\n\t\t\t\t<p\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tclassName=\"px-basalt-panel-x py-basalt-panel-y 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\t<footer className=\"flex flex-wrap items-center justify-between gap-basalt-content-gap border-t border-basalt-border px-basalt-panel-x py-basalt-panel-y\">\n\t\t\t\t{vm.status === \"applied\" ? (\n\t\t\t\t\t<p\n\t\t\t\t\t\trole=\"status\"\n\t\t\t\t\t\tclassName=\"inline-flex items-center gap-basalt-space-md text-basalt-base\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Check aria-hidden=\"true\" className=\"size-basalt-icon\" />\n\t\t\t\t\t\t{vm.selected.length} changes applied\n\t\t\t\t\t</p>\n\t\t\t\t) : (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<span className=\"text-basalt-sm tabular-nums text-basalt-muted-foreground\">\n\t\t\t\t\t\t\t{vm.removals} removals · {vm.additions} additions\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\tloading={vm.status === \"applying\"}\n\t\t\t\t\t\t\tdisabled={vm.blocked || vm.selected.length === 0}\n\t\t\t\t\t\t\tonClick={() => void vm.apply()}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tApply {vm.selected.length} changes\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</footer>\n\t\t</LayerCard>\n\t);\n}\n"],"mappings":"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"}
@@ -22,7 +22,7 @@ p.displayName = o.Content.displayName;
22
22
  var m = i.forwardRef(({ className: n, ...r }, i) => /* @__PURE__ */ a(o.Item, {
23
23
  "data-basalt-hover-item": "",
24
24
  ref: i,
25
- className: t(e("relative outline-hidden data-disabled:pointer-events-none data-disabled:opacity-50", n)),
25
+ className: t(e("relative data-disabled:pointer-events-none data-disabled:opacity-50", n)),
26
26
  ...r
27
27
  }));
28
28
  m.displayName = o.Item.displayName;
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown-menu.js","names":["React","DropdownMenuPrimitive","DropdownMenu","DropdownMenuTrigger","DropdownMenuGroup","DropdownMenuPortal","DropdownMenuSub","DropdownMenuRadioGroup","DropdownMenuContent","props","highlightRef","useHoverHighlight","ref","overlayPanelClass","cn","className","DropdownMenuItem","overlayItemClass"],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { useHoverHighlight } from \"../utils/use-hover-highlight\";\nimport { MENU_GAP, overlayItemClass, overlayPanelClass } from \"./overlay\";\n\ntype RadixDropdownMenuProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>;\ntype RadixDropdownMenuTriggerProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Trigger\n>;\ntype RadixDropdownMenuGroupProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Group\n>;\ntype RadixDropdownMenuPortalProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Portal\n>;\ntype RadixDropdownMenuSubProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Sub>;\ntype RadixDropdownMenuRadioGroupProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.RadioGroup\n>;\ntype RadixDropdownMenuContentProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Content\n>;\ntype RadixDropdownMenuItemProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item>;\n\nexport interface DropdownMenuProps\n\textends Omit<\n\t\tRadixDropdownMenuProps,\n\t\t\"open\" | \"defaultOpen\" | \"onOpenChange\" | \"dir\" | \"modal\" | \"children\"\n\t> {\n\t/**\n\t * Structure elements comprising the dropdown menu, typically trigger and content.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The controlled open state of the dropdown menu.\n\t */\n\topen?: RadixDropdownMenuProps[\"open\"];\n\t/**\n\t * The uncontrolled initial open state of the dropdown menu.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixDropdownMenuProps[\"defaultOpen\"];\n\t/**\n\t * Called when the open state changes.\n\t */\n\tonOpenChange?: RadixDropdownMenuProps[\"onOpenChange\"];\n\t/**\n\t * The reading direction of the dropdown menu. Inherited from DirectionProvider if present,\n\t * or defaults to \"ltr\".\n\t * @default \"ltr\"\n\t */\n\tdir?: RadixDropdownMenuProps[\"dir\"];\n\t/**\n\t * The modality of the dropdown menu. When set to true, interaction with outside elements\n\t * will be disabled and only menu content will be visible to screen readers.\n\t * @default true\n\t */\n\tmodal?: RadixDropdownMenuProps[\"modal\"];\n}\n\nexport const DropdownMenu: React.FC<DropdownMenuProps> = DropdownMenuPrimitive.Root;\n\nexport interface DropdownMenuTriggerProps\n\textends Omit<RadixDropdownMenuTriggerProps, \"asChild\" | \"children\"> {\n\t/**\n\t * Trigger element content.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * DropdownMenuTrigger forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuTriggerProps[\"asChild\"];\n}\n\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\nexport interface DropdownMenuGroupProps\n\textends Omit<RadixDropdownMenuGroupProps, \"asChild\" | \"children\"> {\n\t/**\n\t * Menu items or elements grouped together.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuGroup forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuGroupProps[\"asChild\"];\n}\n\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\nexport interface DropdownMenuPortalProps\n\textends Omit<RadixDropdownMenuPortalProps, \"container\" | \"forceMount\" | \"children\"> {\n\t/**\n\t * Content to render into the portal target.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Specify a container element to portal the content into.\n\t * Note: Only controls direct portal children; does not override the destination\n\t * container of the built-in portal inside DropdownMenuContent.\n\t */\n\tcontainer?: RadixDropdownMenuPortalProps[\"container\"];\n\t/**\n\t * Used to force mounting when more control is needed. Useful when\n\t * controlling animation with React animation libraries.\n\t */\n\tforceMount?: RadixDropdownMenuPortalProps[\"forceMount\"];\n}\n\nexport const DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\nexport interface DropdownMenuSubProps\n\textends Omit<RadixDropdownMenuSubProps, \"open\" | \"defaultOpen\" | \"onOpenChange\" | \"children\"> {\n\t/**\n\t * Submenu structure elements.\n\t * Note: Basalt does not export styled DropdownMenuSubTrigger or DropdownMenuSubContent components;\n\t * compose with underlying Radix primitives when building nested submenus.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The controlled open state of the submenu.\n\t */\n\topen?: RadixDropdownMenuSubProps[\"open\"];\n\t/**\n\t * The uncontrolled initial open state of the submenu.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixDropdownMenuSubProps[\"defaultOpen\"];\n\t/**\n\t * Event handler called when the open state of the submenu changes.\n\t */\n\tonOpenChange?: RadixDropdownMenuSubProps[\"onOpenChange\"];\n}\n\nexport const DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\nexport interface DropdownMenuRadioGroupProps\n\textends Omit<\n\t\tRadixDropdownMenuRadioGroupProps,\n\t\t\"value\" | \"onValueChange\" | \"asChild\" | \"children\"\n\t> {\n\t/**\n\t * Radio item elements grouped together.\n\t * Note: Basalt does not export styled DropdownMenuRadioItem or indicator components;\n\t * compose with underlying Radix primitives when building radio selection groups.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The value of the currently selected radio item.\n\t */\n\tvalue?: RadixDropdownMenuRadioGroupProps[\"value\"];\n\t/**\n\t * Event handler called when the value changes.\n\t */\n\tonValueChange?: RadixDropdownMenuRadioGroupProps[\"onValueChange\"];\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuRadioGroup forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuRadioGroupProps[\"asChild\"];\n}\n\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nexport interface DropdownMenuContentProps\n\textends Omit<\n\t\tRadixDropdownMenuContentProps,\n\t\t| \"side\"\n\t\t| \"sideOffset\"\n\t\t| \"align\"\n\t\t| \"alignOffset\"\n\t\t| \"avoidCollisions\"\n\t\t| \"collisionBoundary\"\n\t\t| \"collisionPadding\"\n\t\t| \"arrowPadding\"\n\t\t| \"sticky\"\n\t\t| \"hideWhenDetached\"\n\t\t| \"updatePositionStrategy\"\n\t\t| \"loop\"\n\t\t| \"onCloseAutoFocus\"\n\t\t| \"onEscapeKeyDown\"\n\t\t| \"onPointerDownOutside\"\n\t\t| \"onFocusOutside\"\n\t\t| \"onInteractOutside\"\n\t\t| \"forceMount\"\n\t\t| \"asChild\"\n\t> {\n\t/**\n\t * Preferred placement side relative to trigger.\n\t * @default \"bottom\"\n\t */\n\tside?: RadixDropdownMenuContentProps[\"side\"];\n\t/**\n\t * Distance in pixels between trigger and floating content panel.\n\t * In Basalt, defaults to MENU_GAP (8).\n\t * @default 8\n\t */\n\tsideOffset?: RadixDropdownMenuContentProps[\"sideOffset\"];\n\t/**\n\t * Preferred alignment along the side axis.\n\t * @default \"center\"\n\t */\n\talign?: RadixDropdownMenuContentProps[\"align\"];\n\t/**\n\t * Offset in pixels from the start or end alignment position.\n\t * @default 0\n\t */\n\talignOffset?: RadixDropdownMenuContentProps[\"alignOffset\"];\n\t/**\n\t * Whether to reposition content to avoid viewport boundary collisions.\n\t * @default true\n\t */\n\tavoidCollisions?: RadixDropdownMenuContentProps[\"avoidCollisions\"];\n\t/**\n\t * Element or elements bounding boundary collision calculations.\n\t * @default []\n\t */\n\tcollisionBoundary?: RadixDropdownMenuContentProps[\"collisionBoundary\"];\n\t/**\n\t * Virtual padding from collision boundaries in pixels.\n\t * @default 0\n\t */\n\tcollisionPadding?: RadixDropdownMenuContentProps[\"collisionPadding\"];\n\t/**\n\t * Padding in pixels between popper arrow and floating panel edge.\n\t * @default 0\n\t */\n\tarrowPadding?: RadixDropdownMenuContentProps[\"arrowPadding\"];\n\t/**\n\t * Sticky positioning behavior along the align axis when overflowing.\n\t * @default \"partial\"\n\t */\n\tsticky?: RadixDropdownMenuContentProps[\"sticky\"];\n\t/**\n\t * Whether to hide content completely when trigger is fully occluded.\n\t * @default false\n\t */\n\thideWhenDetached?: RadixDropdownMenuContentProps[\"hideWhenDetached\"];\n\t/**\n\t * Strategy used to calculate and update popper position.\n\t * @default \"optimized\"\n\t */\n\tupdatePositionStrategy?: RadixDropdownMenuContentProps[\"updatePositionStrategy\"];\n\t/**\n\t * Whether keyboard navigation should loop around item boundaries.\n\t * @default false\n\t */\n\tloop?: RadixDropdownMenuContentProps[\"loop\"];\n\t/**\n\t * Callback fired when auto-focusing on close. Can be prevented.\n\t */\n\tonCloseAutoFocus?: RadixDropdownMenuContentProps[\"onCloseAutoFocus\"];\n\t/**\n\t * Callback fired when the Escape key is down on the content layer. Can be prevented.\n\t */\n\tonEscapeKeyDown?: RadixDropdownMenuContentProps[\"onEscapeKeyDown\"];\n\t/**\n\t * Callback fired when a pointerdown event happens outside the bounds of the content. Can be prevented.\n\t */\n\tonPointerDownOutside?: RadixDropdownMenuContentProps[\"onPointerDownOutside\"];\n\t/**\n\t * Callback fired when focus moves outside the bounds of the content. Can be prevented.\n\t */\n\tonFocusOutside?: RadixDropdownMenuContentProps[\"onFocusOutside\"];\n\t/**\n\t * Callback fired when an interaction (pointerdown or focus) happens outside the bounds of the content. Can be prevented.\n\t */\n\tonInteractOutside?: RadixDropdownMenuContentProps[\"onInteractOutside\"];\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?: true;\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuContent forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuContentProps[\"asChild\"];\n}\n\nexport const DropdownMenuContent = React.forwardRef<\n\tReact.ElementRef<typeof DropdownMenuPrimitive.Content>,\n\tDropdownMenuContentProps\n>(({ className, sideOffset = MENU_GAP, ...props }, ref) => {\n\tconst highlightRef = useHoverHighlight(ref);\n\treturn (\n\t\t<DropdownMenuPrimitive.Portal forceMount={props.forceMount}>\n\t\t\t<DropdownMenuPrimitive.Content\n\t\t\t\tref={highlightRef}\n\t\t\t\tsideOffset={sideOffset}\n\t\t\t\tclassName={overlayPanelClass(cn(\"basalt-hover-list min-w-basalt-40\", className))}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</DropdownMenuPrimitive.Portal>\n\t);\n});\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nexport interface DropdownMenuItemProps\n\textends Omit<RadixDropdownMenuItemProps, \"disabled\" | \"onSelect\" | \"textValue\" | \"asChild\"> {\n\t/**\n\t * Disable the menu item.\n\t * @default false\n\t */\n\tdisabled?: RadixDropdownMenuItemProps[\"disabled\"];\n\t/**\n\t * Event handler called when the menu item is selected (via click or keyboard).\n\t * Note that this is a Radix CustomEvent, not native DOM onSelect.\n\t */\n\tonSelect?: RadixDropdownMenuItemProps[\"onSelect\"];\n\t/**\n\t * Optional text used for typeahead navigation. By default typeahead uses item text content.\n\t */\n\ttextValue?: RadixDropdownMenuItemProps[\"textValue\"];\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuItem forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuItemProps[\"asChild\"];\n}\n\nexport const DropdownMenuItem = React.forwardRef<\n\tReact.ElementRef<typeof DropdownMenuPrimitive.Item>,\n\tDropdownMenuItemProps\n>(({ className, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Item\n\t\tdata-basalt-hover-item=\"\"\n\t\tref={ref}\n\t\tclassName={overlayItemClass(\n\t\t\tcn(\n\t\t\t\t\"relative outline-hidden data-disabled:pointer-events-none data-disabled:opacity-50\",\n\t\t\t\tclassName,\n\t\t\t),\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n"],"mappings":";;;;;;;;AA6DA,IAAaE,IAA4CD,EAAsB,MAgBlEE,IAAsBF,EAAsB,SAgB5CG,IAAoBH,EAAsB,OAqB1CI,IAAqBJ,EAAsB,QAyB3CK,IAAkBL,EAAsB,KA6BxCM,IAAyBN,EAAsB,YAyH/CO,IAAsBR,EAAM,YAGtC,EAAE,cAAW,gBAAA,GAAuB,GAAGS,KAAS,MAAQ;CAC1D,IAAMC,IAAeC,EAAkBC,CAAG;CAC1C,OACC,kBAACX,EAAsB,QAAvB;EAA8B,YAAYQ,EAAM;EAC/C,UAAA,kBAACR,EAAsB,SAAvB;GACC,KAAKS;GACO;GACZ,WAAWG,EAAkBC,EAAG,qCAAqCC,CAAS,CAAC;GAC/E,GAAIN;EACJ,CAAA;CAC4B,CAAA;AAEhC,CAAC;AACD,EAAoB,cAAcR,EAAsB,QAAQ;AA0BhE,IAAae,IAAmBhB,EAAM,YAGnC,EAAE,cAAW,GAAGS,KAAS,MAC3B,kBAACR,EAAsB,MAAvB;CACC,0BAAuB;CAClB;CACL,WAAWgB,EACVH,EACC,sFACAC,CACD,CACD;CACA,GAAIN;AACJ,CAAA,CACD;AACD,EAAiB,cAAcR,EAAsB,KAAK"}
1
+ {"version":3,"file":"dropdown-menu.js","names":["React","DropdownMenuPrimitive","DropdownMenu","DropdownMenuTrigger","DropdownMenuGroup","DropdownMenuPortal","DropdownMenuSub","DropdownMenuRadioGroup","DropdownMenuContent","props","highlightRef","useHoverHighlight","ref","overlayPanelClass","cn","className","DropdownMenuItem","overlayItemClass"],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { useHoverHighlight } from \"../utils/use-hover-highlight\";\nimport { MENU_GAP, overlayItemClass, overlayPanelClass } from \"./overlay\";\n\ntype RadixDropdownMenuProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>;\ntype RadixDropdownMenuTriggerProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Trigger\n>;\ntype RadixDropdownMenuGroupProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Group\n>;\ntype RadixDropdownMenuPortalProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Portal\n>;\ntype RadixDropdownMenuSubProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Sub>;\ntype RadixDropdownMenuRadioGroupProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.RadioGroup\n>;\ntype RadixDropdownMenuContentProps = React.ComponentPropsWithoutRef<\n\ttypeof DropdownMenuPrimitive.Content\n>;\ntype RadixDropdownMenuItemProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item>;\n\nexport interface DropdownMenuProps\n\textends Omit<\n\t\tRadixDropdownMenuProps,\n\t\t\"open\" | \"defaultOpen\" | \"onOpenChange\" | \"dir\" | \"modal\" | \"children\"\n\t> {\n\t/**\n\t * Structure elements comprising the dropdown menu, typically trigger and content.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The controlled open state of the dropdown menu.\n\t */\n\topen?: RadixDropdownMenuProps[\"open\"];\n\t/**\n\t * The uncontrolled initial open state of the dropdown menu.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixDropdownMenuProps[\"defaultOpen\"];\n\t/**\n\t * Called when the open state changes.\n\t */\n\tonOpenChange?: RadixDropdownMenuProps[\"onOpenChange\"];\n\t/**\n\t * The reading direction of the dropdown menu. Inherited from DirectionProvider if present,\n\t * or defaults to \"ltr\".\n\t * @default \"ltr\"\n\t */\n\tdir?: RadixDropdownMenuProps[\"dir\"];\n\t/**\n\t * The modality of the dropdown menu. When set to true, interaction with outside elements\n\t * will be disabled and only menu content will be visible to screen readers.\n\t * @default true\n\t */\n\tmodal?: RadixDropdownMenuProps[\"modal\"];\n}\n\nexport const DropdownMenu: React.FC<DropdownMenuProps> = DropdownMenuPrimitive.Root;\n\nexport interface DropdownMenuTriggerProps\n\textends Omit<RadixDropdownMenuTriggerProps, \"asChild\" | \"children\"> {\n\t/**\n\t * Trigger element content.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Change the default rendered button element to the child element, merging props and behavior.\n\t * DropdownMenuTrigger forwards ref to HTMLButtonElement and inherits native button attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuTriggerProps[\"asChild\"];\n}\n\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\nexport interface DropdownMenuGroupProps\n\textends Omit<RadixDropdownMenuGroupProps, \"asChild\" | \"children\"> {\n\t/**\n\t * Menu items or elements grouped together.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuGroup forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuGroupProps[\"asChild\"];\n}\n\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\nexport interface DropdownMenuPortalProps\n\textends Omit<RadixDropdownMenuPortalProps, \"container\" | \"forceMount\" | \"children\"> {\n\t/**\n\t * Content to render into the portal target.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * Specify a container element to portal the content into.\n\t * Note: Only controls direct portal children; does not override the destination\n\t * container of the built-in portal inside DropdownMenuContent.\n\t */\n\tcontainer?: RadixDropdownMenuPortalProps[\"container\"];\n\t/**\n\t * Used to force mounting when more control is needed. Useful when\n\t * controlling animation with React animation libraries.\n\t */\n\tforceMount?: RadixDropdownMenuPortalProps[\"forceMount\"];\n}\n\nexport const DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\nexport interface DropdownMenuSubProps\n\textends Omit<RadixDropdownMenuSubProps, \"open\" | \"defaultOpen\" | \"onOpenChange\" | \"children\"> {\n\t/**\n\t * Submenu structure elements.\n\t * Note: Basalt does not export styled DropdownMenuSubTrigger or DropdownMenuSubContent components;\n\t * compose with underlying Radix primitives when building nested submenus.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The controlled open state of the submenu.\n\t */\n\topen?: RadixDropdownMenuSubProps[\"open\"];\n\t/**\n\t * The uncontrolled initial open state of the submenu.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixDropdownMenuSubProps[\"defaultOpen\"];\n\t/**\n\t * Event handler called when the open state of the submenu changes.\n\t */\n\tonOpenChange?: RadixDropdownMenuSubProps[\"onOpenChange\"];\n}\n\nexport const DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\nexport interface DropdownMenuRadioGroupProps\n\textends Omit<\n\t\tRadixDropdownMenuRadioGroupProps,\n\t\t\"value\" | \"onValueChange\" | \"asChild\" | \"children\"\n\t> {\n\t/**\n\t * Radio item elements grouped together.\n\t * Note: Basalt does not export styled DropdownMenuRadioItem or indicator components;\n\t * compose with underlying Radix primitives when building radio selection groups.\n\t */\n\tchildren?: React.ReactNode;\n\t/**\n\t * The value of the currently selected radio item.\n\t */\n\tvalue?: RadixDropdownMenuRadioGroupProps[\"value\"];\n\t/**\n\t * Event handler called when the value changes.\n\t */\n\tonValueChange?: RadixDropdownMenuRadioGroupProps[\"onValueChange\"];\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuRadioGroup forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuRadioGroupProps[\"asChild\"];\n}\n\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nexport interface DropdownMenuContentProps\n\textends Omit<\n\t\tRadixDropdownMenuContentProps,\n\t\t| \"side\"\n\t\t| \"sideOffset\"\n\t\t| \"align\"\n\t\t| \"alignOffset\"\n\t\t| \"avoidCollisions\"\n\t\t| \"collisionBoundary\"\n\t\t| \"collisionPadding\"\n\t\t| \"arrowPadding\"\n\t\t| \"sticky\"\n\t\t| \"hideWhenDetached\"\n\t\t| \"updatePositionStrategy\"\n\t\t| \"loop\"\n\t\t| \"onCloseAutoFocus\"\n\t\t| \"onEscapeKeyDown\"\n\t\t| \"onPointerDownOutside\"\n\t\t| \"onFocusOutside\"\n\t\t| \"onInteractOutside\"\n\t\t| \"forceMount\"\n\t\t| \"asChild\"\n\t> {\n\t/**\n\t * Preferred placement side relative to trigger.\n\t * @default \"bottom\"\n\t */\n\tside?: RadixDropdownMenuContentProps[\"side\"];\n\t/**\n\t * Distance in pixels between trigger and floating content panel.\n\t * In Basalt, defaults to MENU_GAP (8).\n\t * @default 8\n\t */\n\tsideOffset?: RadixDropdownMenuContentProps[\"sideOffset\"];\n\t/**\n\t * Preferred alignment along the side axis.\n\t * @default \"center\"\n\t */\n\talign?: RadixDropdownMenuContentProps[\"align\"];\n\t/**\n\t * Offset in pixels from the start or end alignment position.\n\t * @default 0\n\t */\n\talignOffset?: RadixDropdownMenuContentProps[\"alignOffset\"];\n\t/**\n\t * Whether to reposition content to avoid viewport boundary collisions.\n\t * @default true\n\t */\n\tavoidCollisions?: RadixDropdownMenuContentProps[\"avoidCollisions\"];\n\t/**\n\t * Element or elements bounding boundary collision calculations.\n\t * @default []\n\t */\n\tcollisionBoundary?: RadixDropdownMenuContentProps[\"collisionBoundary\"];\n\t/**\n\t * Virtual padding from collision boundaries in pixels.\n\t * @default 0\n\t */\n\tcollisionPadding?: RadixDropdownMenuContentProps[\"collisionPadding\"];\n\t/**\n\t * Padding in pixels between popper arrow and floating panel edge.\n\t * @default 0\n\t */\n\tarrowPadding?: RadixDropdownMenuContentProps[\"arrowPadding\"];\n\t/**\n\t * Sticky positioning behavior along the align axis when overflowing.\n\t * @default \"partial\"\n\t */\n\tsticky?: RadixDropdownMenuContentProps[\"sticky\"];\n\t/**\n\t * Whether to hide content completely when trigger is fully occluded.\n\t * @default false\n\t */\n\thideWhenDetached?: RadixDropdownMenuContentProps[\"hideWhenDetached\"];\n\t/**\n\t * Strategy used to calculate and update popper position.\n\t * @default \"optimized\"\n\t */\n\tupdatePositionStrategy?: RadixDropdownMenuContentProps[\"updatePositionStrategy\"];\n\t/**\n\t * Whether keyboard navigation should loop around item boundaries.\n\t * @default false\n\t */\n\tloop?: RadixDropdownMenuContentProps[\"loop\"];\n\t/**\n\t * Callback fired when auto-focusing on close. Can be prevented.\n\t */\n\tonCloseAutoFocus?: RadixDropdownMenuContentProps[\"onCloseAutoFocus\"];\n\t/**\n\t * Callback fired when the Escape key is down on the content layer. Can be prevented.\n\t */\n\tonEscapeKeyDown?: RadixDropdownMenuContentProps[\"onEscapeKeyDown\"];\n\t/**\n\t * Callback fired when a pointerdown event happens outside the bounds of the content. Can be prevented.\n\t */\n\tonPointerDownOutside?: RadixDropdownMenuContentProps[\"onPointerDownOutside\"];\n\t/**\n\t * Callback fired when focus moves outside the bounds of the content. Can be prevented.\n\t */\n\tonFocusOutside?: RadixDropdownMenuContentProps[\"onFocusOutside\"];\n\t/**\n\t * Callback fired when an interaction (pointerdown or focus) happens outside the bounds of the content. Can be prevented.\n\t */\n\tonInteractOutside?: RadixDropdownMenuContentProps[\"onInteractOutside\"];\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?: true;\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuContent forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuContentProps[\"asChild\"];\n}\n\nexport const DropdownMenuContent = React.forwardRef<\n\tReact.ElementRef<typeof DropdownMenuPrimitive.Content>,\n\tDropdownMenuContentProps\n>(({ className, sideOffset = MENU_GAP, ...props }, ref) => {\n\tconst highlightRef = useHoverHighlight(ref);\n\treturn (\n\t\t<DropdownMenuPrimitive.Portal forceMount={props.forceMount}>\n\t\t\t<DropdownMenuPrimitive.Content\n\t\t\t\tref={highlightRef}\n\t\t\t\tsideOffset={sideOffset}\n\t\t\t\tclassName={overlayPanelClass(cn(\"basalt-hover-list min-w-basalt-40\", className))}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</DropdownMenuPrimitive.Portal>\n\t);\n});\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nexport interface DropdownMenuItemProps\n\textends Omit<RadixDropdownMenuItemProps, \"disabled\" | \"onSelect\" | \"textValue\" | \"asChild\"> {\n\t/**\n\t * Disable the menu item.\n\t * @default false\n\t */\n\tdisabled?: RadixDropdownMenuItemProps[\"disabled\"];\n\t/**\n\t * Event handler called when the menu item is selected (via click or keyboard).\n\t * Note that this is a Radix CustomEvent, not native DOM onSelect.\n\t */\n\tonSelect?: RadixDropdownMenuItemProps[\"onSelect\"];\n\t/**\n\t * Optional text used for typeahead navigation. By default typeahead uses item text content.\n\t */\n\ttextValue?: RadixDropdownMenuItemProps[\"textValue\"];\n\t/**\n\t * Change the default rendered div element to the child element, merging props and behavior.\n\t * DropdownMenuItem forwards ref to HTMLDivElement and inherits native div attributes.\n\t * @default false\n\t */\n\tasChild?: RadixDropdownMenuItemProps[\"asChild\"];\n}\n\nexport const DropdownMenuItem = React.forwardRef<\n\tReact.ElementRef<typeof DropdownMenuPrimitive.Item>,\n\tDropdownMenuItemProps\n>(({ className, ...props }, ref) => (\n\t<DropdownMenuPrimitive.Item\n\t\tdata-basalt-hover-item=\"\"\n\t\tref={ref}\n\t\tclassName={overlayItemClass(\n\t\t\tcn(\"relative data-disabled:pointer-events-none data-disabled:opacity-50\", className),\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n"],"mappings":";;;;;;;;AA6DA,IAAaE,IAA4CD,EAAsB,MAgBlEE,IAAsBF,EAAsB,SAgB5CG,IAAoBH,EAAsB,OAqB1CI,IAAqBJ,EAAsB,QAyB3CK,IAAkBL,EAAsB,KA6BxCM,IAAyBN,EAAsB,YAyH/CO,IAAsBR,EAAM,YAGtC,EAAE,cAAW,gBAAA,GAAuB,GAAGS,KAAS,MAAQ;CAC1D,IAAMC,IAAeC,EAAkBC,CAAG;CAC1C,OACC,kBAACX,EAAsB,QAAvB;EAA8B,YAAYQ,EAAM;EAC/C,UAAA,kBAACR,EAAsB,SAAvB;GACC,KAAKS;GACO;GACZ,WAAWG,EAAkBC,EAAG,qCAAqCC,CAAS,CAAC;GAC/E,GAAIN;EACJ,CAAA;CAC4B,CAAA;AAEhC,CAAC;AACD,EAAoB,cAAcR,EAAsB,QAAQ;AA0BhE,IAAae,IAAmBhB,EAAM,YAGnC,EAAE,cAAW,GAAGS,KAAS,MAC3B,kBAACR,EAAsB,MAAvB;CACC,0BAAuB;CAClB;CACL,WAAWgB,EACVH,EAAG,uEAAuEC,CAAS,CACpF;CACA,GAAIN;AACJ,CAAA,CACD;AACD,EAAiB,cAAcR,EAAsB,KAAK"}
@@ -49,13 +49,13 @@ function g({ label: d, href: g, onSelect: _, selected: v = !1, icon: y, count: b
49
49
  M.current = !e && t !== "blur", k(e);
50
50
  }
51
51
  }) : /* @__PURE__ */ h("div", {
52
- className: "flex min-w-0 items-center gap-basalt-nav-gap",
52
+ className: "basalt-nav-actions flex min-w-0 items-center gap-basalt-space-xs",
53
53
  children: [
54
54
  /* @__PURE__ */ m(r, {
55
55
  asChild: !!g,
56
56
  variant: "ghost",
57
57
  disabled: C,
58
- className: e(a, n, "h-auto flex-1 justify-start hover:bg-transparent hover:border-transparent focus-visible:ring-offset-0"),
58
+ className: e(a, n, "h-auto flex-1 justify-start hover:bg-transparent hover:border-transparent"),
59
59
  "aria-current": v ? "page" : void 0,
60
60
  "aria-label": d,
61
61
  "aria-describedby": b == null ? void 0 : A,
@@ -1 +1 @@
1
- {"version":3,"file":"editable-nav-item.js","names":["_Fragment","Fragment$1","EditableNavItem","editing","setEditing","useState","countId","useId","rename","useRef","restore","content","icon","label","count","selected","disabled","cn","BASALT_UI_CLASS","className","onRename","InlineEditable","renameLabel","next","reason","Button","href","NAV_ROW_CLASS","FOCUS_INSET","onSelect","Link","Pencil","actions","FolderNavItem","Folder","props"],"sources":["../../src/components/editable-nav-item.tsx"],"sourcesContent":["import { Folder, Pencil } from \"lucide-react\";\nimport { type ReactNode, useId, useLayoutEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { NAV_ROW_CLASS } from \"../utils/navigation\";\nimport { Button } from \"./button\";\nimport { InlineEditable } from \"./inline-editable\";\nimport { Link } from \"./link\";\nimport { FOCUS_INSET } from \"./overlay\";\n\nexport interface EditableNavItemProps {\n\t/** Current display name. */\n\tlabel: string;\n\t/** Application route, interpreted by LinkProvider. */\n\thref?: string;\n\t/** Navigation/selection request. */\n\tonSelect?: () => void;\n\t/** Selected location. @default false */\n\tselected?: boolean;\n\t/** Caller-owned leading icon. */\n\ticon?: ReactNode;\n\t/** Caller-formatted count or status. */\n\tcount?: ReactNode;\n\t/** Separate row actions, never nested inside the navigation button/link. */\n\tactions?: ReactNode;\n\t/** Enable renaming; rejected promises keep the editor and draft available. */\n\tonRename?: (name: string) => void | Promise<void>;\n\t/** Disable navigation and renaming. Application action slots retain their own permissions. @default false */\n\tdisabled?: boolean;\n\t/** Rename action prefix. @default \"Rename\" */\n\trenameLabel?: string;\n\t/** Accessible save action. @default \"Save\" */\n\tsaveLabel?: string;\n\t/** Accessible cancel action. @default \"Cancel\" */\n\tcancelLabel?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\nexport function EditableNavItem({\n\tlabel,\n\thref,\n\tonSelect,\n\tselected = false,\n\ticon,\n\tcount,\n\tactions,\n\tonRename,\n\tdisabled = false,\n\trenameLabel = \"Rename\",\n\tsaveLabel = \"Save\",\n\tcancelLabel = \"Cancel\",\n\tclassName,\n}: EditableNavItemProps) {\n\tconst [editing, setEditing] = useState(false);\n\tconst countId = useId();\n\tconst rename = useRef<HTMLButtonElement>(null);\n\tconst restore = useRef(false);\n\tuseLayoutEffect(() => {\n\t\tif (!editing && restore.current) {\n\t\t\trestore.current = false;\n\t\t\trename.current?.focus();\n\t\t}\n\t}, [editing]);\n\tconst content = (\n\t\t<>\n\t\t\t{icon && (\n\t\t\t\t<span\n\t\t\t\t\tclassName=\"flex size-basalt-icon-lg shrink-0 items-center justify-center [&>svg]:size-basalt-icon-lg\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t{icon}\n\t\t\t\t</span>\n\t\t\t)}\n\t\t\t<span className=\"min-w-0 flex-1 truncate text-left\">{label}</span>\n\t\t\t{count != null && (\n\t\t\t\t<span\n\t\t\t\t\tid={countId}\n\t\t\t\t\tclassName=\"shrink-0 text-basalt-sm tabular-nums text-basalt-muted-foreground\"\n\t\t\t\t>\n\t\t\t\t\t{\" \"}\n\t\t\t\t\t{count}\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</>\n\t);\n\treturn (\n\t\t<div\n\t\t\tdata-basalt-hover-item={editing ? undefined : \"\"}\n\t\t\tdata-hover-selected={selected && !editing}\n\t\t\tdata-disabled={disabled ? \"\" : undefined}\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"basalt-nav-item min-w-0 shrink-0 rounded-basalt-md data-disabled:cursor-default data-disabled:hover:bg-transparent\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{editing && onRename ? (\n\t\t\t\t<InlineEditable\n\t\t\t\t\tclassName=\"p-basalt-space-lg\"\n\t\t\t\t\tlabel={`${renameLabel} ${label}`}\n\t\t\t\t\tvalue={label}\n\t\t\t\t\tediting\n\t\t\t\t\tonSave={onRename}\n\t\t\t\t\tsaveLabel={saveLabel}\n\t\t\t\t\tcancelLabel={cancelLabel}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonEditingChange={(next, reason) => {\n\t\t\t\t\t\trestore.current = !next && reason !== \"blur\";\n\t\t\t\t\t\tsetEditing(next);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex min-w-0 items-center gap-basalt-nav-gap\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tasChild={!!href}\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\tNAV_ROW_CLASS,\n\t\t\t\t\t\t\tFOCUS_INSET,\n\t\t\t\t\t\t\t\"h-auto flex-1 justify-start hover:bg-transparent hover:border-transparent focus-visible:ring-offset-0\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t\taria-current={selected ? \"page\" : undefined}\n\t\t\t\t\t\taria-label={label}\n\t\t\t\t\t\taria-describedby={count != null ? countId : undefined}\n\t\t\t\t\t\tonClick={onSelect}\n\t\t\t\t\t>\n\t\t\t\t\t\t{href ? (\n\t\t\t\t\t\t\t<Link href={href} className=\"text-inherit no-underline hover:no-underline\">\n\t\t\t\t\t\t\t\t{content}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tcontent\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Button>\n\t\t\t\t\t{onRename && (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tref={rename}\n\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\taria-label={`${renameLabel} ${label}`}\n\t\t\t\t\t\t\tonClick={() => setEditing(true)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Pencil />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t\t{actions && (\n\t\t\t\t\t\t<div className=\"flex shrink-0 items-center gap-basalt-space-sm\">{actions}</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nexport type FolderNavItemProps = EditableNavItemProps;\n/** Folder presentation with an overridable icon; no tree, router or permission model. */\nexport function FolderNavItem({\n\ticon = <Folder className=\"size-basalt-icon-lg\" />,\n\t...props\n}: FolderNavItemProps) {\n\treturn <EditableNavItem icon={icon} {...props} />;\n}\n"],"mappings":";;;;;;;;;;;;AAsCA,SAAgBE,EAAgB,EAC/B,UACA,SACA,aACA,cAAW,IACX,SACA,UACA,YACA,aACA,cAAW,IACX,iBAAc,UACd,eAAY,QACZ,iBAAc,UACd,gBACwB;CACxB,IAAM,CAACC,GAASC,KAAcC,EAAS,EAAK,GACtCC,IAAUC,EAAM,GAChBC,IAASC,EAA0B,IAAI,GACvCC,IAAUD,EAAO,EAAK;CAC5B,QAAsB;EACrB,AAAI,CAACN,KAAWO,EAAQ,YACvB,EAAQ,UAAU,IAClBF,EAAO,SAAS,MAAM;CAExB,GAAG,CAACL,CAAO,CAAC;CACZ,IAAMQ,IACL,kBAAAX,GAAA,EAAA,UAAA;EACEY,KACA,kBAAC,QAAD;GACC,WAAU;GACV,eAAY;GAEX,UAAAA;EACI,CAAA;EAEP,kBAAC,QAAD;GAAM,WAAU;GAAqC,UAAAC;EAAY,CAAA;EAChEC,KAAS,QACT,kBAAC,QAAD;GACC,IAAIR;GACJ,WAAU;GAFX,UAAA,CAIE,KACAQ,CACI;;CAEN,EAAA,CAAA;CAEH,OACC,kBAAC,OAAD;EACC,0BAAwBX,IAAU,KAAA,IAAY;EAC9C,uBAAqBY,KAAY,CAACZ;EAClC,iBAAea,IAAW,KAAK,KAAA;EAC/B,WAAWC,EACVC,GACA,sHACAC,CACD;EAEC,UAAAhB,KAAWiB,IACX,kBAACC,GAAD;GACC,WAAU;GACV,OAAO,GAAGC,EAAY,GAAGT;GACzB,OAAOA;GACP,SAAA;GACA,QAAQO;GACG;GACE;GACH;GACV,kBAAkB,GAAM,MAAW;IAElC,AADA,EAAQ,UAAU,CAACG,KAAQC,MAAW,QACtCpB,EAAWmB,CAAI;GAChB;EACA,CAAA,IAED,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACC,kBAACE,GAAD;KACC,SAAS,CAAC,CAACC;KACX,SAAQ;KACE;KACV,WAAWT,EACVU,GACAC,GACA,uGACD;KACA,gBAAcb,IAAW,SAAS,KAAA;KAClC,cAAYF;KACZ,oBAAkBC,KAAS,OAAiB,KAAA,IAAVR;KAClC,SAASuB;KAER,UAAAH,IACA,kBAACI,GAAD;MAAY;MAAM,WAAU;MAC1B,UAAAnB;KACI,CAAA,IAENA;IAEM,CAAA;IACPS,KACA,kBAACK,GAAD;KACC,KAAKjB;KACL,MAAK;KACL,SAAQ;KACE;KACV,cAAY,GAAGc,EAAY,GAAGT;KAC9B,eAAeT,EAAW,EAAI;KAE9B,UAAA,kBAAC2B,GAAD,CAAS,CAAA;IACF,CAAA;IAERC,KACA,kBAAC,OAAD;KAAK,WAAU;KAAkD,UAAAA;IAAa,CAAA;GAE3E;;CAEF,CAAA;AAEP;AAIA,SAAgBC,EAAc,EAC7B,UAAO,kBAACC,GAAD,EAAQ,WAAU,sBAAuB,CAAA,GAChD,GAAGC,KACmB;CACtB,OAAO,kBAACjC,GAAD;EAAuB;EAAM,GAAIiC;CAAQ,CAAA;AACjD"}
1
+ {"version":3,"file":"editable-nav-item.js","names":["_Fragment","Fragment$1","EditableNavItem","editing","setEditing","useState","countId","useId","rename","useRef","restore","content","icon","label","count","selected","disabled","cn","BASALT_UI_CLASS","className","onRename","InlineEditable","renameLabel","next","reason","Button","href","NAV_ROW_CLASS","FOCUS_INSET","onSelect","Link","Pencil","actions","FolderNavItem","Folder","props"],"sources":["../../src/components/editable-nav-item.tsx"],"sourcesContent":["import { Folder, Pencil } from \"lucide-react\";\nimport { type ReactNode, useId, useLayoutEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { NAV_ROW_CLASS } from \"../utils/navigation\";\nimport { Button } from \"./button\";\nimport { InlineEditable } from \"./inline-editable\";\nimport { Link } from \"./link\";\nimport { FOCUS_INSET } from \"./overlay\";\n\nexport interface EditableNavItemProps {\n\t/** Current display name. */\n\tlabel: string;\n\t/** Application route, interpreted by LinkProvider. */\n\thref?: string;\n\t/** Navigation/selection request. */\n\tonSelect?: () => void;\n\t/** Selected location. @default false */\n\tselected?: boolean;\n\t/** Caller-owned leading icon. */\n\ticon?: ReactNode;\n\t/** Caller-formatted count or status. */\n\tcount?: ReactNode;\n\t/** Separate row actions, never nested inside the navigation button/link. */\n\tactions?: ReactNode;\n\t/** Enable renaming; rejected promises keep the editor and draft available. */\n\tonRename?: (name: string) => void | Promise<void>;\n\t/** Disable navigation and renaming. Application action slots retain their own permissions. @default false */\n\tdisabled?: boolean;\n\t/** Rename action prefix. @default \"Rename\" */\n\trenameLabel?: string;\n\t/** Accessible save action. @default \"Save\" */\n\tsaveLabel?: string;\n\t/** Accessible cancel action. @default \"Cancel\" */\n\tcancelLabel?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\nexport function EditableNavItem({\n\tlabel,\n\thref,\n\tonSelect,\n\tselected = false,\n\ticon,\n\tcount,\n\tactions,\n\tonRename,\n\tdisabled = false,\n\trenameLabel = \"Rename\",\n\tsaveLabel = \"Save\",\n\tcancelLabel = \"Cancel\",\n\tclassName,\n}: EditableNavItemProps) {\n\tconst [editing, setEditing] = useState(false);\n\tconst countId = useId();\n\tconst rename = useRef<HTMLButtonElement>(null);\n\tconst restore = useRef(false);\n\tuseLayoutEffect(() => {\n\t\tif (!editing && restore.current) {\n\t\t\trestore.current = false;\n\t\t\trename.current?.focus();\n\t\t}\n\t}, [editing]);\n\tconst content = (\n\t\t<>\n\t\t\t{icon && (\n\t\t\t\t<span\n\t\t\t\t\tclassName=\"flex size-basalt-icon-lg shrink-0 items-center justify-center [&>svg]:size-basalt-icon-lg\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t{icon}\n\t\t\t\t</span>\n\t\t\t)}\n\t\t\t<span className=\"min-w-0 flex-1 truncate text-left\">{label}</span>\n\t\t\t{count != null && (\n\t\t\t\t<span\n\t\t\t\t\tid={countId}\n\t\t\t\t\tclassName=\"shrink-0 text-basalt-sm tabular-nums text-basalt-muted-foreground\"\n\t\t\t\t>\n\t\t\t\t\t{\" \"}\n\t\t\t\t\t{count}\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</>\n\t);\n\treturn (\n\t\t<div\n\t\t\tdata-basalt-hover-item={editing ? undefined : \"\"}\n\t\t\tdata-hover-selected={selected && !editing}\n\t\t\tdata-disabled={disabled ? \"\" : undefined}\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"basalt-nav-item min-w-0 shrink-0 rounded-basalt-md data-disabled:cursor-default data-disabled:hover:bg-transparent\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{editing && onRename ? (\n\t\t\t\t<InlineEditable\n\t\t\t\t\tclassName=\"p-basalt-space-lg\"\n\t\t\t\t\tlabel={`${renameLabel} ${label}`}\n\t\t\t\t\tvalue={label}\n\t\t\t\t\tediting\n\t\t\t\t\tonSave={onRename}\n\t\t\t\t\tsaveLabel={saveLabel}\n\t\t\t\t\tcancelLabel={cancelLabel}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonEditingChange={(next, reason) => {\n\t\t\t\t\t\trestore.current = !next && reason !== \"blur\";\n\t\t\t\t\t\tsetEditing(next);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"basalt-nav-actions flex min-w-0 items-center gap-basalt-space-xs\">\n\t\t\t\t\t<Button\n\t\t\t\t\t\tasChild={!!href}\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\tNAV_ROW_CLASS,\n\t\t\t\t\t\t\tFOCUS_INSET,\n\t\t\t\t\t\t\t\"h-auto flex-1 justify-start hover:bg-transparent hover:border-transparent\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t\taria-current={selected ? \"page\" : undefined}\n\t\t\t\t\t\taria-label={label}\n\t\t\t\t\t\taria-describedby={count != null ? countId : undefined}\n\t\t\t\t\t\tonClick={onSelect}\n\t\t\t\t\t>\n\t\t\t\t\t\t{href ? (\n\t\t\t\t\t\t\t<Link href={href} className=\"text-inherit no-underline hover:no-underline\">\n\t\t\t\t\t\t\t\t{content}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tcontent\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Button>\n\t\t\t\t\t{onRename && (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tref={rename}\n\t\t\t\t\t\t\tsize=\"icon\"\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\taria-label={`${renameLabel} ${label}`}\n\t\t\t\t\t\t\tonClick={() => setEditing(true)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Pencil />\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t\t{actions && (\n\t\t\t\t\t\t<div className=\"flex shrink-0 items-center gap-basalt-space-sm\">{actions}</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nexport type FolderNavItemProps = EditableNavItemProps;\n/** Folder presentation with an overridable icon; no tree, router or permission model. */\nexport function FolderNavItem({\n\ticon = <Folder className=\"size-basalt-icon-lg\" />,\n\t...props\n}: FolderNavItemProps) {\n\treturn <EditableNavItem icon={icon} {...props} />;\n}\n"],"mappings":";;;;;;;;;;;;AAsCA,SAAgBE,EAAgB,EAC/B,UACA,SACA,aACA,cAAW,IACX,SACA,UACA,YACA,aACA,cAAW,IACX,iBAAc,UACd,eAAY,QACZ,iBAAc,UACd,gBACwB;CACxB,IAAM,CAACC,GAASC,KAAcC,EAAS,EAAK,GACtCC,IAAUC,EAAM,GAChBC,IAASC,EAA0B,IAAI,GACvCC,IAAUD,EAAO,EAAK;CAC5B,QAAsB;EACrB,AAAI,CAACN,KAAWO,EAAQ,YACvB,EAAQ,UAAU,IAClBF,EAAO,SAAS,MAAM;CAExB,GAAG,CAACL,CAAO,CAAC;CACZ,IAAMQ,IACL,kBAAAX,GAAA,EAAA,UAAA;EACEY,KACA,kBAAC,QAAD;GACC,WAAU;GACV,eAAY;GAEX,UAAAA;EACI,CAAA;EAEP,kBAAC,QAAD;GAAM,WAAU;GAAqC,UAAAC;EAAY,CAAA;EAChEC,KAAS,QACT,kBAAC,QAAD;GACC,IAAIR;GACJ,WAAU;GAFX,UAAA,CAIE,KACAQ,CACI;;CAEN,EAAA,CAAA;CAEH,OACC,kBAAC,OAAD;EACC,0BAAwBX,IAAU,KAAA,IAAY;EAC9C,uBAAqBY,KAAY,CAACZ;EAClC,iBAAea,IAAW,KAAK,KAAA;EAC/B,WAAWC,EACVC,GACA,sHACAC,CACD;EAEC,UAAAhB,KAAWiB,IACX,kBAACC,GAAD;GACC,WAAU;GACV,OAAO,GAAGC,EAAY,GAAGT;GACzB,OAAOA;GACP,SAAA;GACA,QAAQO;GACG;GACE;GACH;GACV,kBAAkB,GAAM,MAAW;IAElC,AADA,EAAQ,UAAU,CAACG,KAAQC,MAAW,QACtCpB,EAAWmB,CAAI;GAChB;EACA,CAAA,IAED,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACC,kBAACE,GAAD;KACC,SAAS,CAAC,CAACC;KACX,SAAQ;KACE;KACV,WAAWT,EACVU,GACAC,GACA,2EACD;KACA,gBAAcb,IAAW,SAAS,KAAA;KAClC,cAAYF;KACZ,oBAAkBC,KAAS,OAAiB,KAAA,IAAVR;KAClC,SAASuB;KAER,UAAAH,IACA,kBAACI,GAAD;MAAY;MAAM,WAAU;MAC1B,UAAAnB;KACI,CAAA,IAENA;IAEM,CAAA;IACPS,KACA,kBAACK,GAAD;KACC,KAAKjB;KACL,MAAK;KACL,SAAQ;KACE;KACV,cAAY,GAAGc,EAAY,GAAGT;KAC9B,eAAeT,EAAW,EAAI;KAE9B,UAAA,kBAAC2B,GAAD,CAAS,CAAA;IACF,CAAA;IAERC,KACA,kBAAC,OAAD;KAAK,WAAU;KAAkD,UAAAA;IAAa,CAAA;GAE3E;;CAEF,CAAA;AAEP;AAIA,SAAgBC,EAAc,EAC7B,UAAO,kBAACC,GAAD,EAAQ,WAAU,sBAAuB,CAAA,GAChD,GAAGC,KACmB;CACtB,OAAO,kBAACjC,GAAD;EAAuB;EAAM,GAAIiC;CAAQ,CAAA;AACjD"}
@@ -65,7 +65,7 @@ function u({ label: u, description: d, accept: f = "", multiple: p = !0, maxFile
65
65
  onDrop: (e) => {
66
66
  e.preventDefault(), e.stopPropagation(), T.current = 0, D(!1), j(Array.from(e.dataTransfer.files));
67
67
  },
68
- className: e("flex w-full min-w-0 flex-col items-center gap-basalt-space-lg rounded-basalt-lg border-2 border-dashed px-basalt-card py-basalt-card text-center transition-colors basalt-motion focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-basalt-ring disabled:cursor-not-allowed disabled:opacity-50", E && !_ ? "border-basalt-primary bg-basalt-selected" : "border-basalt-border bg-basalt-control hover:bg-basalt-hover"),
68
+ className: e("basalt-focus flex w-full min-w-0 flex-col items-center gap-basalt-space-lg rounded-basalt-lg border-2 border-dashed px-basalt-card py-basalt-card text-center transition-colors basalt-motion disabled:cursor-not-allowed disabled:opacity-50", E && !_ ? "border-basalt-primary bg-basalt-selected" : "border-basalt-border bg-basalt-control hover:bg-basalt-hover"),
69
69
  children: [
70
70
  /* @__PURE__ */ o(a, {
71
71
  className: "size-basalt-icon-display text-basalt-muted-foreground",
@@ -1 +1 @@
1
- {"version":3,"file":"file-dropzone.js","names":["accepts","rules","accept","rule","file","REASONS","FileDropzone","input","useRef","depth","dragging","setDragging","useState","rejections","setRejections","id","useId","receive","disabled","accepted","rejected","limit","multiple","maxFiles","files","code","maxSize","fileCount","onFilesAccepted","onFilesRejected","label","cn","BASALT_UI_CLASS","className","event","browseLabel","description","Upload","dropLabel","formatRejection","item","index"],"sources":["../../src/components/file-dropzone.tsx"],"sourcesContent":["import { Upload } from \"lucide-react\";\nimport { useId, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport interface FileRejection {\n\t/** Original File; the component never creates preview URLs. */\n\tfile: File;\n\t/** Machine-readable reason for application handling. */\n\tcode: \"file-invalid-type\" | \"file-too-large\" | \"too-many-files\";\n}\n\nexport interface FileDropzoneProps {\n\t/** Visible and accessible upload field name. */\n\tlabel: string;\n\t/** Optional file requirements shown under the label. */\n\tdescription?: string;\n\t/** Accepted extensions/MIME types using native accept syntax, e.g. .pdf,image/*. */\n\taccept?: string;\n\t/** Allow multiple files. @default true */\n\tmultiple?: boolean;\n\t/** Maximum accepted file count including fileCount. @default Infinity */\n\tmaxFiles?: number;\n\t/** Number already held by the application. @default 0 */\n\tfileCount?: number;\n\t/** Maximum size of an individual file in bytes. @default Infinity */\n\tmaxSize?: number;\n\t/** Prevent both file browsing and drops. @default false */\n\tdisabled?: boolean;\n\t/** Accepted files from this gesture; transport and queue ownership belong to the caller. */\n\tonFilesAccepted: (files: File[]) => void;\n\t/** Rejected files from this gesture, with one primary reason per file. */\n\tonFilesRejected?: (rejections: FileRejection[]) => void;\n\t/** Browse action text. @default \"Browse files\" */\n\tbrowseLabel?: string;\n\t/** Text while a file is dragged over the field. @default \"Drop files here\" */\n\tdropLabel?: string;\n\t/** Localized rejection message; defaults to a name and reason. */\n\tformatRejection?: (rejection: FileRejection) => string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\nfunction accepts(file: File, accept: string) {\n\tconst rules = accept\n\t\t.split(\",\")\n\t\t.map((rule) => rule.trim().toLowerCase())\n\t\t.filter(Boolean);\n\treturn (\n\t\trules.length === 0 ||\n\t\trules.some((rule) =>\n\t\t\trule.startsWith(\".\")\n\t\t\t\t? file.name.toLowerCase().endsWith(rule)\n\t\t\t\t: rule.endsWith(\"/*\")\n\t\t\t\t\t? file.type.toLowerCase().startsWith(rule.slice(0, -1))\n\t\t\t\t\t: file.type.toLowerCase() === rule,\n\t\t)\n\t);\n}\n\nconst REASONS = {\n\t\"file-invalid-type\": \"File type is not accepted.\",\n\t\"file-too-large\": \"File exceeds the size limit.\",\n\t\"too-many-files\": \"File count limit reached.\",\n};\n\nexport function FileDropzone({\n\tlabel,\n\tdescription,\n\taccept = \"\",\n\tmultiple = true,\n\tmaxFiles = Infinity,\n\tfileCount = 0,\n\tmaxSize = Infinity,\n\tdisabled = false,\n\tonFilesAccepted,\n\tonFilesRejected,\n\tbrowseLabel = \"Browse files\",\n\tdropLabel = \"Drop files here\",\n\tformatRejection,\n\tclassName,\n}: FileDropzoneProps) {\n\tconst input = useRef<HTMLInputElement>(null);\n\tconst depth = useRef(0);\n\tconst [dragging, setDragging] = useState(false);\n\tconst [rejections, setRejections] = useState<FileRejection[]>([]);\n\tconst id = useId();\n\tfunction receive(files: File[]) {\n\t\tif (disabled) return;\n\t\tconst accepted: File[] = [];\n\t\tconst rejected: FileRejection[] = [];\n\t\tconst limit = Math.max(0, multiple ? maxFiles : Math.min(1, maxFiles));\n\t\tfor (const file of files) {\n\t\t\tconst code = !accepts(file, accept)\n\t\t\t\t? \"file-invalid-type\"\n\t\t\t\t: file.size > maxSize\n\t\t\t\t\t? \"file-too-large\"\n\t\t\t\t\t: accepted.length + fileCount >= limit\n\t\t\t\t\t\t? \"too-many-files\"\n\t\t\t\t\t\t: null;\n\t\t\tif (code) rejected.push({ file, code });\n\t\t\telse accepted.push(file);\n\t\t}\n\t\tsetRejections(rejected);\n\t\tif (accepted.length) onFilesAccepted(accepted);\n\t\tif (rejected.length) onFilesRejected?.(rejected);\n\t}\n\treturn (\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-label={label}\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"min-w-0 space-y-basalt-space-lg\", className)}\n\t\t>\n\t\t\t<input\n\t\t\t\tref={input}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={accept}\n\t\t\t\tmultiple={multiple}\n\t\t\t\tdisabled={disabled}\n\t\t\t\ttabIndex={-1}\n\t\t\t\taria-label={label}\n\t\t\t\tclassName=\"hidden\"\n\t\t\t\tonChange={(event) => {\n\t\t\t\t\treceive(Array.from(event.currentTarget.files ?? []));\n\t\t\t\t\tevent.currentTarget.value = \"\";\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tdisabled={disabled}\n\t\t\t\taria-label={`${browseLabel}: ${label}`}\n\t\t\t\taria-describedby={description ? `${id}-description` : undefined}\n\t\t\t\tdata-drag-active={dragging && !disabled}\n\t\t\t\tonClick={() => input.current?.click()}\n\t\t\t\tonDragEnter={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tdepth.current += 1;\n\t\t\t\t\tif (!disabled) setDragging(true);\n\t\t\t\t}}\n\t\t\t\tonDragOver={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tif (!disabled) event.dataTransfer.dropEffect = \"copy\";\n\t\t\t\t}}\n\t\t\t\tonDragLeave={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tdepth.current = Math.max(0, depth.current - 1);\n\t\t\t\t\tif (depth.current === 0) setDragging(false);\n\t\t\t\t}}\n\t\t\t\tonDrop={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\tdepth.current = 0;\n\t\t\t\t\tsetDragging(false);\n\t\t\t\t\treceive(Array.from(event.dataTransfer.files));\n\t\t\t\t}}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex w-full min-w-0 flex-col items-center gap-basalt-space-lg rounded-basalt-lg border-2 border-dashed px-basalt-card py-basalt-card text-center transition-colors basalt-motion focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-basalt-ring disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tdragging && !disabled\n\t\t\t\t\t\t? \"border-basalt-primary bg-basalt-selected\"\n\t\t\t\t\t\t: \"border-basalt-border bg-basalt-control hover:bg-basalt-hover\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Upload\n\t\t\t\t\tclassName=\"size-basalt-icon-display text-basalt-muted-foreground\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t/>\n\t\t\t\t<span className=\"text-basalt-base font-medium\">\n\t\t\t\t\t{dragging && !disabled ? dropLabel : label}\n\t\t\t\t</span>\n\t\t\t\t{description && (\n\t\t\t\t\t<span id={`${id}-description`} className=\"text-basalt-sm text-basalt-muted-foreground\">\n\t\t\t\t\t\t{description}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t\t<span className=\"rounded-basalt-md border border-basalt-border px-basalt-space-lg py-basalt-space-sm text-basalt-sm\">\n\t\t\t\t\t{browseLabel}\n\t\t\t\t</span>\n\t\t\t</button>\n\t\t\t{rejections.length > 0 && (\n\t\t\t\t<ul role=\"alert\" className=\"space-y-basalt-space-sm text-basalt-sm text-basalt-destructive\">\n\t\t\t\t\t{rejections.map((item, index) => (\n\t\t\t\t\t\t<li key={`${item.file.name}-${index}`} className=\"break-words\">\n\t\t\t\t\t\t\t{formatRejection ? formatRejection(item) : `${item.file.name}: ${REASONS[item.code]}`}\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"file-dropzone.js","names":["accepts","rules","accept","rule","file","REASONS","FileDropzone","input","useRef","depth","dragging","setDragging","useState","rejections","setRejections","id","useId","receive","disabled","accepted","rejected","limit","multiple","maxFiles","files","code","maxSize","fileCount","onFilesAccepted","onFilesRejected","label","cn","BASALT_UI_CLASS","className","event","browseLabel","description","Upload","dropLabel","formatRejection","item","index"],"sources":["../../src/components/file-dropzone.tsx"],"sourcesContent":["import { Upload } from \"lucide-react\";\nimport { useId, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport interface FileRejection {\n\t/** Original File; the component never creates preview URLs. */\n\tfile: File;\n\t/** Machine-readable reason for application handling. */\n\tcode: \"file-invalid-type\" | \"file-too-large\" | \"too-many-files\";\n}\n\nexport interface FileDropzoneProps {\n\t/** Visible and accessible upload field name. */\n\tlabel: string;\n\t/** Optional file requirements shown under the label. */\n\tdescription?: string;\n\t/** Accepted extensions/MIME types using native accept syntax, e.g. .pdf,image/*. */\n\taccept?: string;\n\t/** Allow multiple files. @default true */\n\tmultiple?: boolean;\n\t/** Maximum accepted file count including fileCount. @default Infinity */\n\tmaxFiles?: number;\n\t/** Number already held by the application. @default 0 */\n\tfileCount?: number;\n\t/** Maximum size of an individual file in bytes. @default Infinity */\n\tmaxSize?: number;\n\t/** Prevent both file browsing and drops. @default false */\n\tdisabled?: boolean;\n\t/** Accepted files from this gesture; transport and queue ownership belong to the caller. */\n\tonFilesAccepted: (files: File[]) => void;\n\t/** Rejected files from this gesture, with one primary reason per file. */\n\tonFilesRejected?: (rejections: FileRejection[]) => void;\n\t/** Browse action text. @default \"Browse files\" */\n\tbrowseLabel?: string;\n\t/** Text while a file is dragged over the field. @default \"Drop files here\" */\n\tdropLabel?: string;\n\t/** Localized rejection message; defaults to a name and reason. */\n\tformatRejection?: (rejection: FileRejection) => string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\nfunction accepts(file: File, accept: string) {\n\tconst rules = accept\n\t\t.split(\",\")\n\t\t.map((rule) => rule.trim().toLowerCase())\n\t\t.filter(Boolean);\n\treturn (\n\t\trules.length === 0 ||\n\t\trules.some((rule) =>\n\t\t\trule.startsWith(\".\")\n\t\t\t\t? file.name.toLowerCase().endsWith(rule)\n\t\t\t\t: rule.endsWith(\"/*\")\n\t\t\t\t\t? file.type.toLowerCase().startsWith(rule.slice(0, -1))\n\t\t\t\t\t: file.type.toLowerCase() === rule,\n\t\t)\n\t);\n}\n\nconst REASONS = {\n\t\"file-invalid-type\": \"File type is not accepted.\",\n\t\"file-too-large\": \"File exceeds the size limit.\",\n\t\"too-many-files\": \"File count limit reached.\",\n};\n\nexport function FileDropzone({\n\tlabel,\n\tdescription,\n\taccept = \"\",\n\tmultiple = true,\n\tmaxFiles = Infinity,\n\tfileCount = 0,\n\tmaxSize = Infinity,\n\tdisabled = false,\n\tonFilesAccepted,\n\tonFilesRejected,\n\tbrowseLabel = \"Browse files\",\n\tdropLabel = \"Drop files here\",\n\tformatRejection,\n\tclassName,\n}: FileDropzoneProps) {\n\tconst input = useRef<HTMLInputElement>(null);\n\tconst depth = useRef(0);\n\tconst [dragging, setDragging] = useState(false);\n\tconst [rejections, setRejections] = useState<FileRejection[]>([]);\n\tconst id = useId();\n\tfunction receive(files: File[]) {\n\t\tif (disabled) return;\n\t\tconst accepted: File[] = [];\n\t\tconst rejected: FileRejection[] = [];\n\t\tconst limit = Math.max(0, multiple ? maxFiles : Math.min(1, maxFiles));\n\t\tfor (const file of files) {\n\t\t\tconst code = !accepts(file, accept)\n\t\t\t\t? \"file-invalid-type\"\n\t\t\t\t: file.size > maxSize\n\t\t\t\t\t? \"file-too-large\"\n\t\t\t\t\t: accepted.length + fileCount >= limit\n\t\t\t\t\t\t? \"too-many-files\"\n\t\t\t\t\t\t: null;\n\t\t\tif (code) rejected.push({ file, code });\n\t\t\telse accepted.push(file);\n\t\t}\n\t\tsetRejections(rejected);\n\t\tif (accepted.length) onFilesAccepted(accepted);\n\t\tif (rejected.length) onFilesRejected?.(rejected);\n\t}\n\treturn (\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-label={label}\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"min-w-0 space-y-basalt-space-lg\", className)}\n\t\t>\n\t\t\t<input\n\t\t\t\tref={input}\n\t\t\t\ttype=\"file\"\n\t\t\t\taccept={accept}\n\t\t\t\tmultiple={multiple}\n\t\t\t\tdisabled={disabled}\n\t\t\t\ttabIndex={-1}\n\t\t\t\taria-label={label}\n\t\t\t\tclassName=\"hidden\"\n\t\t\t\tonChange={(event) => {\n\t\t\t\t\treceive(Array.from(event.currentTarget.files ?? []));\n\t\t\t\t\tevent.currentTarget.value = \"\";\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tdisabled={disabled}\n\t\t\t\taria-label={`${browseLabel}: ${label}`}\n\t\t\t\taria-describedby={description ? `${id}-description` : undefined}\n\t\t\t\tdata-drag-active={dragging && !disabled}\n\t\t\t\tonClick={() => input.current?.click()}\n\t\t\t\tonDragEnter={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tdepth.current += 1;\n\t\t\t\t\tif (!disabled) setDragging(true);\n\t\t\t\t}}\n\t\t\t\tonDragOver={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tif (!disabled) event.dataTransfer.dropEffect = \"copy\";\n\t\t\t\t}}\n\t\t\t\tonDragLeave={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tdepth.current = Math.max(0, depth.current - 1);\n\t\t\t\t\tif (depth.current === 0) setDragging(false);\n\t\t\t\t}}\n\t\t\t\tonDrop={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\tdepth.current = 0;\n\t\t\t\t\tsetDragging(false);\n\t\t\t\t\treceive(Array.from(event.dataTransfer.files));\n\t\t\t\t}}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"basalt-focus flex w-full min-w-0 flex-col items-center gap-basalt-space-lg rounded-basalt-lg border-2 border-dashed px-basalt-card py-basalt-card text-center transition-colors basalt-motion disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tdragging && !disabled\n\t\t\t\t\t\t? \"border-basalt-primary bg-basalt-selected\"\n\t\t\t\t\t\t: \"border-basalt-border bg-basalt-control hover:bg-basalt-hover\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Upload\n\t\t\t\t\tclassName=\"size-basalt-icon-display text-basalt-muted-foreground\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t/>\n\t\t\t\t<span className=\"text-basalt-base font-medium\">\n\t\t\t\t\t{dragging && !disabled ? dropLabel : label}\n\t\t\t\t</span>\n\t\t\t\t{description && (\n\t\t\t\t\t<span id={`${id}-description`} className=\"text-basalt-sm text-basalt-muted-foreground\">\n\t\t\t\t\t\t{description}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t\t<span className=\"rounded-basalt-md border border-basalt-border px-basalt-space-lg py-basalt-space-sm text-basalt-sm\">\n\t\t\t\t\t{browseLabel}\n\t\t\t\t</span>\n\t\t\t</button>\n\t\t\t{rejections.length > 0 && (\n\t\t\t\t<ul role=\"alert\" className=\"space-y-basalt-space-sm text-basalt-sm text-basalt-destructive\">\n\t\t\t\t\t{rejections.map((item, index) => (\n\t\t\t\t\t\t<li key={`${item.file.name}-${index}`} className=\"break-words\">\n\t\t\t\t\t\t\t{formatRejection ? formatRejection(item) : `${item.file.name}: ${REASONS[item.code]}`}\n\t\t\t\t\t\t</li>\n\t\t\t\t\t))}\n\t\t\t\t</ul>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
@@ -38,7 +38,7 @@ function s({ label: n, value: o, onRemove: s, removeLabel: c, disabled: l = !1,
38
38
  disabled: l,
39
39
  "aria-label": c ?? `Remove ${n}`,
40
40
  onClick: s,
41
- className: "shrink-0 rounded-basalt-full p-basalt-space-sm focus-visible:outline-2 focus-visible:outline-basalt-ring disabled:opacity-50",
41
+ className: "basalt-focus basalt-focus-inset shrink-0 rounded-basalt-full p-basalt-space-sm disabled:opacity-50",
42
42
  children: /* @__PURE__ */ i(r, {
43
43
  className: "size-basalt-icon-sm",
44
44
  "aria-hidden": "true"
@@ -1 +1 @@
1
- {"version":3,"file":"filter-bar.js","names":["FilterBar","label","cn","BASALT_UI_CLASS","className","children","active","onClear","Button","clearLabel","chips","FilterChip","value","removeLabel","onRemove","X"],"sources":["../../src/components/filter-bar.tsx"],"sourcesContent":["import { X } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Button } from \"./button\";\n\nexport interface FilterBarProps {\n\t/** Accessible group name. */\n\tlabel: string;\n\t/** Application-owned search, select, and date controls. */\n\tchildren: ReactNode;\n\t/** Active chips, shown on their own wrapping row. */\n\tchips?: ReactNode;\n\t/** Whether the clear action is available. @default false */\n\tactive?: boolean;\n\t/** Requests clearing application-owned filters. */\n\tonClear?: () => void;\n\t/** Clear action text. @default \"Clear filters\" */\n\tclearLabel?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\n/** Layout only; URL serialization, query execution, and date presets belong to the caller. */\nexport function FilterBar({\n\tlabel,\n\tchildren,\n\tchips,\n\tactive = false,\n\tonClear,\n\tclearLabel = \"Clear filters\",\n\tclassName,\n}: FilterBarProps) {\n\treturn (\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-label={label}\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"min-w-0 space-y-basalt-space-lg\", className)}\n\t\t>\n\t\t\t<div className=\"flex flex-wrap items-end gap-basalt-space-lg [&>*]:min-w-0\">\n\t\t\t\t{children}\n\t\t\t\t{active && onClear && (\n\t\t\t\t\t<Button size=\"sm\" variant=\"ghost\" onClick={onClear}>\n\t\t\t\t\t\t{clearLabel}\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t{chips != null && (\n\t\t\t\t<div className=\"flex flex-wrap items-center gap-basalt-space-lg\">{chips}</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nexport interface FilterChipProps {\n\t/** Filter dimension, e.g. Status. */\n\tlabel: string;\n\t/** Display value. */\n\tvalue: ReactNode;\n\t/** Requests removal from the application's filter state. */\n\tonRemove: () => void;\n\t/** Full accessible removal label; defaults to Remove plus the dimension label. */\n\tremoveLabel?: string;\n\t/** Disable removal. @default false */\n\tdisabled?: boolean;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\nexport function FilterChip({\n\tlabel,\n\tvalue,\n\tonRemove,\n\tremoveLabel,\n\tdisabled = false,\n\tclassName,\n}: FilterChipProps) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"inline-flex max-w-full items-center gap-basalt-space-sm rounded-basalt-full border border-basalt-border bg-basalt-selected py-basalt-space-sm pl-basalt-space-lg pr-basalt-space-sm text-basalt-sm\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"min-w-0 break-words\">\n\t\t\t\t<span className=\"text-basalt-muted-foreground\">{label}: </span>\n\t\t\t\t{value}\n\t\t\t</span>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tdisabled={disabled}\n\t\t\t\taria-label={removeLabel ?? `Remove ${label}`}\n\t\t\t\tonClick={onRemove}\n\t\t\t\tclassName=\"shrink-0 rounded-basalt-full p-basalt-space-sm focus-visible:outline-2 focus-visible:outline-basalt-ring disabled:opacity-50\"\n\t\t\t>\n\t\t\t\t<X className=\"size-basalt-icon-sm\" aria-hidden=\"true\" />\n\t\t\t</button>\n\t\t</span>\n\t);\n}\n"],"mappings":";;;;;;;AAwBA,SAAgBA,EAAU,EACzB,UACA,aACA,UACA,YAAS,IACT,YACA,gBAAa,iBACb,gBACkB;CAClB,OACC,kBAAC,OAAD;EACC,MAAK;EACL,cAAYC;EACZ,WAAWC,EAAGC,GAAiB,mCAAmCC,CAAS;EAH5E,UAAA,CAKC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACEC,GACAC,KAAUC,KACV,kBAACC,GAAD;IAAQ,MAAK;IAAK,SAAQ;IAAQ,SAASD;IACzC,UAAAE;GACM,CAAA,CAEL;EACJ,CAAA,GAAAC,KAAS,QACT,kBAAC,OAAD;GAAK,WAAU;GAAmD,UAAAA;EAAW,CAAA,CAE1E;;AAEP;AAiBA,SAAgBC,EAAW,EAC1B,UACA,UACA,aACA,gBACA,cAAW,IACX,gBACmB;CACnB,OACC,kBAAC,QAAD;EACC,WAAWT,EACVC,GACA,sMACAC,CACD;EALD,UAAA,CAOC,kBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACC,kBAAC,QAAD;IAAM,WAAU;IAAhB,UAAA,CAAgDH,GAAM,IAAQ;GAC7D,CAAA,GAAAW,CACI;EACN,CAAA,GAAA,kBAAC,UAAD;GACC,MAAK;GACK;GACV,cAAYC,KAAe,UAAUZ;GACrC,SAASa;GACT,WAAU;GAEV,UAAA,kBAACC,GAAD;IAAG,WAAU;IAAsB,eAAY;GAAQ,CAAA;EAChD,CAAA,CACH;;AAER"}
1
+ {"version":3,"file":"filter-bar.js","names":["FilterBar","label","cn","BASALT_UI_CLASS","className","children","active","onClear","Button","clearLabel","chips","FilterChip","value","removeLabel","onRemove","X"],"sources":["../../src/components/filter-bar.tsx"],"sourcesContent":["import { X } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Button } from \"./button\";\n\nexport interface FilterBarProps {\n\t/** Accessible group name. */\n\tlabel: string;\n\t/** Application-owned search, select, and date controls. */\n\tchildren: ReactNode;\n\t/** Active chips, shown on their own wrapping row. */\n\tchips?: ReactNode;\n\t/** Whether the clear action is available. @default false */\n\tactive?: boolean;\n\t/** Requests clearing application-owned filters. */\n\tonClear?: () => void;\n\t/** Clear action text. @default \"Clear filters\" */\n\tclearLabel?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\n/** Layout only; URL serialization, query execution, and date presets belong to the caller. */\nexport function FilterBar({\n\tlabel,\n\tchildren,\n\tchips,\n\tactive = false,\n\tonClear,\n\tclearLabel = \"Clear filters\",\n\tclassName,\n}: FilterBarProps) {\n\treturn (\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-label={label}\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"min-w-0 space-y-basalt-space-lg\", className)}\n\t\t>\n\t\t\t<div className=\"flex flex-wrap items-end gap-basalt-space-lg [&>*]:min-w-0\">\n\t\t\t\t{children}\n\t\t\t\t{active && onClear && (\n\t\t\t\t\t<Button size=\"sm\" variant=\"ghost\" onClick={onClear}>\n\t\t\t\t\t\t{clearLabel}\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t{chips != null && (\n\t\t\t\t<div className=\"flex flex-wrap items-center gap-basalt-space-lg\">{chips}</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nexport interface FilterChipProps {\n\t/** Filter dimension, e.g. Status. */\n\tlabel: string;\n\t/** Display value. */\n\tvalue: ReactNode;\n\t/** Requests removal from the application's filter state. */\n\tonRemove: () => void;\n\t/** Full accessible removal label; defaults to Remove plus the dimension label. */\n\tremoveLabel?: string;\n\t/** Disable removal. @default false */\n\tdisabled?: boolean;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\nexport function FilterChip({\n\tlabel,\n\tvalue,\n\tonRemove,\n\tremoveLabel,\n\tdisabled = false,\n\tclassName,\n}: FilterChipProps) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"inline-flex max-w-full items-center gap-basalt-space-sm rounded-basalt-full border border-basalt-border bg-basalt-selected py-basalt-space-sm pl-basalt-space-lg pr-basalt-space-sm text-basalt-sm\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"min-w-0 break-words\">\n\t\t\t\t<span className=\"text-basalt-muted-foreground\">{label}: </span>\n\t\t\t\t{value}\n\t\t\t</span>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tdisabled={disabled}\n\t\t\t\taria-label={removeLabel ?? `Remove ${label}`}\n\t\t\t\tonClick={onRemove}\n\t\t\t\tclassName=\"basalt-focus basalt-focus-inset shrink-0 rounded-basalt-full p-basalt-space-sm disabled:opacity-50\"\n\t\t\t>\n\t\t\t\t<X className=\"size-basalt-icon-sm\" aria-hidden=\"true\" />\n\t\t\t</button>\n\t\t</span>\n\t);\n}\n"],"mappings":";;;;;;;AAwBA,SAAgBA,EAAU,EACzB,UACA,aACA,UACA,YAAS,IACT,YACA,gBAAa,iBACb,gBACkB;CAClB,OACC,kBAAC,OAAD;EACC,MAAK;EACL,cAAYC;EACZ,WAAWC,EAAGC,GAAiB,mCAAmCC,CAAS;EAH5E,UAAA,CAKC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACEC,GACAC,KAAUC,KACV,kBAACC,GAAD;IAAQ,MAAK;IAAK,SAAQ;IAAQ,SAASD;IACzC,UAAAE;GACM,CAAA,CAEL;EACJ,CAAA,GAAAC,KAAS,QACT,kBAAC,OAAD;GAAK,WAAU;GAAmD,UAAAA;EAAW,CAAA,CAE1E;;AAEP;AAiBA,SAAgBC,EAAW,EAC1B,UACA,UACA,aACA,gBACA,cAAW,IACX,gBACmB;CACnB,OACC,kBAAC,QAAD;EACC,WAAWT,EACVC,GACA,sMACAC,CACD;EALD,UAAA,CAOC,kBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACC,kBAAC,QAAD;IAAM,WAAU;IAAhB,UAAA,CAAgDH,GAAM,IAAQ;GAC7D,CAAA,GAAAW,CACI;EACN,CAAA,GAAA,kBAAC,UAAD;GACC,MAAK;GACK;GACV,cAAYC,KAAe,UAAUZ;GACrC,SAASa;GACT,WAAU;GAEV,UAAA,kBAACC,GAAD;IAAG,WAAU;IAAsB,eAAY;GAAQ,CAAA;EAChD,CAAA,CACH;;AAER"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn as e } from "../utils/cn.js";
3
3
  import { BASALT_UI_CLASS as t } from "../utils/control-surface.js";
4
- import { FOCUS_INSET as n } from "./overlay.js";
4
+ import { FOCUS_RING as n } from "./overlay.js";
5
5
  import { Button as r } from "./button.js";
6
6
  import { Input as i } from "./input.js";
7
7
  import { Popover as a, PopoverContent as o, PopoverTrigger as s } from "./popover.js";
@@ -63,7 +63,7 @@ function h({ label: h, options: g, value: _, defaultValue: v = "", onValueChange
63
63
  type: "single",
64
64
  "aria-label": h,
65
65
  value: P,
66
- className: "grid max-h-basalt-64 grid-cols-2 gap-basalt-space-lg overflow-y-auto",
66
+ className: "grid max-h-basalt-64 grid-cols-2 gap-basalt-space-lg overflow-y-auto p-basalt-space-sm",
67
67
  onValueChange: (e) => {
68
68
  e && (_ === void 0 && k(e), y?.(e), j(!1), N(""));
69
69
  },
@@ -72,7 +72,7 @@ function h({ label: h, options: g, value: _, defaultValue: v = "", onValueChange
72
72
  disabled: t.disabled,
73
73
  "aria-label": t.label,
74
74
  title: t.label,
75
- className: e("group relative flex min-w-0 flex-col items-center justify-center gap-basalt-space-lg rounded-basalt-md p-basalt-layout-sm text-basalt-foreground data-[state=on]:bg-basalt-primary data-[state=on]:text-basalt-primary-foreground disabled:cursor-not-allowed disabled:opacity-40", n, "data-[state=on]:focus-visible:ring-basalt-primary-foreground"),
75
+ className: e("group relative flex min-w-0 flex-col items-center justify-center gap-basalt-space-lg rounded-basalt-md p-basalt-layout-sm text-basalt-foreground data-[state=on]:bg-basalt-primary data-[state=on]:text-basalt-primary-foreground disabled:cursor-not-allowed disabled:opacity-40", n),
76
76
  children: [
77
77
  /* @__PURE__ */ f("span", {
78
78
  "aria-hidden": "true",
@@ -1 +1 @@
1
- {"version":3,"file":"icon-picker.js","names":["ToggleGroupPrimitive","IconPicker","ariaInvalid","describedBy","localValue","setLocalValue","useState","defaultValue","open","setOpen","query","setQuery","selected","value","option","options","matches","Popover","disabled","next","PopoverTrigger","Button","label","placeholder","cn","BASALT_UI_CLASS","className","ChevronDown","PopoverContent","Search","Input","searchPlaceholder","event","onValueChange","item","FOCUS_INSET","Check","emptyLabel"],"sources":["../../src/components/icon-picker.tsx"],"sourcesContent":["import * as ToggleGroupPrimitive from \"@radix-ui/react-toggle-group\";\nimport { Check, ChevronDown, Search } from \"lucide-react\";\nimport { type AriaAttributes, type ReactNode, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Button } from \"./button\";\nimport { Input } from \"./input\";\nimport { FOCUS_INSET } from \"./overlay\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\n\nexport interface IconPickerOption {\n\t/** Stable application-owned identifier. */\n\tvalue: string;\n\t/** Visible selection text and accessible icon name. */\n\tlabel: string;\n\t/** Caller-rendered icon, from a deliberately small subset. */\n\ticon: ReactNode;\n\t/** Exclude this option from selection and keyboard navigation. */\n\tdisabled?: boolean;\n}\nexport interface IconPickerProps {\n\t/** Accessible picker name. */\n\tlabel: string;\n\t/** Caller-supplied icon subset; the library never imports an icon catalog. */\n\toptions: readonly IconPickerOption[];\n\t/** Controlled icon identifier. */\n\tvalue?: string;\n\t/** Initial uncontrolled icon identifier. */\n\tdefaultValue?: string;\n\t/** Selection request. */\n\tonValueChange?: (value: string) => void;\n\t/** Disable selection. @default false */\n\tdisabled?: boolean;\n\t/** Empty selection prompt. @default \"Choose icon\" */\n\tplaceholder?: string;\n\t/** Search placeholder. @default \"Search icons…\" */\n\tsearchPlaceholder?: string;\n\t/** Empty-search text. @default \"No icons found.\" */\n\temptyLabel?: string;\n\t/** Forwarded to the trigger so Field and Label can own it. */\n\tid?: string;\n\t/** Forwarded to the trigger; Field sets it while the value is invalid. */\n\t\"aria-invalid\"?: AriaAttributes[\"aria-invalid\"];\n\t/** Forwarded to the trigger; Field points it at the hint or error. */\n\t\"aria-describedby\"?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\nexport function IconPicker({\n\tlabel,\n\toptions,\n\tvalue,\n\tdefaultValue = \"\",\n\tonValueChange,\n\tdisabled = false,\n\tplaceholder = \"Choose icon\",\n\tsearchPlaceholder = \"Search icons…\",\n\temptyLabel = \"No icons found.\",\n\tid,\n\t\"aria-invalid\": ariaInvalid,\n\t\"aria-describedby\": describedBy,\n\tclassName,\n}: IconPickerProps) {\n\tconst [localValue, setLocalValue] = useState(defaultValue);\n\tconst [open, setOpen] = useState(false);\n\tconst [query, setQuery] = useState(\"\");\n\tconst selected = value ?? localValue;\n\tconst option = options.find((option) => option.value === selected);\n\tconst matches = options.filter((option) =>\n\t\toption.label.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()),\n\t);\n\treturn (\n\t\t<Popover\n\t\t\topen={open && !disabled}\n\t\t\tonOpenChange={(next) => {\n\t\t\t\tsetOpen(next);\n\t\t\t\tif (!next) setQuery(\"\");\n\t\t\t}}\n\t\t>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tid={id}\n\t\t\t\t\taria-invalid={ariaInvalid}\n\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\taria-label={`${label}: ${option?.label ?? placeholder}`}\n\t\t\t\t\tclassName={cn(BASALT_UI_CLASS, \"max-w-full\", className)}\n\t\t\t\t>\n\t\t\t\t\t<span aria-hidden=\"true\" className=\"shrink-0\">\n\t\t\t\t\t\t{option?.icon}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"truncate\">{option?.label ?? placeholder}</span>\n\t\t\t\t\t<ChevronDown className=\"shrink-0\" />\n\t\t\t\t</Button>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent\n\t\t\t\talign=\"start\"\n\t\t\t\tarrow={false}\n\t\t\t\tclassName=\"w-basalt-72 max-w-[calc(100vw-2rem)] space-y-basalt-layout-sm\"\n\t\t\t\taria-label={label}\n\t\t\t>\n\t\t\t\t<div className=\"relative\">\n\t\t\t\t\t<Search\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclassName=\"pointer-events-none absolute left-basalt-space-lg top-1/2 size-basalt-icon -translate-y-1/2 text-basalt-muted-foreground\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tclassName=\"pl-basalt-card-xl\"\n\t\t\t\t\t\taria-label={`${label}: search`}\n\t\t\t\t\t\tvalue={query}\n\t\t\t\t\t\tplaceholder={searchPlaceholder}\n\t\t\t\t\t\tonChange={(event) => setQuery(event.target.value)}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<ToggleGroupPrimitive.Root\n\t\t\t\t\ttype=\"single\"\n\t\t\t\t\taria-label={label}\n\t\t\t\t\tvalue={selected}\n\t\t\t\t\tclassName=\"grid max-h-basalt-64 grid-cols-2 gap-basalt-space-lg overflow-y-auto\"\n\t\t\t\t\tonValueChange={(next) => {\n\t\t\t\t\t\tif (!next) return;\n\t\t\t\t\t\tif (value === undefined) setLocalValue(next);\n\t\t\t\t\t\tonValueChange?.(next);\n\t\t\t\t\t\tsetOpen(false);\n\t\t\t\t\t\tsetQuery(\"\");\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{matches.map((item) => (\n\t\t\t\t\t\t<ToggleGroupPrimitive.Item\n\t\t\t\t\t\t\tkey={item.value}\n\t\t\t\t\t\t\tvalue={item.value}\n\t\t\t\t\t\t\tdisabled={item.disabled}\n\t\t\t\t\t\t\taria-label={item.label}\n\t\t\t\t\t\t\ttitle={item.label}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t// Accent choice grid: selection is the documented primary fill and its\n\t\t\t\t\t\t\t\t// contrast-corrected foreground, never a control fill plus a frame.\n\t\t\t\t\t\t\t\t\"group relative flex min-w-0 flex-col items-center justify-center gap-basalt-space-lg rounded-basalt-md p-basalt-layout-sm text-basalt-foreground data-[state=on]:bg-basalt-primary data-[state=on]:text-basalt-primary-foreground disabled:cursor-not-allowed disabled:opacity-40\",\n\t\t\t\t\t\t\t\tFOCUS_INSET,\n\t\t\t\t\t\t\t\t\"data-[state=on]:focus-visible:ring-basalt-primary-foreground\",\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclassName=\"flex size-basalt-6 items-center justify-center [&>svg]:size-basalt-6\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{item.icon}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span className=\"max-w-full break-words text-basalt-sm font-medium\">\n\t\t\t\t\t\t\t\t{item.label}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<Check\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclassName=\"absolute right-basalt-space-sm top-basalt-space-sm size-basalt-icon-sm opacity-0 group-data-[state=on]:opacity-100\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</ToggleGroupPrimitive.Item>\n\t\t\t\t\t))}\n\t\t\t\t</ToggleGroupPrimitive.Root>\n\t\t\t\t{matches.length === 0 && (\n\t\t\t\t\t<p role=\"status\" className=\"text-basalt-base text-basalt-muted-foreground\">\n\t\t\t\t\t\t{emptyLabel}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;AAgDA,SAAgBC,EAAW,EAC1B,UACA,YACA,UACA,kBAAe,IACf,kBACA,cAAW,IACX,iBAAc,eACd,uBAAoB,iBACpB,gBAAa,mBACb,OACA,gBAAgBC,GAChB,oBAAoBC,GACpB,gBACmB;CACnB,IAAM,CAACC,GAAYC,KAAiBC,EAASC,CAAY,GACnD,CAACC,GAAMC,KAAWH,EAAS,EAAK,GAChC,CAACI,GAAOC,KAAYL,EAAS,EAAE,GAC/BM,IAAWC,KAAST,GACpBU,IAASC,EAAQ,MAAM,MAAWD,EAAO,UAAUF,CAAQ,GAC3DI,IAAUD,EAAQ,QAAQ,MAC/BD,EAAO,MAAM,kBAAkB,CAAC,CAAC,SAASJ,EAAM,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAC3E;CACA,OACC,kBAACO,GAAD;EACC,MAAMT,KAAQ,CAACU;EACf,eAAe,MAAS;GAEvB,AADAT,EAAQU,CAAI,GACPA,KAAMR,EAAS,EAAE;EACvB;EALD,UAAA,CAOC,kBAACS,GAAD;GAAgB,SAAA;GACf,UAAA,kBAACC,GAAD;IACC,SAAQ;IACE;IACN;IACJ,gBAAcnB;IACd,oBAAkBC;IAClB,cAAY,GAAGmB,EAAM,IAAIR,GAAQ,SAASS;IAC1C,WAAWC,EAAGC,GAAiB,cAAcC,CAAS;IAPvD,UAAA;KASC,kBAAC,QAAD;MAAM,eAAY;MAAO,WAAU;MACjC,UAAAZ,GAAQ;KACJ,CAAA;KACN,kBAAC,QAAD;MAAM,WAAU;MAAY,UAAAA,GAAQ,SAASS;KAAkB,CAAA;KAC/D,kBAACI,GAAD,EAAa,WAAU,WAAY,CAAA;IAC5B;;EACO,CAAA,GAChB,kBAACC,GAAD;GACC,OAAM;GACN,OAAO;GACP,WAAU;GACV,cAAYN;GAJb,UAAA;IAMC,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACC,kBAACO,GAAD;MACC,eAAY;MACZ,WAAU;KACV,CAAA,GACD,kBAACC,GAAD;MACC,WAAU;MACV,cAAY,GAAGR,EAAM;MACrB,OAAOZ;MACP,aAAaqB;MACb,WAAW,MAAUpB,EAASqB,EAAM,OAAO,KAAK;KAChD,CAAA,CACG;;IACL,kBAAChC,EAAqB,MAAtB;KACC,MAAK;KACL,cAAYsB;KACZ,OAAOV;KACP,WAAU;KACV,gBAAgB,MAAS;MACxB,AAAKO,MACDN,MAAU,KAAA,KAAWR,EAAcc,CAAI,GAC3Cc,IAAgBd,CAAI,GACpBV,EAAQ,EAAK,GACbE,EAAS,EAAE;KACZ;KAEC,UAAAK,EAAQ,KAAK,MACb,kBAAChB,EAAqB,MAAtB;MAEC,OAAOkC,EAAK;MACZ,UAAUA,EAAK;MACf,cAAYA,EAAK;MACjB,OAAOA,EAAK;MACZ,WAAWV,EAGV,qRACAW,GACA,8DACD;MAZD,UAAA;OAcC,kBAAC,QAAD;QACC,eAAY;QACZ,WAAU;QAET,UAAAD,EAAK;OACD,CAAA;OACN,kBAAC,QAAD;QAAM,WAAU;QACd,UAAAA,EAAK;OACD,CAAA;OACN,kBAACE,GAAD;QACC,eAAY;QACZ,WAAU;OACV,CAAA;MACyB;KA1BrB,GAAAF,EAAK,KA0BgB,CAC3B;IACyB,CAAA;IAC1BlB,EAAQ,WAAW,KACnB,kBAAC,KAAD;KAAG,MAAK;KAAS,WAAU;KACzB,UAAAqB;IACC,CAAA;GAEW;EACR,CAAA,CAAA;;AAEX"}
1
+ {"version":3,"file":"icon-picker.js","names":["ToggleGroupPrimitive","IconPicker","ariaInvalid","describedBy","localValue","setLocalValue","useState","defaultValue","open","setOpen","query","setQuery","selected","value","option","options","matches","Popover","disabled","next","PopoverTrigger","Button","label","placeholder","cn","BASALT_UI_CLASS","className","ChevronDown","PopoverContent","Search","Input","searchPlaceholder","event","onValueChange","item","FOCUS_RING","Check","emptyLabel"],"sources":["../../src/components/icon-picker.tsx"],"sourcesContent":["import * as ToggleGroupPrimitive from \"@radix-ui/react-toggle-group\";\nimport { Check, ChevronDown, Search } from \"lucide-react\";\nimport { type AriaAttributes, type ReactNode, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Button } from \"./button\";\nimport { Input } from \"./input\";\nimport { FOCUS_RING } from \"./overlay\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\n\nexport interface IconPickerOption {\n\t/** Stable application-owned identifier. */\n\tvalue: string;\n\t/** Visible selection text and accessible icon name. */\n\tlabel: string;\n\t/** Caller-rendered icon, from a deliberately small subset. */\n\ticon: ReactNode;\n\t/** Exclude this option from selection and keyboard navigation. */\n\tdisabled?: boolean;\n}\nexport interface IconPickerProps {\n\t/** Accessible picker name. */\n\tlabel: string;\n\t/** Caller-supplied icon subset; the library never imports an icon catalog. */\n\toptions: readonly IconPickerOption[];\n\t/** Controlled icon identifier. */\n\tvalue?: string;\n\t/** Initial uncontrolled icon identifier. */\n\tdefaultValue?: string;\n\t/** Selection request. */\n\tonValueChange?: (value: string) => void;\n\t/** Disable selection. @default false */\n\tdisabled?: boolean;\n\t/** Empty selection prompt. @default \"Choose icon\" */\n\tplaceholder?: string;\n\t/** Search placeholder. @default \"Search icons…\" */\n\tsearchPlaceholder?: string;\n\t/** Empty-search text. @default \"No icons found.\" */\n\temptyLabel?: string;\n\t/** Forwarded to the trigger so Field and Label can own it. */\n\tid?: string;\n\t/** Forwarded to the trigger; Field sets it while the value is invalid. */\n\t\"aria-invalid\"?: AriaAttributes[\"aria-invalid\"];\n\t/** Forwarded to the trigger; Field points it at the hint or error. */\n\t\"aria-describedby\"?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\nexport function IconPicker({\n\tlabel,\n\toptions,\n\tvalue,\n\tdefaultValue = \"\",\n\tonValueChange,\n\tdisabled = false,\n\tplaceholder = \"Choose icon\",\n\tsearchPlaceholder = \"Search icons…\",\n\temptyLabel = \"No icons found.\",\n\tid,\n\t\"aria-invalid\": ariaInvalid,\n\t\"aria-describedby\": describedBy,\n\tclassName,\n}: IconPickerProps) {\n\tconst [localValue, setLocalValue] = useState(defaultValue);\n\tconst [open, setOpen] = useState(false);\n\tconst [query, setQuery] = useState(\"\");\n\tconst selected = value ?? localValue;\n\tconst option = options.find((option) => option.value === selected);\n\tconst matches = options.filter((option) =>\n\t\toption.label.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()),\n\t);\n\treturn (\n\t\t<Popover\n\t\t\topen={open && !disabled}\n\t\t\tonOpenChange={(next) => {\n\t\t\t\tsetOpen(next);\n\t\t\t\tif (!next) setQuery(\"\");\n\t\t\t}}\n\t\t>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tid={id}\n\t\t\t\t\taria-invalid={ariaInvalid}\n\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\taria-label={`${label}: ${option?.label ?? placeholder}`}\n\t\t\t\t\tclassName={cn(BASALT_UI_CLASS, \"max-w-full\", className)}\n\t\t\t\t>\n\t\t\t\t\t<span aria-hidden=\"true\" className=\"shrink-0\">\n\t\t\t\t\t\t{option?.icon}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"truncate\">{option?.label ?? placeholder}</span>\n\t\t\t\t\t<ChevronDown className=\"shrink-0\" />\n\t\t\t\t</Button>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent\n\t\t\t\talign=\"start\"\n\t\t\t\tarrow={false}\n\t\t\t\tclassName=\"w-basalt-72 max-w-[calc(100vw-2rem)] space-y-basalt-layout-sm\"\n\t\t\t\taria-label={label}\n\t\t\t>\n\t\t\t\t<div className=\"relative\">\n\t\t\t\t\t<Search\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclassName=\"pointer-events-none absolute left-basalt-space-lg top-1/2 size-basalt-icon -translate-y-1/2 text-basalt-muted-foreground\"\n\t\t\t\t\t/>\n\t\t\t\t\t<Input\n\t\t\t\t\t\tclassName=\"pl-basalt-card-xl\"\n\t\t\t\t\t\taria-label={`${label}: search`}\n\t\t\t\t\t\tvalue={query}\n\t\t\t\t\t\tplaceholder={searchPlaceholder}\n\t\t\t\t\t\tonChange={(event) => setQuery(event.target.value)}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<ToggleGroupPrimitive.Root\n\t\t\t\t\ttype=\"single\"\n\t\t\t\t\taria-label={label}\n\t\t\t\t\tvalue={selected}\n\t\t\t\t\tclassName=\"grid max-h-basalt-64 grid-cols-2 gap-basalt-space-lg overflow-y-auto p-basalt-space-sm\"\n\t\t\t\t\tonValueChange={(next) => {\n\t\t\t\t\t\tif (!next) return;\n\t\t\t\t\t\tif (value === undefined) setLocalValue(next);\n\t\t\t\t\t\tonValueChange?.(next);\n\t\t\t\t\t\tsetOpen(false);\n\t\t\t\t\t\tsetQuery(\"\");\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{matches.map((item) => (\n\t\t\t\t\t\t<ToggleGroupPrimitive.Item\n\t\t\t\t\t\t\tkey={item.value}\n\t\t\t\t\t\t\tvalue={item.value}\n\t\t\t\t\t\t\tdisabled={item.disabled}\n\t\t\t\t\t\t\taria-label={item.label}\n\t\t\t\t\t\t\ttitle={item.label}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t// Accent choice grid: selection is the documented primary fill and its\n\t\t\t\t\t\t\t\t// contrast-corrected foreground, never a control fill plus a frame.\n\t\t\t\t\t\t\t\t\"group relative flex min-w-0 flex-col items-center justify-center gap-basalt-space-lg rounded-basalt-md p-basalt-layout-sm text-basalt-foreground data-[state=on]:bg-basalt-primary data-[state=on]:text-basalt-primary-foreground disabled:cursor-not-allowed disabled:opacity-40\",\n\t\t\t\t\t\t\t\tFOCUS_RING,\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclassName=\"flex size-basalt-6 items-center justify-center [&>svg]:size-basalt-6\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{item.icon}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span className=\"max-w-full break-words text-basalt-sm font-medium\">\n\t\t\t\t\t\t\t\t{item.label}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<Check\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclassName=\"absolute right-basalt-space-sm top-basalt-space-sm size-basalt-icon-sm opacity-0 group-data-[state=on]:opacity-100\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</ToggleGroupPrimitive.Item>\n\t\t\t\t\t))}\n\t\t\t\t</ToggleGroupPrimitive.Root>\n\t\t\t\t{matches.length === 0 && (\n\t\t\t\t\t<p role=\"status\" className=\"text-basalt-base text-basalt-muted-foreground\">\n\t\t\t\t\t\t{emptyLabel}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;AAgDA,SAAgBC,EAAW,EAC1B,UACA,YACA,UACA,kBAAe,IACf,kBACA,cAAW,IACX,iBAAc,eACd,uBAAoB,iBACpB,gBAAa,mBACb,OACA,gBAAgBC,GAChB,oBAAoBC,GACpB,gBACmB;CACnB,IAAM,CAACC,GAAYC,KAAiBC,EAASC,CAAY,GACnD,CAACC,GAAMC,KAAWH,EAAS,EAAK,GAChC,CAACI,GAAOC,KAAYL,EAAS,EAAE,GAC/BM,IAAWC,KAAST,GACpBU,IAASC,EAAQ,MAAM,MAAWD,EAAO,UAAUF,CAAQ,GAC3DI,IAAUD,EAAQ,QAAQ,MAC/BD,EAAO,MAAM,kBAAkB,CAAC,CAAC,SAASJ,EAAM,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAC3E;CACA,OACC,kBAACO,GAAD;EACC,MAAMT,KAAQ,CAACU;EACf,eAAe,MAAS;GAEvB,AADAT,EAAQU,CAAI,GACPA,KAAMR,EAAS,EAAE;EACvB;EALD,UAAA,CAOC,kBAACS,GAAD;GAAgB,SAAA;GACf,UAAA,kBAACC,GAAD;IACC,SAAQ;IACE;IACN;IACJ,gBAAcnB;IACd,oBAAkBC;IAClB,cAAY,GAAGmB,EAAM,IAAIR,GAAQ,SAASS;IAC1C,WAAWC,EAAGC,GAAiB,cAAcC,CAAS;IAPvD,UAAA;KASC,kBAAC,QAAD;MAAM,eAAY;MAAO,WAAU;MACjC,UAAAZ,GAAQ;KACJ,CAAA;KACN,kBAAC,QAAD;MAAM,WAAU;MAAY,UAAAA,GAAQ,SAASS;KAAkB,CAAA;KAC/D,kBAACI,GAAD,EAAa,WAAU,WAAY,CAAA;IAC5B;;EACO,CAAA,GAChB,kBAACC,GAAD;GACC,OAAM;GACN,OAAO;GACP,WAAU;GACV,cAAYN;GAJb,UAAA;IAMC,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACC,kBAACO,GAAD;MACC,eAAY;MACZ,WAAU;KACV,CAAA,GACD,kBAACC,GAAD;MACC,WAAU;MACV,cAAY,GAAGR,EAAM;MACrB,OAAOZ;MACP,aAAaqB;MACb,WAAW,MAAUpB,EAASqB,EAAM,OAAO,KAAK;KAChD,CAAA,CACG;;IACL,kBAAChC,EAAqB,MAAtB;KACC,MAAK;KACL,cAAYsB;KACZ,OAAOV;KACP,WAAU;KACV,gBAAgB,MAAS;MACxB,AAAKO,MACDN,MAAU,KAAA,KAAWR,EAAcc,CAAI,GAC3Cc,IAAgBd,CAAI,GACpBV,EAAQ,EAAK,GACbE,EAAS,EAAE;KACZ;KAEC,UAAAK,EAAQ,KAAK,MACb,kBAAChB,EAAqB,MAAtB;MAEC,OAAOkC,EAAK;MACZ,UAAUA,EAAK;MACf,cAAYA,EAAK;MACjB,OAAOA,EAAK;MACZ,WAAWV,EAGV,qRACAW,CACD;MAXD,UAAA;OAaC,kBAAC,QAAD;QACC,eAAY;QACZ,WAAU;QAET,UAAAD,EAAK;OACD,CAAA;OACN,kBAAC,QAAD;QAAM,WAAU;QACd,UAAAA,EAAK;OACD,CAAA;OACN,kBAACE,GAAD;QACC,eAAY;QACZ,WAAU;OACV,CAAA;MACyB;KAzBrB,GAAAF,EAAK,KAyBgB,CAC3B;IACyB,CAAA;IAC1BlB,EAAQ,WAAW,KACnB,kBAAC,KAAD;KAAG,MAAK;KAAS,WAAU;KACzB,UAAAqB;IACC,CAAA;GAEW;EACR,CAAA,CAAA;;AAEX"}
@@ -92,7 +92,7 @@ function f({ label: f, value: p, onSave: m, editing: h, defaultEditing: g = !1,
92
92
  type: "button",
93
93
  disabled: b || v,
94
94
  "aria-label": `${E} ${f}`,
95
- className: "group flex max-w-full items-center gap-basalt-space-lg rounded-basalt-md px-basalt-space-sm py-basalt-space-sm text-left text-basalt-base hover:bg-basalt-hover focus-visible:outline-2 focus-visible:outline-basalt-ring disabled:opacity-50",
95
+ className: "basalt-focus group flex max-w-full items-center gap-basalt-space-lg rounded-basalt-md px-basalt-space-sm py-basalt-space-sm text-left text-basalt-base hover:bg-basalt-hover disabled:opacity-50",
96
96
  onClick: () => {
97
97
  I(p), B(void 0), Z(!0, "edit");
98
98
  },
@@ -1 +1 @@
1
- {"version":3,"file":"inline-editable.js","names":["InlineEditable","localEditing","setLocalEditing","useState","defaultEditing","draft","setDraft","value","saving","setSaving","failure","setFailure","input","useRef","trigger","mounted","operation","locked","restore","id","useId","isEditing","editing","busy","pending","message","error","useEffect","useLayoutEffect","disabled","changeEditing","next","onEditingChange","reason","finish","save","trim","invalid","required","requiredLabel","validate","ticket","onSave","cause","errorLabel","label","cn","BASALT_UI_CLASS","className","saveOnBlur","event","Input","Button","saveLabel","cancelLabel","editLabel","placeholder","Pencil","pendingLabel"],"sources":["../../src/components/inline-editable.tsx"],"sourcesContent":["import { Pencil } from \"lucide-react\";\nimport { useEffect, useId, useLayoutEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Button } from \"./button\";\nimport { Input } from \"./input\";\n\nexport type InlineEditableChangeReason = \"edit\" | \"save\" | \"blur\" | \"cancel\";\nexport interface InlineEditableProps {\n\t/** Accessible name of the edited field. */\n\tlabel: string;\n\t/** Committed value, owned by the application. */\n\tvalue: string;\n\t/** Persist the draft. Return a promise to keep the editor pending; rejection preserves the draft. */\n\tonSave: (value: string) => void | Promise<void>;\n\t/** Controlled edit mode. */\n\tediting?: boolean;\n\t/** Initial uncontrolled edit mode. @default false */\n\tdefaultEditing?: boolean;\n\t/** Edit-mode requests with their cause, including blur that must not steal focus. */\n\tonEditingChange?: (editing: boolean, reason: InlineEditableChangeReason) => void;\n\t/** External pending state. @default false */\n\tpending?: boolean;\n\t/** Application-owned error message. */\n\terror?: string;\n\t/** Disable editing and saving. @default false */\n\tdisabled?: boolean;\n\t/** Reject an empty draft. @default true */\n\trequired?: boolean;\n\t/** Trim whitespace before validation and save. @default true */\n\ttrim?: boolean;\n\t/** Commit when focus leaves the whole editor, including its actions. @default true */\n\tsaveOnBlur?: boolean;\n\t/** Return a validation message to retain the draft without invoking onSave. */\n\tvalidate?: (value: string) => string | undefined;\n\t/** Empty committed-value prompt. @default \"Untitled\" */\n\tplaceholder?: string;\n\t/** Edit action label prefix. @default \"Edit\" */\n\teditLabel?: string;\n\t/** Save action text. @default \"Save\" */\n\tsaveLabel?: string;\n\t/** Cancel action text. @default \"Cancel\" */\n\tcancelLabel?: string;\n\t/** Pending announcement. @default \"Saving…\" */\n\tpendingLabel?: string;\n\t/** Empty-value validation message. @default \"Enter a value.\" */\n\trequiredLabel?: string;\n\t/** Fallback for non-Error rejections. @default \"Could not save changes.\" */\n\terrorLabel?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\nexport function InlineEditable({\n\tlabel,\n\tvalue,\n\tonSave,\n\tediting,\n\tdefaultEditing = false,\n\tonEditingChange,\n\tpending = false,\n\terror,\n\tdisabled = false,\n\trequired = true,\n\ttrim = true,\n\tsaveOnBlur = true,\n\tvalidate,\n\tplaceholder = \"Untitled\",\n\teditLabel = \"Edit\",\n\tsaveLabel = \"Save\",\n\tcancelLabel = \"Cancel\",\n\tpendingLabel = \"Saving…\",\n\trequiredLabel = \"Enter a value.\",\n\terrorLabel = \"Could not save changes.\",\n\tclassName,\n}: InlineEditableProps) {\n\tconst [localEditing, setLocalEditing] = useState(defaultEditing);\n\tconst [draft, setDraft] = useState(value);\n\tconst [saving, setSaving] = useState(false);\n\tconst [failure, setFailure] = useState<string>();\n\tconst input = useRef<HTMLInputElement>(null);\n\tconst trigger = useRef<HTMLButtonElement>(null);\n\tconst mounted = useRef(true);\n\tconst operation = useRef(0);\n\tconst locked = useRef(false);\n\tconst restore = useRef(false);\n\tconst id = useId();\n\tconst isEditing = editing ?? localEditing;\n\tconst busy = pending || saving;\n\tconst message = error ?? failure;\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t\toperation.current += 1;\n\t\t};\n\t}, []);\n\tuseLayoutEffect(() => {\n\t\tif (isEditing && !disabled) {\n\t\t\tinput.current?.focus();\n\t\t\tinput.current?.select();\n\t\t} else if (!isEditing && restore.current) {\n\t\t\trestore.current = false;\n\t\t\ttrigger.current?.focus();\n\t\t}\n\t}, [isEditing, disabled]);\n\tuseEffect(() => {\n\t\tif (!isEditing) {\n\t\t\toperation.current += 1;\n\t\t\tlocked.current = false;\n\t\t\tsetSaving(false);\n\t\t\tsetDraft(value);\n\t\t\tsetFailure(undefined);\n\t\t}\n\t}, [isEditing, value]);\n\tfunction changeEditing(next: boolean, reason: InlineEditableChangeReason) {\n\t\tif (editing === undefined) setLocalEditing(next);\n\t\tonEditingChange?.(next, reason);\n\t}\n\tfunction finish(reason: InlineEditableChangeReason) {\n\t\trestore.current = reason !== \"blur\";\n\t\tchangeEditing(false, reason);\n\t}\n\tasync function save(reason: \"save\" | \"blur\") {\n\t\tif (!isEditing || disabled || busy || locked.current) return;\n\t\tconst next = trim ? draft.trim() : draft;\n\t\tconst invalid = required && !next ? requiredLabel : validate?.(next);\n\t\tif (invalid) {\n\t\t\tsetFailure(invalid);\n\t\t\treturn;\n\t\t}\n\t\tif (next === value) {\n\t\t\tfinish(reason);\n\t\t\treturn;\n\t\t}\n\t\tlocked.current = true;\n\t\tsetSaving(true);\n\t\tsetFailure(undefined);\n\t\tconst ticket = ++operation.current;\n\t\ttry {\n\t\t\tawait onSave(next);\n\t\t\tif (mounted.current && ticket === operation.current) finish(reason);\n\t\t} catch (cause) {\n\t\t\tif (mounted.current && ticket === operation.current)\n\t\t\t\tsetFailure(cause instanceof Error && cause.message ? cause.message : errorLabel);\n\t\t} finally {\n\t\t\tif (mounted.current && ticket === operation.current) {\n\t\t\t\tlocked.current = false;\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t}\n\treturn (\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-label={label}\n\t\t\taria-busy={busy}\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"min-w-0 space-y-basalt-space-lg\", className)}\n\t\t\tonBlur={(event) => {\n\t\t\t\tif (saveOnBlur && !event.currentTarget.contains(event.relatedTarget)) void save(\"blur\");\n\t\t\t}}\n\t\t>\n\t\t\t{isEditing ? (\n\t\t\t\t<div className=\"flex flex-wrap items-center gap-basalt-space-lg\">\n\t\t\t\t\t<Input\n\t\t\t\t\t\tref={input}\n\t\t\t\t\t\taria-label={label}\n\t\t\t\t\t\tclassName=\"min-w-0 flex-1 basis-32\"\n\t\t\t\t\t\tvalue={draft}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\treadOnly={busy}\n\t\t\t\t\t\taria-invalid={!!message}\n\t\t\t\t\t\taria-describedby={message ? `${id}-error` : undefined}\n\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\tsetDraft(event.target.value);\n\t\t\t\t\t\t\tsetFailure(undefined);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\t\t\tif (event.nativeEvent.isComposing) return;\n\t\t\t\t\t\t\tif (event.key === \"Enter\") {\n\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\tvoid save(\"save\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.key === \"Escape\" && !busy) {\n\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t\t\tsetDraft(value);\n\t\t\t\t\t\t\t\tsetFailure(undefined);\n\t\t\t\t\t\t\t\tfinish(\"cancel\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t\t<Button size=\"sm\" disabled={disabled || busy} onClick={() => void save(\"save\")}>\n\t\t\t\t\t\t{saveLabel}\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\tsetDraft(value);\n\t\t\t\t\t\t\tsetFailure(undefined);\n\t\t\t\t\t\t\tfinish(\"cancel\");\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{cancelLabel}\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\t<button\n\t\t\t\t\tref={trigger}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={disabled || pending}\n\t\t\t\t\taria-label={`${editLabel} ${label}`}\n\t\t\t\t\tclassName=\"group flex max-w-full items-center gap-basalt-space-lg rounded-basalt-md px-basalt-space-sm py-basalt-space-sm text-left text-basalt-base hover:bg-basalt-hover focus-visible:outline-2 focus-visible:outline-basalt-ring disabled:opacity-50\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tsetDraft(value);\n\t\t\t\t\t\tsetFailure(undefined);\n\t\t\t\t\t\tchangeEditing(true, \"edit\");\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<span className={cn(\"min-w-0 break-words\", !value && \"text-basalt-muted-foreground\")}>\n\t\t\t\t\t\t{value || placeholder}\n\t\t\t\t\t</span>\n\t\t\t\t\t<Pencil\n\t\t\t\t\t\tclassName=\"size-basalt-icon shrink-0 text-basalt-muted-foreground\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t/>\n\t\t\t\t</button>\n\t\t\t)}\n\t\t\t{busy && (\n\t\t\t\t<p role=\"status\" className=\"text-basalt-sm text-basalt-muted-foreground\">\n\t\t\t\t\t{pendingLabel}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t{message && (\n\t\t\t\t<p id={`${id}-error`} role=\"alert\" className=\"text-basalt-sm text-basalt-destructive\">\n\t\t\t\t\t{message}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inline-editable.js","names":["InlineEditable","localEditing","setLocalEditing","useState","defaultEditing","draft","setDraft","value","saving","setSaving","failure","setFailure","input","useRef","trigger","mounted","operation","locked","restore","id","useId","isEditing","editing","busy","pending","message","error","useEffect","useLayoutEffect","disabled","changeEditing","next","onEditingChange","reason","finish","save","trim","invalid","required","requiredLabel","validate","ticket","onSave","cause","errorLabel","label","cn","BASALT_UI_CLASS","className","saveOnBlur","event","Input","Button","saveLabel","cancelLabel","editLabel","placeholder","Pencil","pendingLabel"],"sources":["../../src/components/inline-editable.tsx"],"sourcesContent":["import { Pencil } from \"lucide-react\";\nimport { useEffect, useId, useLayoutEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Button } from \"./button\";\nimport { Input } from \"./input\";\n\nexport type InlineEditableChangeReason = \"edit\" | \"save\" | \"blur\" | \"cancel\";\nexport interface InlineEditableProps {\n\t/** Accessible name of the edited field. */\n\tlabel: string;\n\t/** Committed value, owned by the application. */\n\tvalue: string;\n\t/** Persist the draft. Return a promise to keep the editor pending; rejection preserves the draft. */\n\tonSave: (value: string) => void | Promise<void>;\n\t/** Controlled edit mode. */\n\tediting?: boolean;\n\t/** Initial uncontrolled edit mode. @default false */\n\tdefaultEditing?: boolean;\n\t/** Edit-mode requests with their cause, including blur that must not steal focus. */\n\tonEditingChange?: (editing: boolean, reason: InlineEditableChangeReason) => void;\n\t/** External pending state. @default false */\n\tpending?: boolean;\n\t/** Application-owned error message. */\n\terror?: string;\n\t/** Disable editing and saving. @default false */\n\tdisabled?: boolean;\n\t/** Reject an empty draft. @default true */\n\trequired?: boolean;\n\t/** Trim whitespace before validation and save. @default true */\n\ttrim?: boolean;\n\t/** Commit when focus leaves the whole editor, including its actions. @default true */\n\tsaveOnBlur?: boolean;\n\t/** Return a validation message to retain the draft without invoking onSave. */\n\tvalidate?: (value: string) => string | undefined;\n\t/** Empty committed-value prompt. @default \"Untitled\" */\n\tplaceholder?: string;\n\t/** Edit action label prefix. @default \"Edit\" */\n\teditLabel?: string;\n\t/** Save action text. @default \"Save\" */\n\tsaveLabel?: string;\n\t/** Cancel action text. @default \"Cancel\" */\n\tcancelLabel?: string;\n\t/** Pending announcement. @default \"Saving…\" */\n\tpendingLabel?: string;\n\t/** Empty-value validation message. @default \"Enter a value.\" */\n\trequiredLabel?: string;\n\t/** Fallback for non-Error rejections. @default \"Could not save changes.\" */\n\terrorLabel?: string;\n\t/** Additional root classes. */\n\tclassName?: string;\n}\n\nexport function InlineEditable({\n\tlabel,\n\tvalue,\n\tonSave,\n\tediting,\n\tdefaultEditing = false,\n\tonEditingChange,\n\tpending = false,\n\terror,\n\tdisabled = false,\n\trequired = true,\n\ttrim = true,\n\tsaveOnBlur = true,\n\tvalidate,\n\tplaceholder = \"Untitled\",\n\teditLabel = \"Edit\",\n\tsaveLabel = \"Save\",\n\tcancelLabel = \"Cancel\",\n\tpendingLabel = \"Saving…\",\n\trequiredLabel = \"Enter a value.\",\n\terrorLabel = \"Could not save changes.\",\n\tclassName,\n}: InlineEditableProps) {\n\tconst [localEditing, setLocalEditing] = useState(defaultEditing);\n\tconst [draft, setDraft] = useState(value);\n\tconst [saving, setSaving] = useState(false);\n\tconst [failure, setFailure] = useState<string>();\n\tconst input = useRef<HTMLInputElement>(null);\n\tconst trigger = useRef<HTMLButtonElement>(null);\n\tconst mounted = useRef(true);\n\tconst operation = useRef(0);\n\tconst locked = useRef(false);\n\tconst restore = useRef(false);\n\tconst id = useId();\n\tconst isEditing = editing ?? localEditing;\n\tconst busy = pending || saving;\n\tconst message = error ?? failure;\n\tuseEffect(() => {\n\t\tmounted.current = true;\n\t\treturn () => {\n\t\t\tmounted.current = false;\n\t\t\toperation.current += 1;\n\t\t};\n\t}, []);\n\tuseLayoutEffect(() => {\n\t\tif (isEditing && !disabled) {\n\t\t\tinput.current?.focus();\n\t\t\tinput.current?.select();\n\t\t} else if (!isEditing && restore.current) {\n\t\t\trestore.current = false;\n\t\t\ttrigger.current?.focus();\n\t\t}\n\t}, [isEditing, disabled]);\n\tuseEffect(() => {\n\t\tif (!isEditing) {\n\t\t\toperation.current += 1;\n\t\t\tlocked.current = false;\n\t\t\tsetSaving(false);\n\t\t\tsetDraft(value);\n\t\t\tsetFailure(undefined);\n\t\t}\n\t}, [isEditing, value]);\n\tfunction changeEditing(next: boolean, reason: InlineEditableChangeReason) {\n\t\tif (editing === undefined) setLocalEditing(next);\n\t\tonEditingChange?.(next, reason);\n\t}\n\tfunction finish(reason: InlineEditableChangeReason) {\n\t\trestore.current = reason !== \"blur\";\n\t\tchangeEditing(false, reason);\n\t}\n\tasync function save(reason: \"save\" | \"blur\") {\n\t\tif (!isEditing || disabled || busy || locked.current) return;\n\t\tconst next = trim ? draft.trim() : draft;\n\t\tconst invalid = required && !next ? requiredLabel : validate?.(next);\n\t\tif (invalid) {\n\t\t\tsetFailure(invalid);\n\t\t\treturn;\n\t\t}\n\t\tif (next === value) {\n\t\t\tfinish(reason);\n\t\t\treturn;\n\t\t}\n\t\tlocked.current = true;\n\t\tsetSaving(true);\n\t\tsetFailure(undefined);\n\t\tconst ticket = ++operation.current;\n\t\ttry {\n\t\t\tawait onSave(next);\n\t\t\tif (mounted.current && ticket === operation.current) finish(reason);\n\t\t} catch (cause) {\n\t\t\tif (mounted.current && ticket === operation.current)\n\t\t\t\tsetFailure(cause instanceof Error && cause.message ? cause.message : errorLabel);\n\t\t} finally {\n\t\t\tif (mounted.current && ticket === operation.current) {\n\t\t\t\tlocked.current = false;\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t}\n\treturn (\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-label={label}\n\t\t\taria-busy={busy}\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"min-w-0 space-y-basalt-space-lg\", className)}\n\t\t\tonBlur={(event) => {\n\t\t\t\tif (saveOnBlur && !event.currentTarget.contains(event.relatedTarget)) void save(\"blur\");\n\t\t\t}}\n\t\t>\n\t\t\t{isEditing ? (\n\t\t\t\t<div className=\"flex flex-wrap items-center gap-basalt-space-lg\">\n\t\t\t\t\t<Input\n\t\t\t\t\t\tref={input}\n\t\t\t\t\t\taria-label={label}\n\t\t\t\t\t\tclassName=\"min-w-0 flex-1 basis-32\"\n\t\t\t\t\t\tvalue={draft}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\treadOnly={busy}\n\t\t\t\t\t\taria-invalid={!!message}\n\t\t\t\t\t\taria-describedby={message ? `${id}-error` : undefined}\n\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\tsetDraft(event.target.value);\n\t\t\t\t\t\t\tsetFailure(undefined);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\t\t\tif (event.nativeEvent.isComposing) return;\n\t\t\t\t\t\t\tif (event.key === \"Enter\") {\n\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\tvoid save(\"save\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.key === \"Escape\" && !busy) {\n\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t\t\tsetDraft(value);\n\t\t\t\t\t\t\t\tsetFailure(undefined);\n\t\t\t\t\t\t\t\tfinish(\"cancel\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t\t<Button size=\"sm\" disabled={disabled || busy} onClick={() => void save(\"save\")}>\n\t\t\t\t\t\t{saveLabel}\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tdisabled={busy}\n\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\tsetDraft(value);\n\t\t\t\t\t\t\tsetFailure(undefined);\n\t\t\t\t\t\t\tfinish(\"cancel\");\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{cancelLabel}\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\t<button\n\t\t\t\t\tref={trigger}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={disabled || pending}\n\t\t\t\t\taria-label={`${editLabel} ${label}`}\n\t\t\t\t\tclassName=\"basalt-focus group flex max-w-full items-center gap-basalt-space-lg rounded-basalt-md px-basalt-space-sm py-basalt-space-sm text-left text-basalt-base hover:bg-basalt-hover disabled:opacity-50\"\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tsetDraft(value);\n\t\t\t\t\t\tsetFailure(undefined);\n\t\t\t\t\t\tchangeEditing(true, \"edit\");\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<span className={cn(\"min-w-0 break-words\", !value && \"text-basalt-muted-foreground\")}>\n\t\t\t\t\t\t{value || placeholder}\n\t\t\t\t\t</span>\n\t\t\t\t\t<Pencil\n\t\t\t\t\t\tclassName=\"size-basalt-icon shrink-0 text-basalt-muted-foreground\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t/>\n\t\t\t\t</button>\n\t\t\t)}\n\t\t\t{busy && (\n\t\t\t\t<p role=\"status\" className=\"text-basalt-sm text-basalt-muted-foreground\">\n\t\t\t\t\t{pendingLabel}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t{message && (\n\t\t\t\t<p id={`${id}-error`} role=\"alert\" className=\"text-basalt-sm text-basalt-destructive\">\n\t\t\t\t\t{message}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
@@ -8,7 +8,7 @@ import { jsx as i } from "react/jsx-runtime";
8
8
  var a = {
9
9
  sm: "min-h-basalt-textarea-sm px-basalt-space-lg py-basalt-space-md text-basalt-sm",
10
10
  default: "min-h-basalt-textarea px-basalt-control-x py-basalt-space-lg text-basalt-base",
11
- lg: "min-h-basalt-textarea-lg px-basalt-control-x-lg py-basalt-space-lg text-basalt-lg"
11
+ lg: "min-h-basalt-textarea-lg px-basalt-control-x-lg py-basalt-space-lg text-basalt-base"
12
12
  }, o = {
13
13
  "data-1p-ignore": "true",
14
14
  "data-bwignore": "true",
@@ -1 +1 @@
1
- {"version":3,"file":"input-area.js","names":["React","INPUT_AREA_SIZE_CLASS","PASSWORD_MANAGER_MARKERS","InputArea","props","controlSurfaceClass","cn","size","FOCUS_BORDER","passwordManagerIgnore","className"],"sources":["../../src/components/input-area.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { controlSurfaceClass } from \"../utils/control-surface\";\nimport { FOCUS_BORDER } from \"./overlay\";\n\nexport type InputAreaSize = \"sm\" | \"default\" | \"lg\";\n\nconst INPUT_AREA_SIZE_CLASS: Record<InputAreaSize, string> = {\n\tsm: \"min-h-basalt-textarea-sm px-basalt-space-lg py-basalt-space-md text-basalt-sm\",\n\tdefault: \"min-h-basalt-textarea px-basalt-control-x py-basalt-space-lg text-basalt-base\",\n\tlg: \"min-h-basalt-textarea-lg px-basalt-control-x-lg py-basalt-space-lg text-basalt-lg\",\n};\n\nconst PASSWORD_MANAGER_MARKERS = {\n\t\"data-1p-ignore\": \"true\",\n\t\"data-bwignore\": \"true\",\n\t\"data-form-type\": \"other\",\n\t\"data-lpignore\": \"true\",\n} as const;\n\nexport type InputAreaProps = Omit<React.ComponentProps<\"textarea\">, \"rows\"> & {\n\t/**\n\t * The visible text row count.\n\t */\n\trows?: number;\n\t/**\n\t * The visual size of the text area.\n\t * @default default\n\t */\n\tsize?: InputAreaSize;\n\t/**\n\t * Ignore password managers on this field.\n\t * @default false\n\t */\n\tpasswordManagerIgnore?: boolean;\n};\n\nexport const InputArea = React.forwardRef<HTMLTextAreaElement, InputAreaProps>(\n\t({ className, size = \"default\", passwordManagerIgnore = false, ...props }, ref) => (\n\t\t<textarea\n\t\t\tref={ref}\n\t\t\tclassName={controlSurfaceClass(\n\t\t\t\tcn(\n\t\t\t\t\t\"flex w-full text-basalt-foreground shadow-xs placeholder:text-basalt-muted-foreground disabled:cursor-not-allowed disabled:border-transparent disabled:text-basalt-muted-foreground/40\",\n\t\t\t\t\tINPUT_AREA_SIZE_CLASS[size],\n\t\t\t\t\tFOCUS_BORDER,\n\t\t\t\t\t\"aria-invalid:border-basalt-destructive aria-invalid:focus-visible:border-basalt-destructive\",\n\t\t\t\t\tpasswordManagerIgnore && \"keeper-ignore\",\n\t\t\t\t\tclassName,\n\t\t\t\t),\n\t\t\t)}\n\t\t\t{...props}\n\t\t\t{...(passwordManagerIgnore ? PASSWORD_MANAGER_MARKERS : {})}\n\t\t/>\n\t),\n);\nInputArea.displayName = \"InputArea\";\n"],"mappings":";;;;;;;AAOA,IAAMC,IAAuD;CAC5D,IAAI;CACJ,SAAS;CACT,IAAI;AACL,GAEMC,IAA2B;CAChC,kBAAkB;CAClB,iBAAiB;CACjB,kBAAkB;CAClB,iBAAiB;AAClB,GAmBaC,IAAYH,EAAM,YAC7B,EAAE,cAAW,UAAO,WAAW,2BAAwB,IAAO,GAAGI,KAAS,MAC1E,kBAAC,YAAD;CACM;CACL,WAAWC,EACVC,EACC,0LACAL,EAAsBM,IACtBC,GACA,+FACAC,KAAyB,iBACzBC,CACD,CACD;CACA,GAAIN;CACJ,GAAKK,IAAwBP,IAA2B,CAAC;AACzD,CAAA,CAEH;AACA,EAAU,cAAc"}
1
+ {"version":3,"file":"input-area.js","names":["React","INPUT_AREA_SIZE_CLASS","PASSWORD_MANAGER_MARKERS","InputArea","props","controlSurfaceClass","cn","size","FOCUS_BORDER","passwordManagerIgnore","className"],"sources":["../../src/components/input-area.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { controlSurfaceClass } from \"../utils/control-surface\";\nimport { FOCUS_BORDER } from \"./overlay\";\n\nexport type InputAreaSize = \"sm\" | \"default\" | \"lg\";\n\nconst INPUT_AREA_SIZE_CLASS: Record<InputAreaSize, string> = {\n\tsm: \"min-h-basalt-textarea-sm px-basalt-space-lg py-basalt-space-md text-basalt-sm\",\n\tdefault: \"min-h-basalt-textarea px-basalt-control-x py-basalt-space-lg text-basalt-base\",\n\tlg: \"min-h-basalt-textarea-lg px-basalt-control-x-lg py-basalt-space-lg text-basalt-base\",\n};\n\nconst PASSWORD_MANAGER_MARKERS = {\n\t\"data-1p-ignore\": \"true\",\n\t\"data-bwignore\": \"true\",\n\t\"data-form-type\": \"other\",\n\t\"data-lpignore\": \"true\",\n} as const;\n\nexport type InputAreaProps = Omit<React.ComponentProps<\"textarea\">, \"rows\"> & {\n\t/**\n\t * The visible text row count.\n\t */\n\trows?: number;\n\t/**\n\t * The visual size of the text area.\n\t * @default default\n\t */\n\tsize?: InputAreaSize;\n\t/**\n\t * Ignore password managers on this field.\n\t * @default false\n\t */\n\tpasswordManagerIgnore?: boolean;\n};\n\nexport const InputArea = React.forwardRef<HTMLTextAreaElement, InputAreaProps>(\n\t({ className, size = \"default\", passwordManagerIgnore = false, ...props }, ref) => (\n\t\t<textarea\n\t\t\tref={ref}\n\t\t\tclassName={controlSurfaceClass(\n\t\t\t\tcn(\n\t\t\t\t\t\"flex w-full text-basalt-foreground shadow-xs placeholder:text-basalt-muted-foreground disabled:cursor-not-allowed disabled:border-transparent disabled:text-basalt-muted-foreground/40\",\n\t\t\t\t\tINPUT_AREA_SIZE_CLASS[size],\n\t\t\t\t\tFOCUS_BORDER,\n\t\t\t\t\t\"aria-invalid:border-basalt-destructive aria-invalid:focus-visible:border-basalt-destructive\",\n\t\t\t\t\tpasswordManagerIgnore && \"keeper-ignore\",\n\t\t\t\t\tclassName,\n\t\t\t\t),\n\t\t\t)}\n\t\t\t{...props}\n\t\t\t{...(passwordManagerIgnore ? PASSWORD_MANAGER_MARKERS : {})}\n\t\t/>\n\t),\n);\nInputArea.displayName = \"InputArea\";\n"],"mappings":";;;;;;;AAOA,IAAMC,IAAuD;CAC5D,IAAI;CACJ,SAAS;CACT,IAAI;AACL,GAEMC,IAA2B;CAChC,kBAAkB;CAClB,iBAAiB;CACjB,kBAAkB;CAClB,iBAAiB;AAClB,GAmBaC,IAAYH,EAAM,YAC7B,EAAE,cAAW,UAAO,WAAW,2BAAwB,IAAO,GAAGI,KAAS,MAC1E,kBAAC,YAAD;CACM;CACL,WAAWC,EACVC,EACC,0LACAL,EAAsBM,IACtBC,GACA,+FACAC,KAAyB,iBACzBC,CACD,CACD;CACA,GAAIN;CACJ,GAAKK,IAAwBP,IAA2B,CAAC;AACzD,CAAA,CAEH;AACA,EAAU,cAAc"}
@@ -14,7 +14,7 @@ var o = i.createContext(!1), s = i.forwardRef(({ className: n, disabled: r, onCl
14
14
  "data-disabled": r ? "" : void 0,
15
15
  "aria-disabled": r || void 0,
16
16
  inert: r || void 0,
17
- className: t(e("flex w-full items-center text-basalt-base shadow-xs", "[&>:first-child]:rounded-l-basalt-md [&>:last-child]:rounded-r-basalt-md", "outline-hidden focus-within:border-basalt-ring", "has-[[data-slot=input-group-addon-start]]:[&_input]:pl-basalt-space-lg", "has-[[data-slot=input-group-addon-end]]:[&_input]:pr-basalt-space-lg", "has-[[data-slot=input-group-suffix]]:[&_input]:flex-none", "has-[[data-slot=input-group-suffix]]:[&_input]:[field-sizing:content]", "has-[[data-slot=input-group-suffix]]:[&_input]:pr-0", "data-[disabled]:pointer-events-none data-[disabled]:opacity-50", n)),
17
+ className: t(e("flex w-full items-center text-basalt-base shadow-xs", "[&>:first-child]:rounded-l-basalt-md [&>:last-child]:rounded-r-basalt-md", "basalt-focus-group has-[input[aria-invalid=true]]:border-basalt-destructive", "has-[[data-slot=input-group-addon-start]]:[&_input]:pl-basalt-space-lg", "has-[[data-slot=input-group-addon-end]]:[&_input]:pr-basalt-space-lg", "has-[[data-slot=input-group-suffix]]:[&_input]:flex-none", "has-[[data-slot=input-group-suffix]]:[&_input]:[field-sizing:content]", "has-[[data-slot=input-group-suffix]]:[&_input]:pr-0", "data-[disabled]:pointer-events-none data-[disabled]:opacity-50", n)),
18
18
  onClick: (e) => {
19
19
  i?.(e), !(e.defaultPrevented || r) && (e.target.closest("input, textarea, button, a") || e.currentTarget.querySelector("input")?.focus());
20
20
  },
@@ -28,7 +28,7 @@ var c = i.forwardRef(({ className: t, disabled: n, ...s }, c) => {
28
28
  return /* @__PURE__ */ a(r, {
29
29
  ref: c,
30
30
  disabled: n || l,
31
- className: e("min-w-0 w-auto! flex-1 rounded-none border-0 bg-transparent px-basalt-space-lg shadow-none", "outline-hidden focus-visible:border-transparent focus-visible:ring-0", t),
31
+ className: e("min-w-0 w-auto! flex-1 rounded-none border-0 bg-transparent px-basalt-space-lg shadow-none", t),
32
32
  ...s
33
33
  });
34
34
  });
@@ -1 +1 @@
1
- {"version":3,"file":"input-group.js","names":["React","InputGroupDisabled","InputGroupRoot","props","disabled","controlSurfaceClass","cn","className","onClick","event","InputGroupInput","groupDisabled","Input","InputGroupAddon","align","InputGroupSuffix","InputGroupButton","Button","InputGroup"],"sources":["../../src/components/input-group.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { controlSurfaceClass } from \"../utils/control-surface\";\nimport { Button, type ButtonProps } from \"./button\";\nimport { Input } from \"./input\";\n\nexport type InputGroupProps = React.HTMLAttributes<HTMLDivElement> & {\n\t/**\n\t * Disable the input and nested actions.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n};\n\nconst InputGroupDisabled = React.createContext(false);\n\nconst InputGroupRoot = React.forwardRef<HTMLDivElement, InputGroupProps>(\n\t({ className, disabled, onClick, children, ...props }, ref) => (\n\t\t<InputGroupDisabled.Provider value={Boolean(disabled)}>\n\t\t\t<div\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"input-group\"\n\t\t\t\tdata-disabled={disabled ? \"\" : undefined}\n\t\t\t\taria-disabled={disabled || undefined}\n\t\t\t\tinert={disabled || undefined}\n\t\t\t\tclassName={controlSurfaceClass(\n\t\t\t\t\tcn(\n\t\t\t\t\t\t\"flex w-full items-center text-basalt-base shadow-xs\",\n\t\t\t\t\t\t\"[&>:first-child]:rounded-l-basalt-md [&>:last-child]:rounded-r-basalt-md\",\n\t\t\t\t\t\t\"outline-hidden focus-within:border-basalt-ring\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-basalt-space-lg\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-basalt-space-lg\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-suffix]]:[&_input]:flex-none\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-suffix]]:[&_input]:[field-sizing:content]\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-suffix]]:[&_input]:pr-0\",\n\t\t\t\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t),\n\t\t\t\t)}\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\tonClick?.(event);\n\t\t\t\t\tif (event.defaultPrevented || disabled) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst target = event.target as HTMLElement;\n\t\t\t\t\tif (target.closest(\"input, textarea, button, a\")) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tevent.currentTarget.querySelector(\"input\")?.focus();\n\t\t\t\t}}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</InputGroupDisabled.Provider>\n\t),\n);\nInputGroupRoot.displayName = \"InputGroup\";\n\nexport type InputGroupInputProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof Input>,\n\t\"type\" | \"size\" | \"passwordManagerIgnore\"\n> & {\n\t/**\n\t * The type of input control to render.\n\t */\n\ttype?: React.HTMLInputTypeAttribute;\n};\n\nconst InputGroupInput = React.forwardRef<HTMLInputElement, InputGroupInputProps>(\n\t({ className, disabled, ...props }, ref) => {\n\t\tconst groupDisabled = React.useContext(InputGroupDisabled);\n\t\treturn (\n\t\t\t<Input\n\t\t\t\tref={ref}\n\t\t\t\tdisabled={disabled || groupDisabled}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"min-w-0 w-auto! flex-1 rounded-none border-0 bg-transparent px-basalt-space-lg shadow-none\",\n\t\t\t\t\t\"outline-hidden focus-visible:border-transparent focus-visible:ring-0\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInputGroupInput.displayName = \"InputGroup.Input\";\n\nexport type InputGroupAddonProps = React.HTMLAttributes<HTMLDivElement> & {\n\t/**\n\t * Place the addon at the start or end of the group.\n\t * @default start\n\t */\n\talign?: \"start\" | \"end\";\n};\n\nfunction InputGroupAddon({ align = \"start\", className, children, ...props }: InputGroupAddonProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot={align === \"end\" ? \"input-group-addon-end\" : \"input-group-addon-start\"}\n\t\t\tclassName={cn(\n\t\t\t\t\"pointer-events-none flex shrink-0 items-center text-basalt-muted-foreground *:pointer-events-auto [&_svg]:size-basalt-icon-lg\",\n\t\t\t\talign === \"start\" ? \"-order-1 pl-basalt-space-lg\" : \"order-1 pr-basalt-space-lg\",\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</div>\n\t);\n}\nInputGroupAddon.displayName = \"InputGroup.Addon\";\n\nexport type InputGroupSuffixProps = React.HTMLAttributes<HTMLDivElement>;\n\nfunction InputGroupSuffix({ className, children, ...props }: InputGroupSuffixProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"input-group-suffix\"\n\t\t\tclassName={cn(\n\t\t\t\t\"pointer-events-none flex min-w-0 flex-1 items-center pr-basalt-space-lg text-basalt-muted-foreground select-none\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<span className=\"truncate\">{children}</span>\n\t\t</div>\n\t);\n}\nInputGroupSuffix.displayName = \"InputGroup.Suffix\";\n\nexport interface InputGroupButtonProps\n\textends Omit<ButtonProps, \"variant\" | \"size\" | \"asChild\" | \"loading\" | \"icon\"> {\n\t/**\n\t * Visual style for the nested action.\n\t * @default ghost\n\t */\n\tvariant?: ButtonProps[\"variant\"];\n\t/**\n\t * Size for the nested action.\n\t * @default icon\n\t */\n\tsize?: ButtonProps[\"size\"];\n\t/**\n\t * Render the nested action through its child element.\n\t * @default false\n\t */\n\tasChild?: boolean;\n\t/**\n\t * Show a spinner and disable the nested action.\n\t * @default false\n\t */\n\tloading?: boolean;\n\t/**\n\t * Icon rendered before the nested action label.\n\t */\n\ticon?: React.ReactNode;\n}\n\nconst InputGroupButton = React.forwardRef<HTMLButtonElement, InputGroupButtonProps>(\n\t({ className, variant = \"ghost\", size = \"icon\", disabled, ...props }, ref) => {\n\t\tconst groupDisabled = React.useContext(InputGroupDisabled);\n\t\treturn (\n\t\t\t<Button\n\t\t\t\tref={ref}\n\t\t\t\tvariant={variant}\n\t\t\t\tsize={size}\n\t\t\t\tdisabled={disabled || groupDisabled}\n\t\t\t\tclassName={cn(\"basalt-action-inset shrink-0 rounded-basalt-sm\", className)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInputGroupButton.displayName = \"InputGroup.Button\";\n\nexport const InputGroup = Object.assign(InputGroupRoot, {\n\tInput: InputGroupInput,\n\tAddon: InputGroupAddon,\n\tSuffix: InputGroupSuffix,\n\tButton: InputGroupButton,\n});\n"],"mappings":";;;;;;;;AAcA,IAAMC,IAAqBD,EAAM,cAAc,EAAK,GAE9CE,IAAiBF,EAAM,YAC3B,EAAE,cAAW,aAAU,YAAS,aAAU,GAAGG,KAAS,MACtD,kBAACF,EAAmB,UAApB;CAA6B,OAAO,EAAQG;CAC3C,UAAA,kBAAC,OAAD;EACM;EACL,aAAU;EACV,iBAAeA,IAAW,KAAK,KAAA;EAC/B,iBAAeA,KAAY,KAAA;EAC3B,OAAOA,KAAY,KAAA;EACnB,WAAWC,EACVC,EACC,uDACA,4EACA,kDACA,0EACA,wEACA,4DACA,yEACA,uDACA,kEACAC,CACD,CACD;EACA,UAAU,MAAU;GAEnB,AADAC,IAAUC,CAAK,GACX,IAAM,oBAAoBL,OAGfK,EAAM,OACV,QAAQ,4BAA4B,KAG/CA,EAAM,cAAc,cAAc,OAAO,CAAC,EAAE,MAAM;EACnD;EACA,GAAIN;EAEH;CACG,CAAA;AACuB,CAAA,CAE/B;AACA,EAAe,cAAc;AAY7B,IAAMO,IAAkBV,EAAM,YAC5B,EAAE,cAAW,aAAU,GAAGG,KAAS,MAAQ;CAC3C,IAAMQ,IAAgBX,EAAM,WAAWC,CAAkB;CACzD,OACC,kBAACW,GAAD;EACM;EACL,UAAUR,KAAYO;EACtB,WAAWL,EACV,8FACA,wEACAC,CACD;EACA,GAAIJ;CACJ,CAAA;AAEH,CACD;AACA,EAAgB,cAAc;AAU9B,SAASU,EAAgB,EAAE,WAAQ,SAAS,cAAW,aAAU,GAAGV,KAA+B;CAClG,OACC,kBAAC,OAAD;EACC,aAAWW,MAAU,QAAQ,0BAA0B;EACvD,WAAWR,EACV,iIACAQ,MAAU,UAAU,gCAAgC,8BACpDP,CACD;EACA,GAAIJ;EAEH;CACG,CAAA;AAEP;AACA,EAAgB,cAAc;AAI9B,SAASY,EAAiB,EAAE,cAAW,aAAU,GAAGZ,KAAgC;CACnF,OACC,kBAAC,OAAD;EACC,aAAU;EACV,WAAWG,EACV,oHACAC,CACD;EACA,GAAIJ;EAEJ,UAAA,kBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA;CACvC,CAAA;AAEP;AACA,EAAiB,cAAc;AA8B/B,IAAMa,IAAmBhB,EAAM,YAC7B,EAAE,cAAW,aAAU,SAAS,UAAO,QAAQ,aAAU,GAAGG,KAAS,MAAQ;CAC7E,IAAMQ,IAAgBX,EAAM,WAAWC,CAAkB;CACzD,OACC,kBAACgB,GAAD;EACM;EACI;EACH;EACN,UAAUb,KAAYO;EACtB,WAAWL,EAAG,kDAAkDC,CAAS;EACzE,GAAIJ;CACJ,CAAA;AAEH,CACD;AACA,EAAiB,cAAc;AAE/B,IAAae,IAAa,OAAO,OAAOhB,GAAgB;CACvD,OAAOQ;CACP,OAAOG;CACP,QAAQE;CACR,QAAQC;AACT,CAAC"}
1
+ {"version":3,"file":"input-group.js","names":["React","InputGroupDisabled","InputGroupRoot","props","disabled","controlSurfaceClass","cn","className","onClick","event","InputGroupInput","groupDisabled","Input","InputGroupAddon","align","InputGroupSuffix","InputGroupButton","Button","InputGroup"],"sources":["../../src/components/input-group.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { controlSurfaceClass } from \"../utils/control-surface\";\nimport { Button, type ButtonProps } from \"./button\";\nimport { Input } from \"./input\";\n\nexport type InputGroupProps = React.HTMLAttributes<HTMLDivElement> & {\n\t/**\n\t * Disable the input and nested actions.\n\t * @default false\n\t */\n\tdisabled?: boolean;\n};\n\nconst InputGroupDisabled = React.createContext(false);\n\nconst InputGroupRoot = React.forwardRef<HTMLDivElement, InputGroupProps>(\n\t({ className, disabled, onClick, children, ...props }, ref) => (\n\t\t<InputGroupDisabled.Provider value={Boolean(disabled)}>\n\t\t\t<div\n\t\t\t\tref={ref}\n\t\t\t\tdata-slot=\"input-group\"\n\t\t\t\tdata-disabled={disabled ? \"\" : undefined}\n\t\t\t\taria-disabled={disabled || undefined}\n\t\t\t\tinert={disabled || undefined}\n\t\t\t\tclassName={controlSurfaceClass(\n\t\t\t\t\tcn(\n\t\t\t\t\t\t\"flex w-full items-center text-basalt-base shadow-xs\",\n\t\t\t\t\t\t\"[&>:first-child]:rounded-l-basalt-md [&>:last-child]:rounded-r-basalt-md\",\n\t\t\t\t\t\t\"basalt-focus-group has-[input[aria-invalid=true]]:border-basalt-destructive\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-addon-start]]:[&_input]:pl-basalt-space-lg\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-basalt-space-lg\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-suffix]]:[&_input]:flex-none\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-suffix]]:[&_input]:[field-sizing:content]\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-suffix]]:[&_input]:pr-0\",\n\t\t\t\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t),\n\t\t\t\t)}\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\tonClick?.(event);\n\t\t\t\t\tif (event.defaultPrevented || disabled) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst target = event.target as HTMLElement;\n\t\t\t\t\tif (target.closest(\"input, textarea, button, a\")) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tevent.currentTarget.querySelector(\"input\")?.focus();\n\t\t\t\t}}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</InputGroupDisabled.Provider>\n\t),\n);\nInputGroupRoot.displayName = \"InputGroup\";\n\nexport type InputGroupInputProps = Omit<\n\tReact.ComponentPropsWithoutRef<typeof Input>,\n\t\"type\" | \"size\" | \"passwordManagerIgnore\"\n> & {\n\t/**\n\t * The type of input control to render.\n\t */\n\ttype?: React.HTMLInputTypeAttribute;\n};\n\nconst InputGroupInput = React.forwardRef<HTMLInputElement, InputGroupInputProps>(\n\t({ className, disabled, ...props }, ref) => {\n\t\tconst groupDisabled = React.useContext(InputGroupDisabled);\n\t\treturn (\n\t\t\t<Input\n\t\t\t\tref={ref}\n\t\t\t\tdisabled={disabled || groupDisabled}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"min-w-0 w-auto! flex-1 rounded-none border-0 bg-transparent px-basalt-space-lg shadow-none\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInputGroupInput.displayName = \"InputGroup.Input\";\n\nexport type InputGroupAddonProps = React.HTMLAttributes<HTMLDivElement> & {\n\t/**\n\t * Place the addon at the start or end of the group.\n\t * @default start\n\t */\n\talign?: \"start\" | \"end\";\n};\n\nfunction InputGroupAddon({ align = \"start\", className, children, ...props }: InputGroupAddonProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot={align === \"end\" ? \"input-group-addon-end\" : \"input-group-addon-start\"}\n\t\t\tclassName={cn(\n\t\t\t\t\"pointer-events-none flex shrink-0 items-center text-basalt-muted-foreground *:pointer-events-auto [&_svg]:size-basalt-icon-lg\",\n\t\t\t\talign === \"start\" ? \"-order-1 pl-basalt-space-lg\" : \"order-1 pr-basalt-space-lg\",\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</div>\n\t);\n}\nInputGroupAddon.displayName = \"InputGroup.Addon\";\n\nexport type InputGroupSuffixProps = React.HTMLAttributes<HTMLDivElement>;\n\nfunction InputGroupSuffix({ className, children, ...props }: InputGroupSuffixProps) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"input-group-suffix\"\n\t\t\tclassName={cn(\n\t\t\t\t\"pointer-events-none flex min-w-0 flex-1 items-center pr-basalt-space-lg text-basalt-muted-foreground select-none\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<span className=\"truncate\">{children}</span>\n\t\t</div>\n\t);\n}\nInputGroupSuffix.displayName = \"InputGroup.Suffix\";\n\nexport interface InputGroupButtonProps\n\textends Omit<ButtonProps, \"variant\" | \"size\" | \"asChild\" | \"loading\" | \"icon\"> {\n\t/**\n\t * Visual style for the nested action.\n\t * @default ghost\n\t */\n\tvariant?: ButtonProps[\"variant\"];\n\t/**\n\t * Size for the nested action.\n\t * @default icon\n\t */\n\tsize?: ButtonProps[\"size\"];\n\t/**\n\t * Render the nested action through its child element.\n\t * @default false\n\t */\n\tasChild?: boolean;\n\t/**\n\t * Show a spinner and disable the nested action.\n\t * @default false\n\t */\n\tloading?: boolean;\n\t/**\n\t * Icon rendered before the nested action label.\n\t */\n\ticon?: React.ReactNode;\n}\n\nconst InputGroupButton = React.forwardRef<HTMLButtonElement, InputGroupButtonProps>(\n\t({ className, variant = \"ghost\", size = \"icon\", disabled, ...props }, ref) => {\n\t\tconst groupDisabled = React.useContext(InputGroupDisabled);\n\t\treturn (\n\t\t\t<Button\n\t\t\t\tref={ref}\n\t\t\t\tvariant={variant}\n\t\t\t\tsize={size}\n\t\t\t\tdisabled={disabled || groupDisabled}\n\t\t\t\tclassName={cn(\"basalt-action-inset shrink-0 rounded-basalt-sm\", className)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInputGroupButton.displayName = \"InputGroup.Button\";\n\nexport const InputGroup = Object.assign(InputGroupRoot, {\n\tInput: InputGroupInput,\n\tAddon: InputGroupAddon,\n\tSuffix: InputGroupSuffix,\n\tButton: InputGroupButton,\n});\n"],"mappings":";;;;;;;;AAcA,IAAMC,IAAqBD,EAAM,cAAc,EAAK,GAE9CE,IAAiBF,EAAM,YAC3B,EAAE,cAAW,aAAU,YAAS,aAAU,GAAGG,KAAS,MACtD,kBAACF,EAAmB,UAApB;CAA6B,OAAO,EAAQG;CAC3C,UAAA,kBAAC,OAAD;EACM;EACL,aAAU;EACV,iBAAeA,IAAW,KAAK,KAAA;EAC/B,iBAAeA,KAAY,KAAA;EAC3B,OAAOA,KAAY,KAAA;EACnB,WAAWC,EACVC,EACC,uDACA,4EACA,+EACA,0EACA,wEACA,4DACA,yEACA,uDACA,kEACAC,CACD,CACD;EACA,UAAU,MAAU;GAEnB,AADAC,IAAUC,CAAK,GACX,IAAM,oBAAoBL,OAGfK,EAAM,OACV,QAAQ,4BAA4B,KAG/CA,EAAM,cAAc,cAAc,OAAO,CAAC,EAAE,MAAM;EACnD;EACA,GAAIN;EAEH;CACG,CAAA;AACuB,CAAA,CAE/B;AACA,EAAe,cAAc;AAY7B,IAAMO,IAAkBV,EAAM,YAC5B,EAAE,cAAW,aAAU,GAAGG,KAAS,MAAQ;CAC3C,IAAMQ,IAAgBX,EAAM,WAAWC,CAAkB;CACzD,OACC,kBAACW,GAAD;EACM;EACL,UAAUR,KAAYO;EACtB,WAAWL,EACV,8FACAC,CACD;EACA,GAAIJ;CACJ,CAAA;AAEH,CACD;AACA,EAAgB,cAAc;AAU9B,SAASU,EAAgB,EAAE,WAAQ,SAAS,cAAW,aAAU,GAAGV,KAA+B;CAClG,OACC,kBAAC,OAAD;EACC,aAAWW,MAAU,QAAQ,0BAA0B;EACvD,WAAWR,EACV,iIACAQ,MAAU,UAAU,gCAAgC,8BACpDP,CACD;EACA,GAAIJ;EAEH;CACG,CAAA;AAEP;AACA,EAAgB,cAAc;AAI9B,SAASY,EAAiB,EAAE,cAAW,aAAU,GAAGZ,KAAgC;CACnF,OACC,kBAAC,OAAD;EACC,aAAU;EACV,WAAWG,EACV,oHACAC,CACD;EACA,GAAIJ;EAEJ,UAAA,kBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA;CACvC,CAAA;AAEP;AACA,EAAiB,cAAc;AA8B/B,IAAMa,IAAmBhB,EAAM,YAC7B,EAAE,cAAW,aAAU,SAAS,UAAO,QAAQ,aAAU,GAAGG,KAAS,MAAQ;CAC7E,IAAMQ,IAAgBX,EAAM,WAAWC,CAAkB;CACzD,OACC,kBAACgB,GAAD;EACM;EACI;EACH;EACN,UAAUb,KAAYO;EACtB,WAAWL,EAAG,kDAAkDC,CAAS;EACzE,GAAIJ;CACJ,CAAA;AAEH,CACD;AACA,EAAiB,cAAc;AAE/B,IAAae,IAAa,OAAO,OAAOhB,GAAgB;CACvD,OAAOQ;CACP,OAAOG;CACP,QAAQE;CACR,QAAQC;AACT,CAAC"}