@keboola/design 17.2.0 → 17.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +10 -0
  3. package/dist/{AIKit-DiF0LtVr.js → AIKit-DgyoP_kW.js} +10 -10
  4. package/dist/{AIKit-DiF0LtVr.js.map → AIKit-DgyoP_kW.js.map} +1 -1
  5. package/dist/{Alert-BQB-og_I.js → Alert-CcAVKRSM.js} +2 -2
  6. package/dist/{Alert-BQB-og_I.js.map → Alert-CcAVKRSM.js.map} +1 -1
  7. package/dist/{AlertModal-BkmyEvsR.js → AlertModal-DG3GuHtd.js} +2 -2
  8. package/dist/{AlertModal-BkmyEvsR.js.map → AlertModal-DG3GuHtd.js.map} +1 -1
  9. package/dist/{AppShell-CDbecT-t.js → AppShell-CPr3vmUv.js} +2 -2
  10. package/dist/{AppShell-CDbecT-t.js.map → AppShell-CPr3vmUv.js.map} +1 -1
  11. package/dist/Badge-CFRhducL.js.map +1 -1
  12. package/dist/{BrandEditor-BHE6nsob.js → BrandEditor-8PxfTIcN.js} +6 -6
  13. package/dist/{BrandEditor-BHE6nsob.js.map → BrandEditor-8PxfTIcN.js.map} +1 -1
  14. package/dist/{BrandLogo-n4Qhi1tI.js → BrandLogo-DZLi6TZV.js} +2 -2
  15. package/dist/{BrandLogo-n4Qhi1tI.js.map → BrandLogo-DZLi6TZV.js.map} +1 -1
  16. package/dist/{Breadcrumb-BAwQTo0c.js → Breadcrumb-B_4zm7jJ.js} +3 -3
  17. package/dist/{Breadcrumb-BAwQTo0c.js.map → Breadcrumb-B_4zm7jJ.js.map} +1 -1
  18. package/dist/{Button-BAMX1iuI.js → Button-BgjVUBON.js} +2 -2
  19. package/dist/{Button-BAMX1iuI.js.map → Button-BgjVUBON.js.map} +1 -1
  20. package/dist/{Checkbox-CfjpwIcg.js → Checkbox-CsvhT9Bj.js} +2 -2
  21. package/dist/{Checkbox-CfjpwIcg.js.map → Checkbox-CsvhT9Bj.js.map} +1 -1
  22. package/dist/{Clipboard-BaU3cDi5.js → Clipboard-C6clKAwX.js} +2 -2
  23. package/dist/{Clipboard-BaU3cDi5.js.map → Clipboard-C6clKAwX.js.map} +1 -1
  24. package/dist/{ClipboardButton-BWeaQEM2.js → ClipboardButton-1ISIYJQj.js} +3 -3
  25. package/dist/{ClipboardButton-BWeaQEM2.js.map → ClipboardButton-1ISIYJQj.js.map} +1 -1
  26. package/dist/{CodeEditor-BdTxkPD4.js → CodeEditor-Dx9gyVHV.js} +4 -4
  27. package/dist/{CodeEditor-BdTxkPD4.js.map → CodeEditor-Dx9gyVHV.js.map} +1 -1
  28. package/dist/{ColorInput-BoVdBxJ7.js → ColorInput-CT3OTIOu.js} +3 -3
  29. package/dist/{ColorInput-BoVdBxJ7.js.map → ColorInput-CT3OTIOu.js.map} +1 -1
  30. package/dist/{ColorModeSwitch-BDkdmHYl.js → ColorModeSwitch-BsZ13XeH.js} +2 -2
  31. package/dist/{ColorModeSwitch-BDkdmHYl.js.map → ColorModeSwitch-BsZ13XeH.js.map} +1 -1
  32. package/dist/{Combobox-CakN_1cF.js → Combobox-D_modNUu.js} +4 -4
  33. package/dist/{Combobox-CakN_1cF.js.map → Combobox-D_modNUu.js.map} +1 -1
  34. package/dist/{Command-D6XYzzJf.js → Command-ZOAxNfFf.js} +2 -2
  35. package/dist/{Command-D6XYzzJf.js.map → Command-ZOAxNfFf.js.map} +1 -1
  36. package/dist/{CopyField-9WBU8thS.js → CopyField-CXdg8t3Y.js} +2 -2
  37. package/dist/{CopyField-9WBU8thS.js.map → CopyField-CXdg8t3Y.js.map} +1 -1
  38. package/dist/{DateInput-CCYG0AtT.js → DateInput-DpoPkZRC.js} +3 -3
  39. package/dist/{DateInput-CCYG0AtT.js.map → DateInput-DpoPkZRC.js.map} +1 -1
  40. package/dist/{DateRangeInput-CpZK1IFp.js → DateRangeInput-DhmYH6V9.js} +3 -3
  41. package/dist/{DateRangeInput-CpZK1IFp.js.map → DateRangeInput-DhmYH6V9.js.map} +1 -1
  42. package/dist/{DateRangePicker-B2AUKX7u.js → DateRangePicker-CQXMvR3C.js} +2 -2
  43. package/dist/{DateRangePicker-B2AUKX7u.js.map → DateRangePicker-CQXMvR3C.js.map} +1 -1
  44. package/dist/{FieldItem-eM7IHBt5.js → FieldItem-D5EpKxjN.js} +3 -3
  45. package/dist/{FieldItem-eM7IHBt5.js.map → FieldItem-D5EpKxjN.js.map} +1 -1
  46. package/dist/{FileUpload-d-hNPfPV.js → FileUpload-CpdNficK.js} +2 -2
  47. package/dist/{FileUpload-d-hNPfPV.js.map → FileUpload-CpdNficK.js.map} +1 -1
  48. package/dist/{Form-B_9sNehB.js → Form-CXYgF4uw.js} +7 -7
  49. package/dist/{Form-B_9sNehB.js.map → Form-CXYgF4uw.js.map} +1 -1
  50. package/dist/{FormGroup-D7ahkK1q.js → FormGroup-B-_HsL1J.js} +3 -3
  51. package/dist/{FormGroup-D7ahkK1q.js.map → FormGroup-B-_HsL1J.js.map} +1 -1
  52. package/dist/{FullScreenModal-CiRKNsls.js → FullScreenModal-xMdgp0A-.js} +2 -2
  53. package/dist/{FullScreenModal-CiRKNsls.js.map → FullScreenModal-xMdgp0A-.js.map} +1 -1
  54. package/dist/{InlineEdit-BzOox46S.js → InlineEdit-DDPFk6Ak.js} +4 -4
  55. package/dist/{InlineEdit-BzOox46S.js.map → InlineEdit-DDPFk6Ak.js.map} +1 -1
  56. package/dist/{InputGroup-DnGP9-ZQ.js → InputGroup-oui6630r.js} +2 -2
  57. package/dist/{InputGroup-DnGP9-ZQ.js.map → InputGroup-oui6630r.js.map} +1 -1
  58. package/dist/{Kbd-6velz9J-.js → Kbd-D4F65jXO.js} +2 -2
  59. package/dist/{Kbd-6velz9J-.js.map → Kbd-D4F65jXO.js.map} +1 -1
  60. package/dist/{MermaidDiagram-l83gco3r.js → MermaidDiagram-Cg-c8jjI.js} +2 -2
  61. package/dist/{MermaidDiagram-l83gco3r.js.map → MermaidDiagram-Cg-c8jjI.js.map} +1 -1
  62. package/dist/{Modal-CLu6Eg5p.js → Modal-Cro4XHuT.js} +2 -2
  63. package/dist/{Modal-CLu6Eg5p.js.map → Modal-Cro4XHuT.js.map} +1 -1
  64. package/dist/{MultiActionButtonGroup-B3-wNw7w.js → MultiActionButtonGroup-DSxYdeRE.js} +3 -3
  65. package/dist/{MultiActionButtonGroup-B3-wNw7w.js.map → MultiActionButtonGroup-DSxYdeRE.js.map} +1 -1
  66. package/dist/{Navbar-BEc-Pqo5.js → Navbar-DB2YAs_2.js} +2 -2
  67. package/dist/{Navbar-BEc-Pqo5.js.map → Navbar-DB2YAs_2.js.map} +1 -1
  68. package/dist/{PageToolbar-NmiausP7.js → PageToolbar-BTYKQCao.js} +2 -2
  69. package/dist/{PageToolbar-NmiausP7.js.map → PageToolbar-BTYKQCao.js.map} +1 -1
  70. package/dist/{Pagination-DidOPSPB.js → Pagination-C4pi5DHG.js} +2 -2
  71. package/dist/{Pagination-DidOPSPB.js.map → Pagination-C4pi5DHG.js.map} +1 -1
  72. package/dist/{Popconfirm-C4ryoeGP.js → Popconfirm-DOWgVS2t.js} +2 -2
  73. package/dist/{Popconfirm-C4ryoeGP.js.map → Popconfirm-DOWgVS2t.js.map} +1 -1
  74. package/dist/{RadioGroup-BIElT-nH.js → RadioGroup-BCpVnOjW.js} +2 -2
  75. package/dist/{RadioGroup-BIElT-nH.js.map → RadioGroup-BCpVnOjW.js.map} +1 -1
  76. package/dist/{Search-xDWaQ2z3.js → Search-hED5IJlr.js} +2 -2
  77. package/dist/{Search-xDWaQ2z3.js.map → Search-hED5IJlr.js.map} +1 -1
  78. package/dist/{SearchInput-BwlJ77mV.js → SearchInput-BTTnMdb1.js} +3 -3
  79. package/dist/{SearchInput-BwlJ77mV.js.map → SearchInput-BTTnMdb1.js.map} +1 -1
  80. package/dist/{SectionNav-DV3Hwj-5.js → SectionNav-O5hcU01h.js} +3 -3
  81. package/dist/{SectionNav-DV3Hwj-5.js.map → SectionNav-O5hcU01h.js.map} +1 -1
  82. package/dist/{Select-C3Q_Xk_Z.js → Select-DguW42V3.js} +2 -2
  83. package/dist/{Select-C3Q_Xk_Z.js.map → Select-DguW42V3.js.map} +1 -1
  84. package/dist/{Sheet-D7NnOyud.js → Sheet-DGqQqtof.js} +2 -2
  85. package/dist/{Sheet-D7NnOyud.js.map → Sheet-DGqQqtof.js.map} +1 -1
  86. package/dist/{Sidebar-DaUDM8jm.js → Sidebar-BD9iGHqL.js} +5 -5
  87. package/dist/{Sidebar-DaUDM8jm.js.map → Sidebar-BD9iGHqL.js.map} +1 -1
  88. package/dist/{Slider-Cdl8FOvI.js → Slider-D12JmXyd.js} +3 -3
  89. package/dist/{Slider-Cdl8FOvI.js.map → Slider-D12JmXyd.js.map} +1 -1
  90. package/dist/{Tabs-DUOUQKh7.js → Tabs-Z6ckOaSb.js} +2 -2
  91. package/dist/{Tabs-DUOUQKh7.js.map → Tabs-Z6ckOaSb.js.map} +1 -1
  92. package/dist/{TextInput-BAL-zOAN.js → TextInput-tWtbWBFQ.js} +3 -3
  93. package/dist/{TextInput-BAL-zOAN.js.map → TextInput-tWtbWBFQ.js.map} +1 -1
  94. package/dist/{ThemeProvider-MzVbTDBj.js → ThemeProvider-DHf_Tvwk.js} +2 -2
  95. package/dist/{ThemeProvider-MzVbTDBj.js.map → ThemeProvider-DHf_Tvwk.js.map} +1 -1
  96. package/dist/{ToggleAllTooltip-DQE5Lw6w.js → ToggleAllTooltip-EghNnsQC.js} +2 -2
  97. package/dist/{ToggleAllTooltip-DQE5Lw6w.js.map → ToggleAllTooltip-EghNnsQC.js.map} +1 -1
  98. package/dist/{ZoomableSvg-CIOqAYpd.js → ZoomableSvg-Cp2zJNIG.js} +4 -4
  99. package/dist/{ZoomableSvg-CIOqAYpd.js.map → ZoomableSvg-Cp2zJNIG.js.map} +1 -1
  100. package/dist/editors.js +3 -3
  101. package/dist/flint.js +1 -1
  102. package/dist/index.js +46 -46
  103. package/dist/internal/blocks/AIKit.js +1 -1
  104. package/dist/internal/blocks/AppShell.js +1 -1
  105. package/dist/internal/blocks/AuthLayout.js +1 -1
  106. package/dist/internal/blocks/BrandEditor.js +1 -1
  107. package/dist/internal/blocks/BulkActionsBar.js +1 -1
  108. package/dist/internal/blocks/ChipEditor.js +2 -2
  109. package/dist/internal/blocks/ClipboardButton.js +1 -1
  110. package/dist/internal/blocks/ColorInput.js +1 -1
  111. package/dist/internal/blocks/ColorModeSwitch.js +1 -1
  112. package/dist/internal/blocks/Command.js +1 -1
  113. package/dist/internal/blocks/CopyField.js +1 -1
  114. package/dist/internal/blocks/DateInput.js +1 -1
  115. package/dist/internal/blocks/DateRangeInput.js +1 -1
  116. package/dist/internal/blocks/ExportMenu.js +2 -2
  117. package/dist/internal/blocks/Form/connectors/ComboboxField.js +2 -2
  118. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
  119. package/dist/internal/blocks/Form.js +2 -2
  120. package/dist/internal/blocks/FormGroup.js +1 -1
  121. package/dist/internal/blocks/InlineEdit.js +1 -1
  122. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
  123. package/dist/internal/blocks/MultiCombobox.js +3 -3
  124. package/dist/internal/blocks/NumberInput.js +1 -1
  125. package/dist/internal/blocks/PageToolbar.js +1 -1
  126. package/dist/internal/blocks/PasswordInput.js +2 -2
  127. package/dist/internal/blocks/SearchInput.js +1 -1
  128. package/dist/internal/blocks/SearchInputWithNavigation.js +3 -3
  129. package/dist/internal/blocks/SectionNav.js +1 -1
  130. package/dist/internal/blocks/SplitButton.js +1 -1
  131. package/dist/internal/blocks/TextInput.js +1 -1
  132. package/dist/internal/blocks/Textarea.js +1 -1
  133. package/dist/internal/blocks/TimeInput.js +2 -2
  134. package/dist/internal/components/Alert.js +1 -1
  135. package/dist/internal/components/AlertModal.js +1 -1
  136. package/dist/internal/components/Avatar.js +1 -1
  137. package/dist/internal/components/BrandLogo.js +1 -1
  138. package/dist/internal/components/Breadcrumb.js +1 -1
  139. package/dist/internal/components/Button.js +1 -1
  140. package/dist/internal/components/Checkbox.js +1 -1
  141. package/dist/internal/components/Clipboard.js +1 -1
  142. package/dist/internal/components/CollapsiblePanel.js +1 -1
  143. package/dist/internal/components/Combobox.js +1 -1
  144. package/dist/internal/components/DateRangePicker.js +1 -1
  145. package/dist/internal/components/FileUpload.js +1 -1
  146. package/dist/internal/components/FullScreenModal.js +1 -1
  147. package/dist/internal/components/InputGroup.js +1 -1
  148. package/dist/internal/components/Kbd.js +1 -1
  149. package/dist/internal/components/Modal.js +1 -1
  150. package/dist/internal/components/Navbar.js +1 -1
  151. package/dist/internal/components/Pagination.js +1 -1
  152. package/dist/internal/components/Popconfirm.js +1 -1
  153. package/dist/internal/components/RadioGroup.js +1 -1
  154. package/dist/internal/components/Search.js +1 -1
  155. package/dist/internal/components/Select.js +1 -1
  156. package/dist/internal/components/Sheet.js +1 -1
  157. package/dist/internal/components/Sidebar.js +1 -1
  158. package/dist/internal/components/Slider.js +1 -1
  159. package/dist/internal/components/Tabs.js +1 -1
  160. package/dist/internal/components/ThemeProvider.js +1 -1
  161. package/dist/internal/components/Tooltip.js +1 -1
  162. package/dist/internal/components/Truncated.js +1 -1
  163. package/dist/internal/components/ZoomableSvg.js +1 -1
  164. package/dist/internal/utils.js +1 -1
  165. package/dist/markdown-editor.js +6 -6
  166. package/dist/mermaid.js +1 -1
  167. package/dist/rjsf.js +11 -11
  168. package/dist/testing.js +1 -1
  169. package/dist/{utils-BxEJOnFD.js → utils-CLNKe1ar.js} +10 -1
  170. package/dist/{utils-BxEJOnFD.js.map → utils-CLNKe1ar.js.map} +1 -1
  171. package/package.json +24 -24
@@ -1 +1 @@
1
- {"version":3,"file":"Button-BAMX1iuI.js","names":[],"sources":["../src/components/Button/motion.ts","../src/components/Button/ButtonLabel.tsx","../src/components/Button/styles.ts","../src/components/Button/Button.tsx","../src/components/Button/ButtonInline.tsx"],"sourcesContent":["const ends = (animation: Animation) =>\n Number.isFinite(animation.effect?.getComputedTiming().endTime);\n\n/** Runs `callback` once the finite `animations` have finished or been cancelled; returns a cancel. */\nexport const afterAnimations = (animations: Animation[], callback: () => void) => {\n let isCurrent = true;\n Promise.allSettled(animations.filter(ends).map((animation) => animation.finished)).then(() => {\n if (isCurrent) callback();\n });\n return () => {\n isCurrent = false;\n };\n};\n\nlet waiting = new Set<Element>();\nlet framed = new Set<Element>();\nlet isTicking = false;\n\nconst tick = () => {\n for (const node of framed) if (node.isConnected) node.setAttribute('data-button-ready', '');\n framed = waiting;\n waiting = new Set();\n isTicking = framed.size > 0;\n if (isTicking) requestAnimationFrame(tick);\n};\n\n/**\n * Sets `data-button-ready` on `node` two frames after it mounts, arming its entry animations.\n *\n * - One shared frame loop serves every Button mounting at once.\n * - Arming twice is a no-op, so a re-attached ref doesn't restart the countdown.\n */\nexport const armMotion = (node: Element) => {\n if (node.hasAttribute('data-button-ready') || waiting.has(node) || framed.has(node)) return;\n waiting.add(node);\n if (!isTicking) {\n isTicking = true;\n requestAnimationFrame(tick);\n }\n};\n","import {\n createElement,\n Fragment,\n isValidElement,\n type ReactNode,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport { afterAnimations } from './motion';\n\nconst isText = (node: ReactNode): node is string | number =>\n typeof node === 'string' || typeof node === 'number';\n\n/** Milliseconds from a computed `transition-duration` such as `0.3s`. */\nconst toMs = (duration: string) => parseFloat(duration) * (duration.endsWith('ms') ? 1 : 1000);\n\n/**\n * A button's text, rolled over when it changes.\n *\n * - The new text rolls in; the old one stays absolutely positioned while it rolls out.\n * - The width animates from the old text's to the new one's, so neighbours slide instead of jumping.\n * - Motion lives in `styles.css` under `[data-slot='button-label']`.\n */\nconst ButtonLabel = ({ text }: { text: string }) => {\n const ref = useRef<HTMLSpanElement>(null);\n const exitRef = useRef<HTMLSpanElement>(null);\n const interruptedWidthRef = useRef<number | null>(null);\n const [shown, setShown] = useState(text);\n const [exiting, setExiting] = useState<string | null>(null);\n const [hasChanged, setHasChanged] = useState(false);\n if (shown !== text) {\n setShown(text);\n setExiting(shown);\n setHasChanged(true);\n }\n\n useLayoutEffect(() => {\n const node = ref.current;\n // An interrupted animation's on-screen width, else the outgoing text's, still in the DOM.\n const from = interruptedWidthRef.current ?? exitRef.current?.offsetWidth;\n interruptedWidthRef.current = null;\n if (!node || !from || !node.closest('[data-button-ready]')) return;\n\n const to = node.offsetWidth;\n if (\n Math.abs(to - from) < 0.5 ||\n window.matchMedia?.('(prefers-reduced-motion: reduce)').matches\n )\n return;\n\n const { transitionDuration, transitionTimingFunction } = getComputedStyle(node);\n const animation = node.animate?.(\n [\n { width: `${from}px`, overflowX: 'clip', textAlign: 'start' },\n { width: `${to}px`, overflowX: 'clip', textAlign: 'start' },\n ],\n { duration: toMs(transitionDuration), easing: transitionTimingFunction },\n );\n return () => {\n if (animation?.playState === 'running') {\n interruptedWidthRef.current = node.offsetWidth;\n }\n animation?.cancel();\n };\n }, [text]);\n\n useEffect(() => {\n const node = exitRef.current;\n if (!node) return;\n return afterAnimations(node.getAnimations?.() ?? [], () => setExiting(null));\n }, [exiting]);\n\n // Bare text until the first change, so an unchanged button keeps its markup.\n if (!hasChanged) return text;\n\n return (\n <span ref={ref} data-slot=\"button-label\">\n <span key={text} data-slot=\"button-label-text\">\n {text}\n </span>\n {exiting !== null && (\n <span key={exiting} ref={exitRef} aria-hidden data-slot=\"button-label-exit\">\n {exiting}\n </span>\n )}\n </span>\n );\n};\n\n/**\n * `children` with each run of text wrapped in a `ButtonLabel`.\n *\n * - Positions are kept: a joined run leaves `null` behind, so siblings keep their identity.\n * - Whitespace-only text stays bare: as a span it would become a flex item and take a gap.\n */\nexport const withLabels = (children: ReactNode): ReactNode => {\n if (isValidElement<{ children?: ReactNode }>(children) && children.type === Fragment) {\n return withLabels(children.props.children);\n }\n const items = Array.isArray(children) ? children : [children];\n const wrapped = items.map((item: ReactNode, index) => {\n if (!isText(item)) return item;\n if (index > 0 && isText(items[index - 1])) return null;\n\n let text = '';\n for (let i = index; i < items.length && isText(items[i]); i++) text += String(items[i]);\n return text.trim() ? <ButtonLabel key={index} text={text} /> : text;\n });\n return createElement(Fragment, null, ...wrapped);\n};\n","import { cva } from 'class-variance-authority';\n\n// Opaque tints use `bg-[color-mix(in_oklab,rgb(var(--tint))_N%,rgb(var(--base)))]`, not `bg-<token>/N`.\n//\n// - `bg-<token>/N` mixes into `transparent`, showing whatever the button overlaps.\n// - Raw `--*` triples: `--color-*` exist at build time only; unresolved → `transparent`.\n// - Write the whole class literally — Tailwind scans source; assembled strings get no CSS.\n\nexport const buttonVariants = cva(\n [\n 'tailwindcss-preflight',\n\n // layout\n 'tw:relative',\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:whitespace-nowrap',\n 'tw:gap-2',\n\n // border\n 'tw:border',\n 'tw:border-transparent',\n 'tw:rounded-[var(--radius-lg,0.25rem)]',\n\n // text\n 'tw:font-medium',\n 'tw:select-none',\n\n // focus visible\n 'tw:!outline-hidden',\n 'tw:focus-visible:ring-2',\n\n // disabled\n 'tw:disabled:cursor-not-allowed',\n 'tw:disabled:opacity-disabled',\n 'tw:active:opacity-60',\n\n 'tw:transition-all',\n\n // anchor support\n 'tw:!no-underline',\n 'tw:aria-disabled:cursor-not-allowed',\n 'tw:aria-disabled:opacity-disabled',\n\n // icon\n 'tw:shrink-0',\n 'tw:[&_svg]:pointer-events-none',\n 'tw:[&_svg]:shrink-0',\n \"tw:[&_svg:not([class*='tw:size-'])]:size-4\",\n ],\n {\n defaultVariants: {\n variant: 'primary',\n size: 'medium',\n },\n variants: {\n block: {\n true: ['tw:w-full'],\n },\n variant: {\n primary: [\n 'tw:bg-primary',\n 'tw:text-primary-foreground',\n 'tw:[a]:hover:bg-primary/80',\n 'tw:hover:not-disabled:bg-primary/90',\n 'tw:hover:text-primary-foreground',\n 'tw:focus:text-primary-foreground',\n\n 'tw:focus-visible:border-primary',\n 'tw:focus-visible:ring-ring/50',\n ],\n secondary: [\n 'tw:bg-primary/10',\n 'tw:text-primary',\n 'tw:hover:not-disabled:bg-primary/20',\n\n 'tw:focus-visible:border-primary',\n 'tw:focus-visible:ring-ring/50',\n ],\n\n // Kai's actions: its gradient, three light pools drifting behind the label.\n // The gradient sits on the primary blue, so the label is primary's own foreground.\n kai: [\n 'tw:bg-kai',\n 'tw:animate-kai-drift',\n 'tw:motion-reduce:animate-none',\n 'tw:text-primary-foreground',\n 'tw:hover:text-primary-foreground',\n 'tw:focus:text-primary-foreground',\n 'tw:hover:not-disabled:brightness-110',\n 'tw:focus-visible:ring-ring/50',\n ],\n // should be called \"destructive\" by Figma\n danger: [\n 'tw:bg-destructive',\n 'tw:text-destructive-foreground',\n 'tw:hover:not-disabled:bg-destructive/90',\n 'tw:hover:text-destructive-foreground',\n 'tw:focus:text-destructive-foreground',\n\n 'tw:focus-visible:border-destructive',\n 'tw:focus-visible:ring-destructive/20',\n ],\n outline: [\n 'tw:!border-input',\n 'tw:bg-background',\n 'tw:bg-clip-padding',\n // Semantic text color so the label/icon flips in dark mode (matches `invisible`).\n 'tw:text-foreground',\n // Hover hue comes from the brand primary, not the fixed `accent` blue.\n //\n // - Fill mixes into `--background`: `bg-clip-padding` gives a translucent fill no backing.\n // - The *chrome* border carries the state (fill is ~1.5:1); `--primary` is for `focus-visible`.\n // - Border is solid, not a tint: its contrast would depend on the call site.\n 'tw:hover:not-disabled:bg-[color-mix(in_oklab,rgb(var(--primary))_10%,rgb(var(--background)))]',\n 'tw:hover:not-disabled:!border-muted-foreground',\n 'tw:hover:not-disabled:text-primary',\n 'tw:hover:active:bg-background',\n 'tw:focus-visible:!border-primary',\n 'tw:focus-visible:ring-ring/50',\n ],\n\n // should be called \"ghost\" by Figma\n invisible: [\n 'tw:bg-transparent',\n 'tw:bg-clip-padding',\n 'tw:text-foreground',\n 'tw:hover:not-disabled:bg-primary/10',\n 'tw:hover:not-disabled:text-primary',\n 'tw:hover:not-disabled:border-primary/10',\n\n 'tw:focus-visible:ring-ring/50',\n ],\n // should be called \"link\" by Figma\n inline: [\n 'tw:bg-transparent',\n 'tw:text-primary',\n 'tw:hover:underline',\n 'tw:hover:active:bg-transparent',\n 'tw:focus-visible:ring-ring/50',\n ],\n },\n size: {\n // should be called \"default\" by Figma\n medium: ['tw:max-h-9', 'tw:py-2', 'tw:px-4', 'tw:text-sm'],\n // should be called \"small\" by Figma\n small: ['tw:max-h-8', 'tw:py-2', 'tw:px-3', 'tw:text-xs'],\n // should be called \"large\" by Figma\n large: ['tw:max-h-10', 'tw:py-2.5', 'tw:px-6', 'tw:text-sm'],\n\n 'icon-lg': ['tw:size-10'],\n icon: ['tw:size-9'],\n 'icon-sm': ['tw:size-8'],\n 'icon-xs': ['tw:size-6'],\n // No size of their own: the button takes its content's.\n 'icon-2xs': [],\n 'icon-3xs': [],\n },\n },\n },\n);\n","import {\n type ComponentProps,\n Fragment,\n isValidElement,\n type ReactNode,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Root, Slottable } from '@radix-ui/react-slot';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { Loader2 } from '../../icons';\nimport { cn, mergeRefs } from '../../utils';\nimport { Tooltip } from '../Tooltip';\n\nimport { withLabels } from './ButtonLabel';\nimport { afterAnimations, armMotion } from './motion';\nimport { buttonVariants } from './styles';\n\n/** Props for `Button`; icons are composed as children. */\ntype Props = {\n /** Shows a spinner in place of the leading icon, or before the label when there is none. The caller still controls `disabled`. */\n isLoading?: boolean;\n /** Render as a Radix `Slot` so the parent JSX (e.g. a `react-router` `<Link>`) becomes the button element. */\n asChild?: boolean;\n /** Disables the button and shows this on hover and focus; the button stays focusable. */\n disabledReason?: ReactNode;\n} & ComponentProps<'button'> &\n VariantProps<typeof buttonVariants>;\n\n/** The children that render anything, looking through arrays and fragments. */\nconst renderedChildren = (node: ReactNode): ReactNode[] => {\n if (Array.isArray(node)) return node.flatMap(renderedChildren);\n if (isValidElement<{ children?: ReactNode }>(node) && node.type === Fragment) {\n return renderedChildren(node.props.children);\n }\n const isBlank =\n node == null || typeof node === 'boolean' || (typeof node === 'string' && !node.trim());\n return isBlank ? [] : [node];\n};\n\n/**\n * Any user-initiated action; `size=\"icon-*\"` with no children is the icon-only button.\n *\n * - Not for: inline text links (`ButtonInline`), URL navigation (`Link`), action + dropdown (`SplitButton`).\n * - Wrap in `Tooltip` when icon-only; `disabledReason` when disabled; `Popconfirm` for destructive actions.\n *\n * @see RECIPES.md#confirm-dialog\n */\nexport const Button = ({\n ref,\n children,\n disabled = false,\n className,\n type = 'button',\n isLoading = false,\n asChild = false,\n onClick,\n variant = 'primary',\n size = 'medium',\n block = false,\n disabledReason,\n ...buttonProps\n}: Props) => {\n const Comp = asChild ? Root : 'button';\n const isIconOnly = String(size).startsWith('icon');\n const classNames = buttonVariants({ variant, size, block, className });\n\n const content =\n asChild && isValidElement<{ children?: ReactNode }>(children)\n ? children.props.children\n : children;\n const rendered = renderedChildren(content);\n const leadsWithElement = isValidElement(rendered[0]);\n const elementTypes = rendered.flatMap((child) => (isValidElement(child) ? [child.type] : []));\n\n // The previous render's children, which decide how the spinner and a new icon enter.\n const [prev, setPrev] = useState({ leadsWithElement, elementTypes });\n const [spinnerEnter, setSpinnerEnter] = useState<'grow' | 'fade' | null>(\n isLoading ? 'fade' : null,\n );\n const [iconEnter, setIconEnter] = useState<'grow' | 'fade'>('fade');\n const placement = isIconOnly ? 'center' : leadsWithElement ? 'leading' : 'inline';\n\n if (isLoading && !spinnerEnter) {\n // `fade` also when the caller dropped its leading icon this render: the spinner takes that icon's place.\n setSpinnerEnter(placement === 'inline' && !prev.leadsWithElement ? 'grow' : 'fade');\n }\n const typesChanged =\n prev.elementTypes.length !== elementTypes.length ||\n prev.elementTypes.some((type, index) => type !== elementTypes[index]);\n if (typesChanged || prev.leadsWithElement !== leadsWithElement) {\n setPrev({ leadsWithElement, elementTypes });\n }\n if (typesChanged) {\n const isAdded = elementTypes.length > prev.elementTypes.length;\n setIconEnter(isAdded && !isLoading && !spinnerEnter ? 'grow' : 'fade');\n }\n\n // The spinner stays mounted through its exit transition and unmounts when that ends.\n const spinnerRef = useRef<HTMLSpanElement>(null);\n useEffect(() => {\n const node = spinnerRef.current;\n if (isLoading || !node) return;\n return afterAnimations(node.getAnimations?.() ?? [], () => setSpinnerEnter(null));\n }, [isLoading]);\n\n // A leading spinner is kept centred over the leading icon while the button resizes.\n useLayoutEffect(() => {\n const slot = spinnerRef.current;\n const button = slot?.offsetParent;\n if (!slot || !button || placement !== 'leading') return;\n const centre = () => {\n const icon = slot.nextElementSibling;\n if (!(icon instanceof SVGElement)) return;\n const [iconBox, buttonBox] = [icon.getBoundingClientRect(), button.getBoundingClientRect()];\n const scale = buttonBox.width / (button instanceof HTMLElement ? button.offsetWidth : 1) || 1;\n const x = (iconBox.left - buttonBox.left + iconBox.width / 2) / scale - button.clientLeft;\n slot.style.left = `${x - parseFloat(getComputedStyle(slot).width) / 2}px`;\n };\n centre();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(centre);\n observer.observe(button);\n return () => observer.disconnect();\n }, [placement, spinnerEnter]);\n\n // `data-button-ready` arms the entry animations a frame after mount, so nothing animates on page load.\n const buttonRef = useRef<HTMLButtonElement>(null);\n const armRef = useCallback(\n (node: HTMLButtonElement | null) => (node ? armMotion(node) : undefined),\n [],\n );\n const mergedRef = useMemo(() => mergeRefs(ref, buttonRef, armRef), [ref, armRef]);\n\n // `grow` lasts only through the entry, so a later rotation or swap keeps the default origin.\n useEffect(() => {\n const node = buttonRef.current;\n if (iconEnter !== 'grow' || !node) return;\n const entries = [...node.querySelectorAll(':scope > svg')].flatMap(\n (icon) => icon.getAnimations?.() ?? [],\n );\n return afterAnimations(entries, () => setIconEnter('fade'));\n }, [iconEnter]);\n\n const hasDisabledReason = !!disabledReason;\n\n const handleClick: ComponentProps<'button'>['onClick'] = (event) => {\n const isAnchor = event.currentTarget.tagName === 'A';\n\n // <a/> does not support disabled by default, and we cannot use pointer-events: none because cursor-not-allowed would not work.\n if ((isAnchor && disabled) || hasDisabledReason) {\n event.preventDefault();\n return;\n }\n\n onClick?.(event);\n };\n\n const button = (\n <Comp\n {...buttonProps}\n ref={mergedRef}\n // A disabled reason keeps the button focusable and hoverable, so its tooltip can show.\n disabled={disabled && !hasDisabledReason}\n // An explicit `aria-disabled` wins: unavailable yet focusable, unlike `disabled`.\n aria-disabled={buttonProps['aria-disabled'] ?? (disabled || hasDisabledReason)}\n data-variant={variant}\n // Icon-only flag; `ButtonGroup space=\"block\"` stretches only non-icon children.\n data-icon-only={isIconOnly}\n data-icon-enter={iconEnter}\n type={type}\n onClick={handleClick}\n className={cn(classNames)}\n >\n {spinnerEnter && (\n // Motion lives in `styles.css` under `[data-slot='button-spinner']`.\n <span\n ref={spinnerRef}\n aria-hidden\n data-slot=\"button-spinner\"\n data-state={isLoading ? 'open' : 'closed'}\n data-placement={placement}\n data-enter={spinnerEnter}\n >\n <Loader2 className=\"tw:animate-spin\" />\n </span>\n )}\n <Slottable>{asChild ? children : withLabels(children)}</Slottable>\n </Comp>\n );\n\n if (!hasDisabledReason) return button;\n return (\n <Tooltip tooltip={disabledReason} placement=\"top\" variant=\"explanatory\" triggerAsChild>\n {button}\n </Tooltip>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Root } from '@radix-ui/react-slot';\nimport type { VariantProps } from 'class-variance-authority';\nimport { cva } from 'class-variance-authority';\n\nconst buttonInlineVariants = cva(\n [\n 'tailwindcss-preflight',\n\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n 'tw:underline-offset-2',\n\n 'tw:disabled:opacity-40',\n 'tw:disabled:cursor-not-allowed',\n 'tw:disabled:text-muted-foreground',\n 'tw:disabled:no-underline',\n 'tw:disabled:[&_svg]:text-muted-foreground',\n\n // Default size for nested Lucide icons; callers can override on the icon.\n \"tw:[&_svg.lucide:not([class*='tw:size-'])]:size-4\",\n 'tw:[&_svg]:shrink-0',\n ],\n {\n defaultVariants: {\n variant: 'link',\n color: 'link',\n },\n variants: {\n color: {\n link: ['tw:text-primary', 'tw:hover:text-primary/90', 'tw:[&_svg]:text-primary'],\n dark: ['tw:text-foreground tw:[&_svg]:text-muted-foreground'],\n danger: ['tw:text-error-500 tw:[&_svg]:text-error-500'],\n muted: ['tw:text-muted-foreground tw:[&_svg]:text-muted-foreground'],\n custom: [],\n },\n variant: {\n link: ['tw:underline', 'tw:hover:no-underline'],\n 'link-reverse': ['tw:no-underline', '', 'tw:hover:underline'],\n custom: [],\n },\n },\n },\n);\n\ntype Props = ComponentProps<'button'> &\n VariantProps<typeof buttonInlineVariants> & { asChild?: boolean };\n\nexport const ButtonInline = ({\n ref,\n children,\n className,\n variant,\n color,\n type = 'button',\n asChild = false,\n ...buttonProps\n}: Props) => {\n const Comp = asChild ? Root : 'button';\n\n return (\n <Comp\n {...buttonProps}\n ref={ref}\n type={asChild ? undefined : type}\n className={buttonInlineVariants({ variant, color, className })}\n >\n {children}\n </Comp>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"Button-BgjVUBON.js","names":[],"sources":["../src/components/Button/motion.ts","../src/components/Button/ButtonLabel.tsx","../src/components/Button/styles.ts","../src/components/Button/Button.tsx","../src/components/Button/ButtonInline.tsx"],"sourcesContent":["const ends = (animation: Animation) =>\n Number.isFinite(animation.effect?.getComputedTiming().endTime);\n\n/** Runs `callback` once the finite `animations` have finished or been cancelled; returns a cancel. */\nexport const afterAnimations = (animations: Animation[], callback: () => void) => {\n let isCurrent = true;\n Promise.allSettled(animations.filter(ends).map((animation) => animation.finished)).then(() => {\n if (isCurrent) callback();\n });\n return () => {\n isCurrent = false;\n };\n};\n\nlet waiting = new Set<Element>();\nlet framed = new Set<Element>();\nlet isTicking = false;\n\nconst tick = () => {\n for (const node of framed) if (node.isConnected) node.setAttribute('data-button-ready', '');\n framed = waiting;\n waiting = new Set();\n isTicking = framed.size > 0;\n if (isTicking) requestAnimationFrame(tick);\n};\n\n/**\n * Sets `data-button-ready` on `node` two frames after it mounts, arming its entry animations.\n *\n * - One shared frame loop serves every Button mounting at once.\n * - Arming twice is a no-op, so a re-attached ref doesn't restart the countdown.\n */\nexport const armMotion = (node: Element) => {\n if (node.hasAttribute('data-button-ready') || waiting.has(node) || framed.has(node)) return;\n waiting.add(node);\n if (!isTicking) {\n isTicking = true;\n requestAnimationFrame(tick);\n }\n};\n","import {\n createElement,\n Fragment,\n isValidElement,\n type ReactNode,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport { afterAnimations } from './motion';\n\nconst isText = (node: ReactNode): node is string | number =>\n typeof node === 'string' || typeof node === 'number';\n\n/** Milliseconds from a computed `transition-duration` such as `0.3s`. */\nconst toMs = (duration: string) => parseFloat(duration) * (duration.endsWith('ms') ? 1 : 1000);\n\n/**\n * A button's text, rolled over when it changes.\n *\n * - The new text rolls in; the old one stays absolutely positioned while it rolls out.\n * - The width animates from the old text's to the new one's, so neighbours slide instead of jumping.\n * - Motion lives in `styles.css` under `[data-slot='button-label']`.\n */\nconst ButtonLabel = ({ text }: { text: string }) => {\n const ref = useRef<HTMLSpanElement>(null);\n const exitRef = useRef<HTMLSpanElement>(null);\n const interruptedWidthRef = useRef<number | null>(null);\n const [shown, setShown] = useState(text);\n const [exiting, setExiting] = useState<string | null>(null);\n const [hasChanged, setHasChanged] = useState(false);\n if (shown !== text) {\n setShown(text);\n setExiting(shown);\n setHasChanged(true);\n }\n\n useLayoutEffect(() => {\n const node = ref.current;\n // An interrupted animation's on-screen width, else the outgoing text's, still in the DOM.\n const from = interruptedWidthRef.current ?? exitRef.current?.offsetWidth;\n interruptedWidthRef.current = null;\n if (!node || !from || !node.closest('[data-button-ready]')) return;\n\n const to = node.offsetWidth;\n if (\n Math.abs(to - from) < 0.5 ||\n window.matchMedia?.('(prefers-reduced-motion: reduce)').matches\n )\n return;\n\n const { transitionDuration, transitionTimingFunction } = getComputedStyle(node);\n const animation = node.animate?.(\n [\n { width: `${from}px`, overflowX: 'clip', textAlign: 'start' },\n { width: `${to}px`, overflowX: 'clip', textAlign: 'start' },\n ],\n { duration: toMs(transitionDuration), easing: transitionTimingFunction },\n );\n return () => {\n if (animation?.playState === 'running') {\n interruptedWidthRef.current = node.offsetWidth;\n }\n animation?.cancel();\n };\n }, [text]);\n\n useEffect(() => {\n const node = exitRef.current;\n if (!node) return;\n return afterAnimations(node.getAnimations?.() ?? [], () => setExiting(null));\n }, [exiting]);\n\n // Bare text until the first change, so an unchanged button keeps its markup.\n if (!hasChanged) return text;\n\n return (\n <span ref={ref} data-slot=\"button-label\">\n <span key={text} data-slot=\"button-label-text\">\n {text}\n </span>\n {exiting !== null && (\n <span key={exiting} ref={exitRef} aria-hidden data-slot=\"button-label-exit\">\n {exiting}\n </span>\n )}\n </span>\n );\n};\n\n/**\n * `children` with each run of text wrapped in a `ButtonLabel`.\n *\n * - Positions are kept: a joined run leaves `null` behind, so siblings keep their identity.\n * - Whitespace-only text stays bare: as a span it would become a flex item and take a gap.\n */\nexport const withLabels = (children: ReactNode): ReactNode => {\n if (isValidElement<{ children?: ReactNode }>(children) && children.type === Fragment) {\n return withLabels(children.props.children);\n }\n const items = Array.isArray(children) ? children : [children];\n const wrapped = items.map((item: ReactNode, index) => {\n if (!isText(item)) return item;\n if (index > 0 && isText(items[index - 1])) return null;\n\n let text = '';\n for (let i = index; i < items.length && isText(items[i]); i++) text += String(items[i]);\n return text.trim() ? <ButtonLabel key={index} text={text} /> : text;\n });\n return createElement(Fragment, null, ...wrapped);\n};\n","import { cva } from 'class-variance-authority';\n\n// Opaque tints use `bg-[color-mix(in_oklab,rgb(var(--tint))_N%,rgb(var(--base)))]`, not `bg-<token>/N`.\n//\n// - `bg-<token>/N` mixes into `transparent`, showing whatever the button overlaps.\n// - Raw `--*` triples: `--color-*` exist at build time only; unresolved → `transparent`.\n// - Write the whole class literally — Tailwind scans source; assembled strings get no CSS.\n\nexport const buttonVariants = cva(\n [\n 'tailwindcss-preflight',\n\n // layout\n 'tw:relative',\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:whitespace-nowrap',\n 'tw:gap-2',\n\n // border\n 'tw:border',\n 'tw:border-transparent',\n 'tw:rounded-[var(--radius-lg,0.25rem)]',\n\n // text\n 'tw:font-medium',\n 'tw:select-none',\n\n // focus visible\n 'tw:!outline-hidden',\n 'tw:focus-visible:ring-2',\n\n // disabled\n 'tw:disabled:cursor-not-allowed',\n 'tw:disabled:opacity-disabled',\n 'tw:active:opacity-60',\n\n 'tw:transition-all',\n\n // anchor support\n 'tw:!no-underline',\n 'tw:aria-disabled:cursor-not-allowed',\n 'tw:aria-disabled:opacity-disabled',\n\n // icon\n 'tw:shrink-0',\n 'tw:[&_svg]:pointer-events-none',\n 'tw:[&_svg]:shrink-0',\n \"tw:[&_svg:not([class*='tw:size-'])]:size-4\",\n ],\n {\n defaultVariants: {\n variant: 'primary',\n size: 'medium',\n },\n variants: {\n block: {\n true: ['tw:w-full'],\n },\n variant: {\n primary: [\n 'tw:bg-primary',\n 'tw:text-primary-foreground',\n 'tw:[a]:hover:bg-primary/80',\n 'tw:hover:not-disabled:bg-primary/90',\n 'tw:hover:text-primary-foreground',\n 'tw:focus:text-primary-foreground',\n\n 'tw:focus-visible:border-primary',\n 'tw:focus-visible:ring-ring/50',\n ],\n secondary: [\n 'tw:bg-primary/10',\n 'tw:text-primary',\n 'tw:hover:not-disabled:bg-primary/20',\n\n 'tw:focus-visible:border-primary',\n 'tw:focus-visible:ring-ring/50',\n ],\n\n // Kai's actions: its gradient, three light pools drifting behind the label.\n // The gradient sits on the primary blue, so the label is primary's own foreground.\n kai: [\n 'tw:bg-kai',\n 'tw:animate-kai-drift',\n 'tw:motion-reduce:animate-none',\n 'tw:text-primary-foreground',\n 'tw:hover:text-primary-foreground',\n 'tw:focus:text-primary-foreground',\n 'tw:hover:not-disabled:brightness-110',\n 'tw:focus-visible:ring-ring/50',\n ],\n // should be called \"destructive\" by Figma\n danger: [\n 'tw:bg-destructive',\n 'tw:text-destructive-foreground',\n 'tw:hover:not-disabled:bg-destructive/90',\n 'tw:hover:text-destructive-foreground',\n 'tw:focus:text-destructive-foreground',\n\n 'tw:focus-visible:border-destructive',\n 'tw:focus-visible:ring-destructive/20',\n ],\n outline: [\n 'tw:!border-input',\n 'tw:bg-background',\n 'tw:bg-clip-padding',\n // Semantic text color so the label/icon flips in dark mode (matches `invisible`).\n 'tw:text-foreground',\n // Hover hue comes from the brand primary, not the fixed `accent` blue.\n //\n // - Fill mixes into `--background`: `bg-clip-padding` gives a translucent fill no backing.\n // - The *chrome* border carries the state (fill is ~1.5:1); `--primary` is for `focus-visible`.\n // - Border is solid, not a tint: its contrast would depend on the call site.\n 'tw:hover:not-disabled:bg-[color-mix(in_oklab,rgb(var(--primary))_10%,rgb(var(--background)))]',\n 'tw:hover:not-disabled:!border-muted-foreground',\n 'tw:hover:not-disabled:text-primary',\n 'tw:hover:active:bg-background',\n 'tw:focus-visible:!border-primary',\n 'tw:focus-visible:ring-ring/50',\n ],\n\n // should be called \"ghost\" by Figma\n invisible: [\n 'tw:bg-transparent',\n 'tw:bg-clip-padding',\n 'tw:text-foreground',\n 'tw:hover:not-disabled:bg-primary/10',\n 'tw:hover:not-disabled:text-primary',\n 'tw:hover:not-disabled:border-primary/10',\n\n 'tw:focus-visible:ring-ring/50',\n ],\n // should be called \"link\" by Figma\n inline: [\n 'tw:bg-transparent',\n 'tw:text-primary',\n 'tw:hover:underline',\n 'tw:hover:active:bg-transparent',\n 'tw:focus-visible:ring-ring/50',\n ],\n },\n size: {\n // should be called \"default\" by Figma\n medium: ['tw:max-h-9', 'tw:py-2', 'tw:px-4', 'tw:text-sm'],\n // should be called \"small\" by Figma\n small: ['tw:max-h-8', 'tw:py-2', 'tw:px-3', 'tw:text-xs'],\n // should be called \"large\" by Figma\n large: ['tw:max-h-10', 'tw:py-2.5', 'tw:px-6', 'tw:text-sm'],\n\n 'icon-lg': ['tw:size-10'],\n icon: ['tw:size-9'],\n 'icon-sm': ['tw:size-8'],\n 'icon-xs': ['tw:size-6'],\n // No size of their own: the button takes its content's.\n 'icon-2xs': [],\n 'icon-3xs': [],\n },\n },\n },\n);\n","import {\n type ComponentProps,\n Fragment,\n isValidElement,\n type ReactNode,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Root, Slottable } from '@radix-ui/react-slot';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { Loader2 } from '../../icons';\nimport { cn, mergeRefs } from '../../utils';\nimport { Tooltip } from '../Tooltip';\n\nimport { withLabels } from './ButtonLabel';\nimport { afterAnimations, armMotion } from './motion';\nimport { buttonVariants } from './styles';\n\n/** Props for `Button`; icons are composed as children. */\ntype Props = {\n /** Shows a spinner in place of the leading icon, or before the label when there is none. The caller still controls `disabled`. */\n isLoading?: boolean;\n /** Render as a Radix `Slot` so the parent JSX (e.g. a `react-router` `<Link>`) becomes the button element. */\n asChild?: boolean;\n /** Disables the button and shows this on hover and focus; the button stays focusable. */\n disabledReason?: ReactNode;\n} & ComponentProps<'button'> &\n VariantProps<typeof buttonVariants>;\n\n/** The children that render anything, looking through arrays and fragments. */\nconst renderedChildren = (node: ReactNode): ReactNode[] => {\n if (Array.isArray(node)) return node.flatMap(renderedChildren);\n if (isValidElement<{ children?: ReactNode }>(node) && node.type === Fragment) {\n return renderedChildren(node.props.children);\n }\n const isBlank =\n node == null || typeof node === 'boolean' || (typeof node === 'string' && !node.trim());\n return isBlank ? [] : [node];\n};\n\n/**\n * Any user-initiated action; `size=\"icon-*\"` with no children is the icon-only button.\n *\n * - Not for: inline text links (`ButtonInline`), URL navigation (`Link`), action + dropdown (`SplitButton`).\n * - Wrap in `Tooltip` when icon-only; `disabledReason` when disabled; `Popconfirm` for destructive actions.\n *\n * @see RECIPES.md#confirm-dialog\n */\nexport const Button = ({\n ref,\n children,\n disabled = false,\n className,\n type = 'button',\n isLoading = false,\n asChild = false,\n onClick,\n variant = 'primary',\n size = 'medium',\n block = false,\n disabledReason,\n ...buttonProps\n}: Props) => {\n const Comp = asChild ? Root : 'button';\n const isIconOnly = String(size).startsWith('icon');\n const classNames = buttonVariants({ variant, size, block, className });\n\n const content =\n asChild && isValidElement<{ children?: ReactNode }>(children)\n ? children.props.children\n : children;\n const rendered = renderedChildren(content);\n const leadsWithElement = isValidElement(rendered[0]);\n const elementTypes = rendered.flatMap((child) => (isValidElement(child) ? [child.type] : []));\n\n // The previous render's children, which decide how the spinner and a new icon enter.\n const [prev, setPrev] = useState({ leadsWithElement, elementTypes });\n const [spinnerEnter, setSpinnerEnter] = useState<'grow' | 'fade' | null>(\n isLoading ? 'fade' : null,\n );\n const [iconEnter, setIconEnter] = useState<'grow' | 'fade'>('fade');\n const placement = isIconOnly ? 'center' : leadsWithElement ? 'leading' : 'inline';\n\n if (isLoading && !spinnerEnter) {\n // `fade` also when the caller dropped its leading icon this render: the spinner takes that icon's place.\n setSpinnerEnter(placement === 'inline' && !prev.leadsWithElement ? 'grow' : 'fade');\n }\n const typesChanged =\n prev.elementTypes.length !== elementTypes.length ||\n prev.elementTypes.some((type, index) => type !== elementTypes[index]);\n if (typesChanged || prev.leadsWithElement !== leadsWithElement) {\n setPrev({ leadsWithElement, elementTypes });\n }\n if (typesChanged) {\n const isAdded = elementTypes.length > prev.elementTypes.length;\n setIconEnter(isAdded && !isLoading && !spinnerEnter ? 'grow' : 'fade');\n }\n\n // The spinner stays mounted through its exit transition and unmounts when that ends.\n const spinnerRef = useRef<HTMLSpanElement>(null);\n useEffect(() => {\n const node = spinnerRef.current;\n if (isLoading || !node) return;\n return afterAnimations(node.getAnimations?.() ?? [], () => setSpinnerEnter(null));\n }, [isLoading]);\n\n // A leading spinner is kept centred over the leading icon while the button resizes.\n useLayoutEffect(() => {\n const slot = spinnerRef.current;\n const button = slot?.offsetParent;\n if (!slot || !button || placement !== 'leading') return;\n const centre = () => {\n const icon = slot.nextElementSibling;\n if (!(icon instanceof SVGElement)) return;\n const [iconBox, buttonBox] = [icon.getBoundingClientRect(), button.getBoundingClientRect()];\n const scale = buttonBox.width / (button instanceof HTMLElement ? button.offsetWidth : 1) || 1;\n const x = (iconBox.left - buttonBox.left + iconBox.width / 2) / scale - button.clientLeft;\n slot.style.left = `${x - parseFloat(getComputedStyle(slot).width) / 2}px`;\n };\n centre();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(centre);\n observer.observe(button);\n return () => observer.disconnect();\n }, [placement, spinnerEnter]);\n\n // `data-button-ready` arms the entry animations a frame after mount, so nothing animates on page load.\n const buttonRef = useRef<HTMLButtonElement>(null);\n const armRef = useCallback(\n (node: HTMLButtonElement | null) => (node ? armMotion(node) : undefined),\n [],\n );\n const mergedRef = useMemo(() => mergeRefs(ref, buttonRef, armRef), [ref, armRef]);\n\n // `grow` lasts only through the entry, so a later rotation or swap keeps the default origin.\n useEffect(() => {\n const node = buttonRef.current;\n if (iconEnter !== 'grow' || !node) return;\n const entries = [...node.querySelectorAll(':scope > svg')].flatMap(\n (icon) => icon.getAnimations?.() ?? [],\n );\n return afterAnimations(entries, () => setIconEnter('fade'));\n }, [iconEnter]);\n\n const hasDisabledReason = !!disabledReason;\n\n const handleClick: ComponentProps<'button'>['onClick'] = (event) => {\n const isAnchor = event.currentTarget.tagName === 'A';\n\n // <a/> does not support disabled by default, and we cannot use pointer-events: none because cursor-not-allowed would not work.\n if ((isAnchor && disabled) || hasDisabledReason) {\n event.preventDefault();\n return;\n }\n\n onClick?.(event);\n };\n\n const button = (\n <Comp\n {...buttonProps}\n ref={mergedRef}\n // A disabled reason keeps the button focusable and hoverable, so its tooltip can show.\n disabled={disabled && !hasDisabledReason}\n // An explicit `aria-disabled` wins: unavailable yet focusable, unlike `disabled`.\n aria-disabled={buttonProps['aria-disabled'] ?? (disabled || hasDisabledReason)}\n data-variant={variant}\n // Icon-only flag; `ButtonGroup space=\"block\"` stretches only non-icon children.\n data-icon-only={isIconOnly}\n data-icon-enter={iconEnter}\n type={type}\n onClick={handleClick}\n className={cn(classNames)}\n >\n {spinnerEnter && (\n // Motion lives in `styles.css` under `[data-slot='button-spinner']`.\n <span\n ref={spinnerRef}\n aria-hidden\n data-slot=\"button-spinner\"\n data-state={isLoading ? 'open' : 'closed'}\n data-placement={placement}\n data-enter={spinnerEnter}\n >\n <Loader2 className=\"tw:animate-spin\" />\n </span>\n )}\n <Slottable>{asChild ? children : withLabels(children)}</Slottable>\n </Comp>\n );\n\n if (!hasDisabledReason) return button;\n return (\n <Tooltip tooltip={disabledReason} placement=\"top\" variant=\"explanatory\" triggerAsChild>\n {button}\n </Tooltip>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Root } from '@radix-ui/react-slot';\nimport type { VariantProps } from 'class-variance-authority';\nimport { cva } from 'class-variance-authority';\n\nconst buttonInlineVariants = cva(\n [\n 'tailwindcss-preflight',\n\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n 'tw:underline-offset-2',\n\n 'tw:disabled:opacity-40',\n 'tw:disabled:cursor-not-allowed',\n 'tw:disabled:text-muted-foreground',\n 'tw:disabled:no-underline',\n 'tw:disabled:[&_svg]:text-muted-foreground',\n\n // Default size for nested Lucide icons; callers can override on the icon.\n \"tw:[&_svg.lucide:not([class*='tw:size-'])]:size-4\",\n 'tw:[&_svg]:shrink-0',\n ],\n {\n defaultVariants: {\n variant: 'link',\n color: 'link',\n },\n variants: {\n color: {\n link: ['tw:text-primary', 'tw:hover:text-primary/90', 'tw:[&_svg]:text-primary'],\n dark: ['tw:text-foreground tw:[&_svg]:text-muted-foreground'],\n danger: ['tw:text-error-500 tw:[&_svg]:text-error-500'],\n muted: ['tw:text-muted-foreground tw:[&_svg]:text-muted-foreground'],\n custom: [],\n },\n variant: {\n link: ['tw:underline', 'tw:hover:no-underline'],\n 'link-reverse': ['tw:no-underline', '', 'tw:hover:underline'],\n custom: [],\n },\n },\n },\n);\n\ntype Props = ComponentProps<'button'> &\n VariantProps<typeof buttonInlineVariants> & { asChild?: boolean };\n\nexport const ButtonInline = ({\n ref,\n children,\n className,\n variant,\n color,\n type = 'button',\n asChild = false,\n ...buttonProps\n}: Props) => {\n const Comp = asChild ? Root : 'button';\n\n return (\n <Comp\n {...buttonProps}\n ref={ref}\n type={asChild ? undefined : type}\n className={buttonInlineVariants({ variant, color, className })}\n >\n {children}\n </Comp>\n );\n};\n"],"mappings":";;;;;;;;;AAAA,MAAM,QAAQ,cACZ,OAAO,SAAS,UAAU,QAAQ,kBAAkB,CAAC,CAAC,OAAO;;AAG/D,MAAa,mBAAmB,YAAyB,aAAyB;CAChF,IAAI,YAAY;CAChB,QAAQ,WAAW,WAAW,OAAO,IAAI,CAAC,CAAC,KAAK,cAAc,UAAU,QAAQ,CAAC,CAAC,CAAC,WAAW;EAC5F,IAAI,WAAW,SAAS;CAC1B,CAAC;CACD,aAAa;EACX,YAAY;CACd;AACF;AAEA,IAAI,0BAAU,IAAI,IAAa;AAC/B,IAAI,yBAAS,IAAI,IAAa;AAC9B,IAAI,YAAY;AAEhB,MAAM,aAAa;CACjB,KAAK,MAAM,QAAQ,QAAQ,IAAI,KAAK,aAAa,KAAK,aAAa,qBAAqB,EAAE;CAC1F,SAAS;CACT,0BAAU,IAAI,IAAI;CAClB,YAAY,OAAO,OAAO;CAC1B,IAAI,WAAW,sBAAsB,IAAI;AAC3C;;;;;;;AAQA,MAAa,aAAa,SAAkB;CAC1C,IAAI,KAAK,aAAa,mBAAmB,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,GAAG;CACrF,QAAQ,IAAI,IAAI;CAChB,IAAI,CAAC,WAAW;EACd,YAAY;EACZ,sBAAsB,IAAI;CAC5B;AACF;;AC1BA,MAAM,UAAU,SACd,OAAO,SAAS,YAAY,OAAO,SAAS;;AAG9C,MAAM,QAAQ,aAAqB,WAAW,QAAQ,KAAK,SAAS,SAAS,IAAI,IAAI,IAAI;;;;;;;;AASzF,MAAM,eAAe,EAAE,WAA6B;CAClD,MAAM,MAAM,OAAwB,IAAI;CACxC,MAAM,UAAU,OAAwB,IAAI;CAC5C,MAAM,sBAAsB,OAAsB,IAAI;CACtD,MAAM,CAAC,OAAO,YAAY,SAAS,IAAI;CACvC,MAAM,CAAC,SAAS,cAAc,SAAwB,IAAI;CAC1D,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,IAAI,UAAU,MAAM;EAClB,SAAS,IAAI;EACb,WAAW,KAAK;EAChB,cAAc,IAAI;CACpB;CAEA,sBAAsB;EACpB,MAAM,OAAO,IAAI;EAEjB,MAAM,OAAO,oBAAoB,WAAW,QAAQ,SAAS;EAC7D,oBAAoB,UAAU;EAC9B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,QAAQ,qBAAqB,GAAG;EAE5D,MAAM,KAAK,KAAK;EAChB,IACE,KAAK,IAAI,KAAK,IAAI,IAAI,MACtB,OAAO,aAAa,kCAAkC,CAAC,CAAC,SAExD;EAEF,MAAM,EAAE,oBAAoB,6BAA6B,iBAAiB,IAAI;EAC9E,MAAM,YAAY,KAAK,UACrB,CACE;GAAE,OAAO,GAAG,KAAK;GAAK,WAAW;GAAQ,WAAW;EAAQ,GAC5D;GAAE,OAAO,GAAG,GAAG;GAAK,WAAW;GAAQ,WAAW;EAAQ,CAC5D,GACA;GAAE,UAAU,KAAK,kBAAkB;GAAG,QAAQ;EAAyB,CACzE;EACA,aAAa;GACX,IAAI,WAAW,cAAc,WAC3B,oBAAoB,UAAU,KAAK;GAErC,WAAW,OAAO;EACpB;CACF,GAAG,CAAC,IAAI,CAAC;CAET,gBAAgB;EACd,MAAM,OAAO,QAAQ;EACrB,IAAI,CAAC,MAAM;EACX,OAAO,gBAAgB,KAAK,gBAAgB,KAAK,CAAC,SAAS,WAAW,IAAI,CAAC;CAC7E,GAAG,CAAC,OAAO,CAAC;CAGZ,IAAI,CAAC,YAAY,OAAO;CAExB,OACE,qBAAC,QAAD;EAAW;EAAK,aAAU;EAA1B,UAAA,CACE,oBAAC,QAAD;GAAiB,aAAU;GACxB,UAAA;EACG,GAFK,IAEL,GACL,YAAY,QACX,oBAAC,QAAD;GAAoB,KAAK;GAAS,eAAA;GAAY,aAAU;GACrD,UAAA;EACG,GAFK,OAEL,CAEJ;;AAEV;;;;;;;AAQA,MAAa,cAAc,aAAmC;CAC5D,IAAI,eAAyC,QAAQ,KAAK,SAAS,SAAS,UAC1E,OAAO,WAAW,SAAS,MAAM,QAAQ;CAE3C,MAAM,QAAQ,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ;CAC5D,MAAM,UAAU,MAAM,KAAK,MAAiB,UAAU;EACpD,IAAI,CAAC,OAAO,IAAI,GAAG,OAAO;EAC1B,IAAI,QAAQ,KAAK,OAAO,MAAM,QAAQ,EAAE,GAAG,OAAO;EAElD,IAAI,OAAO;EACX,KAAK,IAAI,IAAI,OAAO,IAAI,MAAM,UAAU,OAAO,MAAM,EAAE,GAAG,KAAK,QAAQ,OAAO,MAAM,EAAE;EACtF,OAAO,KAAK,KAAK,IAAI,oBAAC,aAAD,EAA+B,KAAO,GAApB,KAAoB,IAAI;CACjE,CAAC;CACD,OAAO,cAAc,UAAU,MAAM,GAAG,OAAO;AACjD;;ACxGA,MAAa,iBAAiB,IAC5B;CACE;CAGA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CAGA;CACA;CAGA;CACA;CACA;CAEA;CAGA;CACA;CACA;CAGA;CACA;CACA;CACA;AACF,GACA;CACE,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;CACA,UAAU;EACR,OAAO,EACL,MAAM,CAAC,WAAW,EACpB;EACA,SAAS;GACP,SAAS;IACP;IACA;IACA;IACA;IACA;IACA;IAEA;IACA;GACF;GACA,WAAW;IACT;IACA;IACA;IAEA;IACA;GACF;GAIA,KAAK;IACH;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACF;GAEA,QAAQ;IACN;IACA;IACA;IACA;IACA;IAEA;IACA;GACF;GACA,SAAS;IACP;IACA;IACA;IAEA;IAMA;IACA;IACA;IACA;IACA;IACA;GACF;GAGA,WAAW;IACT;IACA;IACA;IACA;IACA;IACA;IAEA;GACF;GAEA,QAAQ;IACN;IACA;IACA;IACA;IACA;GACF;EACF;EACA,MAAM;GAEJ,QAAQ;IAAC;IAAc;IAAW;IAAW;GAAY;GAEzD,OAAO;IAAC;IAAc;IAAW;IAAW;GAAY;GAExD,OAAO;IAAC;IAAe;IAAa;IAAW;GAAY;GAE3D,WAAW,CAAC,YAAY;GACxB,MAAM,CAAC,WAAW;GAClB,WAAW,CAAC,WAAW;GACvB,WAAW,CAAC,WAAW;GAEvB,YAAY,CAAC;GACb,YAAY,CAAC;EACf;CACF;AACF,CACF;;;AC9HA,MAAM,oBAAoB,SAAiC;CACzD,IAAI,MAAM,QAAQ,IAAI,GAAG,OAAO,KAAK,QAAQ,gBAAgB;CAC7D,IAAI,eAAyC,IAAI,KAAK,KAAK,SAAS,UAClE,OAAO,iBAAiB,KAAK,MAAM,QAAQ;CAI7C,OADE,QAAQ,QAAQ,OAAO,SAAS,aAAc,OAAO,SAAS,YAAY,CAAC,KAAK,KAAK,IACtE,CAAC,IAAI,CAAC,IAAI;AAC7B;;;;;;;;;AAUA,MAAa,UAAU,EACrB,KACA,UACA,WAAW,OACX,WACA,OAAO,UACP,YAAY,OACZ,UAAU,OACV,SACA,UAAU,WACV,OAAO,UACP,QAAQ,OACR,gBACA,GAAG,kBACQ;CACX,MAAM,OAAO,UAAU,OAAO;CAC9B,MAAM,aAAa,OAAO,IAAI,CAAC,CAAC,WAAW,MAAM;CACjD,MAAM,aAAa,eAAe;EAAE;EAAS;EAAM;EAAO;CAAU,CAAC;CAErE,MAAM,UACJ,WAAW,eAAyC,QAAQ,IACxD,SAAS,MAAM,WACf;CACN,MAAM,WAAW,iBAAiB,OAAO;CACzC,MAAM,mBAAmB,eAAe,SAAS,EAAE;CACnD,MAAM,eAAe,SAAS,SAAS,UAAW,eAAe,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAE;CAG5F,MAAM,CAAC,MAAM,WAAW,SAAS;EAAE;EAAkB;CAAa,CAAC;CACnE,MAAM,CAAC,cAAc,mBAAmB,SACtC,YAAY,SAAS,IACvB;CACA,MAAM,CAAC,WAAW,gBAAgB,SAA0B,MAAM;CAClE,MAAM,YAAY,aAAa,WAAW,mBAAmB,YAAY;CAEzE,IAAI,aAAa,CAAC,cAEhB,gBAAgB,cAAc,YAAY,CAAC,KAAK,mBAAmB,SAAS,MAAM;CAEpF,MAAM,eACJ,KAAK,aAAa,WAAW,aAAa,UAC1C,KAAK,aAAa,MAAM,MAAM,UAAU,SAAS,aAAa,MAAM;CACtE,IAAI,gBAAgB,KAAK,qBAAqB,kBAC5C,QAAQ;EAAE;EAAkB;CAAa,CAAC;CAE5C,IAAI,cAEF,aADgB,aAAa,SAAS,KAAK,aAAa,UAChC,CAAC,aAAa,CAAC,eAAe,SAAS,MAAM;CAIvE,MAAM,aAAa,OAAwB,IAAI;CAC/C,gBAAgB;EACd,MAAM,OAAO,WAAW;EACxB,IAAI,aAAa,CAAC,MAAM;EACxB,OAAO,gBAAgB,KAAK,gBAAgB,KAAK,CAAC,SAAS,gBAAgB,IAAI,CAAC;CAClF,GAAG,CAAC,SAAS,CAAC;CAGd,sBAAsB;EACpB,MAAM,OAAO,WAAW;EACxB,MAAM,SAAS,MAAM;EACrB,IAAI,CAAC,QAAQ,CAAC,UAAU,cAAc,WAAW;EACjD,MAAM,eAAe;GACnB,MAAM,OAAO,KAAK;GAClB,IAAI,EAAE,gBAAgB,aAAa;GACnC,MAAM,CAAC,SAAS,aAAa,CAAC,KAAK,sBAAsB,GAAG,OAAO,sBAAsB,CAAC;GAC1F,MAAM,QAAQ,UAAU,SAAS,kBAAkB,cAAc,OAAO,cAAc,MAAM;GAC5F,MAAM,KAAK,QAAQ,OAAO,UAAU,OAAO,QAAQ,QAAQ,KAAK,QAAQ,OAAO;GAC/E,KAAK,MAAM,OAAO,GAAG,IAAI,WAAW,iBAAiB,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE;EACxE;EACA,OAAO;EACP,IAAI,OAAO,mBAAmB,aAAa;EAC3C,MAAM,WAAW,IAAI,eAAe,MAAM;EAC1C,SAAS,QAAQ,MAAM;EACvB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,WAAW,YAAY,CAAC;CAG5B,MAAM,YAAY,OAA0B,IAAI;CAChD,MAAM,SAAS,aACZ,SAAoC,OAAO,UAAU,IAAI,IAAI,KAAA,GAC9D,CAAC,CACH;CACA,MAAM,YAAY,cAAc,UAAU,KAAK,WAAW,MAAM,GAAG,CAAC,KAAK,MAAM,CAAC;CAGhF,gBAAgB;EACd,MAAM,OAAO,UAAU;EACvB,IAAI,cAAc,UAAU,CAAC,MAAM;EACnC,MAAM,UAAU,CAAC,GAAG,KAAK,iBAAiB,cAAc,CAAC,CAAC,CAAC,SACxD,SAAS,KAAK,gBAAgB,KAAK,CAAC,CACvC;EACA,OAAO,gBAAgB,eAAe,aAAa,MAAM,CAAC;CAC5D,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,oBAAoB,CAAC,CAAC;CAE5B,MAAM,eAAoD,UAAU;EAIlE,IAHiB,MAAM,cAAc,YAAY,OAGhC,YAAa,mBAAmB;GAC/C,MAAM,eAAe;GACrB;EACF;EAEA,UAAU,KAAK;CACjB;CAEA,MAAM,SACJ,qBAAC,MAAD;EACE,GAAI;EACJ,KAAK;EAEL,UAAU,YAAY,CAAC;EAEvB,iBAAe,YAAY,qBAAqB,YAAY;EAC5D,gBAAc;EAEd,kBAAgB;EAChB,mBAAiB;EACX;EACN,SAAS;EACT,WAAW,GAAG,UAAU;EAb1B,UAAA,CAeG,gBAEC,oBAAC,QAAD;GACE,KAAK;GACL,eAAA;GACA,aAAU;GACV,cAAY,YAAY,SAAS;GACjC,kBAAgB;GAChB,cAAY;GAEZ,UAAA,oBAAC,SAAD,EAAS,WAAU,kBAAmB,CAAA;EAClC,CAAA,GAER,oBAAC,WAAD,EAAA,UAAY,UAAU,WAAW,WAAW,QAAQ,EAAa,CAAA,CAC7D;;CAGR,IAAI,CAAC,mBAAmB,OAAO;CAC/B,OACE,oBAAC,SAAD;EAAS,SAAS;EAAgB,WAAU;EAAM,SAAQ;EAAc,gBAAA;EACrE,UAAA;CACM,CAAA;AAEb;;ACrMA,MAAM,uBAAuB,IAC3B;CACE;CAEA;CACA;CACA;CAEA;CAEA;CACA;CACA;CACA;CACA;CAGA;CACA;AACF,GACA;CACE,iBAAiB;EACf,SAAS;EACT,OAAO;CACT;CACA,UAAU;EACR,OAAO;GACL,MAAM;IAAC;IAAmB;IAA4B;GAAyB;GAC/E,MAAM,CAAC,qDAAqD;GAC5D,QAAQ,CAAC,6CAA6C;GACtD,OAAO,CAAC,2DAA2D;GACnE,QAAQ,CAAC;EACX;EACA,SAAS;GACP,MAAM,CAAC,gBAAgB,uBAAuB;GAC9C,gBAAgB;IAAC;IAAmB;IAAI;GAAoB;GAC5D,QAAQ,CAAC;EACX;CACF;AACF,CACF;AAKA,MAAa,gBAAgB,EAC3B,KACA,UACA,WACA,SACA,OACA,OAAO,UACP,UAAU,OACV,GAAG,kBACQ;CAGX,OACE,oBAHW,UAAU,OAAO,UAG5B;EACE,GAAI;EACC;EACL,MAAM,UAAU,KAAA,IAAY;EAC5B,WAAW,qBAAqB;GAAE;GAAS;GAAO;EAAU,CAAC;EAE5D;CACG,CAAA;AAEV"}
@@ -1,4 +1,4 @@
1
- import { Tooltip } from "./utils-BxEJOnFD.js";
1
+ import { Tooltip } from "./utils-CLNKe1ar.js";
2
2
  import { Check, Minus } from "./icons-DDR9dFSr.js";
3
3
  import { FieldBox } from "./FieldBox-DdSdJ3ZN.js";
4
4
  import { useId } from "react";
@@ -67,4 +67,4 @@ function Checkbox({ className, id: idProp, children, description, variant, posit
67
67
  }
68
68
  export { Checkbox };
69
69
 
70
- //# sourceMappingURL=Checkbox-CfjpwIcg.js.map
70
+ //# sourceMappingURL=Checkbox-CsvhT9Bj.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox-CfjpwIcg.js","names":[],"sources":["../src/components/Checkbox/styles.ts","../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\n\nexport const rootVariants = cva([\n // reset\n 'tailwindcss-preflight',\n\n // position\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-center',\n\n 'tw:peer',\n 'tw:size-4',\n 'tw:shrink-0',\n 'tw:cursor-pointer',\n\n // border\n 'tw:border',\n 'tw:border-solid',\n\n // disabled\n 'tw:disabled:opacity-disabled',\n 'tw:disabled:cursor-not-allowed',\n\n 'tw:rounded',\n 'tw:border-input',\n 'tw:transition-colors',\n\n 'tw:data-[state=checked]:bg-primary',\n 'tw:data-[state=checked]:border-primary',\n\n 'tw:data-[state=indeterminate]:bg-primary',\n 'tw:data-[state=indeterminate]:border-primary',\n\n // focus\n 'tw:focus-visible:outline-hidden',\n 'tw:focus-visible:border-primary',\n 'tw:focus-visible:ring-2',\n 'tw:focus-visible:ring-ring/50',\n]);\n\nexport const indicatorVariants = cva([\n 'tw:group',\n 'tw:flex',\n 'tw:items-center',\n 'tw:text-primary-foreground',\n]);\n","import { useId } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport type { CheckedState } from '@radix-ui/react-checkbox';\nimport { Indicator, Root } from '@radix-ui/react-checkbox';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { Check, Minus } from '../../icons';\nimport { FieldBox } from '../FieldBox';\nimport type { fieldBoxVariants } from '../FieldBox/styles';\nimport type { Props as TooltipProps } from '../Tooltip';\nimport { Tooltip } from '../Tooltip';\n\nimport { indicatorVariants, rootVariants } from './styles';\n\ntype Props = {\n id?: string | number;\n description?: ReactNode;\n variant?: VariantProps<typeof fieldBoxVariants>['variant'];\n position?: 'start' | 'end';\n tooltip?: TooltipProps['tooltip'];\n tooltipPlacement?: TooltipProps['placement'];\n} & Omit<ComponentProps<typeof Root>, 'id'>;\n\nexport function Checkbox(\n prop: Omit<Props, 'checked' | 'onCheckedChange'> & {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n },\n): ReactNode;\n\nexport function Checkbox(\n prop: Omit<Props, 'checked' | 'onCheckedChange'> & {\n checked?: CheckedState;\n onCheckedChange?: (checked: CheckedState) => void;\n },\n): ReactNode;\n\nexport function Checkbox({\n className,\n id: idProp,\n children,\n description,\n variant,\n position,\n tooltip,\n tooltipPlacement = 'top',\n ...rest\n}: Props) {\n const fallbackId = useId();\n const id = idProp?.toString() ?? fallbackId;\n\n const checkboxElement = (\n <Root id={id} {...rest} className={rootVariants({ className })}>\n <Indicator className={indicatorVariants()}>\n <Check className=\"tw:hidden tw:size-3 tw:stroke-[4px] tw:group-data-[state=checked]:block\" />\n <Minus className=\"tw:hidden tw:size-3 tw:stroke-[4px] tw:group-data-[state=indeterminate]:block\" />\n </Indicator>\n </Root>\n );\n\n const rendered = !children ? (\n checkboxElement\n ) : (\n <FieldBox htmlFor={id} variant={variant} position={position} control={checkboxElement}>\n <FieldBox.Title>{children}</FieldBox.Title>\n {description && <FieldBox.Description>{description}</FieldBox.Description>}\n </FieldBox>\n );\n\n if (!tooltip) return rendered;\n\n // `asChild` only onto the labelled FieldBox: on the bare Radix `Root` the tooltip's\n // `data-state` overwrites the checkbox's and it stops toggling.\n return (\n <Tooltip tooltip={tooltip} placement={tooltipPlacement} triggerAsChild={!!children}>\n {rendered}\n </Tooltip>\n );\n}\n"],"mappings":";;;;;;;;AAEA,MAAa,eAAe,IAAI;CAE9B;CAGA;CACA;CACA;CAEA;CACA;CACA;CACA;CAGA;CACA;CAGA;CACA;CAEA;CACA;CACA;CAEA;CACA;CAEA;CACA;CAGA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAa,oBAAoB,IAAI;CACnC;CACA;CACA;CACA;AACF,CAAC;;ACTD,SAAgB,SAAS,EACvB,WACA,IAAI,QACJ,UACA,aACA,SACA,UACA,SACA,mBAAmB,OACnB,GAAG,QACK;CACR,MAAM,aAAa,MAAM;CACzB,MAAM,KAAK,QAAQ,SAAS,KAAK;CAEjC,MAAM,kBACJ,oBAAC,MAAD;EAAU;EAAI,GAAI;EAAM,WAAW,aAAa,EAAE,UAAU,CAAC;EAC3D,UAAA,qBAAC,WAAD;GAAW,WAAW,kBAAkB;GAAxC,UAAA,CACE,oBAAC,OAAD,EAAO,WAAU,0EAA2E,CAAA,GAC5F,oBAAC,OAAD,EAAO,WAAU,gFAAiF,CAAA,CACzF;;CACP,CAAA;CAGR,MAAM,WAAW,CAAC,WAChB,kBAEA,qBAAC,UAAD;EAAU,SAAS;EAAa;EAAmB;EAAU,SAAS;EAAtE,UAAA,CACE,oBAAC,SAAS,OAAV,EAAiB,SAAyB,CAAA,GACzC,eAAe,oBAAC,SAAS,aAAV,EAAA,UAAuB,YAAkC,CAAA,CACjE;;CAGZ,IAAI,CAAC,SAAS,OAAO;CAIrB,OACE,oBAAC,SAAD;EAAkB;EAAS,WAAW;EAAkB,gBAAgB,CAAC,CAAC;EACvE,UAAA;CACM,CAAA;AAEb"}
1
+ {"version":3,"file":"Checkbox-CsvhT9Bj.js","names":[],"sources":["../src/components/Checkbox/styles.ts","../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\n\nexport const rootVariants = cva([\n // reset\n 'tailwindcss-preflight',\n\n // position\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-center',\n\n 'tw:peer',\n 'tw:size-4',\n 'tw:shrink-0',\n 'tw:cursor-pointer',\n\n // border\n 'tw:border',\n 'tw:border-solid',\n\n // disabled\n 'tw:disabled:opacity-disabled',\n 'tw:disabled:cursor-not-allowed',\n\n 'tw:rounded',\n 'tw:border-input',\n 'tw:transition-colors',\n\n 'tw:data-[state=checked]:bg-primary',\n 'tw:data-[state=checked]:border-primary',\n\n 'tw:data-[state=indeterminate]:bg-primary',\n 'tw:data-[state=indeterminate]:border-primary',\n\n // focus\n 'tw:focus-visible:outline-hidden',\n 'tw:focus-visible:border-primary',\n 'tw:focus-visible:ring-2',\n 'tw:focus-visible:ring-ring/50',\n]);\n\nexport const indicatorVariants = cva([\n 'tw:group',\n 'tw:flex',\n 'tw:items-center',\n 'tw:text-primary-foreground',\n]);\n","import { useId } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport type { CheckedState } from '@radix-ui/react-checkbox';\nimport { Indicator, Root } from '@radix-ui/react-checkbox';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { Check, Minus } from '../../icons';\nimport { FieldBox } from '../FieldBox';\nimport type { fieldBoxVariants } from '../FieldBox/styles';\nimport type { Props as TooltipProps } from '../Tooltip';\nimport { Tooltip } from '../Tooltip';\n\nimport { indicatorVariants, rootVariants } from './styles';\n\ntype Props = {\n id?: string | number;\n description?: ReactNode;\n variant?: VariantProps<typeof fieldBoxVariants>['variant'];\n position?: 'start' | 'end';\n tooltip?: TooltipProps['tooltip'];\n tooltipPlacement?: TooltipProps['placement'];\n} & Omit<ComponentProps<typeof Root>, 'id'>;\n\nexport function Checkbox(\n prop: Omit<Props, 'checked' | 'onCheckedChange'> & {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n },\n): ReactNode;\n\nexport function Checkbox(\n prop: Omit<Props, 'checked' | 'onCheckedChange'> & {\n checked?: CheckedState;\n onCheckedChange?: (checked: CheckedState) => void;\n },\n): ReactNode;\n\nexport function Checkbox({\n className,\n id: idProp,\n children,\n description,\n variant,\n position,\n tooltip,\n tooltipPlacement = 'top',\n ...rest\n}: Props) {\n const fallbackId = useId();\n const id = idProp?.toString() ?? fallbackId;\n\n const checkboxElement = (\n <Root id={id} {...rest} className={rootVariants({ className })}>\n <Indicator className={indicatorVariants()}>\n <Check className=\"tw:hidden tw:size-3 tw:stroke-[4px] tw:group-data-[state=checked]:block\" />\n <Minus className=\"tw:hidden tw:size-3 tw:stroke-[4px] tw:group-data-[state=indeterminate]:block\" />\n </Indicator>\n </Root>\n );\n\n const rendered = !children ? (\n checkboxElement\n ) : (\n <FieldBox htmlFor={id} variant={variant} position={position} control={checkboxElement}>\n <FieldBox.Title>{children}</FieldBox.Title>\n {description && <FieldBox.Description>{description}</FieldBox.Description>}\n </FieldBox>\n );\n\n if (!tooltip) return rendered;\n\n // `asChild` only onto the labelled FieldBox: on the bare Radix `Root` the tooltip's\n // `data-state` overwrites the checkbox's and it stops toggling.\n return (\n <Tooltip tooltip={tooltip} placement={tooltipPlacement} triggerAsChild={!!children}>\n {rendered}\n </Tooltip>\n );\n}\n"],"mappings":";;;;;;;;AAEA,MAAa,eAAe,IAAI;CAE9B;CAGA;CACA;CACA;CAEA;CACA;CACA;CACA;CAGA;CACA;CAGA;CACA;CAEA;CACA;CACA;CAEA;CACA;CAEA;CACA;CAGA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAa,oBAAoB,IAAI;CACnC;CACA;CACA;CACA;AACF,CAAC;;ACTD,SAAgB,SAAS,EACvB,WACA,IAAI,QACJ,UACA,aACA,SACA,UACA,SACA,mBAAmB,OACnB,GAAG,QACK;CACR,MAAM,aAAa,MAAM;CACzB,MAAM,KAAK,QAAQ,SAAS,KAAK;CAEjC,MAAM,kBACJ,oBAAC,MAAD;EAAU;EAAI,GAAI;EAAM,WAAW,aAAa,EAAE,UAAU,CAAC;EAC3D,UAAA,qBAAC,WAAD;GAAW,WAAW,kBAAkB;GAAxC,UAAA,CACE,oBAAC,OAAD,EAAO,WAAU,0EAA2E,CAAA,GAC5F,oBAAC,OAAD,EAAO,WAAU,gFAAiF,CAAA,CACzF;;CACP,CAAA;CAGR,MAAM,WAAW,CAAC,WAChB,kBAEA,qBAAC,UAAD;EAAU,SAAS;EAAa;EAAmB;EAAU,SAAS;EAAtE,UAAA,CACE,oBAAC,SAAS,OAAV,EAAiB,SAAyB,CAAA,GACzC,eAAe,oBAAC,SAAS,aAAV,EAAA,UAAuB,YAAkC,CAAA,CACjE;;CAGZ,IAAI,CAAC,SAAS,OAAO;CAIrB,OACE,oBAAC,SAAD;EAAkB;EAAS,WAAW;EAAkB,gBAAgB,CAAC,CAAC;EACvE,UAAA;CACM,CAAA;AAEb"}
@@ -1,5 +1,5 @@
1
1
  import { cn } from "./classNames-DkX30VJU.js";
2
- import { Tooltip, copyToClipboard } from "./utils-BxEJOnFD.js";
2
+ import { Tooltip, copyToClipboard } from "./utils-CLNKe1ar.js";
3
3
  import { useState } from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  // src/components/Clipboard/Clipboard.tsx
@@ -56,4 +56,4 @@ const Clipboard = ({ ref, text: textProp, children, tooltip = "Copy to Clipboard
56
56
  };
57
57
  export { Clipboard };
58
58
 
59
- //# sourceMappingURL=Clipboard-BaU3cDi5.js.map
59
+ //# sourceMappingURL=Clipboard-C6clKAwX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Clipboard-BaU3cDi5.js","names":[],"sources":["../src/components/Clipboard/Clipboard.tsx"],"sourcesContent":["import { useState } from 'react';\nimport type { ComponentProps, MouseEventHandler } from 'react';\n\nimport { cn, copyToClipboard } from '../../utils';\nimport { type Props as TooltipProps, Tooltip } from '../Tooltip';\n\ntype Props = {\n tooltip?: TooltipProps['tooltip'];\n tooltipPlacement?: TooltipProps['placement'];\n tooltipVariant?: TooltipProps['variant'];\n asChild?: TooltipProps['triggerAsChild'];\n text?: string | (() => string);\n /** Called once per copy attempt, after it settles, with whether it succeeded; not when no copy ran. */\n onCopied?: (copied: boolean) => void;\n} & ComponentProps<'button'>;\n\nexport const Clipboard = ({\n ref,\n text: textProp,\n children,\n tooltip = 'Copy to Clipboard',\n tooltipPlacement = 'top',\n tooltipVariant: tooltipVariantProp = 'action',\n asChild = false,\n onClick,\n onCopied,\n className,\n ...restButtonProps\n}: Props) => {\n const [isTooltipOpen, setIsTooltipOpen] = useState(false);\n const [state, setState] = useState<'ready' | 'copied' | 'error'>('ready');\n const text = typeof textProp === 'function' ? textProp() : textProp;\n\n const copy = async (text: string) => {\n let copied = true;\n try {\n // For the clipboard feature to work reliably, the window must be in focus for security reasons.\n // However, the button can be clicked without the window being focused.\n if (!document.hasFocus()) window.focus();\n\n await copyToClipboard(text);\n } catch {\n copied = false;\n }\n setState(copied ? 'copied' : 'error');\n onCopied?.(copied);\n };\n\n const handleOnClick: MouseEventHandler<HTMLButtonElement> = (event) => {\n // Open on click rather than waiting for hover. Radix opens on pointer-enter via a\n // `delayDuration` timer (300ms here), so clicking faster than that left the outcome invisible\n // until the timer caught up — the message was already rendered, just inside a closed tooltip.\n setIsTooltipOpen(true);\n if (text && state === 'ready') void copy(text);\n onClick?.(event);\n };\n\n const handleOnOpenChange: ComponentProps<typeof Tooltip.Root>['onOpenChange'] = (open) => {\n // Reset when the tooltip closes, allowing the user to leave the copy button.\n if (!open && state !== 'ready') setState('ready');\n setIsTooltipOpen(open);\n };\n\n const tooltipContent = (() => {\n if (!text) return 'Nothing to copy';\n if (state === 'error') return 'Failed to copy';\n if (state === 'copied') return 'Copied to Clipboard';\n return tooltip;\n })();\n\n const tooltipVariant: TooltipProps['variant'] =\n state === 'ready' && !!text ? tooltipVariantProp : 'action';\n\n // `tooltip={null}` leaves nothing to say until there is an outcome. Not rendering `Content` at all\n // is what makes that work: hovering still opens the tooltip, there is simply nothing in it, and\n // the copied / failed message appears in place the moment `state` changes. It also keeps Radix\n // from pointing the trigger's `aria-describedby` at content that has no text.\n const hasTooltipContent = tooltipContent !== null && tooltipContent !== undefined;\n\n return (\n <Tooltip.Root open={isTooltipOpen} onOpenChange={handleOnOpenChange}>\n <Tooltip.Trigger\n {...restButtonProps}\n asChild={asChild}\n keepOpenOnClick\n onClick={handleOnClick}\n className={cn('tw:cursor-pointer', className)}\n ref={ref}\n >\n {children ?? text}\n </Tooltip.Trigger>\n\n {hasTooltipContent && (\n <Tooltip.Content\n keepOpenOnPointerDownOutside\n placement={tooltipPlacement}\n variant={tooltipVariant}\n >\n {tooltipContent}\n </Tooltip.Content>\n )}\n </Tooltip.Root>\n );\n};\n"],"mappings":";;;;;AAgBA,MAAa,aAAa,EACxB,KACA,MAAM,UACN,UACA,UAAU,qBACV,mBAAmB,OACnB,gBAAgB,qBAAqB,UACrC,UAAU,OACV,SACA,UACA,WACA,GAAG,sBACQ;CACX,MAAM,CAAC,eAAe,oBAAoB,SAAS,KAAK;CACxD,MAAM,CAAC,OAAO,YAAY,SAAuC,OAAO;CACxE,MAAM,OAAO,OAAO,aAAa,aAAa,SAAS,IAAI;CAE3D,MAAM,OAAO,OAAO,SAAiB;EACnC,IAAI,SAAS;EACb,IAAI;GAGF,IAAI,CAAC,SAAS,SAAS,GAAG,OAAO,MAAM;GAEvC,MAAM,gBAAgB,IAAI;EAC5B,QAAQ;GACN,SAAS;EACX;EACA,SAAS,SAAS,WAAW,OAAO;EACpC,WAAW,MAAM;CACnB;CAEA,MAAM,iBAAuD,UAAU;EAIrE,iBAAiB,IAAI;EACrB,IAAI,QAAQ,UAAU,SAAS,KAAU,IAAI;EAC7C,UAAU,KAAK;CACjB;CAEA,MAAM,sBAA2E,SAAS;EAExF,IAAI,CAAC,QAAQ,UAAU,SAAS,SAAS,OAAO;EAChD,iBAAiB,IAAI;CACvB;CAEA,MAAM,wBAAwB;EAC5B,IAAI,CAAC,MAAM,OAAO;EAClB,IAAI,UAAU,SAAS,OAAO;EAC9B,IAAI,UAAU,UAAU,OAAO;EAC/B,OAAO;CACT,EAAA,CAAG;CAEH,MAAM,iBACJ,UAAU,WAAW,CAAC,CAAC,OAAO,qBAAqB;CAMrD,MAAM,oBAAoB,mBAAmB,QAAQ,mBAAmB,KAAA;CAExE,OACE,qBAAC,QAAQ,MAAT;EAAc,MAAM;EAAe,cAAc;EAAjD,UAAA,CACE,oBAAC,QAAQ,SAAT;GACE,GAAI;GACK;GACT,iBAAA;GACA,SAAS;GACT,WAAW,GAAG,qBAAqB,SAAS;GACvC;GAEJ,UAAA,YAAY;EACE,CAAA,GAEhB,qBACC,oBAAC,QAAQ,SAAT;GACE,8BAAA;GACA,WAAW;GACX,SAAS;GAER,UAAA;EACc,CAAA,CAEP;;AAElB"}
1
+ {"version":3,"file":"Clipboard-C6clKAwX.js","names":[],"sources":["../src/components/Clipboard/Clipboard.tsx"],"sourcesContent":["import { useState } from 'react';\nimport type { ComponentProps, MouseEventHandler } from 'react';\n\nimport { cn, copyToClipboard } from '../../utils';\nimport { type Props as TooltipProps, Tooltip } from '../Tooltip';\n\ntype Props = {\n tooltip?: TooltipProps['tooltip'];\n tooltipPlacement?: TooltipProps['placement'];\n tooltipVariant?: TooltipProps['variant'];\n asChild?: TooltipProps['triggerAsChild'];\n text?: string | (() => string);\n /** Called once per copy attempt, after it settles, with whether it succeeded; not when no copy ran. */\n onCopied?: (copied: boolean) => void;\n} & ComponentProps<'button'>;\n\nexport const Clipboard = ({\n ref,\n text: textProp,\n children,\n tooltip = 'Copy to Clipboard',\n tooltipPlacement = 'top',\n tooltipVariant: tooltipVariantProp = 'action',\n asChild = false,\n onClick,\n onCopied,\n className,\n ...restButtonProps\n}: Props) => {\n const [isTooltipOpen, setIsTooltipOpen] = useState(false);\n const [state, setState] = useState<'ready' | 'copied' | 'error'>('ready');\n const text = typeof textProp === 'function' ? textProp() : textProp;\n\n const copy = async (text: string) => {\n let copied = true;\n try {\n // For the clipboard feature to work reliably, the window must be in focus for security reasons.\n // However, the button can be clicked without the window being focused.\n if (!document.hasFocus()) window.focus();\n\n await copyToClipboard(text);\n } catch {\n copied = false;\n }\n setState(copied ? 'copied' : 'error');\n onCopied?.(copied);\n };\n\n const handleOnClick: MouseEventHandler<HTMLButtonElement> = (event) => {\n // Open on click rather than waiting for hover. Radix opens on pointer-enter via a\n // `delayDuration` timer (300ms here), so clicking faster than that left the outcome invisible\n // until the timer caught up — the message was already rendered, just inside a closed tooltip.\n setIsTooltipOpen(true);\n if (text && state === 'ready') void copy(text);\n onClick?.(event);\n };\n\n const handleOnOpenChange: ComponentProps<typeof Tooltip.Root>['onOpenChange'] = (open) => {\n // Reset when the tooltip closes, allowing the user to leave the copy button.\n if (!open && state !== 'ready') setState('ready');\n setIsTooltipOpen(open);\n };\n\n const tooltipContent = (() => {\n if (!text) return 'Nothing to copy';\n if (state === 'error') return 'Failed to copy';\n if (state === 'copied') return 'Copied to Clipboard';\n return tooltip;\n })();\n\n const tooltipVariant: TooltipProps['variant'] =\n state === 'ready' && !!text ? tooltipVariantProp : 'action';\n\n // `tooltip={null}` leaves nothing to say until there is an outcome. Not rendering `Content` at all\n // is what makes that work: hovering still opens the tooltip, there is simply nothing in it, and\n // the copied / failed message appears in place the moment `state` changes. It also keeps Radix\n // from pointing the trigger's `aria-describedby` at content that has no text.\n const hasTooltipContent = tooltipContent !== null && tooltipContent !== undefined;\n\n return (\n <Tooltip.Root open={isTooltipOpen} onOpenChange={handleOnOpenChange}>\n <Tooltip.Trigger\n {...restButtonProps}\n asChild={asChild}\n keepOpenOnClick\n onClick={handleOnClick}\n className={cn('tw:cursor-pointer', className)}\n ref={ref}\n >\n {children ?? text}\n </Tooltip.Trigger>\n\n {hasTooltipContent && (\n <Tooltip.Content\n keepOpenOnPointerDownOutside\n placement={tooltipPlacement}\n variant={tooltipVariant}\n >\n {tooltipContent}\n </Tooltip.Content>\n )}\n </Tooltip.Root>\n );\n};\n"],"mappings":";;;;;AAgBA,MAAa,aAAa,EACxB,KACA,MAAM,UACN,UACA,UAAU,qBACV,mBAAmB,OACnB,gBAAgB,qBAAqB,UACrC,UAAU,OACV,SACA,UACA,WACA,GAAG,sBACQ;CACX,MAAM,CAAC,eAAe,oBAAoB,SAAS,KAAK;CACxD,MAAM,CAAC,OAAO,YAAY,SAAuC,OAAO;CACxE,MAAM,OAAO,OAAO,aAAa,aAAa,SAAS,IAAI;CAE3D,MAAM,OAAO,OAAO,SAAiB;EACnC,IAAI,SAAS;EACb,IAAI;GAGF,IAAI,CAAC,SAAS,SAAS,GAAG,OAAO,MAAM;GAEvC,MAAM,gBAAgB,IAAI;EAC5B,QAAQ;GACN,SAAS;EACX;EACA,SAAS,SAAS,WAAW,OAAO;EACpC,WAAW,MAAM;CACnB;CAEA,MAAM,iBAAuD,UAAU;EAIrE,iBAAiB,IAAI;EACrB,IAAI,QAAQ,UAAU,SAAS,KAAU,IAAI;EAC7C,UAAU,KAAK;CACjB;CAEA,MAAM,sBAA2E,SAAS;EAExF,IAAI,CAAC,QAAQ,UAAU,SAAS,SAAS,OAAO;EAChD,iBAAiB,IAAI;CACvB;CAEA,MAAM,wBAAwB;EAC5B,IAAI,CAAC,MAAM,OAAO;EAClB,IAAI,UAAU,SAAS,OAAO;EAC9B,IAAI,UAAU,UAAU,OAAO;EAC/B,OAAO;CACT,EAAA,CAAG;CAEH,MAAM,iBACJ,UAAU,WAAW,CAAC,CAAC,OAAO,qBAAqB;CAMrD,MAAM,oBAAoB,mBAAmB,QAAQ,mBAAmB,KAAA;CAExE,OACE,qBAAC,QAAQ,MAAT;EAAc,MAAM;EAAe,cAAc;EAAjD,UAAA,CACE,oBAAC,QAAQ,SAAT;GACE,GAAI;GACK;GACT,iBAAA;GACA,SAAS;GACT,WAAW,GAAG,qBAAqB,SAAS;GACvC;GAEJ,UAAA,YAAY;EACE,CAAA,GAEhB,qBACC,oBAAC,QAAQ,SAAT;GACE,8BAAA;GACA,WAAW;GACX,SAAS;GAER,UAAA;EACc,CAAA,CAEP;;AAElB"}
@@ -1,6 +1,6 @@
1
1
  import { Copy } from "./icons-DDR9dFSr.js";
2
- import { Button, ButtonInline } from "./Button-BAMX1iuI.js";
3
- import { Clipboard } from "./Clipboard-BaU3cDi5.js";
2
+ import { Button, ButtonInline } from "./Button-BgjVUBON.js";
3
+ import { Clipboard } from "./Clipboard-C6clKAwX.js";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  // src/blocks/ClipboardButton/ClipboardButton.tsx
6
6
  const DEFAULT_ICON = /* @__PURE__ */ jsx(Copy, {});
@@ -39,4 +39,4 @@ const ClipboardInline = ({ text, tooltip, tooltipPlacement, tooltipVariant, chil
39
39
  });
40
40
  export { ClipboardButton, ClipboardInline };
41
41
 
42
- //# sourceMappingURL=ClipboardButton-BWeaQEM2.js.map
42
+ //# sourceMappingURL=ClipboardButton-1ISIYJQj.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ClipboardButton-BWeaQEM2.js","names":[],"sources":["../src/blocks/ClipboardButton/ClipboardButton.tsx","../src/blocks/ClipboardButton/ClipboardInline.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Clipboard } from '../../components/Clipboard';\nimport { Copy } from '../../icons';\n\ntype ClipboardProps = Pick<\n ComponentProps<typeof Clipboard>,\n 'text' | 'tooltip' | 'tooltipPlacement' | 'tooltipVariant' | 'onCopied'\n>;\n\ntype ButtonProps = Omit<ComponentProps<typeof Button>, 'disabled' | 'icon'>;\n\ntype Props = ClipboardProps & ButtonProps & { icon?: ReactNode };\n\nconst DEFAULT_ICON: ReactNode = <Copy />;\nconst DEFAULT_ARIA_LABEL = 'Copy';\n\nexport const ClipboardButton = ({\n // clipboard props\n text,\n tooltip,\n tooltipPlacement,\n tooltipVariant,\n onCopied,\n\n // button props\n icon = DEFAULT_ICON,\n variant = 'outline',\n children,\n ...rest\n}: Props) => {\n // Icon-only (no text children): the `tooltip` is visual only, not an accessible\n // name, so fall back to it (when it's a string) or a sensible default. A\n // consumer-supplied `aria-label` in `rest` still wins.\n // A non-empty string tooltip names the action; an empty/absent tooltip still\n // needs a name, so fall back to the default rather than an empty aria-label.\n const defaultAriaLabel =\n typeof tooltip === 'string' && tooltip.trim() ? tooltip : DEFAULT_ARIA_LABEL;\n const ariaLabel = rest['aria-label'] ?? (children == null ? defaultAriaLabel : undefined);\n\n return (\n <Clipboard\n asChild\n tooltip={tooltip}\n tooltipPlacement={tooltipPlacement}\n tooltipVariant={tooltipVariant}\n text={text}\n onCopied={onCopied}\n >\n <Button {...rest} aria-label={ariaLabel} variant={variant} disabled={!text}>\n {icon}\n {children}\n </Button>\n </Clipboard>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { ButtonInline } from '../../components/Button';\nimport { Clipboard } from '../../components/Clipboard';\nimport { Copy } from '../../icons';\n\ntype ClipboardProps = Pick<\n ComponentProps<typeof Clipboard>,\n 'text' | 'tooltip' | 'tooltipPlacement' | 'tooltipVariant'\n>;\n\ntype ButtonProps = Omit<ComponentProps<typeof ButtonInline>, 'disabled'>;\n\ntype Props = { hideIcon?: boolean } & ClipboardProps & ButtonProps;\n\nexport const ClipboardInline = ({\n // clipboard props\n text,\n tooltip,\n tooltipPlacement,\n tooltipVariant,\n\n // button props\n children = 'Copy To Clipboard',\n hideIcon = false,\n ...rest\n}: Props) => (\n <Clipboard\n asChild\n text={text}\n tooltip={tooltip}\n tooltipPlacement={tooltipPlacement}\n tooltipVariant={tooltipVariant}\n >\n <ButtonInline {...rest} disabled={!text}>\n {!hideIcon && <Copy className=\"tw:size-4\" />}\n {children}\n </ButtonInline>\n </Clipboard>\n);\n"],"mappings":";;;;;AAeA,MAAM,eAA0B,oBAAC,MAAD,CAAO,CAAA;AACvC,MAAM,qBAAqB;AAE3B,MAAa,mBAAmB,EAE9B,MACA,SACA,kBACA,gBACA,UAGA,OAAO,cACP,UAAU,WACV,UACA,GAAG,WACQ;CAMX,MAAM,mBACJ,OAAO,YAAY,YAAY,QAAQ,KAAK,IAAI,UAAU;CAC5D,MAAM,YAAY,KAAK,kBAAkB,YAAY,OAAO,mBAAmB,KAAA;CAE/E,OACE,oBAAC,WAAD;EACE,SAAA;EACS;EACS;EACF;EACV;EACI;EAEV,UAAA,qBAAC,QAAD;GAAQ,GAAI;GAAM,cAAY;GAAoB;GAAS,UAAU,CAAC;GAAtE,UAAA,CACG,MACA,QACK;;CACC,CAAA;AAEf;;ACzCA,MAAa,mBAAmB,EAE9B,MACA,SACA,kBACA,gBAGA,WAAW,qBACX,WAAW,OACX,GAAG,WAEH,oBAAC,WAAD;CACE,SAAA;CACM;CACG;CACS;CACF;CAEhB,UAAA,qBAAC,cAAD;EAAc,GAAI;EAAM,UAAU,CAAC;EAAnC,UAAA,CACG,CAAC,YAAY,oBAAC,MAAD,EAAM,WAAU,YAAa,CAAA,GAC1C,QACW;;AACL,CAAA"}
1
+ {"version":3,"file":"ClipboardButton-1ISIYJQj.js","names":[],"sources":["../src/blocks/ClipboardButton/ClipboardButton.tsx","../src/blocks/ClipboardButton/ClipboardInline.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Clipboard } from '../../components/Clipboard';\nimport { Copy } from '../../icons';\n\ntype ClipboardProps = Pick<\n ComponentProps<typeof Clipboard>,\n 'text' | 'tooltip' | 'tooltipPlacement' | 'tooltipVariant' | 'onCopied'\n>;\n\ntype ButtonProps = Omit<ComponentProps<typeof Button>, 'disabled' | 'icon'>;\n\ntype Props = ClipboardProps & ButtonProps & { icon?: ReactNode };\n\nconst DEFAULT_ICON: ReactNode = <Copy />;\nconst DEFAULT_ARIA_LABEL = 'Copy';\n\nexport const ClipboardButton = ({\n // clipboard props\n text,\n tooltip,\n tooltipPlacement,\n tooltipVariant,\n onCopied,\n\n // button props\n icon = DEFAULT_ICON,\n variant = 'outline',\n children,\n ...rest\n}: Props) => {\n // Icon-only (no text children): the `tooltip` is visual only, not an accessible\n // name, so fall back to it (when it's a string) or a sensible default. A\n // consumer-supplied `aria-label` in `rest` still wins.\n // A non-empty string tooltip names the action; an empty/absent tooltip still\n // needs a name, so fall back to the default rather than an empty aria-label.\n const defaultAriaLabel =\n typeof tooltip === 'string' && tooltip.trim() ? tooltip : DEFAULT_ARIA_LABEL;\n const ariaLabel = rest['aria-label'] ?? (children == null ? defaultAriaLabel : undefined);\n\n return (\n <Clipboard\n asChild\n tooltip={tooltip}\n tooltipPlacement={tooltipPlacement}\n tooltipVariant={tooltipVariant}\n text={text}\n onCopied={onCopied}\n >\n <Button {...rest} aria-label={ariaLabel} variant={variant} disabled={!text}>\n {icon}\n {children}\n </Button>\n </Clipboard>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { ButtonInline } from '../../components/Button';\nimport { Clipboard } from '../../components/Clipboard';\nimport { Copy } from '../../icons';\n\ntype ClipboardProps = Pick<\n ComponentProps<typeof Clipboard>,\n 'text' | 'tooltip' | 'tooltipPlacement' | 'tooltipVariant'\n>;\n\ntype ButtonProps = Omit<ComponentProps<typeof ButtonInline>, 'disabled'>;\n\ntype Props = { hideIcon?: boolean } & ClipboardProps & ButtonProps;\n\nexport const ClipboardInline = ({\n // clipboard props\n text,\n tooltip,\n tooltipPlacement,\n tooltipVariant,\n\n // button props\n children = 'Copy To Clipboard',\n hideIcon = false,\n ...rest\n}: Props) => (\n <Clipboard\n asChild\n text={text}\n tooltip={tooltip}\n tooltipPlacement={tooltipPlacement}\n tooltipVariant={tooltipVariant}\n >\n <ButtonInline {...rest} disabled={!text}>\n {!hideIcon && <Copy className=\"tw:size-4\" />}\n {children}\n </ButtonInline>\n </Clipboard>\n);\n"],"mappings":";;;;;AAeA,MAAM,eAA0B,oBAAC,MAAD,CAAO,CAAA;AACvC,MAAM,qBAAqB;AAE3B,MAAa,mBAAmB,EAE9B,MACA,SACA,kBACA,gBACA,UAGA,OAAO,cACP,UAAU,WACV,UACA,GAAG,WACQ;CAMX,MAAM,mBACJ,OAAO,YAAY,YAAY,QAAQ,KAAK,IAAI,UAAU;CAC5D,MAAM,YAAY,KAAK,kBAAkB,YAAY,OAAO,mBAAmB,KAAA;CAE/E,OACE,oBAAC,WAAD;EACE,SAAA;EACS;EACS;EACF;EACV;EACI;EAEV,UAAA,qBAAC,QAAD;GAAQ,GAAI;GAAM,cAAY;GAAoB;GAAS,UAAU,CAAC;GAAtE,UAAA,CACG,MACA,QACK;;CACC,CAAA;AAEf;;ACzCA,MAAa,mBAAmB,EAE9B,MACA,SACA,kBACA,gBAGA,WAAW,qBACX,WAAW,OACX,GAAG,WAEH,oBAAC,WAAD;CACE,SAAA;CACM;CACG;CACS;CACF;CAEhB,UAAA,qBAAC,cAAD;EAAc,GAAI;EAAM,UAAU,CAAC;EAAnC,UAAA,CACG,CAAC,YAAY,oBAAC,MAAD,EAAM,WAAU,YAAa,CAAA,GAC1C,QACW;;AACL,CAAA"}
@@ -1,10 +1,10 @@
1
1
  import { cn } from "./classNames-DkX30VJU.js";
2
- import { isMac, keyCodes } from "./utils-BxEJOnFD.js";
2
+ import { isMac, keyCodes } from "./utils-CLNKe1ar.js";
3
3
  import { findLiteralMatches } from "./findLiteralMatches-BaLZTPtx.js";
4
- import { ClipboardButton } from "./ClipboardButton-BWeaQEM2.js";
4
+ import { ClipboardButton } from "./ClipboardButton-1ISIYJQj.js";
5
5
  import { useStableCallback } from "./internal/hooks/useStableCallback.js";
6
6
  import { HelpBlock } from "./internal/components/HelpBlock.js";
7
- import { Kbd } from "./Kbd-6velz9J-.js";
7
+ import { Kbd } from "./Kbd-D4F65jXO.js";
8
8
  import { resolveToken, useThemeAttributes } from "./themeTokens-B60cQtAY.js";
9
9
  import { useEffect, useLayoutEffect, useMemo, useRef } from "react";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -999,4 +999,4 @@ const CodeEditor = ({ value, previousValue, onChange, variant = "plain", mode =
999
999
  };
1000
1000
  export { CodeEditor, LANGUAGE_MODES, buildBaseThemeStyles, buildBasicSetup, buildCanvasChrome, buildChromeStyles, buildCustomTheme, buildDiffWash, isLanguageMode, searchExtension, updateSearch, useThemedExtension, useTooltipsExtension, useVariableCompletion };
1001
1001
 
1002
- //# sourceMappingURL=CodeEditor-BdTxkPD4.js.map
1002
+ //# sourceMappingURL=CodeEditor-Dx9gyVHV.js.map