@nocoo/basalt 2.1.8 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/ai/INTEGRATION.md +64 -28
  2. package/ai/RECIPES.md +46 -1
  3. package/ai/USAGE.md +2 -2
  4. package/ai/registry.json +56 -14
  5. package/dist/assets/brand-mark.js.map +1 -1
  6. package/dist/charts/area.js.map +1 -1
  7. package/dist/charts/bar.js.map +1 -1
  8. package/dist/charts/bullet.js.map +1 -1
  9. package/dist/charts/charts.js.map +1 -1
  10. package/dist/charts/config.js.map +1 -1
  11. package/dist/charts/custom-chart.js.map +1 -1
  12. package/dist/charts/date-navigation.js.map +1 -1
  13. package/dist/charts/donut.js.map +1 -1
  14. package/dist/charts/frame.js.map +1 -1
  15. package/dist/charts/funnel.js.map +1 -1
  16. package/dist/charts/gauge.js.map +1 -1
  17. package/dist/charts/grouped-bar.js.map +1 -1
  18. package/dist/charts/heatmap-calendar.js.map +1 -1
  19. package/dist/charts/heatmap-matrix.js.map +1 -1
  20. package/dist/charts/item-list.js.map +1 -1
  21. package/dist/charts/legend.js.map +1 -1
  22. package/dist/charts/line.js.map +1 -1
  23. package/dist/charts/palette.js.map +1 -1
  24. package/dist/charts/radar.js.map +1 -1
  25. package/dist/charts/sample.js.map +1 -1
  26. package/dist/charts/sankey.js.map +1 -1
  27. package/dist/charts/series.js.map +1 -1
  28. package/dist/charts/slot-bar.js.map +1 -1
  29. package/dist/charts/sparkline.js.map +1 -1
  30. package/dist/charts/stacked-bar.js.map +1 -1
  31. package/dist/charts/stat-card.js.map +1 -1
  32. package/dist/charts/timeline.js.map +1 -1
  33. package/dist/charts/timeseries.js.map +1 -1
  34. package/dist/charts/tooltip.js.map +1 -1
  35. package/dist/components/accordion.js.map +1 -1
  36. package/dist/components/alert-dialog.js.map +1 -1
  37. package/dist/components/app-header.d.ts +5 -1
  38. package/dist/components/app-header.js +12 -4
  39. package/dist/components/app-header.js.map +1 -1
  40. package/dist/components/app-shell.d.ts +4 -1
  41. package/dist/components/app-shell.js +7 -4
  42. package/dist/components/app-shell.js.map +1 -1
  43. package/dist/components/autocomplete.js.map +1 -1
  44. package/dist/components/avatar.js.map +1 -1
  45. package/dist/components/badge.js.map +1 -1
  46. package/dist/components/banner.js.map +1 -1
  47. package/dist/components/basalt-mark.js.map +1 -1
  48. package/dist/components/battery-meter.js.map +1 -1
  49. package/dist/components/breadcrumbs.js.map +1 -1
  50. package/dist/components/button.js.map +1 -1
  51. package/dist/components/chat-bubble.js.map +1 -1
  52. package/dist/components/chat-composer.js.map +1 -1
  53. package/dist/components/chat-header.js.map +1 -1
  54. package/dist/components/chat-inbox.js.map +1 -1
  55. package/dist/components/checkbox.js.map +1 -1
  56. package/dist/components/clipboard-text.js.map +1 -1
  57. package/dist/components/code.js.map +1 -1
  58. package/dist/components/collapsible.js.map +1 -1
  59. package/dist/components/combobox.js.map +1 -1
  60. package/dist/components/command-palette.js.map +1 -1
  61. package/dist/components/confirm-dialog.d.ts +4 -1
  62. package/dist/components/confirm-dialog.js +20 -18
  63. package/dist/components/confirm-dialog.js.map +1 -1
  64. package/dist/components/context-menu.js.map +1 -1
  65. package/dist/components/data-table.js.map +1 -1
  66. package/dist/components/date-picker.js.map +1 -1
  67. package/dist/components/delete-resource.js.map +1 -1
  68. package/dist/components/description-list.js.map +1 -1
  69. package/dist/components/dialog.js.map +1 -1
  70. package/dist/components/dock.js.map +1 -1
  71. package/dist/components/dropdown-menu.js.map +1 -1
  72. package/dist/components/editable-nav-item.js.map +1 -1
  73. package/dist/components/empty.js.map +1 -1
  74. package/dist/components/fab.js.map +1 -1
  75. package/dist/components/field.js.map +1 -1
  76. package/dist/components/file-dropzone.js.map +1 -1
  77. package/dist/components/filter-bar.js.map +1 -1
  78. package/dist/components/flow.js.map +1 -1
  79. package/dist/components/grid.js.map +1 -1
  80. package/dist/components/hover-card.js.map +1 -1
  81. package/dist/components/icon-picker.js.map +1 -1
  82. package/dist/components/inline-editable.js.map +1 -1
  83. package/dist/components/input-area.js.map +1 -1
  84. package/dist/components/input-group.js.map +1 -1
  85. package/dist/components/input.js.map +1 -1
  86. package/dist/components/label.js.map +1 -1
  87. package/dist/components/layer-card.js.map +1 -1
  88. package/dist/components/link.js.map +1 -1
  89. package/dist/components/loader.js.map +1 -1
  90. package/dist/components/loading-screen.js.map +1 -1
  91. package/dist/components/menu-bar.js.map +1 -1
  92. package/dist/components/meter.js.map +1 -1
  93. package/dist/components/multi-select.js.map +1 -1
  94. package/dist/components/navigation-menu.js.map +1 -1
  95. package/dist/components/overlay.js.map +1 -1
  96. package/dist/components/page-header.js.map +1 -1
  97. package/dist/components/pagination.js.map +1 -1
  98. package/dist/components/popover.js.map +1 -1
  99. package/dist/components/radio.js.map +1 -1
  100. package/dist/components/resource-list.js.map +1 -1
  101. package/dist/components/responsive-master-detail.js +5 -5
  102. package/dist/components/responsive-master-detail.js.map +1 -1
  103. package/dist/components/scroll-area.js.map +1 -1
  104. package/dist/components/section-rule.js.map +1 -1
  105. package/dist/components/segment-control.js.map +1 -1
  106. package/dist/components/select.js.map +1 -1
  107. package/dist/components/sensitive-input.js.map +1 -1
  108. package/dist/components/separator.js.map +1 -1
  109. package/dist/components/sheet.js +1 -0
  110. package/dist/components/sheet.js.map +1 -1
  111. package/dist/components/sidebar.d.ts +3 -1
  112. package/dist/components/sidebar.js +8 -5
  113. package/dist/components/sidebar.js.map +1 -1
  114. package/dist/components/skeleton-line.js.map +1 -1
  115. package/dist/components/slider.js.map +1 -1
  116. package/dist/components/stat-strip.js.map +1 -1
  117. package/dist/components/switch.js.map +1 -1
  118. package/dist/components/table-of-contents.js.map +1 -1
  119. package/dist/components/table-pager.js.map +1 -1
  120. package/dist/components/table.js.map +1 -1
  121. package/dist/components/tabs.js.map +1 -1
  122. package/dist/components/tag-badge.js.map +1 -1
  123. package/dist/components/tag-color-picker.js.map +1 -1
  124. package/dist/components/text.js.map +1 -1
  125. package/dist/components/theme-toggle.js.map +1 -1
  126. package/dist/components/toast.js.map +1 -1
  127. package/dist/components/toggle-group.js.map +1 -1
  128. package/dist/components/toggle.js.map +1 -1
  129. package/dist/components/toolbar.js.map +1 -1
  130. package/dist/components/tooltip.js.map +1 -1
  131. package/dist/components/typeahead-field.js.map +1 -1
  132. package/dist/components/upload-queue.js.map +1 -1
  133. package/dist/providers/accent.js +1 -1
  134. package/dist/providers/accent.js.map +1 -1
  135. package/dist/providers/link.js.map +1 -1
  136. package/dist/providers/theme.js +1 -1
  137. package/dist/providers/theme.js.map +1 -1
  138. package/dist/styles/base.css +116 -0
  139. package/dist/styles/standalone.css +124 -3
  140. package/dist/utils/cn.js.map +1 -1
  141. package/dist/utils/control-surface.js.map +1 -1
  142. package/dist/utils/preference-store.js +1 -1
  143. package/dist/utils/preference-store.js.map +1 -1
  144. package/dist/utils/selection-indicator.js.map +1 -1
  145. package/dist/utils/use-checkable-group.js.map +1 -1
  146. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"dock.js","names":[],"sources":["../../src/components/dock.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { dialogOverlayClass } from \"./dialog\";\nimport { OVERLAY_LAYER, OVERLAY_MOTION } from \"./overlay\";\n\nconst FOCUSABLE =\n\t'button:not([disabled]), [href], input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nfunction tabbables(root: HTMLElement | null) {\n\tif (!root) {\n\t\treturn [];\n\t}\n\treturn [...root.querySelectorAll<HTMLElement>(FOCUSABLE)].filter((node) => {\n\t\tif (node.closest(\"[inert], [hidden]\")) {\n\t\t\treturn false;\n\t\t}\n\t\tif (node.tabIndex < 0) {\n\t\t\treturn false;\n\t\t}\n\t\tif (window.getComputedStyle(node).visibility === \"hidden\") {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let current: HTMLElement | null = node; current; current = current.parentElement) {\n\t\t\tif (window.getComputedStyle(current).display === \"none\") {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t});\n}\n\nexport type DockMode = \"overlay\" | \"push\";\n\nexport interface DockProps {\n\t/**\n\t * Whether the dock occupies its width.\n\t */\n\topen: boolean;\n\t/**\n\t * `push` shrinks the main column. `overlay` covers the local region with a non-modal scrim.\n\t * @default \"push\"\n\t */\n\tmode?: DockMode;\n\t/**\n\t * Width when open.\n\t * @default \"clamp(300px, 32.5vw, 546px)\"\n\t */\n\twidth?: string;\n\t/**\n\t * Overlay scrim click. Ignored in push mode.\n\t */\n\tonDismiss?: () => void;\n\t/**\n\t * Overlay scrim accessible name.\n\t * @default \"Dismiss\"\n\t */\n\tdismissLabel?: string;\n\t/**\n\t * Accessible name.\n\t */\n\t\"aria-label\": string;\n\tclassName?: string;\n\tchildren: ReactNode;\n}\n\nexport interface DockBodyProps {\n\tclassName?: string;\n\tchildren: ReactNode;\n}\n\nexport function DockBody({ className, children }: DockBodyProps) {\n\treturn (\n\t\t<div className={cn(\"flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto px-3 py-3\", className)}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport function Dock({\n\topen,\n\tmode = \"push\",\n\twidth = \"clamp(300px, 32.5vw, 546px)\",\n\tonDismiss,\n\tdismissLabel = \"Dismiss\",\n\tclassName,\n\tchildren,\n\t\"aria-label\": ariaLabel,\n}: DockProps) {\n\tconst overlay = mode === \"overlay\";\n\tconst panelRef = useRef<HTMLElement | null>(null);\n\tconst setPanel = (node: HTMLElement | null) => {\n\t\tpanelRef.current = node;\n\t};\n\tconst wasOpen = useRef(!overlay && open);\n\tconst previousFocus = useRef<HTMLElement | null>(null);\n\n\tuseEffect(() => {\n\t\tif (open) {\n\t\t\tif (wasOpen.current) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpreviousFocus.current =\n\t\t\t\tdocument.activeElement instanceof HTMLElement ? document.activeElement : null;\n\t\t\tconst timer = window.setTimeout(() => {\n\t\t\t\tconst root = panelRef.current;\n\t\t\t\tconst nodes = tabbables(root);\n\t\t\t\t(nodes[0] ?? root)?.focus();\n\t\t\t\twasOpen.current = true;\n\t\t\t}, 0);\n\t\t\treturn () => window.clearTimeout(timer);\n\t\t}\n\t\tif (wasOpen.current) {\n\t\t\tpreviousFocus.current?.focus?.();\n\t\t\tpreviousFocus.current = null;\n\t\t\twasOpen.current = false;\n\t\t}\n\t}, [open]);\n\n\tuseEffect(() => {\n\t\tif (!overlay || !open) {\n\t\t\treturn;\n\t\t}\n\t\tconst onKeyDown = (event: KeyboardEvent) => {\n\t\t\tif (event.key === \"Escape\") {\n\t\t\t\tif (event.defaultPrevented || !onDismiss) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tonDismiss();\n\t\t\t}\n\t\t};\n\t\twindow.addEventListener(\"keydown\", onKeyDown);\n\t\treturn () => window.removeEventListener(\"keydown\", onKeyDown);\n\t}, [overlay, open, onDismiss]);\n\tconst panelClass = cn(\n\t\t\"overflow-hidden bg-basalt-background transition-[width] duration-300 ease-in-out\",\n\t\toverlay ? cn(\"absolute top-0 right-0 h-full\", OVERLAY_LAYER) : \"sticky top-0 h-screen shrink-0\",\n\t\tOVERLAY_MOTION,\n\t\tclassName,\n\t);\n\tconst panelStyle = { width: open ? width : 0 };\n\tconst inner = (\n\t\t<div\n\t\t\tclassName=\"flex h-full flex-col bg-basalt-card shadow-lg ring-1 ring-basalt-border/40\"\n\t\t\tstyle={{ width }}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n\n\tif (!overlay) {\n\t\treturn (\n\t\t\t<aside\n\t\t\t\tref={setPanel}\n\t\t\t\tclassName={cn(BASALT_UI_CLASS, panelClass)}\n\t\t\t\tstyle={panelStyle}\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\taria-hidden={!open}\n\t\t\t\tinert={!open || undefined}\n\t\t\t\ttabIndex={open ? -1 : undefined}\n\t\t\t>\n\t\t\t\t{inner}\n\t\t\t</aside>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className={cn(\"absolute inset-0\", OVERLAY_LAYER, !open && \"pointer-events-none\")}>\n\t\t\t{onDismiss ? (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\ttabIndex={open ? 0 : -1}\n\t\t\t\t\taria-label={dismissLabel}\n\t\t\t\t\taria-hidden={!open}\n\t\t\t\t\tdata-state={open ? \"open\" : \"closed\"}\n\t\t\t\t\tclassName={cn(dialogOverlayClass(\"absolute\"), !open && \"opacity-0\")}\n\t\t\t\t\tonClick={open ? onDismiss : undefined}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div\n\t\t\t\t\taria-hidden\n\t\t\t\t\tdata-state={open ? \"open\" : \"closed\"}\n\t\t\t\t\tclassName={cn(dialogOverlayClass(\"absolute\"), !open && \"opacity-0\")}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tref={setPanel}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\tclassName={cn(BASALT_UI_CLASS, panelClass)}\n\t\t\t\tstyle={panelStyle}\n\t\t\t\taria-hidden={!open}\n\t\t\t\tinert={!open || undefined}\n\t\t\t\ttabIndex={open ? -1 : undefined}\n\t\t\t>\n\t\t\t\t{inner}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"dock.js","names":["FOCUSABLE","tabbables","root","node","current","DockBody","cn","className","Dock","ariaLabel","overlay","mode","panelRef","useRef","setPanel","wasOpen","open","previousFocus","useEffect","timer","onKeyDown","event","onDismiss","panelClass","OVERLAY_LAYER","OVERLAY_MOTION","panelStyle","width","inner","dismissLabel","dialogOverlayClass","BASALT_UI_CLASS"],"sources":["../../src/components/dock.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { dialogOverlayClass } from \"./dialog\";\nimport { OVERLAY_LAYER, OVERLAY_MOTION } from \"./overlay\";\n\nconst FOCUSABLE =\n\t'button:not([disabled]), [href], input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nfunction tabbables(root: HTMLElement | null) {\n\tif (!root) {\n\t\treturn [];\n\t}\n\treturn [...root.querySelectorAll<HTMLElement>(FOCUSABLE)].filter((node) => {\n\t\tif (node.closest(\"[inert], [hidden]\")) {\n\t\t\treturn false;\n\t\t}\n\t\tif (node.tabIndex < 0) {\n\t\t\treturn false;\n\t\t}\n\t\tif (window.getComputedStyle(node).visibility === \"hidden\") {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let current: HTMLElement | null = node; current; current = current.parentElement) {\n\t\t\tif (window.getComputedStyle(current).display === \"none\") {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t});\n}\n\nexport type DockMode = \"overlay\" | \"push\";\n\nexport interface DockProps {\n\t/**\n\t * Whether the dock occupies its width.\n\t */\n\topen: boolean;\n\t/**\n\t * `push` shrinks the main column. `overlay` covers the local region with a non-modal scrim.\n\t * @default \"push\"\n\t */\n\tmode?: DockMode;\n\t/**\n\t * Width when open.\n\t * @default \"clamp(300px, 32.5vw, 546px)\"\n\t */\n\twidth?: string;\n\t/**\n\t * Overlay scrim click. Ignored in push mode.\n\t */\n\tonDismiss?: () => void;\n\t/**\n\t * Overlay scrim accessible name.\n\t * @default \"Dismiss\"\n\t */\n\tdismissLabel?: string;\n\t/**\n\t * Accessible name.\n\t */\n\t\"aria-label\": string;\n\tclassName?: string;\n\tchildren: ReactNode;\n}\n\nexport interface DockBodyProps {\n\tclassName?: string;\n\tchildren: ReactNode;\n}\n\nexport function DockBody({ className, children }: DockBodyProps) {\n\treturn (\n\t\t<div className={cn(\"flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto px-3 py-3\", className)}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport function Dock({\n\topen,\n\tmode = \"push\",\n\twidth = \"clamp(300px, 32.5vw, 546px)\",\n\tonDismiss,\n\tdismissLabel = \"Dismiss\",\n\tclassName,\n\tchildren,\n\t\"aria-label\": ariaLabel,\n}: DockProps) {\n\tconst overlay = mode === \"overlay\";\n\tconst panelRef = useRef<HTMLElement | null>(null);\n\tconst setPanel = (node: HTMLElement | null) => {\n\t\tpanelRef.current = node;\n\t};\n\tconst wasOpen = useRef(!overlay && open);\n\tconst previousFocus = useRef<HTMLElement | null>(null);\n\n\tuseEffect(() => {\n\t\tif (open) {\n\t\t\tif (wasOpen.current) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpreviousFocus.current =\n\t\t\t\tdocument.activeElement instanceof HTMLElement ? document.activeElement : null;\n\t\t\tconst timer = window.setTimeout(() => {\n\t\t\t\tconst root = panelRef.current;\n\t\t\t\tconst nodes = tabbables(root);\n\t\t\t\t(nodes[0] ?? root)?.focus();\n\t\t\t\twasOpen.current = true;\n\t\t\t}, 0);\n\t\t\treturn () => window.clearTimeout(timer);\n\t\t}\n\t\tif (wasOpen.current) {\n\t\t\tpreviousFocus.current?.focus?.();\n\t\t\tpreviousFocus.current = null;\n\t\t\twasOpen.current = false;\n\t\t}\n\t}, [open]);\n\n\tuseEffect(() => {\n\t\tif (!overlay || !open) {\n\t\t\treturn;\n\t\t}\n\t\tconst onKeyDown = (event: KeyboardEvent) => {\n\t\t\tif (event.key === \"Escape\") {\n\t\t\t\tif (event.defaultPrevented || !onDismiss) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tevent.preventDefault();\n\t\t\t\tonDismiss();\n\t\t\t}\n\t\t};\n\t\twindow.addEventListener(\"keydown\", onKeyDown);\n\t\treturn () => window.removeEventListener(\"keydown\", onKeyDown);\n\t}, [overlay, open, onDismiss]);\n\tconst panelClass = cn(\n\t\t\"overflow-hidden bg-basalt-background transition-[width] duration-300 ease-in-out\",\n\t\toverlay ? cn(\"absolute top-0 right-0 h-full\", OVERLAY_LAYER) : \"sticky top-0 h-screen shrink-0\",\n\t\tOVERLAY_MOTION,\n\t\tclassName,\n\t);\n\tconst panelStyle = { width: open ? width : 0 };\n\tconst inner = (\n\t\t<div\n\t\t\tclassName=\"flex h-full flex-col bg-basalt-card shadow-lg ring-1 ring-basalt-border/40\"\n\t\t\tstyle={{ width }}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n\n\tif (!overlay) {\n\t\treturn (\n\t\t\t<aside\n\t\t\t\tref={setPanel}\n\t\t\t\tclassName={cn(BASALT_UI_CLASS, panelClass)}\n\t\t\t\tstyle={panelStyle}\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\taria-hidden={!open}\n\t\t\t\tinert={!open || undefined}\n\t\t\t\ttabIndex={open ? -1 : undefined}\n\t\t\t>\n\t\t\t\t{inner}\n\t\t\t</aside>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className={cn(\"absolute inset-0\", OVERLAY_LAYER, !open && \"pointer-events-none\")}>\n\t\t\t{onDismiss ? (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\ttabIndex={open ? 0 : -1}\n\t\t\t\t\taria-label={dismissLabel}\n\t\t\t\t\taria-hidden={!open}\n\t\t\t\t\tdata-state={open ? \"open\" : \"closed\"}\n\t\t\t\t\tclassName={cn(dialogOverlayClass(\"absolute\"), !open && \"opacity-0\")}\n\t\t\t\t\tonClick={open ? onDismiss : undefined}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div\n\t\t\t\t\taria-hidden\n\t\t\t\t\tdata-state={open ? \"open\" : \"closed\"}\n\t\t\t\t\tclassName={cn(dialogOverlayClass(\"absolute\"), !open && \"opacity-0\")}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tref={setPanel}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-label={ariaLabel}\n\t\t\t\tclassName={cn(BASALT_UI_CLASS, panelClass)}\n\t\t\t\tstyle={panelStyle}\n\t\t\t\taria-hidden={!open}\n\t\t\t\tinert={!open || undefined}\n\t\t\t\ttabIndex={open ? -1 : undefined}\n\t\t\t>\n\t\t\t\t{inner}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown-menu.js","names":[],"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 { 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\t<DropdownMenuPrimitive.Portal forceMount={props.forceMount}>\n\t\t<DropdownMenuPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={overlayPanelClass(cn(\"min-w-40\", className))}\n\t\t\t{...props}\n\t\t/>\n\t</DropdownMenuPrimitive.Portal>\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\tref={ref}\n\t\tclassName={overlayItemClass(\n\t\t\tcn(\n\t\t\t\t\"relative outline-hidden focus:bg-basalt-accent 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":";;;;;;;AA4DA,IAAa,IAA4C,EAAsB,MAgBlE,IAAsB,EAAsB,SAgB5C,IAAoB,EAAsB,OAqB1C,IAAqB,EAAsB,QAyB3C,IAAkB,EAAsB,KA6BxC,IAAyB,EAAsB,YAyH/C,IAAsB,EAAM,YAGtC,EAAE,cAAW,gBAAA,GAAuB,GAAG,KAAS,MAClD,kBAAC,EAAsB,QAAvB;CAA8B,YAAY,EAAM;CAC/C,UAAA,kBAAC,EAAsB,SAAvB;EACM;EACO;EACZ,WAAW,EAAkB,EAAG,YAAY,CAAS,CAAC;EACtD,GAAI;CACJ,CAAA;AAC4B,CAAA,CAC9B;AACD,EAAoB,cAAc,EAAsB,QAAQ;AA0BhE,IAAa,IAAmB,EAAM,YAGnC,EAAE,cAAW,GAAG,KAAS,MAC3B,kBAAC,EAAsB,MAAvB;CACM;CACL,WAAW,EACV,EACC,6GACA,CACD,CACD;CACA,GAAI;AACJ,CAAA,CACD;AACD,EAAiB,cAAc,EAAsB,KAAK"}
1
+ {"version":3,"file":"dropdown-menu.js","names":["React","DropdownMenuPrimitive","DropdownMenu","DropdownMenuTrigger","DropdownMenuGroup","DropdownMenuPortal","DropdownMenuSub","DropdownMenuRadioGroup","DropdownMenuContent","props","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 { 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\t<DropdownMenuPrimitive.Portal forceMount={props.forceMount}>\n\t\t<DropdownMenuPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={overlayPanelClass(cn(\"min-w-40\", className))}\n\t\t\t{...props}\n\t\t/>\n\t</DropdownMenuPrimitive.Portal>\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\tref={ref}\n\t\tclassName={overlayItemClass(\n\t\t\tcn(\n\t\t\t\t\"relative outline-hidden focus:bg-basalt-accent 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":";;;;;;;AA4DA,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,MAClD,kBAACR,EAAsB,QAAvB;CAA8B,YAAYQ,EAAM;CAC/C,UAAA,kBAACR,EAAsB,SAAvB;EACM;EACO;EACZ,WAAWS,EAAkBC,EAAG,YAAYC,CAAS,CAAC;EACtD,GAAIH;CACJ,CAAA;AAC4B,CAAA,CAC9B;AACD,EAAoB,cAAcR,EAAsB,QAAQ;AA0BhE,IAAaY,IAAmBb,EAAM,YAGnC,EAAE,cAAW,GAAGS,KAAS,MAC3B,kBAACR,EAAsB,MAAvB;CACM;CACL,WAAWa,EACVH,EACC,6GACAC,CACD,CACD;CACA,GAAIH;AACJ,CAAA,CACD;AACD,EAAiB,cAAcR,EAAsB,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"editable-nav-item.js","names":[],"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 { Button } from \"./button\";\nimport { InlineEditable } from \"./inline-editable\";\nimport { Link } from \"./link\";\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<span className=\"shrink-0\" aria-hidden=\"true\">\n\t\t\t\t{icon}\n\t\t\t</span>\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 id={countId} className=\"shrink-0 text-xs tabular-nums text-basalt-muted-foreground\">\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\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"min-w-0 rounded-basalt-md\",\n\t\t\t\tselected && \"bg-basalt-accent\",\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-2\"\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-1\">\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=\"min-w-0 flex-1 justify-start gap-2\"\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 && <div className=\"flex shrink-0 items-center gap-1\">{actions}</div>}\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-4\" />,\n\t...props\n}: FolderNavItemProps) {\n\treturn <EditableNavItem icon={icon} {...props} />;\n}\n"],"mappings":";;;;;;;;;;AAoCA,SAAgB,EAAgB,EAC/B,UACA,SACA,aACA,cAAW,IACX,SACA,UACA,YACA,aACA,cAAW,IACX,iBAAc,UACd,eAAY,QACZ,iBAAc,UACd,gBACwB;CACxB,IAAM,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,IAAU,EAAM,GAChB,IAAS,EAA0B,IAAI,GACvC,IAAU,EAAO,EAAK;CAC5B,QAAsB;EACrB,AAAI,CAAC,KAAW,EAAQ,YACvB,EAAQ,UAAU,IAClB,EAAO,SAAS,MAAM;CAExB,GAAG,CAAC,CAAO,CAAC;CACZ,IAAM,IACL,kBAAA,GAAA,EAAA,UAAA;EACC,kBAAC,QAAD;GAAM,WAAU;GAAW,eAAY;GACrC,UAAA;EACI,CAAA;EACN,kBAAC,QAAD;GAAM,WAAU;GAAqC,UAAA;EAAY,CAAA;EAChE,KAAS,QACT,kBAAC,QAAD;GAAM,IAAI;GAAS,WAAU;GAA7B,UAAA,CACE,KACA,CACI;;CAEN,EAAA,CAAA;CAEH,OACC,kBAAC,OAAD;EACC,WAAW,EACV,GACA,6BACA,KAAY,oBACZ,CACD;EAEC,UAAA,KAAW,IACX,kBAAC,GAAD;GACC,WAAU;GACV,OAAO,GAAG,EAAY,GAAG;GACzB,OAAO;GACP,SAAA;GACA,QAAQ;GACG;GACE;GACH;GACV,kBAAkB,GAAM,MAAW;IAElC,AADA,EAAQ,UAAU,CAAC,KAAQ,MAAW,QACtC,EAAW,CAAI;GAChB;EACA,CAAA,IAED,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACC,kBAAC,GAAD;KACC,SAAS,CAAC,CAAC;KACX,SAAQ;KACE;KACV,WAAU;KACV,gBAAc,IAAW,SAAS,KAAA;KAClC,cAAY;KACZ,oBAAkB,KAAS,OAAiB,KAAA,IAAV;KAClC,SAAS;KAER,UAAA,IACA,kBAAC,GAAD;MAAY;MAAM,WAAU;MAC1B,UAAA;KACI,CAAA,IAEN;IAEM,CAAA;IACP,KACA,kBAAC,GAAD;KACC,KAAK;KACL,MAAK;KACL,SAAQ;KACE;KACV,cAAY,GAAG,EAAY,GAAG;KAC9B,eAAe,EAAW,EAAI;KAE9B,UAAA,kBAAC,GAAD,CAAS,CAAA;IACF,CAAA;IAER,KAAW,kBAAC,OAAD;KAAK,WAAU;KAAoC,UAAA;IAAa,CAAA;GACxE;;CAEF,CAAA;AAEP;AAIA,SAAgB,EAAc,EAC7B,UAAO,kBAAC,GAAD,EAAQ,WAAU,SAAU,CAAA,GACnC,GAAG,KACmB;CACtB,OAAO,kBAAC,GAAD;EAAuB;EAAM,GAAI;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","cn","BASALT_UI_CLASS","selected","className","onRename","InlineEditable","renameLabel","next","reason","Button","href","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 { Button } from \"./button\";\nimport { InlineEditable } from \"./inline-editable\";\nimport { Link } from \"./link\";\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<span className=\"shrink-0\" aria-hidden=\"true\">\n\t\t\t\t{icon}\n\t\t\t</span>\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 id={countId} className=\"shrink-0 text-xs tabular-nums text-basalt-muted-foreground\">\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\tclassName={cn(\n\t\t\t\tBASALT_UI_CLASS,\n\t\t\t\t\"min-w-0 rounded-basalt-md\",\n\t\t\t\tselected && \"bg-basalt-accent\",\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-2\"\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-1\">\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=\"min-w-0 flex-1 justify-start gap-2\"\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 && <div className=\"flex shrink-0 items-center gap-1\">{actions}</div>}\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-4\" />,\n\t...props\n}: FolderNavItemProps) {\n\treturn <EditableNavItem icon={icon} {...props} />;\n}\n"],"mappings":";;;;;;;;;;AAoCA,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;EACC,kBAAC,QAAD;GAAM,WAAU;GAAW,eAAY;GACrC,UAAAY;EACI,CAAA;EACN,kBAAC,QAAD;GAAM,WAAU;GAAqC,UAAAC;EAAY,CAAA;EAChEC,KAAS,QACT,kBAAC,QAAD;GAAM,IAAIR;GAAS,WAAU;GAA7B,UAAA,CACE,KACAQ,CACI;;CAEN,EAAA,CAAA;CAEH,OACC,kBAAC,OAAD;EACC,WAAWC,EACVC,GACA,6BACAC,KAAY,oBACZC,CACD;EAEC,UAAAf,KAAWgB,IACX,kBAACC,GAAD;GACC,WAAU;GACV,OAAO,GAAGC,EAAY,GAAGR;GACzB,OAAOA;GACP,SAAA;GACA,QAAQM;GACG;GACE;GACH;GACV,kBAAkB,GAAM,MAAW;IAElC,AADA,EAAQ,UAAU,CAACG,KAAQC,MAAW,QACtCnB,EAAWkB,CAAI;GAChB;EACA,CAAA,IAED,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACC,kBAACE,GAAD;KACC,SAAS,CAAC,CAACC;KACX,SAAQ;KACE;KACV,WAAU;KACV,gBAAcR,IAAW,SAAS,KAAA;KAClC,cAAYJ;KACZ,oBAAkBC,KAAS,OAAiB,KAAA,IAAVR;KAClC,SAASoB;KAER,UAAAD,IACA,kBAACE,GAAD;MAAY;MAAM,WAAU;MAC1B,UAAAhB;KACI,CAAA,IAENA;IAEM,CAAA;IACPQ,KACA,kBAACK,GAAD;KACC,KAAKhB;KACL,MAAK;KACL,SAAQ;KACE;KACV,cAAY,GAAGa,EAAY,GAAGR;KAC9B,eAAeT,EAAW,EAAI;KAE9B,UAAA,kBAACwB,GAAD,CAAS,CAAA;IACF,CAAA;IAERC,KAAW,kBAAC,OAAD;KAAK,WAAU;KAAoC,UAAAA;IAAa,CAAA;GACxE;;CAEF,CAAA;AAEP;AAIA,SAAgBC,EAAc,EAC7B,UAAO,kBAACC,GAAD,EAAQ,WAAU,SAAU,CAAA,GACnC,GAAGC,KACmB;CACtB,OAAO,kBAAC9B,GAAD;EAAuB;EAAM,GAAI8B;CAAQ,CAAA;AACjD"}
@@ -1 +1 @@
1
- {"version":3,"file":"empty.js","names":[],"sources":["../../src/components/empty.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport interface EmptyProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\" | \"children\"> {\n\t/**\n\t * Primary title text displayed in the empty state.\n\t *\n\t * @default \"No results\"\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Secondary supporting description text rendered below the title.\n\t */\n\tdescription?: string;\n\n\t/**\n\t * Visual icon element rendered above the title.\n\t */\n\ticon?: ReactNode;\n\n\t/**\n\t * Interactive call-to-action element (e.g. Button or Link) rendered below content.\n\t */\n\taction?: ReactNode;\n\n\t/**\n\t * Custom supporting content or custom layout rendered between description and action.\n\t */\n\tchildren?: ReactNode;\n}\n\nexport function Empty({\n\ttitle = \"No results\",\n\tdescription,\n\ticon,\n\taction,\n\tchildren,\n\tclassName,\n\t...props\n}: EmptyProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"flex flex-col items-center gap-2 text-center\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{icon ? <div className=\"text-basalt-muted-foreground [&_svg]:size-8\">{icon}</div> : null}\n\t\t\t<p className=\"text-sm font-medium text-basalt-foreground\">{title}</p>\n\t\t\t{description ? <p className=\"text-xs text-basalt-muted-foreground\">{description}</p> : null}\n\t\t\t{children !== undefined && children !== null ? (\n\t\t\t\t<div className=\"text-xs text-basalt-muted-foreground\">{children}</div>\n\t\t\t) : null}\n\t\t\t{action !== undefined && action !== null ? (\n\t\t\t\t<div className=\"mt-2 flex items-center justify-center gap-2\">{action}</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;AAiCA,SAAgB,EAAM,EACrB,WAAQ,cACR,gBACA,SACA,WACA,aACA,cACA,GAAG,KACW;CACd,OACC,kBAAC,OAAD;EACC,WAAW,EAAG,GAAiB,gDAAgD,CAAS;EACxF,GAAI;EAFL,UAAA;GAIE,IAAO,kBAAC,OAAD;IAAK,WAAU;IAA+C,UAAA;GAAU,CAAA,IAAI;GACpF,kBAAC,KAAD;IAAG,WAAU;IAA8C,UAAA;GAAS,CAAA;GACnE,IAAc,kBAAC,KAAD;IAAG,WAAU;IAAwC,UAAA;GAAe,CAAA,IAAI;GACtF,KAAuC,OAEpC,OADH,kBAAC,OAAD;IAAK,WAAU;IAAwC;GAAc,CAAA;GAErE,KAAmC,OAEhC,OADH,kBAAC,OAAD;IAAK,WAAU;IAA+C,UAAA;GAAY,CAAA;EAEvE;;AAEP"}
1
+ {"version":3,"file":"empty.js","names":["Empty","props","cn","BASALT_UI_CLASS","className","icon","title","description","children","action"],"sources":["../../src/components/empty.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nexport interface EmptyProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\" | \"children\"> {\n\t/**\n\t * Primary title text displayed in the empty state.\n\t *\n\t * @default \"No results\"\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Secondary supporting description text rendered below the title.\n\t */\n\tdescription?: string;\n\n\t/**\n\t * Visual icon element rendered above the title.\n\t */\n\ticon?: ReactNode;\n\n\t/**\n\t * Interactive call-to-action element (e.g. Button or Link) rendered below content.\n\t */\n\taction?: ReactNode;\n\n\t/**\n\t * Custom supporting content or custom layout rendered between description and action.\n\t */\n\tchildren?: ReactNode;\n}\n\nexport function Empty({\n\ttitle = \"No results\",\n\tdescription,\n\ticon,\n\taction,\n\tchildren,\n\tclassName,\n\t...props\n}: EmptyProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(BASALT_UI_CLASS, \"flex flex-col items-center gap-2 text-center\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{icon ? <div className=\"text-basalt-muted-foreground [&_svg]:size-8\">{icon}</div> : null}\n\t\t\t<p className=\"text-sm font-medium text-basalt-foreground\">{title}</p>\n\t\t\t{description ? <p className=\"text-xs text-basalt-muted-foreground\">{description}</p> : null}\n\t\t\t{children !== undefined && children !== null ? (\n\t\t\t\t<div className=\"text-xs text-basalt-muted-foreground\">{children}</div>\n\t\t\t) : null}\n\t\t\t{action !== undefined && action !== null ? (\n\t\t\t\t<div className=\"mt-2 flex items-center justify-center gap-2\">{action}</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;AAiCA,SAAgBA,EAAM,EACrB,WAAQ,cACR,gBACA,SACA,WACA,aACA,cACA,GAAGC,KACW;CACd,OACC,kBAAC,OAAD;EACC,WAAWC,EAAGC,GAAiB,gDAAgDC,CAAS;EACxF,GAAIH;EAFL,UAAA;GAIEI,IAAO,kBAAC,OAAD;IAAK,WAAU;IAA+C,UAAAA;GAAU,CAAA,IAAI;GACpF,kBAAC,KAAD;IAAG,WAAU;IAA8C,UAAAC;GAAS,CAAA;GACnEC,IAAc,kBAAC,KAAD;IAAG,WAAU;IAAwC,UAAAA;GAAe,CAAA,IAAI;GACtFC,KAAuC,OAEpC,OADH,kBAAC,OAAD;IAAK,WAAU;IAAwC;GAAc,CAAA;GAErEC,KAAmC,OAEhC,OADH,kBAAC,OAAD;IAAK,WAAU;IAA+C,UAAAA;GAAY,CAAA;EAEvE;;AAEP"}
@@ -1 +1 @@
1
- {"version":3,"file":"fab.js","names":[],"sources":["../../src/components/fab.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Button } from \"./button\";\nimport { OVERLAY_LAYER, OVERLAY_MOTION } from \"./overlay\";\n\nexport type FabPlacement = \"absolute\" | \"fixed\";\n\nexport interface FabProps {\n\t/**\n\t * When true, the launcher hides so a dock can take the corner.\n\t * @default false\n\t */\n\topen?: boolean;\n\t/**\n\t * Viewport pin versus containing frame.\n\t * @default \"fixed\"\n\t */\n\tplacement?: FabPlacement;\n\t/**\n\t * Accessible name.\n\t */\n\t\"aria-label\": string;\n\tonClick?: React.MouseEventHandler<HTMLButtonElement>;\n\tchildren?: React.ReactNode;\n\tclassName?: string;\n\tdisabled?: boolean;\n}\n\nexport const Fab = React.forwardRef<HTMLButtonElement, FabProps>(\n\t(\n\t\t{\n\t\t\topen = false,\n\t\t\tplacement = \"fixed\",\n\t\t\tclassName,\n\t\t\tchildren,\n\t\t\tonClick,\n\t\t\t\"aria-label\": ariaLabel,\n\t\t\tdisabled,\n\t\t},\n\t\tref,\n\t) => (\n\t\t<Button\n\t\t\tref={ref}\n\t\t\tsize=\"icon\"\n\t\t\taria-label={ariaLabel}\n\t\t\taria-expanded={open}\n\t\t\taria-hidden={open || undefined}\n\t\t\ttabIndex={open ? -1 : 0}\n\t\t\tinert={open || undefined}\n\t\t\tdisabled={disabled}\n\t\t\tonClick={open ? undefined : onClick}\n\t\t\tclassName={cn(\n\t\t\t\tplacement === \"absolute\" ? \"absolute\" : \"fixed\",\n\t\t\t\t\"right-4 bottom-4 h-16 w-16 rounded-full shadow-lg\",\n\t\t\t\tOVERLAY_LAYER,\n\t\t\t\t\"transition-[transform,opacity] duration-300 ease-in-out\",\n\t\t\t\tOVERLAY_MOTION,\n\t\t\t\topen ? \"pointer-events-none scale-75 opacity-0\" : \"hover:scale-[1.03] active:scale-[0.98]\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</Button>\n\t),\n);\nFab.displayName = \"Fab\";\n"],"mappings":";;;;;;;AA4BA,IAAa,IAAM,EAAM,YAEvB,EACC,UAAO,IACP,eAAY,SACZ,cACA,aACA,YACA,cAAc,GACd,eAED,MAEA,kBAAC,GAAD;CACM;CACL,MAAK;CACL,cAAY;CACZ,iBAAe;CACf,eAAa,KAAQ,KAAA;CACrB,UAAU,IAAO,KAAK;CACtB,OAAO,KAAQ,KAAA;CACL;CACV,SAAS,IAAO,KAAA,IAAY;CAC5B,WAAW,EACV,MAAc,aAAa,aAAa,SACxC,qDACA,GACA,2DACA,GACA,IAAO,2CAA2C,0CAClD,CACD;CAEC;AACM,CAAA,CAEV;AACA,EAAI,cAAc"}
1
+ {"version":3,"file":"fab.js","names":["React","Fab","ariaLabel","Button","open","onClick","cn","placement","OVERLAY_LAYER","OVERLAY_MOTION","className"],"sources":["../../src/components/fab.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { Button } from \"./button\";\nimport { OVERLAY_LAYER, OVERLAY_MOTION } from \"./overlay\";\n\nexport type FabPlacement = \"absolute\" | \"fixed\";\n\nexport interface FabProps {\n\t/**\n\t * When true, the launcher hides so a dock can take the corner.\n\t * @default false\n\t */\n\topen?: boolean;\n\t/**\n\t * Viewport pin versus containing frame.\n\t * @default \"fixed\"\n\t */\n\tplacement?: FabPlacement;\n\t/**\n\t * Accessible name.\n\t */\n\t\"aria-label\": string;\n\tonClick?: React.MouseEventHandler<HTMLButtonElement>;\n\tchildren?: React.ReactNode;\n\tclassName?: string;\n\tdisabled?: boolean;\n}\n\nexport const Fab = React.forwardRef<HTMLButtonElement, FabProps>(\n\t(\n\t\t{\n\t\t\topen = false,\n\t\t\tplacement = \"fixed\",\n\t\t\tclassName,\n\t\t\tchildren,\n\t\t\tonClick,\n\t\t\t\"aria-label\": ariaLabel,\n\t\t\tdisabled,\n\t\t},\n\t\tref,\n\t) => (\n\t\t<Button\n\t\t\tref={ref}\n\t\t\tsize=\"icon\"\n\t\t\taria-label={ariaLabel}\n\t\t\taria-expanded={open}\n\t\t\taria-hidden={open || undefined}\n\t\t\ttabIndex={open ? -1 : 0}\n\t\t\tinert={open || undefined}\n\t\t\tdisabled={disabled}\n\t\t\tonClick={open ? undefined : onClick}\n\t\t\tclassName={cn(\n\t\t\t\tplacement === \"absolute\" ? \"absolute\" : \"fixed\",\n\t\t\t\t\"right-4 bottom-4 h-16 w-16 rounded-full shadow-lg\",\n\t\t\t\tOVERLAY_LAYER,\n\t\t\t\t\"transition-[transform,opacity] duration-300 ease-in-out\",\n\t\t\t\tOVERLAY_MOTION,\n\t\t\t\topen ? \"pointer-events-none scale-75 opacity-0\" : \"hover:scale-[1.03] active:scale-[0.98]\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</Button>\n\t),\n);\nFab.displayName = \"Fab\";\n"],"mappings":";;;;;;;AA4BA,IAAaC,IAAMD,EAAM,YAEvB,EACC,UAAO,IACP,eAAY,SACZ,cACA,aACA,YACA,cAAcE,GACd,eAED,MAEA,kBAACC,GAAD;CACM;CACL,MAAK;CACL,cAAYD;CACZ,iBAAeE;CACf,eAAaA,KAAQ,KAAA;CACrB,UAAUA,IAAO,KAAK;CACtB,OAAOA,KAAQ,KAAA;CACL;CACV,SAASA,IAAO,KAAA,IAAYC;CAC5B,WAAWC,EACVC,MAAc,aAAa,aAAa,SACxC,qDACAC,GACA,2DACAC,GACAL,IAAO,2CAA2C,0CAClDM,CACD;CAEC;AACM,CAAA,CAEV;AACA,EAAI,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"field.js","names":[],"sources":["../../src/components/field.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Label } from \"./label\";\n\nexport type FieldError = Exclude<React.ReactNode, undefined> | { message: React.ReactNode };\n\ntype FieldControlProps = {\n\tid?: string;\n\t\"aria-describedby\"?: string;\n\t\"aria-invalid\"?: boolean | \"true\" | \"false\";\n};\n\nexport interface FieldProps\n\textends Omit<React.ComponentPropsWithoutRef<\"div\">, \"children\" | \"className\"> {\n\t/**\n\t * Visible label.\n\t */\n\tlabel: React.ReactNode;\n\t/**\n\t * Associates the label and described-by ids.\n\t */\n\thtmlFor?: string;\n\t/**\n\t * Supporting text when there is no error.\n\t */\n\thint?: React.ReactNode;\n\t/**\n\t * Replaces the hint and marks the control invalid.\n\t */\n\terror?: FieldError;\n\t/**\n\t * When false, show (optional) after the label.\n\t */\n\trequired?: boolean;\n\t/**\n\t * Info icon with hover text on the label.\n\t */\n\tlabelTooltip?: React.ReactNode;\n\t/**\n\t * Additional classes for the field root.\n\t */\n\tclassName?: string;\n\t/**\n\t * The control or content to render.\n\t */\n\tchildren: React.ReactNode;\n}\n\nfunction isStructuredError(error: FieldError): error is { message: React.ReactNode } {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t!Array.isArray(error) &&\n\t\t!React.isValidElement(error) &&\n\t\t\"message\" in error\n\t);\n}\n\nfunction fieldErrorMessage(error: FieldError | undefined): React.ReactNode | undefined {\n\tif (error == null) {\n\t\treturn undefined;\n\t}\n\treturn isStructuredError(error) ? error.message : error;\n}\n\nexport const Field = React.forwardRef<HTMLDivElement, FieldProps>(\n\t({ label, htmlFor, hint, error, required, labelTooltip, className, children, ...props }, ref) => {\n\t\tconst generatedId = React.useId();\n\t\tconst child = React.isValidElement(children)\n\t\t\t? (children as React.ReactElement<FieldControlProps>)\n\t\t\t: null;\n\t\tconst controlId = child ? (htmlFor ?? child.props.id ?? generatedId) : htmlFor;\n\t\tconst hintId = controlId ? `${controlId}-hint` : undefined;\n\t\tconst errorId = controlId ? `${controlId}-error` : undefined;\n\t\tconst errorMessage = fieldErrorMessage(error);\n\t\tconst hasError = Boolean(errorMessage);\n\t\tconst describedBy = [hasError ? errorId : null, !hasError && hint ? hintId : null]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\tconst mergedDescribedBy = [describedBy, child?.props[\"aria-describedby\"]]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\treturn (\n\t\t\t<div ref={ref} {...props} className={cn(BASALT_UI_CLASS, \"flex flex-col gap-1.5\", className)}>\n\t\t\t\t<Label htmlFor={controlId} showOptional={required === false} tooltip={labelTooltip}>\n\t\t\t\t\t{label}\n\t\t\t\t</Label>\n\t\t\t\t{child\n\t\t\t\t\t? React.cloneElement(child, {\n\t\t\t\t\t\t\tid: controlId,\n\t\t\t\t\t\t\t\"aria-invalid\": hasError ? true : child.props[\"aria-invalid\"],\n\t\t\t\t\t\t\t\"aria-describedby\": mergedDescribedBy || undefined,\n\t\t\t\t\t\t})\n\t\t\t\t\t: children}\n\t\t\t\t{hint && !hasError ? (\n\t\t\t\t\t<p id={hintId} className=\"text-xs text-basalt-muted-foreground\">\n\t\t\t\t\t\t{hint}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t\t{hasError ? (\n\t\t\t\t\t<p id={errorId} className=\"text-xs text-basalt-destructive\" role=\"alert\">\n\t\t\t\t\t\t{errorMessage}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t);\n\t},\n);\nField.displayName = \"Field\";\n"],"mappings":";;;;;;;AAiDA,SAAS,EAAkB,GAA0D;CACpF,OACC,OAAO,KAAU,cACjB,KACA,CAAC,MAAM,QAAQ,CAAK,KACpB,CAAC,EAAM,eAAe,CAAK,KAC3B,aAAa;AAEf;AAEA,SAAS,EAAkB,GAA4D;CAClF,SAAS,MAGb,OAAO,EAAkB,CAAK,IAAI,EAAM,UAAU;AACnD;AAEA,IAAa,IAAQ,EAAM,YACzB,EAAE,UAAO,YAAS,SAAM,UAAO,aAAU,iBAAc,cAAW,aAAU,GAAG,KAAS,MAAQ;CAChG,IAAM,IAAc,EAAM,MAAM,GAC1B,IAAQ,EAAM,eAAe,CAAQ,IACvC,IACD,MACG,IAAY,IAAS,KAAW,EAAM,MAAM,MAAM,IAAe,GACjE,IAAS,IAAY,GAAG,EAAU,SAAS,KAAA,GAC3C,IAAU,IAAY,GAAG,EAAU,UAAU,KAAA,GAC7C,IAAe,EAAkB,CAAK,GACtC,IAAW,EAAQ,GAInB,IAAoB,CAHN,CAAC,IAAW,IAAU,MAAM,CAAC,KAAY,IAAO,IAAS,IAAI,CAAC,CAChF,OAAO,OAAO,CAAC,CACf,KAAK,GACoB,GAAa,GAAO,MAAM,mBAAmB,CAAC,CACvE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CACV,OACC,kBAAC,OAAD;EAAU;EAAK,GAAI;EAAO,WAAW,EAAG,GAAiB,yBAAyB,CAAS;EAA3F,UAAA;GACC,kBAAC,GAAD;IAAO,SAAS;IAAW,cAAc,MAAa;IAAO,SAAS;IACpE,UAAA;GACK,CAAA;GACN,IACE,EAAM,aAAa,GAAO;IAC1B,IAAI;IACJ,gBAAgB,IAAW,KAAO,EAAM,MAAM;IAC9C,oBAAoB,KAAqB,KAAA;GAC1C,CAAC,IACA;GACF,KAAQ,CAAC,IACT,kBAAC,KAAD;IAAG,IAAI;IAAQ,WAAU;IACvB,UAAA;GACC,CAAA,IACA;GACH,IACA,kBAAC,KAAD;IAAG,IAAI;IAAS,WAAU;IAAkC,MAAK;IAC/D,UAAA;GACC,CAAA,IACA;EACA;;AAEP,CACD;AACA,EAAM,cAAc"}
1
+ {"version":3,"file":"field.js","names":["React","isStructuredError","error","fieldErrorMessage","Field","props","generatedId","child","children","controlId","htmlFor","hintId","errorId","errorMessage","hasError","mergedDescribedBy","hint","cn","BASALT_UI_CLASS","className","Label","required","labelTooltip","label"],"sources":["../../src/components/field.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\nimport { Label } from \"./label\";\n\nexport type FieldError = Exclude<React.ReactNode, undefined> | { message: React.ReactNode };\n\ntype FieldControlProps = {\n\tid?: string;\n\t\"aria-describedby\"?: string;\n\t\"aria-invalid\"?: boolean | \"true\" | \"false\";\n};\n\nexport interface FieldProps\n\textends Omit<React.ComponentPropsWithoutRef<\"div\">, \"children\" | \"className\"> {\n\t/**\n\t * Visible label.\n\t */\n\tlabel: React.ReactNode;\n\t/**\n\t * Associates the label and described-by ids.\n\t */\n\thtmlFor?: string;\n\t/**\n\t * Supporting text when there is no error.\n\t */\n\thint?: React.ReactNode;\n\t/**\n\t * Replaces the hint and marks the control invalid.\n\t */\n\terror?: FieldError;\n\t/**\n\t * When false, show (optional) after the label.\n\t */\n\trequired?: boolean;\n\t/**\n\t * Info icon with hover text on the label.\n\t */\n\tlabelTooltip?: React.ReactNode;\n\t/**\n\t * Additional classes for the field root.\n\t */\n\tclassName?: string;\n\t/**\n\t * The control or content to render.\n\t */\n\tchildren: React.ReactNode;\n}\n\nfunction isStructuredError(error: FieldError): error is { message: React.ReactNode } {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t!Array.isArray(error) &&\n\t\t!React.isValidElement(error) &&\n\t\t\"message\" in error\n\t);\n}\n\nfunction fieldErrorMessage(error: FieldError | undefined): React.ReactNode | undefined {\n\tif (error == null) {\n\t\treturn undefined;\n\t}\n\treturn isStructuredError(error) ? error.message : error;\n}\n\nexport const Field = React.forwardRef<HTMLDivElement, FieldProps>(\n\t({ label, htmlFor, hint, error, required, labelTooltip, className, children, ...props }, ref) => {\n\t\tconst generatedId = React.useId();\n\t\tconst child = React.isValidElement(children)\n\t\t\t? (children as React.ReactElement<FieldControlProps>)\n\t\t\t: null;\n\t\tconst controlId = child ? (htmlFor ?? child.props.id ?? generatedId) : htmlFor;\n\t\tconst hintId = controlId ? `${controlId}-hint` : undefined;\n\t\tconst errorId = controlId ? `${controlId}-error` : undefined;\n\t\tconst errorMessage = fieldErrorMessage(error);\n\t\tconst hasError = Boolean(errorMessage);\n\t\tconst describedBy = [hasError ? errorId : null, !hasError && hint ? hintId : null]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\tconst mergedDescribedBy = [describedBy, child?.props[\"aria-describedby\"]]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" \");\n\t\treturn (\n\t\t\t<div ref={ref} {...props} className={cn(BASALT_UI_CLASS, \"flex flex-col gap-1.5\", className)}>\n\t\t\t\t<Label htmlFor={controlId} showOptional={required === false} tooltip={labelTooltip}>\n\t\t\t\t\t{label}\n\t\t\t\t</Label>\n\t\t\t\t{child\n\t\t\t\t\t? React.cloneElement(child, {\n\t\t\t\t\t\t\tid: controlId,\n\t\t\t\t\t\t\t\"aria-invalid\": hasError ? true : child.props[\"aria-invalid\"],\n\t\t\t\t\t\t\t\"aria-describedby\": mergedDescribedBy || undefined,\n\t\t\t\t\t\t})\n\t\t\t\t\t: children}\n\t\t\t\t{hint && !hasError ? (\n\t\t\t\t\t<p id={hintId} className=\"text-xs text-basalt-muted-foreground\">\n\t\t\t\t\t\t{hint}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t\t{hasError ? (\n\t\t\t\t\t<p id={errorId} className=\"text-xs text-basalt-destructive\" role=\"alert\">\n\t\t\t\t\t\t{errorMessage}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t);\n\t},\n);\nField.displayName = \"Field\";\n"],"mappings":";;;;;;;AAiDA,SAASC,EAAkB,GAA0D;CACpF,OACC,OAAOC,KAAU,cACjBA,KACA,CAAC,MAAM,QAAQA,CAAK,KACpB,CAACF,EAAM,eAAeE,CAAK,KAC3B,aAAaA;AAEf;AAEA,SAASC,EAAkB,GAA4D;CACtF,IAAID,KAAS,MAGb,OAAOD,EAAkBC,CAAK,IAAIA,EAAM,UAAUA;AACnD;AAEA,IAAaE,IAAQJ,EAAM,YACzB,EAAE,UAAO,YAAS,SAAM,UAAO,aAAU,iBAAc,cAAW,aAAU,GAAGK,KAAS,MAAQ;CAChG,IAAMC,IAAcN,EAAM,MAAM,GAC1BO,IAAQP,EAAM,eAAeQ,CAAQ,IACvCA,IACD,MACGC,IAAYF,IAASG,KAAWH,EAAM,MAAM,MAAMD,IAAeI,GACjEC,IAASF,IAAY,GAAGA,EAAU,SAAS,KAAA,GAC3CG,IAAUH,IAAY,GAAGA,EAAU,UAAU,KAAA,GAC7CI,IAAeV,EAAkBD,CAAK,GACtCY,IAAW,EAAQD,GAInBE,IAAoB,CAHN,CAACD,IAAWF,IAAU,MAAM,CAACE,KAAYE,IAAOL,IAAS,IAAI,CAAC,CAChF,OAAO,OAAO,CAAC,CACf,KAAK,GACoB,GAAaJ,GAAO,MAAM,mBAAmB,CAAC,CACvE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CACV,OACC,kBAAC,OAAD;EAAU;EAAK,GAAIF;EAAO,WAAWY,EAAGC,GAAiB,yBAAyBC,CAAS;EAA3F,UAAA;GACC,kBAACC,GAAD;IAAO,SAASX;IAAW,cAAcY,MAAa;IAAO,SAASC;IACpE,UAAAC;GACK,CAAA;GACNhB,IACEP,EAAM,aAAaO,GAAO;IAC1B,IAAIE;IACJ,gBAAgBK,IAAW,KAAOP,EAAM,MAAM;IAC9C,oBAAoBQ,KAAqB,KAAA;GAC1C,CAAC,IACAP;GACFQ,KAAQ,CAACF,IACT,kBAAC,KAAD;IAAG,IAAIH;IAAQ,WAAU;IACvB,UAAAK;GACC,CAAA,IACA;GACHF,IACA,kBAAC,KAAD;IAAG,IAAIF;IAAS,WAAU;IAAkC,MAAK;IAC/D,UAAAC;GACC,CAAA,IACA;EACA;;AAEP,CACD;AACA,EAAM,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-dropzone.js","names":[],"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-2\", 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-2 rounded-basalt-lg border-2 border-dashed px-4 py-7 text-center transition-colors 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-accent\"\n\t\t\t\t\t\t: \"border-basalt-border bg-basalt-card hover:bg-basalt-accent\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Upload className=\"size-6 text-basalt-muted-foreground\" aria-hidden=\"true\" />\n\t\t\t\t<span className=\"text-sm font-medium\">{dragging && !disabled ? dropLabel : label}</span>\n\t\t\t\t{description && (\n\t\t\t\t\t<span id={`${id}-description`} className=\"text-xs 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-3 py-1 text-xs\">\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-1 text-xs 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-2\", 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-2 rounded-basalt-lg border-2 border-dashed px-4 py-7 text-center transition-colors 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-accent\"\n\t\t\t\t\t\t: \"border-basalt-border bg-basalt-card hover:bg-basalt-accent\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Upload className=\"size-6 text-basalt-muted-foreground\" aria-hidden=\"true\" />\n\t\t\t\t<span className=\"text-sm font-medium\">{dragging && !disabled ? dropLabel : label}</span>\n\t\t\t\t{description && (\n\t\t\t\t\t<span id={`${id}-description`} className=\"text-xs 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-3 py-1 text-xs\">\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-1 text-xs 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 +1 @@
1
- {"version":3,"file":"filter-bar.js","names":[],"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-3\", className)}\n\t\t>\n\t\t\t<div className=\"flex flex-wrap items-end gap-3 [&>*]: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 && <div className=\"flex flex-wrap items-center gap-2\">{chips}</div>}\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-1 rounded-full border border-basalt-border bg-basalt-accent py-1 pl-3 pr-1 text-xs\",\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-full p-1 focus-visible:outline-2 focus-visible:outline-basalt-ring disabled:opacity-50\"\n\t\t\t>\n\t\t\t\t<X className=\"size-3\" aria-hidden=\"true\" />\n\t\t\t</button>\n\t\t</span>\n\t);\n}\n"],"mappings":";;;;;;;AAwBA,SAAgB,EAAU,EACzB,UACA,aACA,UACA,YAAS,IACT,YACA,gBAAa,iBACb,gBACkB;CAClB,OACC,kBAAC,OAAD;EACC,MAAK;EACL,cAAY;EACZ,WAAW,EAAG,GAAiB,qBAAqB,CAAS;EAH9D,UAAA,CAKC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,GACA,KAAU,KACV,kBAAC,GAAD;IAAQ,MAAK;IAAK,SAAQ;IAAQ,SAAS;IACzC,UAAA;GACM,CAAA,CAEL;EACJ,CAAA,GAAA,KAAS,QAAQ,kBAAC,OAAD;GAAK,WAAU;GAAqC,UAAA;EAAW,CAAA,CAC7E;;AAEP;AAiBA,SAAgB,EAAW,EAC1B,UACA,UACA,aACA,gBACA,cAAW,IACX,gBACmB;CACnB,OACC,kBAAC,QAAD;EACC,WAAW,EACV,GACA,8HACA,CACD;EALD,UAAA,CAOC,kBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACC,kBAAC,QAAD;IAAM,WAAU;IAAhB,UAAA,CAAgD,GAAM,IAAQ;GAC7D,CAAA,GAAA,CACI;EACN,CAAA,GAAA,kBAAC,UAAD;GACC,MAAK;GACK;GACV,cAAY,KAAe,UAAU;GACrC,SAAS;GACT,WAAU;GAEV,UAAA,kBAAC,GAAD;IAAG,WAAU;IAAS,eAAY;GAAQ,CAAA;EACnC,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-3\", className)}\n\t\t>\n\t\t\t<div className=\"flex flex-wrap items-end gap-3 [&>*]: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 && <div className=\"flex flex-wrap items-center gap-2\">{chips}</div>}\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-1 rounded-full border border-basalt-border bg-basalt-accent py-1 pl-3 pr-1 text-xs\",\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-full p-1 focus-visible:outline-2 focus-visible:outline-basalt-ring disabled:opacity-50\"\n\t\t\t>\n\t\t\t\t<X className=\"size-3\" 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,qBAAqBC,CAAS;EAH9D,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,QAAQ,kBAAC,OAAD;GAAK,WAAU;GAAqC,UAAAA;EAAW,CAAA,CAC7E;;AAEP;AAiBA,SAAgBC,EAAW,EAC1B,UACA,UACA,aACA,gBACA,cAAW,IACX,gBACmB;CACnB,OACC,kBAAC,QAAD;EACC,WAAWT,EACVC,GACA,8HACAC,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;IAAS,eAAY;GAAQ,CAAA;EACnC,CAAA,CACH;;AAER"}
@@ -1 +1 @@
1
- {"version":3,"file":"flow.js","names":[],"sources":["../../src/components/flow.tsx"],"sourcesContent":["import { Children, Fragment, type ReactNode, useId } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nfunction FlowArrow() {\n\tconst id = `flow-arrow-${useId().replace(/:/g, \"\")}`;\n\treturn (\n\t\t<li aria-hidden=\"true\" className=\"flex w-10 shrink-0 items-center text-basalt-muted-foreground\">\n\t\t\t<svg\n\t\t\t\tviewBox=\"0 0 40 16\"\n\t\t\t\tclassName=\"h-4 w-10 overflow-visible\"\n\t\t\t\toverflow=\"visible\"\n\t\t\t\taria-hidden=\"true\"\n\t\t\t>\n\t\t\t\t<defs>\n\t\t\t\t\t<marker\n\t\t\t\t\t\tid={id}\n\t\t\t\t\t\tmarkerWidth=\"8\"\n\t\t\t\t\t\tmarkerHeight=\"8\"\n\t\t\t\t\t\trefX=\"0\"\n\t\t\t\t\t\trefY=\"4\"\n\t\t\t\t\t\torient=\"auto\"\n\t\t\t\t\t\tmarkerUnits=\"userSpaceOnUse\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\td=\"M 0,1.5 Q 0,0 1.5,0 Q 3.5,1 5.8,3.2 Q 6.5,4 5.8,4.8 Q 3.5,7 1.5,8 Q 0,8 0,6.5 Z\"\n\t\t\t\t\t\t\tfill=\"currentColor\"\n\t\t\t\t\t\t\tstroke=\"none\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</marker>\n\t\t\t\t</defs>\n\t\t\t\t<path\n\t\t\t\t\td=\"M 0 8 L 32 8\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\tmarkerEnd={`url(#${id})`}\n\t\t\t\t/>\n\t\t\t</svg>\n\t\t</li>\n\t);\n}\n\nexport type FlowProps = {\n\t/**\n\t * Accessible name for the step list.\n\t * @default \"Flow\"\n\t */\n\t\"aria-label\"?: string;\n\t/**\n\t * Additional classes for the list.\n\t */\n\tclassName?: string;\n\t/**\n\t * Step nodes.\n\t */\n\tchildren: ReactNode;\n};\n\nexport function Flow({ className, children, \"aria-label\": ariaLabel = \"Flow\" }: FlowProps) {\n\tconst nodes = Children.toArray(children);\n\treturn (\n\t\t<ol aria-label={ariaLabel} className={cn(BASALT_UI_CLASS, \"flex items-center\", className)}>\n\t\t\t{nodes.map((child, index) => (\n\t\t\t\t<Fragment key={index}>\n\t\t\t\t\t{child}\n\t\t\t\t\t{index < nodes.length - 1 ? <FlowArrow /> : null}\n\t\t\t\t</Fragment>\n\t\t\t))}\n\t\t</ol>\n\t);\n}\n\nexport type FlowNodeProps = {\n\t/**\n\t * Label for the step.\n\t */\n\tchildren: ReactNode;\n};\n\nexport function FlowNode({ children }: FlowNodeProps) {\n\treturn (\n\t\t<li className=\"rounded-basalt-md border border-basalt-border bg-basalt-secondary px-3 py-2 text-sm\">\n\t\t\t{children}\n\t\t</li>\n\t);\n}\n"],"mappings":";;;;;;AAIA,SAAS,IAAY;CACpB,IAAM,IAAK,cAAc,EAAM,CAAC,CAAC,QAAQ,MAAM,EAAE;CACjD,OACC,kBAAC,MAAD;EAAI,eAAY;EAAO,WAAU;EAChC,UAAA,kBAAC,OAAD;GACC,SAAQ;GACR,WAAU;GACV,UAAS;GACT,eAAY;GAJb,UAAA,CAMC,kBAAC,QAAD,EAAA,UACC,kBAAC,UAAD;IACK;IACJ,aAAY;IACZ,cAAa;IACb,MAAK;IACL,MAAK;IACL,QAAO;IACP,aAAY;IAEZ,UAAA,kBAAC,QAAD;KACC,GAAE;KACF,MAAK;KACL,QAAO;IACP,CAAA;GACM,CAAA,EACH,CAAA,GACN,kBAAC,QAAD;IACC,GAAE;IACF,MAAK;IACL,QAAO;IACP,aAAY;IACZ,WAAW,QAAQ,EAAG;GACtB,CAAA,CACG;;CACF,CAAA;AAEN;AAkBA,SAAgB,EAAK,EAAE,cAAW,aAAU,cAAc,IAAY,UAAqB;CAC1F,IAAM,IAAQ,EAAS,QAAQ,CAAQ;CACvC,OACC,kBAAC,MAAD;EAAI,cAAY;EAAW,WAAW,EAAG,GAAiB,qBAAqB,CAAS;EACtF,UAAA,EAAM,KAAK,GAAO,MAClB,kBAAC,GAAD,EAAA,UAAA,CACE,GACA,IAAQ,EAAM,SAAS,IAAI,kBAAC,GAAD,CAAY,CAAA,IAAI,IACnC,EAAA,GAHK,CAGL,CACV;CACE,CAAA;AAEN;AASA,SAAgB,EAAS,EAAE,eAA2B;CACrD,OACC,kBAAC,MAAD;EAAI,WAAU;EACZ;CACE,CAAA;AAEN"}
1
+ {"version":3,"file":"flow.js","names":["FlowArrow","id","useId","Flow","ariaLabel","nodes","Children","children","cn","BASALT_UI_CLASS","className","Fragment","child","index","FlowNode"],"sources":["../../src/components/flow.tsx"],"sourcesContent":["import { Children, Fragment, type ReactNode, useId } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { BASALT_UI_CLASS } from \"../utils/control-surface\";\n\nfunction FlowArrow() {\n\tconst id = `flow-arrow-${useId().replace(/:/g, \"\")}`;\n\treturn (\n\t\t<li aria-hidden=\"true\" className=\"flex w-10 shrink-0 items-center text-basalt-muted-foreground\">\n\t\t\t<svg\n\t\t\t\tviewBox=\"0 0 40 16\"\n\t\t\t\tclassName=\"h-4 w-10 overflow-visible\"\n\t\t\t\toverflow=\"visible\"\n\t\t\t\taria-hidden=\"true\"\n\t\t\t>\n\t\t\t\t<defs>\n\t\t\t\t\t<marker\n\t\t\t\t\t\tid={id}\n\t\t\t\t\t\tmarkerWidth=\"8\"\n\t\t\t\t\t\tmarkerHeight=\"8\"\n\t\t\t\t\t\trefX=\"0\"\n\t\t\t\t\t\trefY=\"4\"\n\t\t\t\t\t\torient=\"auto\"\n\t\t\t\t\t\tmarkerUnits=\"userSpaceOnUse\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\td=\"M 0,1.5 Q 0,0 1.5,0 Q 3.5,1 5.8,3.2 Q 6.5,4 5.8,4.8 Q 3.5,7 1.5,8 Q 0,8 0,6.5 Z\"\n\t\t\t\t\t\t\tfill=\"currentColor\"\n\t\t\t\t\t\t\tstroke=\"none\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</marker>\n\t\t\t\t</defs>\n\t\t\t\t<path\n\t\t\t\t\td=\"M 0 8 L 32 8\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\tmarkerEnd={`url(#${id})`}\n\t\t\t\t/>\n\t\t\t</svg>\n\t\t</li>\n\t);\n}\n\nexport type FlowProps = {\n\t/**\n\t * Accessible name for the step list.\n\t * @default \"Flow\"\n\t */\n\t\"aria-label\"?: string;\n\t/**\n\t * Additional classes for the list.\n\t */\n\tclassName?: string;\n\t/**\n\t * Step nodes.\n\t */\n\tchildren: ReactNode;\n};\n\nexport function Flow({ className, children, \"aria-label\": ariaLabel = \"Flow\" }: FlowProps) {\n\tconst nodes = Children.toArray(children);\n\treturn (\n\t\t<ol aria-label={ariaLabel} className={cn(BASALT_UI_CLASS, \"flex items-center\", className)}>\n\t\t\t{nodes.map((child, index) => (\n\t\t\t\t<Fragment key={index}>\n\t\t\t\t\t{child}\n\t\t\t\t\t{index < nodes.length - 1 ? <FlowArrow /> : null}\n\t\t\t\t</Fragment>\n\t\t\t))}\n\t\t</ol>\n\t);\n}\n\nexport type FlowNodeProps = {\n\t/**\n\t * Label for the step.\n\t */\n\tchildren: ReactNode;\n};\n\nexport function FlowNode({ children }: FlowNodeProps) {\n\treturn (\n\t\t<li className=\"rounded-basalt-md border border-basalt-border bg-basalt-secondary px-3 py-2 text-sm\">\n\t\t\t{children}\n\t\t</li>\n\t);\n}\n"],"mappings":";;;;;;AAIA,SAASA,IAAY;CACpB,IAAMC,IAAK,cAAcC,EAAM,CAAC,CAAC,QAAQ,MAAM,EAAE;CACjD,OACC,kBAAC,MAAD;EAAI,eAAY;EAAO,WAAU;EAChC,UAAA,kBAAC,OAAD;GACC,SAAQ;GACR,WAAU;GACV,UAAS;GACT,eAAY;GAJb,UAAA,CAMC,kBAAC,QAAD,EAAA,UACC,kBAAC,UAAD;IACK;IACJ,aAAY;IACZ,cAAa;IACb,MAAK;IACL,MAAK;IACL,QAAO;IACP,aAAY;IAEZ,UAAA,kBAAC,QAAD;KACC,GAAE;KACF,MAAK;KACL,QAAO;IACP,CAAA;GACM,CAAA,EACH,CAAA,GACN,kBAAC,QAAD;IACC,GAAE;IACF,MAAK;IACL,QAAO;IACP,aAAY;IACZ,WAAW,QAAQD,EAAG;GACtB,CAAA,CACG;;CACF,CAAA;AAEN;AAkBA,SAAgBE,EAAK,EAAE,cAAW,aAAU,cAAcC,IAAY,UAAqB;CAC1F,IAAMC,IAAQC,EAAS,QAAQC,CAAQ;CACvC,OACC,kBAAC,MAAD;EAAI,cAAYH;EAAW,WAAWI,EAAGC,GAAiB,qBAAqBC,CAAS;EACtF,UAAAL,EAAM,KAAK,GAAO,MAClB,kBAACM,GAAD,EAAA,UAAA,CACEC,GACAC,IAAQR,EAAM,SAAS,IAAI,kBAACL,GAAD,CAAY,CAAA,IAAI,IACnC,EAAA,GAHKa,CAGL,CACV;CACE,CAAA;AAEN;AASA,SAAgBC,EAAS,EAAE,eAA2B;CACrD,OACC,kBAAC,MAAD;EAAI,WAAU;EACZ;CACE,CAAA;AAEN"}
@@ -1 +1 @@
1
- {"version":3,"file":"grid.js","names":[],"sources":["../../src/components/grid.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport type GridProps = {\n\t/**\n\t * Number of equal columns.\n\t * @default 2\n\t */\n\tcolumns?: number;\n\t/**\n\t * Additional classes for the grid.\n\t */\n\tclassName?: string;\n\tchildren?: ReactNode;\n};\n\nexport function Grid({\n\tclassName,\n\tcolumns = 2,\n\tstyle,\n\t...props\n}: GridProps & HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"grid gap-3\", className)}\n\t\t\t{...props}\n\t\t\tstyle={{\n\t\t\t\tgridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nexport interface GridItemProps extends HTMLAttributes<HTMLDivElement> {}\n\nexport function GridItem({ className, ...props }: GridItemProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"flex items-center justify-center rounded-basalt-lg bg-basalt-secondary px-6 py-8 text-sm\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;AAgBA,SAAgB,EAAK,EACpB,cACA,aAAU,GACV,UACA,GAAG,KAC2C;CAC9C,OACC,kBAAC,OAAD;EACC,WAAW,EAAG,cAAc,CAAS;EACrC,GAAI;EACJ,OAAO;GACN,qBAAqB,UAAU,EAAQ;GACvC,GAAG;EACJ;CACA,CAAA;AAEH;AAIA,SAAgB,EAAS,EAAE,cAAW,GAAG,KAAwB;CAChE,OACC,kBAAC,OAAD;EACC,WAAW,EACV,4FACA,CACD;EACA,GAAI;CACJ,CAAA;AAEH"}
1
+ {"version":3,"file":"grid.js","names":["Grid","props","cn","className","columns","style","GridItem"],"sources":["../../src/components/grid.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport type GridProps = {\n\t/**\n\t * Number of equal columns.\n\t * @default 2\n\t */\n\tcolumns?: number;\n\t/**\n\t * Additional classes for the grid.\n\t */\n\tclassName?: string;\n\tchildren?: ReactNode;\n};\n\nexport function Grid({\n\tclassName,\n\tcolumns = 2,\n\tstyle,\n\t...props\n}: GridProps & HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"grid gap-3\", className)}\n\t\t\t{...props}\n\t\t\tstyle={{\n\t\t\t\tgridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nexport interface GridItemProps extends HTMLAttributes<HTMLDivElement> {}\n\nexport function GridItem({ className, ...props }: GridItemProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"flex items-center justify-center rounded-basalt-lg bg-basalt-secondary px-6 py-8 text-sm\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;AAgBA,SAAgBA,EAAK,EACpB,cACA,aAAU,GACV,UACA,GAAGC,KAC2C;CAC9C,OACC,kBAAC,OAAD;EACC,WAAWC,EAAG,cAAcC,CAAS;EACrC,GAAIF;EACJ,OAAO;GACN,qBAAqB,UAAUG,EAAQ;GACvC,GAAGC;EACJ;CACA,CAAA;AAEH;AAIA,SAAgBC,EAAS,EAAE,cAAW,GAAGL,KAAwB;CAChE,OACC,kBAAC,OAAD;EACC,WAAWC,EACV,4FACAC,CACD;EACA,GAAIF;CACJ,CAAA;AAEH"}
@@ -1 +1 @@
1
- {"version":3,"file":"hover-card.js","names":[],"sources":["../../src/components/hover-card.tsx"],"sourcesContent":["import * as HoverCardPrimitive from \"@radix-ui/react-hover-card\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { MENU_GAP, OVERLAY_LAYER, OVERLAY_MOTION } from \"./overlay\";\n\ntype RadixHoverCardProps = React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Root>;\ntype RadixHoverCardTriggerProps = React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Trigger>;\ntype RadixHoverCardContentProps = React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>;\n\nexport interface HoverCardProps\n\textends Omit<\n\t\tRadixHoverCardProps,\n\t\t\"open\" | \"defaultOpen\" | \"onOpenChange\" | \"openDelay\" | \"closeDelay\"\n\t> {\n\t/**\n\t * Controlled open state of the hover card.\n\t */\n\topen?: RadixHoverCardProps[\"open\"];\n\t/**\n\t * Open state of the hover card when initially rendered in uncontrolled mode.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixHoverCardProps[\"defaultOpen\"];\n\t/**\n\t * Callback invoked when open state changes.\n\t */\n\tonOpenChange?: RadixHoverCardProps[\"onOpenChange\"];\n\t/**\n\t * Delay in milliseconds before the hover card opens after hovering trigger.\n\t * @default 700\n\t */\n\topenDelay?: RadixHoverCardProps[\"openDelay\"];\n\t/**\n\t * Delay in milliseconds before the hover card closes after hover leaves trigger or content.\n\t * @default 300\n\t */\n\tcloseDelay?: RadixHoverCardProps[\"closeDelay\"];\n}\n\nexport const HoverCard = HoverCardPrimitive.Root;\n\nexport interface HoverCardTriggerProps extends Omit<RadixHoverCardTriggerProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered anchor element to the child element, merging props and behavior.\n\t * @default false\n\t */\n\tasChild?: RadixHoverCardTriggerProps[\"asChild\"];\n}\n\nexport const HoverCardTrigger = HoverCardPrimitive.Trigger;\n\nexport interface HoverCardContentProps\n\textends Omit<\n\t\tRadixHoverCardContentProps,\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| \"forceMount\"\n\t\t| \"onEscapeKeyDown\"\n\t\t| \"onPointerDownOutside\"\n\t\t| \"onFocusOutside\"\n\t\t| \"onInteractOutside\"\n\t> {\n\t/**\n\t * Preferred placement side relative to trigger.\n\t * @default \"bottom\"\n\t */\n\tside?: RadixHoverCardContentProps[\"side\"];\n\t/**\n\t * Distance in pixels between trigger and floating content panel.\n\t * @default 8\n\t */\n\tsideOffset?: RadixHoverCardContentProps[\"sideOffset\"];\n\t/**\n\t * Preferred alignment along the side axis.\n\t * @default \"center\"\n\t */\n\talign?: RadixHoverCardContentProps[\"align\"];\n\t/**\n\t * Offset in pixels from the start or end alignment position.\n\t * @default 0\n\t */\n\talignOffset?: RadixHoverCardContentProps[\"alignOffset\"];\n\t/**\n\t * Whether to reposition content to avoid viewport boundary collisions.\n\t * @default true\n\t */\n\tavoidCollisions?: RadixHoverCardContentProps[\"avoidCollisions\"];\n\t/**\n\t * Element or elements bounding boundary collision calculations.\n\t * @default []\n\t */\n\tcollisionBoundary?: RadixHoverCardContentProps[\"collisionBoundary\"];\n\t/**\n\t * Virtual padding from collision boundaries in pixels.\n\t * @default 0\n\t */\n\tcollisionPadding?: RadixHoverCardContentProps[\"collisionPadding\"];\n\t/**\n\t * Padding in pixels between popper arrow and floating panel edge.\n\t * @default 0\n\t */\n\tarrowPadding?: RadixHoverCardContentProps[\"arrowPadding\"];\n\t/**\n\t * Sticky positioning behavior along the align axis when overflowing.\n\t * @default \"partial\"\n\t */\n\tsticky?: RadixHoverCardContentProps[\"sticky\"];\n\t/**\n\t * Whether to hide content completely when trigger is fully occluded.\n\t * @default false\n\t */\n\thideWhenDetached?: RadixHoverCardContentProps[\"hideWhenDetached\"];\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 */\n\tforceMount?: true;\n\t/**\n\t * Callback fired when the Escape key is down on the dismissable layer. Can be prevented.\n\t */\n\tonEscapeKeyDown?: RadixHoverCardContentProps[\"onEscapeKeyDown\"];\n\t/**\n\t * Callback fired when a pointerdown event happens outside the bounds of the dismissable layer. Can be prevented.\n\t */\n\tonPointerDownOutside?: RadixHoverCardContentProps[\"onPointerDownOutside\"];\n\t/**\n\t * Callback fired when focus moves outside the bounds of the dismissable layer. Can be prevented.\n\t */\n\tonFocusOutside?: RadixHoverCardContentProps[\"onFocusOutside\"];\n\t/**\n\t * Callback fired when an interaction (pointerdown or focus) happens outside the bounds of the dismissable layer. Can be prevented.\n\t */\n\tonInteractOutside?: RadixHoverCardContentProps[\"onInteractOutside\"];\n}\n\nexport const HoverCardContent = React.forwardRef<\n\tReact.ElementRef<typeof HoverCardPrimitive.Content>,\n\tHoverCardContentProps\n>(({ className, sideOffset = MENU_GAP, ...props }, ref) => (\n\t<HoverCardPrimitive.Portal forceMount={props.forceMount}>\n\t\t<HoverCardPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\tOVERLAY_LAYER,\n\t\t\t\tOVERLAY_MOTION,\n\t\t\t\t\"w-64 rounded-basalt-md border border-basalt-border bg-basalt-popover p-4 text-basalt-popover-foreground shadow-md\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</HoverCardPrimitive.Portal>\n));\nHoverCardContent.displayName = HoverCardPrimitive.Content.displayName;\n"],"mappings":";;;;;;;AAuCA,IAAa,IAAY,EAAmB,MAU/B,IAAmB,EAAmB,SA+FtC,IAAmB,EAAM,YAGnC,EAAE,cAAW,gBAAA,GAAuB,GAAG,KAAS,MAClD,kBAAC,EAAmB,QAApB;CAA2B,YAAY,EAAM;CAC5C,UAAA,kBAAC,EAAmB,SAApB;EACM;EACO;EACZ,WAAW,EACV,GACA,GACA,qHACA,CACD;EACA,GAAI;CACJ,CAAA;AACyB,CAAA,CAC3B;AACD,EAAiB,cAAc,EAAmB,QAAQ"}
1
+ {"version":3,"file":"hover-card.js","names":["React","HoverCardPrimitive","HoverCard","HoverCardTrigger","HoverCardContent","props","cn","OVERLAY_LAYER","OVERLAY_MOTION","className"],"sources":["../../src/components/hover-card.tsx"],"sourcesContent":["import * as HoverCardPrimitive from \"@radix-ui/react-hover-card\";\nimport * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport { MENU_GAP, OVERLAY_LAYER, OVERLAY_MOTION } from \"./overlay\";\n\ntype RadixHoverCardProps = React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Root>;\ntype RadixHoverCardTriggerProps = React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Trigger>;\ntype RadixHoverCardContentProps = React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>;\n\nexport interface HoverCardProps\n\textends Omit<\n\t\tRadixHoverCardProps,\n\t\t\"open\" | \"defaultOpen\" | \"onOpenChange\" | \"openDelay\" | \"closeDelay\"\n\t> {\n\t/**\n\t * Controlled open state of the hover card.\n\t */\n\topen?: RadixHoverCardProps[\"open\"];\n\t/**\n\t * Open state of the hover card when initially rendered in uncontrolled mode.\n\t * @default false\n\t */\n\tdefaultOpen?: RadixHoverCardProps[\"defaultOpen\"];\n\t/**\n\t * Callback invoked when open state changes.\n\t */\n\tonOpenChange?: RadixHoverCardProps[\"onOpenChange\"];\n\t/**\n\t * Delay in milliseconds before the hover card opens after hovering trigger.\n\t * @default 700\n\t */\n\topenDelay?: RadixHoverCardProps[\"openDelay\"];\n\t/**\n\t * Delay in milliseconds before the hover card closes after hover leaves trigger or content.\n\t * @default 300\n\t */\n\tcloseDelay?: RadixHoverCardProps[\"closeDelay\"];\n}\n\nexport const HoverCard = HoverCardPrimitive.Root;\n\nexport interface HoverCardTriggerProps extends Omit<RadixHoverCardTriggerProps, \"asChild\"> {\n\t/**\n\t * Change the default rendered anchor element to the child element, merging props and behavior.\n\t * @default false\n\t */\n\tasChild?: RadixHoverCardTriggerProps[\"asChild\"];\n}\n\nexport const HoverCardTrigger = HoverCardPrimitive.Trigger;\n\nexport interface HoverCardContentProps\n\textends Omit<\n\t\tRadixHoverCardContentProps,\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| \"forceMount\"\n\t\t| \"onEscapeKeyDown\"\n\t\t| \"onPointerDownOutside\"\n\t\t| \"onFocusOutside\"\n\t\t| \"onInteractOutside\"\n\t> {\n\t/**\n\t * Preferred placement side relative to trigger.\n\t * @default \"bottom\"\n\t */\n\tside?: RadixHoverCardContentProps[\"side\"];\n\t/**\n\t * Distance in pixels between trigger and floating content panel.\n\t * @default 8\n\t */\n\tsideOffset?: RadixHoverCardContentProps[\"sideOffset\"];\n\t/**\n\t * Preferred alignment along the side axis.\n\t * @default \"center\"\n\t */\n\talign?: RadixHoverCardContentProps[\"align\"];\n\t/**\n\t * Offset in pixels from the start or end alignment position.\n\t * @default 0\n\t */\n\talignOffset?: RadixHoverCardContentProps[\"alignOffset\"];\n\t/**\n\t * Whether to reposition content to avoid viewport boundary collisions.\n\t * @default true\n\t */\n\tavoidCollisions?: RadixHoverCardContentProps[\"avoidCollisions\"];\n\t/**\n\t * Element or elements bounding boundary collision calculations.\n\t * @default []\n\t */\n\tcollisionBoundary?: RadixHoverCardContentProps[\"collisionBoundary\"];\n\t/**\n\t * Virtual padding from collision boundaries in pixels.\n\t * @default 0\n\t */\n\tcollisionPadding?: RadixHoverCardContentProps[\"collisionPadding\"];\n\t/**\n\t * Padding in pixels between popper arrow and floating panel edge.\n\t * @default 0\n\t */\n\tarrowPadding?: RadixHoverCardContentProps[\"arrowPadding\"];\n\t/**\n\t * Sticky positioning behavior along the align axis when overflowing.\n\t * @default \"partial\"\n\t */\n\tsticky?: RadixHoverCardContentProps[\"sticky\"];\n\t/**\n\t * Whether to hide content completely when trigger is fully occluded.\n\t * @default false\n\t */\n\thideWhenDetached?: RadixHoverCardContentProps[\"hideWhenDetached\"];\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 */\n\tforceMount?: true;\n\t/**\n\t * Callback fired when the Escape key is down on the dismissable layer. Can be prevented.\n\t */\n\tonEscapeKeyDown?: RadixHoverCardContentProps[\"onEscapeKeyDown\"];\n\t/**\n\t * Callback fired when a pointerdown event happens outside the bounds of the dismissable layer. Can be prevented.\n\t */\n\tonPointerDownOutside?: RadixHoverCardContentProps[\"onPointerDownOutside\"];\n\t/**\n\t * Callback fired when focus moves outside the bounds of the dismissable layer. Can be prevented.\n\t */\n\tonFocusOutside?: RadixHoverCardContentProps[\"onFocusOutside\"];\n\t/**\n\t * Callback fired when an interaction (pointerdown or focus) happens outside the bounds of the dismissable layer. Can be prevented.\n\t */\n\tonInteractOutside?: RadixHoverCardContentProps[\"onInteractOutside\"];\n}\n\nexport const HoverCardContent = React.forwardRef<\n\tReact.ElementRef<typeof HoverCardPrimitive.Content>,\n\tHoverCardContentProps\n>(({ className, sideOffset = MENU_GAP, ...props }, ref) => (\n\t<HoverCardPrimitive.Portal forceMount={props.forceMount}>\n\t\t<HoverCardPrimitive.Content\n\t\t\tref={ref}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\tOVERLAY_LAYER,\n\t\t\t\tOVERLAY_MOTION,\n\t\t\t\t\"w-64 rounded-basalt-md border border-basalt-border bg-basalt-popover p-4 text-basalt-popover-foreground shadow-md\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</HoverCardPrimitive.Portal>\n));\nHoverCardContent.displayName = HoverCardPrimitive.Content.displayName;\n"],"mappings":";;;;;;;AAuCA,IAAaE,IAAYD,EAAmB,MAU/BE,IAAmBF,EAAmB,SA+FtCG,IAAmBJ,EAAM,YAGnC,EAAE,cAAW,gBAAA,GAAuB,GAAGK,KAAS,MAClD,kBAACJ,EAAmB,QAApB;CAA2B,YAAYI,EAAM;CAC5C,UAAA,kBAACJ,EAAmB,SAApB;EACM;EACO;EACZ,WAAWK,EACVC,GACAC,GACA,qHACAC,CACD;EACA,GAAIJ;CACJ,CAAA;AACyB,CAAA,CAC3B;AACD,EAAiB,cAAcJ,EAAmB,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"icon-picker.js","names":[],"sources":["../../src/components/icon-picker.tsx"],"sourcesContent":["import { ChevronDown } from \"lucide-react\";\nimport { 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 { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\nimport { ToggleGroup, ToggleGroupItem } from \"./toggle-group\";\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/** 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\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 open={open && !disabled} onOpenChange={setOpen}>\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\taria-label={label}\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\tclassName=\"w-72 max-w-[calc(100vw-2rem)] space-y-3 p-3\"\n\t\t\t\taria-label={label}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\taria-label={`${label}: search`}\n\t\t\t\t\tvalue={query}\n\t\t\t\t\tplaceholder={searchPlaceholder}\n\t\t\t\t\tonChange={(event) => setQuery(event.target.value)}\n\t\t\t\t/>\n\t\t\t\t<ToggleGroup\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=\"flex h-auto flex-wrap justify-start gap-1 rounded-basalt-lg p-1\"\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<ToggleGroupItem\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=\"size-10\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{item.icon}\n\t\t\t\t\t\t</ToggleGroupItem>\n\t\t\t\t\t))}\n\t\t\t\t</ToggleGroup>\n\t\t\t\t{matches.length === 0 && (\n\t\t\t\t\t<p role=\"status\" className=\"text-sm 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":";;;;;;;;;;;AAyCA,SAAgB,EAAW,EAC1B,UACA,YACA,UACA,kBAAe,IACf,kBACA,cAAW,IACX,iBAAc,eACd,uBAAoB,iBACpB,gBAAa,mBACb,gBACmB;CACnB,IAAM,CAAC,GAAY,KAAiB,EAAS,CAAY,GACnD,CAAC,GAAM,KAAW,EAAS,EAAK,GAChC,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,IAAW,KAAS,GACpB,IAAS,EAAQ,MAAM,MAAW,EAAO,UAAU,CAAQ,GAC3D,IAAU,EAAQ,QAAQ,MAC/B,EAAO,MAAM,kBAAkB,CAAC,CAAC,SAAS,EAAM,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAC3E;CACA,OACC,kBAAC,GAAD;EAAS,MAAM,KAAQ,CAAC;EAAU,cAAc;EAAhD,UAAA,CACC,kBAAC,GAAD;GAAgB,SAAA;GACf,UAAA,kBAAC,GAAD;IACC,SAAQ;IACE;IACV,cAAY;IACZ,WAAW,EAAG,GAAiB,cAAc,CAAS;IAJvD,UAAA;KAMC,kBAAC,QAAD;MAAM,eAAY;MAAO,WAAU;MACjC,UAAA,GAAQ;KACJ,CAAA;KACN,kBAAC,QAAD;MAAM,WAAU;MAAY,UAAA,GAAQ,SAAS;KAAkB,CAAA;KAC/D,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;IAC5B;;EACO,CAAA,GAChB,kBAAC,GAAD;GACC,OAAM;GACN,WAAU;GACV,cAAY;GAHb,UAAA;IAKC,kBAAC,GAAD;KACC,cAAY,GAAG,EAAM;KACrB,OAAO;KACP,aAAa;KACb,WAAW,MAAU,EAAS,EAAM,OAAO,KAAK;IAChD,CAAA;IACD,kBAAC,GAAD;KACC,MAAK;KACL,cAAY;KACZ,OAAO;KACP,WAAU;KACV,gBAAgB,MAAS;MACnB,MACD,MAAU,KAAA,KAAW,EAAc,CAAI,GAC3C,IAAgB,CAAI,GACpB,EAAQ,EAAK,GACb,EAAS,EAAE;KACZ;KAEC,UAAA,EAAQ,KAAK,MACb,kBAAC,GAAD;MAEC,OAAO,EAAK;MACZ,UAAU,EAAK;MACf,cAAY,EAAK;MACjB,OAAO,EAAK;MACZ,WAAU;MAET,UAAA,EAAK;KACU,GARX,EAAK,KAQM,CACjB;IACW,CAAA;IACZ,EAAQ,WAAW,KACnB,kBAAC,KAAD;KAAG,MAAK;KAAS,WAAU;KACzB,UAAA;IACC,CAAA;GAEW;EACR,CAAA,CAAA;;AAEX"}
1
+ {"version":3,"file":"icon-picker.js","names":["IconPicker","localValue","setLocalValue","useState","defaultValue","open","setOpen","query","setQuery","selected","value","option","options","matches","Popover","disabled","PopoverTrigger","Button","label","cn","BASALT_UI_CLASS","className","placeholder","ChevronDown","PopoverContent","Input","searchPlaceholder","event","ToggleGroup","next","onValueChange","ToggleGroupItem","item","emptyLabel"],"sources":["../../src/components/icon-picker.tsx"],"sourcesContent":["import { ChevronDown } from \"lucide-react\";\nimport { 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 { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\nimport { ToggleGroup, ToggleGroupItem } from \"./toggle-group\";\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/** 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\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 open={open && !disabled} onOpenChange={setOpen}>\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\taria-label={label}\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\tclassName=\"w-72 max-w-[calc(100vw-2rem)] space-y-3 p-3\"\n\t\t\t\taria-label={label}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\taria-label={`${label}: search`}\n\t\t\t\t\tvalue={query}\n\t\t\t\t\tplaceholder={searchPlaceholder}\n\t\t\t\t\tonChange={(event) => setQuery(event.target.value)}\n\t\t\t\t/>\n\t\t\t\t<ToggleGroup\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=\"flex h-auto flex-wrap justify-start gap-1 rounded-basalt-lg p-1\"\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<ToggleGroupItem\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=\"size-10\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{item.icon}\n\t\t\t\t\t\t</ToggleGroupItem>\n\t\t\t\t\t))}\n\t\t\t\t</ToggleGroup>\n\t\t\t\t{matches.length === 0 && (\n\t\t\t\t\t<p role=\"status\" className=\"text-sm 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":";;;;;;;;;;;AAyCA,SAAgBA,EAAW,EAC1B,UACA,YACA,UACA,kBAAe,IACf,kBACA,cAAW,IACX,iBAAc,eACd,uBAAoB,iBACpB,gBAAa,mBACb,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;EAAS,MAAMT,KAAQ,CAACU;EAAU,cAAcT;EAAhD,UAAA,CACC,kBAACU,GAAD;GAAgB,SAAA;GACf,UAAA,kBAACC,GAAD;IACC,SAAQ;IACE;IACV,cAAYC;IACZ,WAAWC,EAAGC,GAAiB,cAAcC,CAAS;IAJvD,UAAA;KAMC,kBAAC,QAAD;MAAM,eAAY;MAAO,WAAU;MACjC,UAAAV,GAAQ;KACJ,CAAA;KACN,kBAAC,QAAD;MAAM,WAAU;MAAY,UAAAA,GAAQ,SAASW;KAAkB,CAAA;KAC/D,kBAACC,GAAD,EAAa,WAAU,WAAY,CAAA;IAC5B;;EACO,CAAA,GAChB,kBAACC,GAAD;GACC,OAAM;GACN,WAAU;GACV,cAAYN;GAHb,UAAA;IAKC,kBAACO,GAAD;KACC,cAAY,GAAGP,EAAM;KACrB,OAAOX;KACP,aAAamB;KACb,WAAW,MAAUlB,EAASmB,EAAM,OAAO,KAAK;IAChD,CAAA;IACD,kBAACC,GAAD;KACC,MAAK;KACL,cAAYV;KACZ,OAAOT;KACP,WAAU;KACV,gBAAgB,MAAS;MACxB,AAAKoB,MACDnB,MAAU,KAAA,KAAWR,EAAc2B,CAAI,GAC3CC,IAAgBD,CAAI,GACpBvB,EAAQ,EAAK,GACbE,EAAS,EAAE;KACZ;KAEC,UAAAK,EAAQ,KAAK,MACb,kBAACkB,GAAD;MAEC,OAAOC,EAAK;MACZ,UAAUA,EAAK;MACf,cAAYA,EAAK;MACjB,OAAOA,EAAK;MACZ,WAAU;MAET,UAAAA,EAAK;KACU,GARXA,EAAK,KAQM,CACjB;IACW,CAAA;IACZnB,EAAQ,WAAW,KACnB,kBAAC,KAAD;KAAG,MAAK;KAAS,WAAU;KACzB,UAAAoB;IACC,CAAA;GAEW;EACR,CAAA,CAAA;;AAEX"}
@@ -1 +1 @@
1
- {"version":3,"file":"inline-editable.js","names":[],"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-2\", 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-2\">\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-2 rounded-basalt-md px-1 py-1 text-left text-sm hover:bg-basalt-accent 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 className=\"size-3.5 shrink-0 text-basalt-muted-foreground\" aria-hidden=\"true\" />\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-xs 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-xs 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-2\", 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-2\">\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-2 rounded-basalt-md px-1 py-1 text-left text-sm hover:bg-basalt-accent 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 className=\"size-3.5 shrink-0 text-basalt-muted-foreground\" aria-hidden=\"true\" />\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-xs 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-xs 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":";;;;;;;;;AAqDA,SAAgBA,EAAe,EAC9B,UACA,UACA,WACA,YACA,oBAAiB,IACjB,oBACA,aAAU,IACV,UACA,cAAW,IACX,cAAW,IACX,UAAO,IACP,gBAAa,IACb,aACA,iBAAc,YACd,eAAY,QACZ,eAAY,QACZ,iBAAc,UACd,kBAAe,WACf,mBAAgB,kBAChB,gBAAa,2BACb,gBACuB;CACvB,IAAM,CAACC,GAAcC,KAAmBC,EAASC,CAAc,GACzD,CAACC,GAAOC,KAAYH,EAASI,CAAK,GAClC,CAACC,GAAQC,KAAaN,EAAS,EAAK,GACpC,CAACO,GAASC,KAAcR,EAAiB,GACzCS,IAAQC,EAAyB,IAAI,GACrCC,IAAUD,EAA0B,IAAI,GACxCE,IAAUF,EAAO,EAAI,GACrBG,IAAYH,EAAO,CAAC,GACpBI,IAASJ,EAAO,EAAK,GACrBK,IAAUL,EAAO,EAAK,GACtBM,IAAKC,EAAM,GACXC,IAAYC,KAAWrB,GACvBsB,IAAOC,KAAWhB,GAClBiB,IAAUC,KAAShB;CAiBzB,AAhBAiB,SACC,EAAQ,UAAU,UACL;EAEZ,AADA,EAAQ,UAAU,IAClB,EAAU,WAAW;CACtB,IACE,CAAC,CAAC,GACLC,QAAsB;EACrB,AAAIP,KAAa,CAACQ,KACjBjB,EAAM,SAAS,MAAM,GACrBA,EAAM,SAAS,OAAO,KACZ,CAACS,KAAaH,EAAQ,YAChC,EAAQ,UAAU,IAClBJ,EAAQ,SAAS,MAAM;CAEzB,GAAG,CAACO,GAAWQ,CAAQ,CAAC,GACxBF,QAAgB;EACf,AAAKN,MACJ,EAAU,WAAW,GACrB,EAAO,UAAU,IACjBZ,EAAU,EAAK,GACfH,EAASC,CAAK,GACdI,EAAW,KAAA,CAAS;CAEtB,GAAG,CAACU,GAAWd,CAAK,CAAC;CACrB,SAASuB,EAAc,GAAe,GAAoC;EAEzE,AADIR,MAAY,KAAA,KAAWpB,EAAgB6B,CAAI,GAC/CC,IAAkBD,GAAME,CAAM;CAC/B;CACA,SAASC,EAAO,GAAoC;EAEnD,AADA,EAAQ,UAAUD,MAAW,QAC7BH,EAAc,IAAOG,CAAM;CAC5B;CACA,eAAeE,EAAK,GAAyB;EAC5C,IAAI,CAACd,KAAaQ,KAAYN,KAAQN,EAAO,SAAS;EACtD,IAAMc,IAAOK,IAAO/B,EAAM,KAAK,IAAIA,GAC7BgC,IAAUC,KAAY,CAACP,IAAOQ,IAAgBC,IAAWT,CAAI;EACnE,IAAIM,GAAS;GACZ,EAAWA,CAAO;GAClB;EACD;EACA,IAAIN,MAASxB,GAAO;GACnB,EAAO0B,CAAM;GACb;EACD;EAGA,AAFA,EAAO,UAAU,IACjBxB,EAAU,EAAI,GACdE,EAAW,KAAA,CAAS;EACpB,IAAM8B,IAAS,EAAEzB,EAAU;EAC3B,IAAI;GAEH,AADA,MAAM0B,EAAOX,CAAI,GACbhB,EAAQ,WAAW0B,MAAWzB,EAAU,WAASkB,EAAOD,CAAM;EACnE,SAASU,GAAO;GACf,AAAI5B,EAAQ,WAAW0B,MAAWzB,EAAU,WAC3CL,EAAWgC,aAAiB,SAASA,EAAM,UAAUA,EAAM,UAAUC,CAAU;EACjF,UAAU;GACT,AAAI7B,EAAQ,WAAW0B,MAAWzB,EAAU,YAC3C,EAAO,UAAU,IACjBP,EAAU,EAAK;EAEjB;CACD;CACA,OACC,kBAAC,OAAD;EACC,MAAK;EACL,cAAYoC;EACZ,aAAWtB;EACX,WAAWuB,EAAGC,GAAiB,qBAAqBC,CAAS;EAC7D,SAAS,MAAU;GAClB,AAAIC,KAAc,CAACC,EAAM,cAAc,SAASA,EAAM,aAAa,KAAGf,EAAU,MAAM;EACvF;EAPD,UAAA;GASEd,IACA,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACC,kBAAC8B,GAAD;MACC,KAAKvC;MACL,cAAYiC;MACZ,WAAU;MACV,OAAOxC;MACG;MACV,UAAUkB;MACV,gBAAc,CAAC,CAACE;MAChB,oBAAkBA,IAAU,GAAGN,EAAG,UAAU,KAAA;MAC5C,WAAW,MAAU;OAEpB,AADAb,EAAS4C,EAAM,OAAO,KAAK,GAC3BvC,EAAW,KAAA,CAAS;MACrB;MACA,YAAY,MAAU;OACrB,AAAIuC,EAAM,YAAY,gBAClBA,EAAM,QAAQ,YACjBA,EAAM,eAAe,GACrBf,EAAU,MAAM,IAEbe,EAAM,QAAQ,YAAY,CAAC3B,MAC9B2B,EAAM,eAAe,GACrBA,EAAM,gBAAgB,GACtB5C,EAASC,CAAK,GACdI,EAAW,KAAA,CAAS,GACpBuB,EAAO,QAAQ;MAEjB;KACA,CAAA;KACD,kBAACkB,GAAD;MAAQ,MAAK;MAAK,UAAUvB,KAAYN;MAAM,eAAe,KAAKY,EAAK,MAAM;MAC3E,UAAAkB;KACM,CAAA;KACR,kBAACD,GAAD;MACC,MAAK;MACL,SAAQ;MACR,UAAU7B;MACV,eAAe;OAGd,AAFAjB,EAASC,CAAK,GACdI,EAAW,KAAA,CAAS,GACpBuB,EAAO,QAAQ;MAChB;MAEC,UAAAoB;KACM,CAAA;IACJ;GAEL,CAAA,IAAA,kBAAC,UAAD;IACC,KAAKxC;IACL,MAAK;IACL,UAAUe,KAAYL;IACtB,cAAY,GAAG+B,EAAU,GAAGV;IAC5B,WAAU;IACV,eAAe;KAGd,AAFAvC,EAASC,CAAK,GACdI,EAAW,KAAA,CAAS,GACpBmB,EAAc,IAAM,MAAM;IAC3B;IAVD,UAAA,CAYC,kBAAC,QAAD;KAAM,WAAWgB,EAAG,uBAAuB,CAACvC,KAAS,8BAA8B;KACjF,UAAAA,KAASiD;IACL,CAAA,GACN,kBAACC,GAAD;KAAQ,WAAU;KAAiD,eAAY;IAAQ,CAAA,CAChF;;GAERlC,KACA,kBAAC,KAAD;IAAG,MAAK;IAAS,WAAU;IACzB,UAAAmC;GACC,CAAA;GAEHjC,KACA,kBAAC,KAAD;IAAG,IAAI,GAAGN,EAAG;IAAS,MAAK;IAAQ,WAAU;IAC3C,UAAAM;GACC,CAAA;EAEA;;AAEP"}
@@ -1 +1 @@
1
- {"version":3,"file":"input-area.js","names":[],"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-[64px] px-2.5 py-1.5 text-xs\",\n\tdefault: \"min-h-[80px] px-3 py-2 text-sm\",\n\tlg: \"min-h-[96px] px-4 py-2 text-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,IAAM,IAAuD;CAC5D,IAAI;CACJ,SAAS;CACT,IAAI;AACL,GAEM,IAA2B;CAChC,kBAAkB;CAClB,iBAAiB;CACjB,kBAAkB;CAClB,iBAAiB;AAClB,GAmBa,IAAY,EAAM,YAC7B,EAAE,cAAW,UAAO,WAAW,2BAAwB,IAAO,GAAG,KAAS,MAC1E,kBAAC,YAAD;CACM;CACL,WAAW,EACV,EACC,0LACA,EAAsB,IACtB,GACA,+FACA,KAAyB,iBACzB,CACD,CACD;CACA,GAAI;CACJ,GAAK,IAAwB,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-[64px] px-2.5 py-1.5 text-xs\",\n\tdefault: \"min-h-[80px] px-3 py-2 text-sm\",\n\tlg: \"min-h-[96px] px-4 py-2 text-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"}
@@ -1 +1 @@
1
- {"version":3,"file":"input-group.js","names":[],"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 h-9 w-full items-center 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-2\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-2\",\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\"h-full min-w-0 w-auto! flex-1 rounded-none border-0 bg-transparent px-3 py-0 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-4\",\n\t\t\t\talign === \"start\" ? \"-order-1 pl-3\" : \"order-1 pr-3\",\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-3 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(\"h-7 w-7 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,IAAM,IAAqB,EAAM,cAAc,EAAK,GAE9C,IAAiB,EAAM,YAC3B,EAAE,cAAW,aAAU,YAAS,aAAU,GAAG,KAAS,MACtD,kBAAC,EAAmB,UAApB;CAA6B,OAAO,EAAQ;CAC3C,UAAA,kBAAC,OAAD;EACM;EACL,aAAU;EACV,iBAAe,IAAW,KAAK,KAAA;EAC/B,iBAAe,KAAY,KAAA;EAC3B,OAAO,KAAY,KAAA;EACnB,WAAW,EACV,EACC,0CACA,4EACA,kDACA,4DACA,0DACA,4DACA,yEACA,uDACA,kEACA,CACD,CACD;EACA,UAAU,MAAU;GACnB,IAAU,CAAK,GACX,IAAM,oBAAoB,OAGf,EAAM,OACV,QAAQ,4BAA4B,KAG/C,EAAM,cAAc,cAAc,OAAO,CAAC,EAAE,MAAM;EACnD;EACA,GAAI;EAEH;CACG,CAAA;AACuB,CAAA,CAE/B;AACA,EAAe,cAAc;AAY7B,IAAM,IAAkB,EAAM,YAC5B,EAAE,cAAW,aAAU,GAAG,KAAS,MAAQ;CAC3C,IAAM,IAAgB,EAAM,WAAW,CAAkB;CACzD,OACC,kBAAC,GAAD;EACM;EACL,UAAU,KAAY;EACtB,WAAW,EACV,4FACA,wEACA,CACD;EACA,GAAI;CACJ,CAAA;AAEH,CACD;AACA,EAAgB,cAAc;AAU9B,SAAS,EAAgB,EAAE,WAAQ,SAAS,cAAW,aAAU,GAAG,KAA+B;CAClG,OACC,kBAAC,OAAD;EACC,aAAW,MAAU,QAAQ,0BAA0B;EACvD,WAAW,EACV,oHACA,MAAU,UAAU,kBAAkB,gBACtC,CACD;EACA,GAAI;EAEH;CACG,CAAA;AAEP;AACA,EAAgB,cAAc;AAI9B,SAAS,EAAiB,EAAE,cAAW,aAAU,GAAG,KAAgC;CACnF,OACC,kBAAC,OAAD;EACC,aAAU;EACV,WAAW,EACV,sGACA,CACD;EACA,GAAI;EAEJ,UAAA,kBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA;CACvC,CAAA;AAEP;AACA,EAAiB,cAAc;AA8B/B,IAAM,IAAmB,EAAM,YAC7B,EAAE,cAAW,aAAU,SAAS,UAAO,QAAQ,aAAU,GAAG,KAAS,MAAQ;CAC7E,IAAM,IAAgB,EAAM,WAAW,CAAkB;CACzD,OACC,kBAAC,GAAD;EACM;EACI;EACH;EACN,UAAU,KAAY;EACtB,WAAW,EAAG,sCAAsC,CAAS;EAC7D,GAAI;CACJ,CAAA;AAEH,CACD;AACA,EAAiB,cAAc;AAE/B,IAAa,IAAa,OAAO,OAAO,GAAgB;CACvD,OAAO;CACP,OAAO;CACP,QAAQ;CACR,QAAQ;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 h-9 w-full items-center 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-2\",\n\t\t\t\t\t\t\"has-[[data-slot=input-group-addon-end]]:[&_input]:pr-2\",\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\"h-full min-w-0 w-auto! flex-1 rounded-none border-0 bg-transparent px-3 py-0 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-4\",\n\t\t\t\talign === \"start\" ? \"-order-1 pl-3\" : \"order-1 pr-3\",\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-3 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(\"h-7 w-7 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,0CACA,4EACA,kDACA,4DACA,0DACA,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,4FACA,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,oHACAQ,MAAU,UAAU,kBAAkB,gBACtCP,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,sGACAC,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,sCAAsCC,CAAS;EAC7D,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 +1 @@
1
- {"version":3,"file":"input.js","names":[],"sources":["../../src/components/input.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 InputSize = \"sm\" | \"default\" | \"lg\";\n\nconst INPUT_SIZE_CLASS: Record<InputSize, string> = {\n\tsm: \"h-8 px-2.5 py-1.5 text-xs\",\n\tdefault: \"h-9 px-3 py-2 text-sm\",\n\tlg: \"h-10 px-4 py-2 text-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 InputProps = Omit<React.ComponentProps<\"input\">, \"type\" | \"size\"> & {\n\t/**\n\t * The type of input control to render.\n\t */\n\ttype?: React.HTMLInputTypeAttribute;\n\t/**\n\t * The visual size of the input.\n\t * @default default\n\t */\n\tsize?: InputSize;\n\t/**\n\t * Ignore password managers on this field.\n\t * @default false\n\t */\n\tpasswordManagerIgnore?: boolean;\n};\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n\t({ className, type, size = \"default\", passwordManagerIgnore = false, ...props }, ref) => (\n\t\t<input\n\t\t\ttype={type}\n\t\t\tclassName={controlSurfaceClass(\n\t\t\t\tcn(\n\t\t\t\t\t\"flex w-full text-basalt-foreground shadow-xs file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-basalt-muted-foreground disabled:cursor-not-allowed disabled:border-transparent disabled:text-basalt-muted-foreground/40\",\n\t\t\t\t\tINPUT_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\tref={ref}\n\t\t\t{...props}\n\t\t\t{...(passwordManagerIgnore ? PASSWORD_MANAGER_MARKERS : {})}\n\t\t/>\n\t),\n);\nInput.displayName = \"Input\";\n"],"mappings":";;;;;;;AAOA,IAAM,IAA8C;CACnD,IAAI;CACJ,SAAS;CACT,IAAI;AACL,GAEM,IAA2B;CAChC,kBAAkB;CAClB,iBAAiB;CACjB,kBAAkB;CAClB,iBAAiB;AAClB,GAmBa,IAAQ,EAAM,YACzB,EAAE,cAAW,SAAM,UAAO,WAAW,2BAAwB,IAAO,GAAG,KAAS,MAChF,kBAAC,SAAD;CACO;CACN,WAAW,EACV,EACC,0PACA,EAAiB,IACjB,GACA,+FACA,KAAyB,iBACzB,CACD,CACD;CACK;CACL,GAAI;CACJ,GAAK,IAAwB,IAA2B,CAAC;AACzD,CAAA,CAEH;AACA,EAAM,cAAc"}
1
+ {"version":3,"file":"input.js","names":["React","INPUT_SIZE_CLASS","PASSWORD_MANAGER_MARKERS","Input","props","controlSurfaceClass","cn","size","FOCUS_BORDER","passwordManagerIgnore","className"],"sources":["../../src/components/input.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 InputSize = \"sm\" | \"default\" | \"lg\";\n\nconst INPUT_SIZE_CLASS: Record<InputSize, string> = {\n\tsm: \"h-8 px-2.5 py-1.5 text-xs\",\n\tdefault: \"h-9 px-3 py-2 text-sm\",\n\tlg: \"h-10 px-4 py-2 text-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 InputProps = Omit<React.ComponentProps<\"input\">, \"type\" | \"size\"> & {\n\t/**\n\t * The type of input control to render.\n\t */\n\ttype?: React.HTMLInputTypeAttribute;\n\t/**\n\t * The visual size of the input.\n\t * @default default\n\t */\n\tsize?: InputSize;\n\t/**\n\t * Ignore password managers on this field.\n\t * @default false\n\t */\n\tpasswordManagerIgnore?: boolean;\n};\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n\t({ className, type, size = \"default\", passwordManagerIgnore = false, ...props }, ref) => (\n\t\t<input\n\t\t\ttype={type}\n\t\t\tclassName={controlSurfaceClass(\n\t\t\t\tcn(\n\t\t\t\t\t\"flex w-full text-basalt-foreground shadow-xs file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-basalt-muted-foreground disabled:cursor-not-allowed disabled:border-transparent disabled:text-basalt-muted-foreground/40\",\n\t\t\t\t\tINPUT_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\tref={ref}\n\t\t\t{...props}\n\t\t\t{...(passwordManagerIgnore ? PASSWORD_MANAGER_MARKERS : {})}\n\t\t/>\n\t),\n);\nInput.displayName = \"Input\";\n"],"mappings":";;;;;;;AAOA,IAAMC,IAA8C;CACnD,IAAI;CACJ,SAAS;CACT,IAAI;AACL,GAEMC,IAA2B;CAChC,kBAAkB;CAClB,iBAAiB;CACjB,kBAAkB;CAClB,iBAAiB;AAClB,GAmBaC,IAAQH,EAAM,YACzB,EAAE,cAAW,SAAM,UAAO,WAAW,2BAAwB,IAAO,GAAGI,KAAS,MAChF,kBAAC,SAAD;CACO;CACN,WAAWC,EACVC,EACC,0PACAL,EAAiBM,IACjBC,GACA,+FACAC,KAAyB,iBACzBC,CACD,CACD;CACK;CACL,GAAIN;CACJ,GAAKK,IAAwBP,IAA2B,CAAC;AACzD,CAAA,CAEH;AACA,EAAM,cAAc"}