@keboola/design 11.2.0 → 11.3.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.
- package/AGENTS.md +25 -14
- package/CHANGELOG.md +254 -0
- package/COMPONENT-API.md +1 -1
- package/dist/{AIKit-DiS0CVOW.js → AIKit-DaFT7p92.js} +23 -22
- package/dist/AIKit-DaFT7p92.js.map +1 -0
- package/dist/{Alert-DfZq9kGe.js → Alert-CseY3yAj.js} +3 -3
- package/dist/{Alert-DfZq9kGe.js.map → Alert-CseY3yAj.js.map} +1 -1
- package/dist/{AlertModal-Dp_XuJBW.js → AlertModal-DQAGpsEy.js} +3 -3
- package/dist/{AlertModal-Dp_XuJBW.js.map → AlertModal-DQAGpsEy.js.map} +1 -1
- package/dist/{AppShell-B5GQN6Zs.js → AppShell-BUoxM3fv.js} +29 -10
- package/dist/AppShell-BUoxM3fv.js.map +1 -0
- package/dist/{BrandEditor-DyzgfVkl.js → BrandEditor-BnTLMRMp.js} +6 -6
- package/dist/{BrandEditor-DyzgfVkl.js.map → BrandEditor-BnTLMRMp.js.map} +1 -1
- package/dist/{BrandLogo-CJkRd0F8.js → BrandLogo-V2pRUAeO.js} +2 -2
- package/dist/{BrandLogo-CJkRd0F8.js.map → BrandLogo-V2pRUAeO.js.map} +1 -1
- package/dist/{Breadcrumb-Frst8MTA.js → Breadcrumb-CQTPn_KB.js} +3 -3
- package/dist/{Breadcrumb-Frst8MTA.js.map → Breadcrumb-CQTPn_KB.js.map} +1 -1
- package/dist/{Button-6xBX0nNl.js → Button-CPsEQuTN.js} +2 -2
- package/dist/{Button-6xBX0nNl.js.map → Button-CPsEQuTN.js.map} +1 -1
- package/dist/{Card-BAoZ35CV.js → Card-Cd5HSBmv.js} +2 -2
- package/dist/{Card-BAoZ35CV.js.map → Card-Cd5HSBmv.js.map} +1 -1
- package/dist/{Checkbox-GJ8-srt4.js → Checkbox-5VNCcV7E.js} +3 -3
- package/dist/{Checkbox-GJ8-srt4.js.map → Checkbox-5VNCcV7E.js.map} +1 -1
- package/dist/{Clipboard-CBJZiviP.js → Clipboard-B7rckqV_.js} +2 -2
- package/dist/{Clipboard-CBJZiviP.js.map → Clipboard-B7rckqV_.js.map} +1 -1
- package/dist/{ClipboardButton-ClcluT0C.js → ClipboardButton-CQ6Aewpg.js} +3 -3
- package/dist/{ClipboardButton-ClcluT0C.js.map → ClipboardButton-CQ6Aewpg.js.map} +1 -1
- package/dist/{CodeEditor-DyaN-Ij2.js → CodeEditor-CUse8znx.js} +237 -95
- package/dist/CodeEditor-CUse8znx.js.map +1 -0
- package/dist/{ColorInput-B8z4j4Y_.js → ColorInput-Q1D9Vcc_.js} +3 -3
- package/dist/{ColorInput-B8z4j4Y_.js.map → ColorInput-Q1D9Vcc_.js.map} +1 -1
- package/dist/{ColorModeSwitch-dZFZyqy1.js → ColorModeSwitch-B5PXCVqB.js} +3 -3
- package/dist/{ColorModeSwitch-dZFZyqy1.js.map → ColorModeSwitch-B5PXCVqB.js.map} +1 -1
- package/dist/{Combobox-Dgm6Z4ib.js → Combobox-CyoRA7oY.js} +5 -5
- package/dist/Combobox-CyoRA7oY.js.map +1 -0
- package/dist/{Command-C0aZfVTq.js → Command-Ds68v2rX.js} +3 -3
- package/dist/{Command-C0aZfVTq.js.map → Command-Ds68v2rX.js.map} +1 -1
- package/dist/{CopyField-BJ96zvXs.js → CopyField-DI66uY_g.js} +2 -2
- package/dist/{CopyField-BJ96zvXs.js.map → CopyField-DI66uY_g.js.map} +1 -1
- package/dist/{DateInput-B3UdzRfW.js → DateInput-BPj2pzsn.js} +4 -4
- package/dist/{DateInput-B3UdzRfW.js.map → DateInput-BPj2pzsn.js.map} +1 -1
- package/dist/{DatePicker-Dw3DpbUh.js → DatePicker-DyEGuW9m.js} +2 -2
- package/dist/{DatePicker-Dw3DpbUh.js.map → DatePicker-DyEGuW9m.js.map} +1 -1
- package/dist/{DateRangeInput-DTuySEiq.js → DateRangeInput-u9DxNbHW.js} +4 -4
- package/dist/{DateRangeInput-DTuySEiq.js.map → DateRangeInput-u9DxNbHW.js.map} +1 -1
- package/dist/{DateRangePicker-DCmMHg4s.js → DateRangePicker-CYYhX6S7.js} +6 -6
- package/dist/{DateRangePicker-DCmMHg4s.js.map → DateRangePicker-CYYhX6S7.js.map} +1 -1
- package/dist/{DropdownMenu-t90tVw6l.js → DropdownMenu-DpMEcyCq.js} +2 -2
- package/dist/{DropdownMenu-t90tVw6l.js.map → DropdownMenu-DpMEcyCq.js.map} +1 -1
- package/dist/{FieldItem-D-h1NeBo.js → FieldItem-qQKGU9lF.js} +3 -3
- package/dist/{FieldItem-D-h1NeBo.js.map → FieldItem-qQKGU9lF.js.map} +1 -1
- package/dist/{FieldItem-CAPj9lj3.d.ts → FieldItem-vhIJW4pj.d.ts} +2 -10
- package/dist/{FileUpload-BRv0TaZk.js → FileUpload-C336MVnU.js} +2 -2
- package/dist/{FileUpload-BRv0TaZk.js.map → FileUpload-C336MVnU.js.map} +1 -1
- package/dist/{Form-DHvcFoEi.js → Form-CTygENDc.js} +8 -8
- package/dist/{Form-DHvcFoEi.js.map → Form-CTygENDc.js.map} +1 -1
- package/dist/{FormGroup-C41n65cE.js → FormGroup-BnwP0jNu.js} +3 -3
- package/dist/{FormGroup-C41n65cE.js.map → FormGroup-BnwP0jNu.js.map} +1 -1
- package/dist/{FullScreenModal-Cb3PGgh4.js → FullScreenModal-j-M4aPFd.js} +3 -3
- package/dist/{FullScreenModal-Cb3PGgh4.js.map → FullScreenModal-j-M4aPFd.js.map} +1 -1
- package/dist/{HoverCard-WfDkLK1s.js → HoverCard-yQq-O49c.js} +2 -2
- package/dist/{HoverCard-WfDkLK1s.js.map → HoverCard-yQq-O49c.js.map} +1 -1
- package/dist/{InputGroup-CdTq8H7c.js → InputGroup-D7zlmqPB.js} +3 -3
- package/dist/{InputGroup-CdTq8H7c.js.map → InputGroup-D7zlmqPB.js.map} +1 -1
- package/dist/{Kbd-CxHAo1oo.js → Kbd-D6LpR7G2.js} +2 -2
- package/dist/{Kbd-CxHAo1oo.js.map → Kbd-D6LpR7G2.js.map} +1 -1
- package/dist/{MermaidDiagram-ChL3WIQT.js → MermaidDiagram-JlvuGcY-.js} +6 -87
- package/dist/MermaidDiagram-JlvuGcY-.js.map +1 -0
- package/dist/{Modal-wqG8nJiK.js → Modal-o4ATIexE.js} +3 -3
- package/dist/{Modal-wqG8nJiK.js.map → Modal-o4ATIexE.js.map} +1 -1
- package/dist/{MultiActionButtonGroup-BiIIubiL.js → MultiActionButtonGroup-GTeFk-L8.js} +3 -3
- package/dist/{MultiActionButtonGroup-BiIIubiL.js.map → MultiActionButtonGroup-GTeFk-L8.js.map} +1 -1
- package/dist/{Navbar-BfaPeLUL.js → Navbar-CAQs4BZz.js} +2 -2
- package/dist/{Navbar-BfaPeLUL.js.map → Navbar-CAQs4BZz.js.map} +1 -1
- package/dist/{PageToolbar-OQg3mPF-.js → PageToolbar-bG2YtSa3.js} +3 -3
- package/dist/{PageToolbar-OQg3mPF-.js.map → PageToolbar-bG2YtSa3.js.map} +1 -1
- package/dist/{Pagination-Cjfda8KG.js → Pagination-BB3X7ooY.js} +2 -2
- package/dist/{Pagination-Cjfda8KG.js.map → Pagination-BB3X7ooY.js.map} +1 -1
- package/dist/{Popconfirm-D7_vfxFd.js → Popconfirm-C2Ky5hJO.js} +3 -3
- package/dist/{Popconfirm-D7_vfxFd.js.map → Popconfirm-C2Ky5hJO.js.map} +1 -1
- package/dist/{Popover-CzeHjvrB.js → Popover-DsbI2HKu.js} +2 -2
- package/dist/{Popover-CzeHjvrB.js.map → Popover-DsbI2HKu.js.map} +1 -1
- package/dist/{RadioGroup-sIveSsNa.js → RadioGroup-BMxuZEbT.js} +3 -3
- package/dist/{RadioGroup-sIveSsNa.js.map → RadioGroup-BMxuZEbT.js.map} +1 -1
- package/dist/{Search-3UiqNZRj.js → Search-DFeECt5D.js} +2 -2
- package/dist/{Search-3UiqNZRj.js.map → Search-DFeECt5D.js.map} +1 -1
- package/dist/{SearchInput-C7dF_Ir-.js → SearchInput-CCpdUego.js} +3 -3
- package/dist/{SearchInput-C7dF_Ir-.js.map → SearchInput-CCpdUego.js.map} +1 -1
- package/dist/{SectionNav-8NoTOKO8.js → SectionNav-Bw_MVL0_.js} +4 -4
- package/dist/{SectionNav-8NoTOKO8.js.map → SectionNav-Bw_MVL0_.js.map} +1 -1
- package/dist/{Select-Is0VkePH.js → Select-D6IZVvwL.js} +5 -5
- package/dist/Select-D6IZVvwL.js.map +1 -0
- package/dist/{Sheet-Dw9BDvjI.js → Sheet-BIzs2K2H.js} +3 -3
- package/dist/{Sheet-Dw9BDvjI.js.map → Sheet-BIzs2K2H.js.map} +1 -1
- package/dist/{Sidebar-Dcb4rinA.js → Sidebar-r1TW4g_b.js} +5 -5
- package/dist/{Sidebar-Dcb4rinA.js.map → Sidebar-r1TW4g_b.js.map} +1 -1
- package/dist/{Slider-BOPfMOMm.js → Slider-CjxyfEty.js} +3 -3
- package/dist/{Slider-BOPfMOMm.js.map → Slider-CjxyfEty.js.map} +1 -1
- package/dist/{Switch-CX2A0v50.js → Switch-BueTV03C.js} +2 -2
- package/dist/{Switch-CX2A0v50.js.map → Switch-BueTV03C.js.map} +1 -1
- package/dist/{Tabs-UMQuDoW8.js → Tabs-l72-WuhK.js} +2 -2
- package/dist/{Tabs-UMQuDoW8.js.map → Tabs-l72-WuhK.js.map} +1 -1
- package/dist/{TextInput-CMuN1WfY.js → TextInput-DhdRk8qm.js} +3 -3
- package/dist/{TextInput-CMuN1WfY.js.map → TextInput-DhdRk8qm.js.map} +1 -1
- package/dist/{ThemeProvider-QncUrfJn.js → ThemeProvider-DZfGdf1v.js} +5 -4
- package/dist/{ThemeProvider-QncUrfJn.js.map → ThemeProvider-DZfGdf1v.js.map} +1 -1
- package/dist/{TimePicker-D9zktB8A.js → TimePicker-B6d2rAbX.js} +2 -2
- package/dist/{TimePicker-D9zktB8A.js.map → TimePicker-B6d2rAbX.js.map} +1 -1
- package/dist/{Toast-DQSbs3oA.js → Toast-CxXUulYN.js} +2 -2
- package/dist/{Toast-DQSbs3oA.js.map → Toast-CxXUulYN.js.map} +1 -1
- package/dist/{ZoomableSvg-CZEu6sAq.js → ZoomableSvg-CNIzRHKH.js} +4 -4
- package/dist/{ZoomableSvg-CZEu6sAq.js.map → ZoomableSvg-CNIzRHKH.js.map} +1 -1
- package/dist/{context-KxxeMHbR.js → context-BrNtMc1H.js} +3 -33
- package/dist/context-BrNtMc1H.js.map +1 -0
- package/dist/defaults-CTfvj2KB.js +34 -0
- package/dist/defaults-CTfvj2KB.js.map +1 -0
- package/dist/editors.d.ts +12 -2
- package/dist/editors.js +20 -12
- package/dist/editors.js.map +1 -1
- package/dist/flint.d.ts +15 -0
- package/dist/flint.js +212 -0
- package/dist/flint.js.map +1 -0
- package/dist/index.d.ts +49 -7
- package/dist/index.js +57 -55
- package/dist/internal/blocks/AIKit.js +1 -1
- package/dist/internal/blocks/AppShell.js +2 -2
- package/dist/internal/blocks/BrandEditor.js +1 -1
- package/dist/internal/blocks/ChartPanel.js +1 -1
- package/dist/internal/blocks/ClipboardButton.js +1 -1
- package/dist/internal/blocks/ColorInput.js +1 -1
- package/dist/internal/blocks/ColorModeSwitch.js +1 -1
- package/dist/internal/blocks/Command.js +1 -1
- package/dist/internal/blocks/CopyField.js +1 -1
- package/dist/internal/blocks/DateInput.js +1 -1
- package/dist/internal/blocks/DateRangeInput.js +1 -1
- package/dist/{DiagramSkeleton-lwBS2YBa.js → internal/blocks/DiagramShared/DiagramSkeleton.js} +3 -3
- package/dist/internal/blocks/DiagramShared/DiagramSkeleton.js.map +1 -0
- package/dist/internal/blocks/EmptyConfigurationActionCard.js +1 -1
- package/dist/internal/blocks/ErrorState.js +1 -1
- package/dist/internal/blocks/ExportMenu.js +3 -3
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
- package/dist/internal/blocks/Form.js +1 -1
- package/dist/internal/blocks/FormGroup.js +1 -1
- package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
- package/dist/internal/blocks/MultiCombobox.js +4 -3
- package/dist/internal/blocks/MultiCombobox.js.map +1 -1
- package/dist/internal/blocks/NumberInput.js +1 -1
- package/dist/internal/blocks/PageToolbar.js +1 -1
- package/dist/internal/blocks/PasswordInput.js +2 -2
- package/dist/internal/blocks/SearchInput.js +1 -1
- package/dist/internal/blocks/SearchInputWithNavigation.js +3 -3
- package/dist/internal/blocks/SectionNav.js +1 -1
- package/dist/internal/blocks/SplitButton.js +2 -2
- package/dist/internal/blocks/StatCard.js +1 -1
- package/dist/internal/blocks/TextInput.js +1 -1
- package/dist/internal/blocks/Textarea.js +1 -1
- package/dist/internal/blocks/TimeInput.js +3 -3
- package/dist/internal/components/Alert.js +1 -1
- package/dist/internal/components/AlertModal.js +1 -1
- package/dist/internal/components/Avatar.js +1 -1
- package/dist/internal/components/BrandLogo.js +1 -1
- package/dist/internal/components/Breadcrumb.js +1 -1
- package/dist/internal/components/Button.js +1 -1
- package/dist/internal/components/Card.js +1 -1
- package/dist/internal/components/Checkbox.js +1 -1
- package/dist/internal/components/Clipboard.js +1 -1
- package/dist/internal/components/CollapsiblePanel.js +1 -1
- package/dist/internal/components/Combobox.js +1 -1
- package/dist/internal/components/DatePicker.js +1 -1
- package/dist/internal/components/DateRangePicker.js +1 -1
- package/dist/internal/components/DropdownMenu.js +1 -1
- package/dist/internal/components/FileUpload.js +1 -1
- package/dist/internal/components/FullScreenModal.js +1 -1
- package/dist/internal/components/HoverCard.js +1 -1
- package/dist/internal/components/InputGroup.js +1 -1
- package/dist/internal/components/Kbd.js +1 -1
- package/dist/internal/components/Modal.js +1 -1
- package/dist/internal/components/Navbar.js +1 -1
- package/dist/internal/components/Pagination.js +1 -1
- package/dist/internal/components/Popconfirm.js +1 -1
- package/dist/internal/components/Popover.js +1 -1
- package/dist/internal/components/RadioGroup.js +1 -1
- package/dist/internal/components/Search.js +1 -1
- package/dist/internal/components/Select.js +1 -1
- package/dist/internal/components/Sheet.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/Switch.js +1 -1
- package/dist/internal/components/Tabs.js +1 -1
- package/dist/internal/components/ThemeProvider.js +3 -2
- package/dist/internal/components/TimePicker.js +1 -1
- package/dist/internal/components/Toast.js +2 -2
- package/dist/internal/components/Tooltip.js +1 -1
- package/dist/internal/components/Truncated.js +16 -8
- package/dist/internal/components/Truncated.js.map +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/utils.js +1 -1
- package/dist/markdown-editor.js +7 -7
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.js +11 -11
- package/dist/{styles-DSUP_-9Z.js → styles-BAFscjSV.js} +4 -3
- package/dist/styles-BAFscjSV.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/svgTransforms-C9njt92h.js +89 -0
- package/dist/svgTransforms-C9njt92h.js.map +1 -0
- package/dist/testing.js +3 -2
- package/dist/testing.js.map +1 -1
- package/dist/{themeTokens-BNg98Mu9.js → themeTokens-7T1AFLhq.js} +13 -6
- package/dist/{themeTokens-BNg98Mu9.js.map → themeTokens-7T1AFLhq.js.map} +1 -1
- package/dist/{toast-CjkURw0M.js → toast-BweSoKn3.js} +3 -3
- package/dist/toast-BweSoKn3.js.map +1 -0
- package/dist/types-BPcAjMG0.d.ts +10 -0
- package/dist/{useColorSchemeState-CYqcUfSH.js → useColorSchemeState-BJEk6esG.js} +2 -2
- package/dist/{useColorSchemeState-CYqcUfSH.js.map → useColorSchemeState-BJEk6esG.js.map} +1 -1
- package/dist/{utils-D0c5VAyF.js → utils-B-g7d_Jb.js} +2 -2
- package/dist/{utils-D0c5VAyF.js.map → utils-B-g7d_Jb.js.map} +1 -1
- package/dist/vega.d.ts +46 -0
- package/dist/vega.js +26 -0
- package/dist/vega.js.map +1 -0
- package/dist/vegaTheme-FBXgAdHK.js +146 -0
- package/dist/vegaTheme-FBXgAdHK.js.map +1 -0
- package/package.json +26 -7
- package/src/styles.css +27 -4
- package/dist/AIKit-DiS0CVOW.js.map +0 -1
- package/dist/AppShell-B5GQN6Zs.js.map +0 -1
- package/dist/CodeEditor-DyaN-Ij2.js.map +0 -1
- package/dist/Combobox-Dgm6Z4ib.js.map +0 -1
- package/dist/DiagramSkeleton-lwBS2YBa.js.map +0 -1
- package/dist/MermaidDiagram-ChL3WIQT.js.map +0 -1
- package/dist/Select-Is0VkePH.js.map +0 -1
- package/dist/context-KxxeMHbR.js.map +0 -1
- package/dist/styles-DSUP_-9Z.js.map +0 -1
- package/dist/toast-CjkURw0M.js.map +0 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/blocks/DiagramShared/DiagramSource.tsx
|
|
4
|
+
const DiagramSource = ({ code }) => /* @__PURE__ */ jsx("pre", {
|
|
5
|
+
className: cn("tw:my-3 tw:overflow-auto tw:whitespace-pre-wrap tw:break-all", "tw:py-3 tw:px-4", "tw:bg-muted", "tw:rounded-md tw:text-muted-foreground", "tw:text-sm tw:font-mono"),
|
|
6
|
+
children: /* @__PURE__ */ jsx("code", { children: code })
|
|
7
|
+
});
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/blocks/DiagramShared/svgTransforms.ts
|
|
10
|
+
const HTML_TAG = /<[^>]+>/g;
|
|
11
|
+
const FOREIGN_OBJECT = /(<foreignObject\b[^>]*>)([\s\S]*?)(<\/foreignObject>)/g;
|
|
12
|
+
const ROOT_SVG_TAG = /^(\s*<svg\b)([^>]*)(>)/i;
|
|
13
|
+
/**
|
|
14
|
+
* Mermaid renders node labels — including icon-shape (`@{ icon: … }`) labels — as
|
|
15
|
+
* HTML (`<div><span><p>…</p></span></div>`) inside an SVG `<foreignObject>`. The
|
|
16
|
+
* ZoomableSvg DOMPurify pass runs the SVG namespace profile, which strips every
|
|
17
|
+
* XHTML-namespaced element under an `<svg>` root, so those wrapped labels vanish
|
|
18
|
+
* (icon rendered, text gone). DOMPurify keeps *bare text* directly inside a
|
|
19
|
+
* `<foreignObject>`, so collapse each label's HTML to its text content. Mermaid
|
|
20
|
+
* has already sanitized that text under `securityLevel: 'strict'`, and dropping
|
|
21
|
+
* the wrapper tags is strictly safer than keeping them.
|
|
22
|
+
*
|
|
23
|
+
* Entities are left encoded (`&`, `<`, …): as text-node content inside the
|
|
24
|
+
* `<foreignObject>` the browser renders them correctly, and decoding them here
|
|
25
|
+
* would risk turning `<`/`>` back into real angle brackets that could form
|
|
26
|
+
* markup in the sanitized SVG.
|
|
27
|
+
*/
|
|
28
|
+
const flattenForeignObjectLabels = (svg) => svg.replace(FOREIGN_OBJECT, (_match, open, inner, close) => {
|
|
29
|
+
return `${open}${inner.replace(HTML_TAG, " ").replace(/\s+/g, " ").trim()}${close}`;
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Make the diagram fluid: strip the root `<svg>`'s fixed width/height/style and
|
|
33
|
+
* set `width="100%"` plus a `max-width` from the viewBox width so it never
|
|
34
|
+
* overflows its container.
|
|
35
|
+
*
|
|
36
|
+
* Only the ROOT `<svg>` tag is rewritten (anchored to string start). Icon-shape
|
|
37
|
+
* nodes embed their own inner `<svg>` icons with fixed width/height; an earlier
|
|
38
|
+
* unanchored regex matched the first `<svg …height…>` anywhere, so when the root
|
|
39
|
+
* tag carried no height (mermaid emits `width="100%"` alone) it stripped the
|
|
40
|
+
* FIRST icon's height instead — detaching and mis-sizing that icon.
|
|
41
|
+
*
|
|
42
|
+
* The existing `style` attribute is preserved (only an existing `max-width` is
|
|
43
|
+
* replaced): beautiful-mermaid carries theme CSS vars (`--bg`, `--fg`) there that
|
|
44
|
+
* its inner `<style>` block derives node/text colors from — dropping the whole
|
|
45
|
+
* attribute made every derived color resolve to black.
|
|
46
|
+
*/
|
|
47
|
+
const STYLE_ATTR = /\s+style="([^"]*)"/i;
|
|
48
|
+
const makeResponsive = (svgString) => {
|
|
49
|
+
const viewBoxMatch = svgString.match(/viewBox="[^"]*\s([\d.]+)\s[\d.]+"/);
|
|
50
|
+
const vbWidth = viewBoxMatch ? Math.round(Number(viewBoxMatch[1])) : void 0;
|
|
51
|
+
return svgString.replace(ROOT_SVG_TAG, (_match, open, attrs, close) => {
|
|
52
|
+
const styleDecls = (attrs.match(STYLE_ATTR)?.[1] ?? "").replace(/max-width:\s*[^;"]*;?\s*/gi, "").replace(/\s+/g, " ").trim().replace(/;$/, "");
|
|
53
|
+
let nextAttrs = attrs.replace(/\s+width="[^"]*"/i, "").replace(/\s+height="[^"]*"/i, "").replace(STYLE_ATTR, "");
|
|
54
|
+
nextAttrs += " width=\"100%\"";
|
|
55
|
+
const styleParts = [styleDecls, vbWidth ? `max-width: ${vbWidth}px` : ""].filter(Boolean).join("; ");
|
|
56
|
+
if (styleParts) nextAttrs += ` style="${styleParts}"`;
|
|
57
|
+
return `${open}${nextAttrs}${close}`;
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Whether an SVG has drawn content, i.e. a non-degenerate viewBox.
|
|
62
|
+
*
|
|
63
|
+
* - beautiful-mermaid does not throw on every syntax it cannot lay out: an
|
|
64
|
+
* `erDiagram` entity whose quoted name contains a space (`"sample (Copy)"`)
|
|
65
|
+
* returns a well-formed SVG with `viewBox="0 0 0 0"` and an empty `<defs>`.
|
|
66
|
+
* - Such output is truthy, so it would be cached and rendered as an empty box,
|
|
67
|
+
* and the async mermaid renderer — which parses the same code fine — would
|
|
68
|
+
* never run.
|
|
69
|
+
* - A missing viewBox counts as drawn: mermaid's own output is sized via
|
|
70
|
+
* width/height attributes on some diagram types.
|
|
71
|
+
* - Only the ROOT `<svg>` is inspected. Icon-shape nodes embed their own inner
|
|
72
|
+
* `<svg>` / `<symbol>`, so an unanchored search reads a nested viewBox when the
|
|
73
|
+
* root carries none — discarding a diagram that had in fact been drawn. Same
|
|
74
|
+
* trap `makeResponsive` documents above.
|
|
75
|
+
* - Either quote style is accepted, and whitespace around the `=`. Both current
|
|
76
|
+
* renderers emit `viewBox="…"` exactly, so this is future-proofing rather than a
|
|
77
|
+
* live case: a miss reads as "no viewBox", i.e. drawn, silently restoring the
|
|
78
|
+
* empty-diagram bug.
|
|
79
|
+
*/
|
|
80
|
+
const ROOT_VIEWBOX = /^\s*<svg\b[^>]*\sviewBox\s*=\s*(["'])\s*[\d.eE+-]+\s+[\d.eE+-]+\s+([\d.eE+-]+)\s+([\d.eE+-]+)\s*\1/i;
|
|
81
|
+
const hasDrawnContent = (svg) => {
|
|
82
|
+
const viewBox = svg.match(ROOT_VIEWBOX);
|
|
83
|
+
if (!viewBox) return true;
|
|
84
|
+
return Number(viewBox[2]) > 0 && Number(viewBox[3]) > 0;
|
|
85
|
+
};
|
|
86
|
+
//#endregion
|
|
87
|
+
export { DiagramSource, flattenForeignObjectLabels, hasDrawnContent, makeResponsive };
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=svgTransforms-C9njt92h.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svgTransforms-C9njt92h.js","names":[],"sources":["../src/blocks/DiagramShared/DiagramSource.tsx","../src/blocks/DiagramShared/svgTransforms.ts"],"sourcesContent":["import { cn } from '../../utils';\n\n// The raw source of a diagram/chart fence, shown muted when rendering failed —\n// the shared failure fallback of MermaidDiagram and FlintChart.\nexport const DiagramSource = ({ code }: { code: string }) => (\n <pre\n className={cn(\n 'tw:my-3 tw:overflow-auto tw:whitespace-pre-wrap tw:break-all',\n 'tw:py-3 tw:px-4',\n 'tw:bg-muted',\n 'tw:rounded-md tw:text-muted-foreground',\n 'tw:text-sm tw:font-mono',\n )}\n >\n <code>{code}</code>\n </pre>\n);\n","// Pure post-processing of diagram SVG output (mermaid, vega), before it reaches\n// ZoomableSvg's DOMPurify pass. Extracted for unit testing.\n\nconst HTML_TAG = /<[^>]+>/g;\nconst FOREIGN_OBJECT = /(<foreignObject\\b[^>]*>)([\\s\\S]*?)(<\\/foreignObject>)/g;\n// The root <svg> open tag, anchored to the start of the string.\nconst ROOT_SVG_TAG = /^(\\s*<svg\\b)([^>]*)(>)/i;\n\n/**\n * Mermaid renders node labels — including icon-shape (`@{ icon: … }`) labels — as\n * HTML (`<div><span><p>…</p></span></div>`) inside an SVG `<foreignObject>`. The\n * ZoomableSvg DOMPurify pass runs the SVG namespace profile, which strips every\n * XHTML-namespaced element under an `<svg>` root, so those wrapped labels vanish\n * (icon rendered, text gone). DOMPurify keeps *bare text* directly inside a\n * `<foreignObject>`, so collapse each label's HTML to its text content. Mermaid\n * has already sanitized that text under `securityLevel: 'strict'`, and dropping\n * the wrapper tags is strictly safer than keeping them.\n *\n * Entities are left encoded (`&`, `<`, …): as text-node content inside the\n * `<foreignObject>` the browser renders them correctly, and decoding them here\n * would risk turning `<`/`>` back into real angle brackets that could form\n * markup in the sanitized SVG.\n */\nexport const flattenForeignObjectLabels = (svg: string): string =>\n svg.replace(FOREIGN_OBJECT, (_match, open: string, inner: string, close: string) => {\n const text = inner.replace(HTML_TAG, ' ').replace(/\\s+/g, ' ').trim();\n return `${open}${text}${close}`;\n });\n\n/**\n * Make the diagram fluid: strip the root `<svg>`'s fixed width/height/style and\n * set `width=\"100%\"` plus a `max-width` from the viewBox width so it never\n * overflows its container.\n *\n * Only the ROOT `<svg>` tag is rewritten (anchored to string start). Icon-shape\n * nodes embed their own inner `<svg>` icons with fixed width/height; an earlier\n * unanchored regex matched the first `<svg …height…>` anywhere, so when the root\n * tag carried no height (mermaid emits `width=\"100%\"` alone) it stripped the\n * FIRST icon's height instead — detaching and mis-sizing that icon.\n *\n * The existing `style` attribute is preserved (only an existing `max-width` is\n * replaced): beautiful-mermaid carries theme CSS vars (`--bg`, `--fg`) there that\n * its inner `<style>` block derives node/text colors from — dropping the whole\n * attribute made every derived color resolve to black.\n */\nconst STYLE_ATTR = /\\s+style=\"([^\"]*)\"/i;\n\nexport const makeResponsive = (svgString: string): string => {\n const viewBoxMatch = svgString.match(/viewBox=\"[^\"]*\\s([\\d.]+)\\s[\\d.]+\"/);\n const vbWidth = viewBoxMatch ? Math.round(Number(viewBoxMatch[1])) : undefined;\n\n return svgString.replace(ROOT_SVG_TAG, (_match, open: string, attrs: string, close: string) => {\n const existingStyle = attrs.match(STYLE_ATTR)?.[1] ?? '';\n const styleDecls = existingStyle\n .replace(/max-width:\\s*[^;\"]*;?\\s*/gi, '')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/;$/, '');\n\n let nextAttrs = attrs\n .replace(/\\s+width=\"[^\"]*\"/i, '')\n .replace(/\\s+height=\"[^\"]*\"/i, '')\n .replace(STYLE_ATTR, '');\n\n nextAttrs += ' width=\"100%\"';\n\n const styleParts = [styleDecls, vbWidth ? `max-width: ${vbWidth}px` : '']\n .filter(Boolean)\n .join('; ');\n if (styleParts) nextAttrs += ` style=\"${styleParts}\"`;\n\n return `${open}${nextAttrs}${close}`;\n });\n};\n\n/**\n * Whether an SVG has drawn content, i.e. a non-degenerate viewBox.\n *\n * - beautiful-mermaid does not throw on every syntax it cannot lay out: an\n * `erDiagram` entity whose quoted name contains a space (`\"sample (Copy)\"`)\n * returns a well-formed SVG with `viewBox=\"0 0 0 0\"` and an empty `<defs>`.\n * - Such output is truthy, so it would be cached and rendered as an empty box,\n * and the async mermaid renderer — which parses the same code fine — would\n * never run.\n * - A missing viewBox counts as drawn: mermaid's own output is sized via\n * width/height attributes on some diagram types.\n * - Only the ROOT `<svg>` is inspected. Icon-shape nodes embed their own inner\n * `<svg>` / `<symbol>`, so an unanchored search reads a nested viewBox when the\n * root carries none — discarding a diagram that had in fact been drawn. Same\n * trap `makeResponsive` documents above.\n * - Either quote style is accepted, and whitespace around the `=`. Both current\n * renderers emit `viewBox=\"…\"` exactly, so this is future-proofing rather than a\n * live case: a miss reads as \"no viewBox\", i.e. drawn, silently restoring the\n * empty-diagram bug.\n */\nconst ROOT_VIEWBOX =\n /^\\s*<svg\\b[^>]*\\sviewBox\\s*=\\s*([\"'])\\s*[\\d.eE+-]+\\s+[\\d.eE+-]+\\s+([\\d.eE+-]+)\\s+([\\d.eE+-]+)\\s*\\1/i;\n\nexport const hasDrawnContent = (svg: string): boolean => {\n const viewBox = svg.match(ROOT_VIEWBOX);\n if (!viewBox) return true;\n return Number(viewBox[2]) > 0 && Number(viewBox[3]) > 0;\n};\n"],"mappings":";;;AAIA,MAAa,iBAAiB,EAAE,WAC9B,oBAAC,OAAD;CACE,WAAW,GACT,gEACA,mBACA,eACA,0CACA,yBACF;CAEA,UAAA,oBAAC,QAAD,EAAA,UAAO,KAAW,CAAA;AACf,CAAA;;;ACZP,MAAM,WAAW;AACjB,MAAM,iBAAiB;AAEvB,MAAM,eAAe;;;;;;;;;;;;;;;;AAiBrB,MAAa,8BAA8B,QACzC,IAAI,QAAQ,iBAAiB,QAAQ,MAAc,OAAe,UAAkB;CAElF,OAAO,GAAG,OADG,MAAM,QAAQ,UAAU,GAAG,CAAC,CAAC,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAC3C,IAAI;AAC1B,CAAC;;;;;;;;;;;;;;;;;AAkBH,MAAM,aAAa;AAEnB,MAAa,kBAAkB,cAA8B;CAC3D,MAAM,eAAe,UAAU,MAAM,mCAAmC;CACxE,MAAM,UAAU,eAAe,KAAK,MAAM,OAAO,aAAa,EAAE,CAAC,IAAI,KAAA;CAErE,OAAO,UAAU,QAAQ,eAAe,QAAQ,MAAc,OAAe,UAAkB;EAE7F,MAAM,cADgB,MAAM,MAAM,UAAU,CAAC,GAAG,MAAM,GAAA,CAEnD,QAAQ,8BAA8B,EAAE,CAAC,CACzC,QAAQ,QAAQ,GAAG,CAAC,CACpB,KAAK,CAAC,CACN,QAAQ,MAAM,EAAE;EAEnB,IAAI,YAAY,MACb,QAAQ,qBAAqB,EAAE,CAAC,CAChC,QAAQ,sBAAsB,EAAE,CAAC,CACjC,QAAQ,YAAY,EAAE;EAEzB,aAAa;EAEb,MAAM,aAAa,CAAC,YAAY,UAAU,cAAc,QAAQ,MAAM,EAAE,CAAC,CACtE,OAAO,OAAO,CAAC,CACf,KAAK,IAAI;EACZ,IAAI,YAAY,aAAa,WAAW,WAAW;EAEnD,OAAO,GAAG,OAAO,YAAY;CAC/B,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAM,eACJ;AAEF,MAAa,mBAAmB,QAAyB;CACvD,MAAM,UAAU,IAAI,MAAM,YAAY;CACtC,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO,OAAO,QAAQ,EAAE,IAAI,KAAK,OAAO,QAAQ,EAAE,IAAI;AACxD"}
|
package/dist/testing.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { keboolaLegacyIds } from "./defaults-CTfvj2KB.js";
|
|
2
|
+
import { ArgoDesignContext } from "./context-BrNtMc1H.js";
|
|
3
|
+
import { ThemeProvider } from "./ThemeProvider-DZfGdf1v.js";
|
|
3
4
|
import { keboola } from "@keboola/brand-registry";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
5
6
|
import { render } from "@testing-library/react";
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","names":[],"sources":["../src/testing/renderWithTheme.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { render, type RenderOptions, type RenderResult } from '@testing-library/react';\n\nimport { type Brand, keboola } from '@keboola/brand-registry';\n\nimport { ArgoDesignContext, ThemeProvider } from '../components/ThemeProvider';\nimport { keboolaLegacyIds } from '../components/ThemeProvider/defaults';\n\ntype Options = Omit<RenderOptions, 'wrapper'> & {\n /** Brand to drive the wrapping `<ThemeProvider>`. Defaults to `keboola`. */\n brand?: Brand;\n};\n\n/**\n * `@testing-library/react` `render` wrapped in a `<ThemeProvider brand={...}>`.\n *\n * Use in unit tests for any component that calls `useTheme()` or relies on\n * the brand-driven CSS variables. Defaults to the canonical Keboola brand so\n * callers can opt into a specific brand only when they need to assert\n * brand-dependent behaviour (e.g. chrome re-skins under `keboola-legacy`).\n *\n * `ThemeProvider` no longer drives the argo/legacy design language (that is\n * kbc-ui-specific), so this helper also provides `ArgoDesignContext` derived\n * from the brand — a legacy brand renders legacy chrome, any other renders\n * argo — matching how kbc-ui wires it, so brand-dependent chrome tests keep\n * working through a single `brand` option.\n */\nexport const renderWithTheme = (ui: ReactElement, options: Options = {}): RenderResult => {\n const { brand = keboola, ...rest } = options;\n const isArgo = !keboolaLegacyIds.includes(brand.id);\n return render(ui, {\n ...rest,\n wrapper: ({ children }) => (\n <ThemeProvider brands={[brand]} brandId={brand.id}>\n <ArgoDesignContext value={isArgo}>{children}</ArgoDesignContext>\n </ThemeProvider>\n ),\n });\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"testing.js","names":[],"sources":["../src/testing/renderWithTheme.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { render, type RenderOptions, type RenderResult } from '@testing-library/react';\n\nimport { type Brand, keboola } from '@keboola/brand-registry';\n\nimport { ArgoDesignContext, ThemeProvider } from '../components/ThemeProvider';\nimport { keboolaLegacyIds } from '../components/ThemeProvider/defaults';\n\ntype Options = Omit<RenderOptions, 'wrapper'> & {\n /** Brand to drive the wrapping `<ThemeProvider>`. Defaults to `keboola`. */\n brand?: Brand;\n};\n\n/**\n * `@testing-library/react` `render` wrapped in a `<ThemeProvider brand={...}>`.\n *\n * Use in unit tests for any component that calls `useTheme()` or relies on\n * the brand-driven CSS variables. Defaults to the canonical Keboola brand so\n * callers can opt into a specific brand only when they need to assert\n * brand-dependent behaviour (e.g. chrome re-skins under `keboola-legacy`).\n *\n * `ThemeProvider` no longer drives the argo/legacy design language (that is\n * kbc-ui-specific), so this helper also provides `ArgoDesignContext` derived\n * from the brand — a legacy brand renders legacy chrome, any other renders\n * argo — matching how kbc-ui wires it, so brand-dependent chrome tests keep\n * working through a single `brand` option.\n */\nexport const renderWithTheme = (ui: ReactElement, options: Options = {}): RenderResult => {\n const { brand = keboola, ...rest } = options;\n const isArgo = !keboolaLegacyIds.includes(brand.id);\n return render(ui, {\n ...rest,\n wrapper: ({ children }) => (\n <ThemeProvider brands={[brand]} brandId={brand.id}>\n <ArgoDesignContext value={isArgo}>{children}</ArgoDesignContext>\n </ThemeProvider>\n ),\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2BA,MAAa,mBAAmB,IAAkB,UAAmB,CAAC,MAAoB;CACxF,MAAM,EAAE,QAAQ,SAAS,GAAG,SAAS;CACrC,MAAM,SAAS,CAAC,iBAAiB,SAAS,MAAM,EAAE;CAClD,OAAO,OAAO,IAAI;EAChB,GAAG;EACH,UAAU,EAAE,eACV,oBAAC,eAAD;GAAe,QAAQ,CAAC,KAAK;GAAG,SAAS,MAAM;GAC7C,UAAA,oBAAC,mBAAD;IAAmB,OAAO;IAAS;GAA4B,CAAA;EAClD,CAAA;CAEnB,CAAC;AACH"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_BRAND_ID, DEFAULT_COLOR_SCHEME } from "./
|
|
2
|
-
import { BRAND_ATTRIBUTE, THEME_ATTRIBUTE } from "./useColorSchemeState-
|
|
1
|
+
import { DEFAULT_BRAND_ID, DEFAULT_COLOR_SCHEME } from "./defaults-CTfvj2KB.js";
|
|
2
|
+
import { BRAND_ATTRIBUTE, THEME_ATTRIBUTE } from "./useColorSchemeState-BJEk6esG.js";
|
|
3
3
|
import { useSyncExternalStore } from "react";
|
|
4
4
|
//#region src/components/ThemeProvider/useThemeAttributes.ts
|
|
5
5
|
const DEFAULT_ATTRIBUTES = {
|
|
@@ -74,12 +74,19 @@ const resolveToken = (token, fallbackChannels, alpha) => {
|
|
|
74
74
|
*
|
|
75
75
|
* Snapshot per palette build, never module-level — the values change whenever the
|
|
76
76
|
* scheme or brand does, and a cached resolver would keep serving the old ones.
|
|
77
|
+
*
|
|
78
|
+
* {@link createChannelResolver} is the same snapshot answering the raw `"R G B"`
|
|
79
|
+
* channels, for a consumer that needs another serialization.
|
|
77
80
|
*/
|
|
78
|
-
const
|
|
81
|
+
const createChannelResolver = () => {
|
|
79
82
|
const computed = typeof document === "undefined" ? null : getComputedStyle(document.documentElement);
|
|
80
|
-
return (token, fallbackChannels
|
|
83
|
+
return (token, fallbackChannels) => computed?.getPropertyValue(`--${token}`).trim() || fallbackChannels;
|
|
84
|
+
};
|
|
85
|
+
const createTokenResolver = () => {
|
|
86
|
+
const resolve = createChannelResolver();
|
|
87
|
+
return (token, fallbackChannels, alpha) => format(resolve(token, fallbackChannels), alpha);
|
|
81
88
|
};
|
|
82
89
|
//#endregion
|
|
83
|
-
export { createTokenResolver, resolveToken, useThemeAttributes };
|
|
90
|
+
export { createChannelResolver, createTokenResolver, resolveToken, useThemeAttributes };
|
|
84
91
|
|
|
85
|
-
//# sourceMappingURL=themeTokens-
|
|
92
|
+
//# sourceMappingURL=themeTokens-7T1AFLhq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themeTokens-
|
|
1
|
+
{"version":3,"file":"themeTokens-7T1AFLhq.js","names":[],"sources":["../src/components/ThemeProvider/useThemeAttributes.ts","../src/utils/themeTokens.ts"],"sourcesContent":["import { useSyncExternalStore } from 'react';\n\nimport { DEFAULT_BRAND_ID, DEFAULT_COLOR_SCHEME } from './defaults';\nimport type { BrandId, ResolvedColorScheme } from './types';\nimport { BRAND_ATTRIBUTE } from './useBrandState';\nimport { THEME_ATTRIBUTE } from './useColorSchemeState';\n\nexport type ThemeAttributes = {\n /** Changes whenever `scheme` or `brandId` does — the memo key for anything built from live `--*` values. */\n cacheKey: string;\n scheme: ResolvedColorScheme;\n brandId: BrandId;\n};\n\n// No attribute set means the stylesheet's own `:root` block is painting, which is\n// the default scheme — not a third \"unknown\" state. Same value on the server, so\n// the SSR snapshot and the client's first render agree.\nconst DEFAULT_ATTRIBUTES: ThemeAttributes = {\n cacheKey: `${DEFAULT_COLOR_SCHEME}:${DEFAULT_BRAND_ID}`,\n scheme: DEFAULT_COLOR_SCHEME,\n brandId: DEFAULT_BRAND_ID,\n};\n\n// `useSyncExternalStore` re-renders forever on a snapshot whose reference changes\n// on every read, so the object is rebuilt only when the key it stands for moves.\nlet snapshot = DEFAULT_ATTRIBUTES;\n\nconst readThemeAttributes = (): ThemeAttributes => {\n if (typeof document === 'undefined') return DEFAULT_ATTRIBUTES;\n\n const root = document.documentElement;\n const theme = root.getAttribute(THEME_ATTRIBUTE);\n const scheme: ResolvedColorScheme =\n theme === 'dark' || theme === 'light' ? theme : DEFAULT_COLOR_SCHEME;\n const brandId = root.getAttribute(BRAND_ATTRIBUTE) ?? DEFAULT_BRAND_ID;\n const cacheKey = `${scheme}:${brandId}`;\n\n if (cacheKey !== snapshot.cacheKey) snapshot = { cacheKey, scheme, brandId };\n\n return snapshot;\n};\n\nconst subscribe = (onChange: () => void): (() => void) => {\n if (typeof document === 'undefined') return () => {};\n\n const observer = new MutationObserver(onChange);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [THEME_ATTRIBUTE, BRAND_ATTRIBUTE],\n });\n\n return () => observer.disconnect();\n};\n\nconst getServerSnapshot = (): ThemeAttributes => DEFAULT_ATTRIBUTES;\n\n/**\n * The colour scheme and brand currently applied to `<html>`, plus a key that\n * changes whenever they do — for memoizing anything built from `resolveToken`.\n *\n * Read from the DOM rather than `useTheme()` on purpose: `ThemeProvider` writes\n * both attributes from passive effects, so during the render after a scheme\n * change the context already says `dark` while `<html>` — and therefore every\n * computed `--*` value — is still light. Keying off the attributes keeps the\n * values and the key that stands for them in lockstep, and works in a subtree\n * with no `ThemeProvider` above it.\n *\n * Returning `scheme` from the same read is what makes that safe by construction:\n * a caller cannot pick up the new key and the old scheme.\n */\nexport const useThemeAttributes = (): ThemeAttributes =>\n useSyncExternalStore(subscribe, readThemeAttributes, getServerSnapshot);\n","/**\n * Live access to the semantic `--*` design tokens for consumers that cannot use\n * a Tailwind class — a CodeMirror theme object, a mermaid `themeVariables` map,\n * an SVG serialized for export. Those all need a concrete color string at build\n * time, so we resolve the value the browser currently computes for `<html>` and\n * hand the resulting `rgb(...)` to the library.\n *\n * SSR/no-document falls back to a literal; so does a token the stylesheet has\n * not defined (which is what unit tests see, since they load no CSS).\n */\nconst format = (channels: string, alpha?: number): string =>\n alpha === undefined ? `rgb(${channels})` : `rgb(${channels} / ${alpha})`;\n\nexport const resolveToken = (token: string, fallbackChannels: string, alpha?: number): string => {\n const channels =\n typeof document === 'undefined'\n ? fallbackChannels\n : getComputedStyle(document.documentElement).getPropertyValue(`--${token}`).trim() ||\n fallbackChannels;\n return format(channels, alpha);\n};\n\n/**\n * A {@link resolveToken} bound to a single `getComputedStyle` snapshot.\n *\n * Reach for this when building a whole palette at once: `resolveToken` reads the\n * computed style per call, so a config with dozens of token lookups forces dozens\n * of style resolutions for one render. Take a snapshot, read every token off it,\n * throw it away.\n *\n * Snapshot per palette build, never module-level — the values change whenever the\n * scheme or brand does, and a cached resolver would keep serving the old ones.\n *\n * {@link createChannelResolver} is the same snapshot answering the raw `\"R G B\"`\n * channels, for a consumer that needs another serialization.\n */\nexport const createChannelResolver = () => {\n const computed =\n typeof document === 'undefined' ? null : getComputedStyle(document.documentElement);\n\n return (token: string, fallbackChannels: string): string =>\n computed?.getPropertyValue(`--${token}`).trim() || fallbackChannels;\n};\n\nexport const createTokenResolver = () => {\n const resolve = createChannelResolver();\n\n return (token: string, fallbackChannels: string, alpha?: number): string =>\n format(resolve(token, fallbackChannels), alpha);\n};\n"],"mappings":";;;;AAiBA,MAAM,qBAAsC;CAC1C,UAAU,GAAG,qBAAqB,GAAG;CACrC,QAAQ;CACR,SAAS;AACX;AAIA,IAAI,WAAW;AAEf,MAAM,4BAA6C;CACjD,IAAI,OAAO,aAAa,aAAa,OAAO;CAE5C,MAAM,OAAO,SAAS;CACtB,MAAM,QAAQ,KAAK,aAAa,eAAe;CAC/C,MAAM,SACJ,UAAU,UAAU,UAAU,UAAU,QAAQ;CAClD,MAAM,UAAU,KAAK,aAAA,YAA4B,KAAA;CACjD,MAAM,WAAW,GAAG,OAAO,GAAG;CAE9B,IAAI,aAAa,SAAS,UAAU,WAAW;EAAE;EAAU;EAAQ;CAAQ;CAE3E,OAAO;AACT;AAEA,MAAM,aAAa,aAAuC;CACxD,IAAI,OAAO,aAAa,aAAa,aAAa,CAAC;CAEnD,MAAM,WAAW,IAAI,iBAAiB,QAAQ;CAC9C,SAAS,QAAQ,SAAS,iBAAiB;EACzC,YAAY;EACZ,iBAAiB,CAAC,iBAAiB,eAAe;CACpD,CAAC;CAED,aAAa,SAAS,WAAW;AACnC;AAEA,MAAM,0BAA2C;;;;;;;;;;;;;;;AAgBjD,MAAa,2BACX,qBAAqB,WAAW,qBAAqB,iBAAiB;;;;;;;;;;;;;AC7DxE,MAAM,UAAU,UAAkB,UAChC,UAAU,KAAA,IAAY,OAAO,SAAS,KAAK,OAAO,SAAS,KAAK,MAAM;AAExE,MAAa,gBAAgB,OAAe,kBAA0B,UAA2B;CAC/F,MAAM,WACJ,OAAO,aAAa,cAChB,mBACA,iBAAiB,SAAS,eAAe,CAAC,CAAC,iBAAiB,KAAK,OAAO,CAAC,CAAC,KAAK,KAC/E;CACN,OAAO,OAAO,UAAU,KAAK;AAC/B;;;;;;;;;;;;;;;AAgBA,MAAa,8BAA8B;CACzC,MAAM,WACJ,OAAO,aAAa,cAAc,OAAO,iBAAiB,SAAS,eAAe;CAEpF,QAAQ,OAAe,qBACrB,UAAU,iBAAiB,KAAK,OAAO,CAAC,CAAC,KAAK,KAAK;AACvD;AAEA,MAAa,4BAA4B;CACvC,MAAM,UAAU,sBAAsB;CAEtC,QAAQ,OAAe,kBAA0B,UAC/C,OAAO,QAAQ,OAAO,gBAAgB,GAAG,KAAK;AAClD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { useArgoDesign } from "./context-
|
|
2
|
+
import { useArgoDesign } from "./context-BrNtMc1H.js";
|
|
3
3
|
import { AlertCircle, AlertTriangle, CircleCheck, Info, Loader2, X } from "./icons-Cek151jC.js";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -10,7 +10,7 @@ const ToastAction = ({ ref, className, ...rest }) => /* @__PURE__ */ jsx("button
|
|
|
10
10
|
ref,
|
|
11
11
|
"data-slot": "toast-action",
|
|
12
12
|
type: "button",
|
|
13
|
-
className: cn("tw:col-start-3", "tw:row-start-1", "tw:flex", "tw:items-center", "tw:justify-center", "tw:text-xs", "tw:font-medium", "tw:text-primary", "tw:px-2", "tw:h-6", "tw:bg-
|
|
13
|
+
className: cn("tw:col-start-3", "tw:row-start-1", "tw:flex", "tw:items-center", "tw:justify-center", "tw:text-xs", "tw:font-medium", "tw:text-primary", "tw:px-2", "tw:h-6", "tw:bg-white", "tw:rounded", className)
|
|
14
14
|
});
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/components/Toast/ToastDescription.tsx
|
|
@@ -181,4 +181,4 @@ toast$1.dismissAll = () => toast.dismiss();
|
|
|
181
181
|
//#endregion
|
|
182
182
|
export { toast$1 as toast };
|
|
183
183
|
|
|
184
|
-
//# sourceMappingURL=toast-
|
|
184
|
+
//# sourceMappingURL=toast-BweSoKn3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toast-BweSoKn3.js","names":["sonnerToast","toast","sonnerToast"],"sources":["../src/components/Toast/ToastAction.tsx","../src/components/Toast/ToastDescription.tsx","../src/components/Toast/ToastDismiss.tsx","../src/components/Toast/ToastDuration.tsx","../src/components/Toast/ToastTitle.tsx","../src/components/Toast/ToastRoot.tsx","../src/components/Toast/toast.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'button'>;\n\nexport const ToastAction = ({ ref, className, ...rest }: Props) => (\n <button\n {...rest}\n ref={ref}\n data-slot=\"toast-action\"\n type=\"button\"\n className={cn(\n // layout\n 'tw:col-start-3',\n 'tw:row-start-1',\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-center',\n\n // font\n 'tw:text-xs',\n 'tw:font-medium',\n 'tw:text-primary',\n\n // sizing\n 'tw:px-2',\n 'tw:h-6',\n\n // styles\n // Fixed white: this is the chip's surface, not ink on a primary fill.\n // - All four non-`default` toast variants paint a scheme-blind primitive\n // (`bg-error-550`, `bg-blue-600`, `bg-green-700`, `bg-warning-550`), so a\n // chip on them must not move with the scheme either.\n // - `default` (`bg-popover`) is scheme-aware, and the white chip is the same\n // in both schemes there. `text-primary` on it is 3.27:1 in dark — that ink\n // is a separate fix, tracked in UT-5239's follow-ups.\n 'tw:bg-white',\n 'tw:rounded',\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const ToastDescription = ({ ref, className, children, ...rest }: Props) => (\n <div\n ref={ref}\n data-slot=\"toast-description\"\n className={cn(\n 'tw:col-start-2',\n 'tw:font-normal',\n 'tw:break-words',\n 'tw:text-white',\n 'tw:group-data-[variant=default]/toast:text-muted-foreground',\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { X } from '../../icons';\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'button'>;\n\nexport const ToastDismiss = ({ ref, className, ...rest }: Props) => (\n <button\n ref={ref}\n data-slot=\"toast-dismiss\"\n className={cn(\n 'tw:flex',\n 'tw:justify-center',\n 'tw:col-start-4',\n 'tw:row-start-1',\n 'tailwindcss-preflight',\n 'tw:[&_svg]:aspect-square',\n 'tw:[&_svg:not([class*=\"tw:size-\"])]:size-4',\n 'tw:[&_svg]:m-1',\n\n 'tw:text-white',\n 'tw:group-data-[variant=default]/toast:[&_svg]:text-popover-foreground',\n 'tw:group-data-[variant=default]/toast:group-data-[argo=true]/toast:[&_svg]:text-foreground',\n className,\n )}\n type=\"button\"\n {...rest}\n >\n <X />\n <span className=\"tw:sr-only\">Dismiss</span>\n </button>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype ToastDurationProps = ComponentProps<'span'> & {\n duration: number;\n};\n\nexport const ToastDuration = ({ ref, duration, className, style, ...rest }: ToastDurationProps) => (\n <span\n {...rest}\n ref={ref}\n className={cn(\n 'tw:bg-white/30',\n 'tw:group-data-[variant=default]/toast:bg-popover-foreground/20',\n 'tw:group-data-[variant=default]/toast:group-data-[argo=true]/toast:bg-foreground/20',\n 'tw:rounded-bl-lg',\n 'tw:mx-px',\n\n // positioning\n 'tw:absolute',\n 'tw:bottom-0',\n 'tw:left-0',\n\n // sizing\n 'tw:h-1',\n\n // animation\n 'tw:animate-toast-progress',\n 'tw:group-hover/toast:[animation-play-state:paused]',\n className,\n )}\n style={{\n animationDuration: `${duration}ms`,\n ...style,\n }}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const ToastTitle = ({ ref, className, children, ...rest }: Props) => (\n <div\n ref={ref}\n data-slot=\"toast-title\"\n className={cn(\n 'tw:col-start-2',\n 'tw:text-sm',\n 'tw:leading-6',\n 'tw:min-h-6',\n 'tw:self-center',\n 'tw:text-white',\n 'tw:group-data-[variant=default]/toast:text-popover-foreground',\n 'tw:group-data-[variant=default]/toast:group-data-[argo=true]/toast:text-foreground',\n\n 'tw:break-words',\n 'tw:font-medium',\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n);\n","import type { MouseEventHandler, ReactNode } from 'react';\nimport type { VariantProps } from 'class-variance-authority';\nimport { cva } from 'class-variance-authority';\nimport { type Action, toast as sonnerToast } from 'sonner';\n\nimport { AlertCircle, AlertTriangle, CircleCheck, Info, Loader2 } from '../../icons';\nimport { cn } from '../../utils';\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nimport { ToastAction } from './ToastAction';\nimport { ToastDescription } from './ToastDescription';\nimport { ToastDismiss } from './ToastDismiss';\nimport { ToastDuration } from './ToastDuration';\nimport { ToastTitle } from './ToastTitle';\n\nconst variants = cva(\n [\n 'tailwindcss-preflight',\n 'tw:group/toast',\n 'tw:relative',\n\n // layout\n 'tw:grid',\n 'tw:grid-cols-[0_1fr_auto_auto]',\n 'tw:items-start',\n 'tw:has-[[data-slot=toast-description]]:grid-rows-[auto_auto]',\n 'tw:has-[[data-slot=toast-icon]]:grid-cols-[auto_1fr_auto_auto]',\n 'tw:[&_[data-slot=toast-icon]]:mr-2',\n 'tw:[&_[data-slot=toast-title]]:mr-2.5',\n 'tw:[&_[data-slot=toast-description]]:mr-2.5',\n 'tw:[&_[data-slot=toast-action]]:mr-2',\n 'tw:[&_[data-slot=toast-description]]:col-end-3',\n 'tw:gap-y-0',\n\n // styles\n 'tw:p-4',\n 'tw:rounded-lg',\n 'tw:shadow-md',\n ],\n {\n defaultVariants: {\n variant: 'info',\n },\n variants: {\n variant: {\n default: 'tw:border tw:border-border tw:bg-popover',\n error: 'tw:bg-error-550',\n info: 'tw:bg-blue-600',\n success: 'tw:bg-green-700',\n warning: 'tw:bg-warning-550',\n },\n },\n },\n);\n\ntype Variants = VariantProps<typeof variants>;\ntype Variant = NonNullable<Variants['variant']>;\ntype VariantIcon = Exclude<Variant, 'default'>;\n\ntype Props = {\n id: string | number;\n title: ReactNode;\n icon?: ReactNode;\n description?: ReactNode;\n action?: Action;\n loading?: boolean;\n duration?: number;\n // offset?: number;\n} & Variants;\n\nconst DEFAULT_VARIANT_ICON: Record<VariantIcon, ReactNode> = {\n error: <AlertTriangle />,\n info: <Info />,\n success: <CircleCheck />,\n warning: <AlertCircle />,\n};\n\nexport const ToastRoot = ({\n id,\n title,\n description,\n action,\n duration = Infinity,\n variant = 'info',\n loading = false,\n icon: iconProp,\n}: Props) => {\n const renderArgo = useArgoDesign();\n\n const icon: ReactNode = (() => {\n if (loading) return <Loader2 className=\"tw:animate-spin\" />;\n if (iconProp) return iconProp;\n if (variant === 'default' || variant === null) return null;\n return DEFAULT_VARIANT_ICON[variant];\n })();\n\n const handleActionClick: MouseEventHandler<HTMLButtonElement> = (event) => {\n sonnerToast.dismiss(id);\n action?.onClick(event);\n };\n\n return (\n <div\n data-variant={variant}\n data-argo={renderArgo}\n className={cn(\n variants({ variant }),\n 'tw:data-[variant=default]:data-[argo=true]:bg-background',\n )}\n >\n {icon && (\n <span\n data-slot=\"toast-icon\"\n className={cn(\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:self-center',\n 'tw:aspect-square',\n 'tw:size-5',\n 'tw:shrink-0',\n 'tw:[&_svg:not([class*=\"tw:size-\"])]:size-5',\n 'tw:text-white',\n 'tw:group-data-[variant=default]/toast:text-popover-foreground',\n 'tw:group-data-[variant=default]/toast:group-data-[argo=true]/toast:text-foreground',\n )}\n >\n {icon}\n </span>\n )}\n\n <ToastTitle>{title}</ToastTitle>\n {description && <ToastDescription>{description}</ToastDescription>}\n {action && (\n <ToastAction style={action?.actionButtonStyle} onClick={handleActionClick}>\n {action.label}\n </ToastAction>\n )}\n <ToastDismiss onClick={() => sonnerToast.dismiss(id)} />\n {duration !== Infinity && <ToastDuration duration={duration} />}\n </div>\n );\n};\n","import type { ComponentProps, ReactNode } from 'react';\nimport { type ExternalToast, toast as sonnerToast } from 'sonner';\n\nimport { cn } from '../../utils';\n\nimport { ToastRoot } from './ToastRoot';\n\ntype ToastProps = ComponentProps<typeof ToastRoot>;\ntype Title = ToastProps['title'] | ((opts: { dismiss: () => void }) => ReactNode);\n\nexport type ToastOptions = { id?: string | number; title: Title } & Omit<\n ToastProps,\n 'id' | 'title'\n> &\n Pick<\n ExternalToast,\n 'onAutoClose' | 'onDismiss' | 'testId' | 'toasterId' | 'dismissible' | 'position'\n >;\ntype DerivedToastOptions = Omit<ToastOptions, 'title' | 'variant'>;\n\nexport const toast = ({\n onAutoClose,\n onDismiss,\n testId,\n toasterId,\n dismissible = true,\n position,\n title: titleProp,\n ...toast\n}: ToastOptions) => {\n const duration = (() => {\n if (typeof toast.duration === 'number') return toast.duration;\n if (toast.variant === 'error' || toast.variant === 'warning') return Infinity;\n return toast.duration ?? 5000;\n })();\n\n const renderCustomToast: Parameters<typeof sonnerToast.custom>[0] = (id) => {\n const title =\n typeof titleProp === 'function'\n ? titleProp({ dismiss: () => sonnerToast.dismiss(id) })\n : titleProp;\n\n return <ToastRoot {...toast} id={id} title={title} duration={duration} />;\n };\n\n return sonnerToast.custom(renderCustomToast, {\n // toast generated by sonner will always have an id, but we want to allow users to specify their own id if they want to\n // can not pass undefined, as it will break dismiss\n ...(toast.id != null ? { id: toast.id } : {}),\n unstyled: true,\n position,\n onAutoClose,\n onDismiss,\n testId,\n toasterId,\n dismissible,\n duration,\n // override default focus-visible styles to match our design\n className: cn('tw:rounded-lg', 'tw:focus-visible:!ring-4', 'tw:focus-visible:!ring-ring/50'),\n });\n};\n\ntoast.success = (title: Title, options?: DerivedToastOptions) =>\n toast({\n ...options,\n title,\n variant: 'success',\n });\n\ntoast.error = (title: Title, options?: DerivedToastOptions) =>\n toast({\n ...options,\n title,\n variant: 'error',\n duration: options?.duration ?? Infinity,\n });\n\ntoast.warning = (title: Title, options?: DerivedToastOptions) =>\n toast({\n ...options,\n title,\n variant: 'warning',\n duration: options?.duration ?? Infinity,\n });\n\ntoast.info = (title: Title, options?: DerivedToastOptions) =>\n toast({\n ...options,\n title,\n variant: 'info',\n });\n\ntoast.dismiss = (toastId?: ToastOptions['id']) => sonnerToast.dismiss(toastId);\ntoast.dismissAll = () => sonnerToast.dismiss();\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Brand } from "@keboola/brand-registry";
|
|
2
|
+
//#region src/components/ThemeProvider/types.d.ts
|
|
3
|
+
type BrandId = string;
|
|
4
|
+
type ResolvedColorScheme = 'light' | 'dark';
|
|
5
|
+
type ColorScheme = 'system' | ResolvedColorScheme;
|
|
6
|
+
type Tokens = Record<string, string>;
|
|
7
|
+
type Theme = Pick<Brand, 'id' | 'name' | 'shell' | 'logo'>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { BrandId, ColorScheme, ResolvedColorScheme, Theme, Tokens };
|
|
10
|
+
//# sourceMappingURL=types-BPcAjMG0.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_BRAND_ID, DEFAULT_COLOR_SCHEME } from "./
|
|
1
|
+
import { DEFAULT_BRAND_ID, DEFAULT_COLOR_SCHEME } from "./defaults-CTfvj2KB.js";
|
|
2
2
|
import { useCallback, useEffect, useState } from "react";
|
|
3
3
|
//#region src/components/ThemeProvider/useBrandState.ts
|
|
4
4
|
const BRAND_ATTRIBUTE = "data-brand";
|
|
@@ -58,4 +58,4 @@ const useColorSchemeState = ({ defaultScheme = DEFAULT_COLOR_SCHEME, scheme: pro
|
|
|
58
58
|
//#endregion
|
|
59
59
|
export { BRAND_ATTRIBUTE, THEME_ATTRIBUTE, useBrandState, useColorSchemeState };
|
|
60
60
|
|
|
61
|
-
//# sourceMappingURL=useColorSchemeState-
|
|
61
|
+
//# sourceMappingURL=useColorSchemeState-BJEk6esG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useColorSchemeState-
|
|
1
|
+
{"version":3,"file":"useColorSchemeState-BJEk6esG.js","names":[],"sources":["../src/components/ThemeProvider/useBrandState.ts","../src/components/ThemeProvider/useColorSchemeState.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\nimport { DEFAULT_BRAND_ID } from './defaults';\nimport type { BrandId } from './types';\n\nexport const BRAND_ATTRIBUTE = 'data-brand';\n\nexport type UseBrandOptions = {\n /** Initial active brand id for uncontrolled use. Defaults to the design-system sentinel (`DEFAULT_BRAND_ID`) — no brand tokens injected, so the stylesheet defaults apply. */\n defaultBrandId?: BrandId;\n /** Controlled active brand id. When set, the parent owns the value and `setBrand` only notifies via `onBrandIdChange` (it does not mutate internal state). */\n brandId?: BrandId;\n /** Called with the next id whenever `setBrand` runs — required to persist the choice in controlled mode. */\n onBrandIdChange?: (brandId: BrandId) => void;\n};\n\nexport const useBrandState = ({\n defaultBrandId: defaultBrand = DEFAULT_BRAND_ID,\n brandId: controlledBrand,\n onBrandIdChange: onBrandChange,\n}: UseBrandOptions = {}) => {\n const [uncontrolledBrand, setUncontrolledBrand] = useState(defaultBrand);\n\n const isControlled = controlledBrand !== undefined;\n const brandId = isControlled ? controlledBrand : uncontrolledBrand;\n\n const setBrand = useCallback(\n (next: BrandId) => {\n if (!isControlled) setUncontrolledBrand(next);\n onBrandChange?.(next);\n },\n [isControlled, onBrandChange],\n );\n\n useEffect(() => {\n if (typeof document === 'undefined') return;\n document.documentElement.setAttribute(BRAND_ATTRIBUTE, brandId);\n }, [brandId]);\n\n return { brandId, setBrand };\n};\n","import { useCallback, useEffect, useState } from 'react';\n\nimport { DEFAULT_COLOR_SCHEME } from './defaults';\nimport type { ColorScheme, ResolvedColorScheme } from './types';\n\nconst DARK_QUERY = '(prefers-color-scheme: dark)';\nexport const THEME_ATTRIBUTE = 'data-theme';\n\nconst getSystemColorScheme = (): ResolvedColorScheme => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return 'light';\n return window.matchMedia(DARK_QUERY).matches ? 'dark' : 'light';\n};\n\nexport type UseColorSchemeOptions = {\n /** Initial colour scheme for uncontrolled use. Defaults to `light` (`DEFAULT_COLOR_SCHEME`). */\n defaultScheme?: ColorScheme;\n /** Controlled colour scheme (`light` / `dark` / `system`). When set, the parent owns the value and `setScheme` only notifies via `onSchemeChange`. `system` follows `prefers-color-scheme` and resolves reactively. */\n scheme?: ColorScheme;\n /** Called with the next scheme whenever `setScheme` runs — required to persist the choice in controlled mode. */\n onSchemeChange?: (theme: ColorScheme) => void;\n};\n\nexport const useColorSchemeState = ({\n defaultScheme = DEFAULT_COLOR_SCHEME,\n scheme: propScheme,\n onSchemeChange,\n}: UseColorSchemeOptions = {}) => {\n const [uncontrolledScheme, setUncontrolledScheme] = useState(defaultScheme);\n const [systemScheme, setSystemScheme] = useState<ResolvedColorScheme>(getSystemColorScheme);\n\n const isControlled = propScheme !== undefined;\n const scheme = isControlled ? propScheme : uncontrolledScheme;\n\n const setScheme = useCallback(\n (next: ColorScheme) => {\n if (!isControlled) setUncontrolledScheme(next);\n onSchemeChange?.(next);\n },\n [isControlled, onSchemeChange],\n );\n\n // Track the OS preference so `system` stays live as the user flips it.\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;\n const mq = window.matchMedia(DARK_QUERY);\n const onChange = () => setSystemScheme(mq.matches ? 'dark' : 'light');\n onChange();\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, []);\n\n const resolvedScheme: ResolvedColorScheme = scheme === 'system' ? systemScheme : scheme;\n\n useEffect(() => {\n if (typeof document === 'undefined') return;\n document.documentElement.setAttribute(THEME_ATTRIBUTE, resolvedScheme);\n }, [resolvedScheme]);\n\n return { scheme, resolvedScheme, setScheme };\n};\n"],"mappings":";;;AAKA,MAAa,kBAAkB;AAW/B,MAAa,iBAAiB,EAC5B,gBAAgB,eAAe,kBAC/B,SAAS,iBACT,iBAAiB,kBACE,CAAC,MAAM;CAC1B,MAAM,CAAC,mBAAmB,wBAAwB,SAAS,YAAY;CAEvE,MAAM,eAAe,oBAAoB,KAAA;CACzC,MAAM,UAAU,eAAe,kBAAkB;CAEjD,MAAM,WAAW,aACd,SAAkB;EACjB,IAAI,CAAC,cAAc,qBAAqB,IAAI;EAC5C,gBAAgB,IAAI;CACtB,GACA,CAAC,cAAc,aAAa,CAC9B;CAEA,gBAAgB;EACd,IAAI,OAAO,aAAa,aAAa;EACrC,SAAS,gBAAgB,aAAa,iBAAiB,OAAO;CAChE,GAAG,CAAC,OAAO,CAAC;CAEZ,OAAO;EAAE;EAAS;CAAS;AAC7B;;;ACnCA,MAAM,aAAa;AACnB,MAAa,kBAAkB;AAE/B,MAAM,6BAAkD;CACtD,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY,OAAO;CACrF,OAAO,OAAO,WAAW,UAAU,CAAC,CAAC,UAAU,SAAS;AAC1D;AAWA,MAAa,uBAAuB,EAClC,gBAAgB,sBAChB,QAAQ,YACR,mBACyB,CAAC,MAAM;CAChC,MAAM,CAAC,oBAAoB,yBAAyB,SAAS,aAAa;CAC1E,MAAM,CAAC,cAAc,mBAAmB,SAA8B,oBAAoB;CAE1F,MAAM,eAAe,eAAe,KAAA;CACpC,MAAM,SAAS,eAAe,aAAa;CAE3C,MAAM,YAAY,aACf,SAAsB;EACrB,IAAI,CAAC,cAAc,sBAAsB,IAAI;EAC7C,iBAAiB,IAAI;CACvB,GACA,CAAC,cAAc,cAAc,CAC/B;CAGA,gBAAgB;EACd,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;EAC9E,MAAM,KAAK,OAAO,WAAW,UAAU;EACvC,MAAM,iBAAiB,gBAAgB,GAAG,UAAU,SAAS,OAAO;EACpE,SAAS;EACT,GAAG,iBAAiB,UAAU,QAAQ;EACtC,aAAa,GAAG,oBAAoB,UAAU,QAAQ;CACxD,GAAG,CAAC,CAAC;CAEL,MAAM,iBAAsC,WAAW,WAAW,eAAe;CAEjF,gBAAgB;EACd,IAAI,OAAO,aAAa,aAAa;EACrC,SAAS,gBAAgB,aAAa,iBAAiB,cAAc;CACvE,GAAG,CAAC,cAAc,CAAC;CAEnB,OAAO;EAAE;EAAQ;EAAgB;CAAU;AAC7C"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { useArgoDesign } from "./context-
|
|
2
|
+
import { useArgoDesign } from "./context-BrNtMc1H.js";
|
|
3
3
|
import { Slot } from "@radix-ui/react-slot";
|
|
4
4
|
import { useEffect, useState } from "react";
|
|
5
5
|
import { Content, Portal, Provider, Root as Root$1, Trigger } from "@radix-ui/react-tooltip";
|
|
@@ -305,4 +305,4 @@ const useSHA256 = (text) => {
|
|
|
305
305
|
//#endregion
|
|
306
306
|
export { Tooltip, TooltipProvider, copyToClipboard, createChangeInputEvent, createPrefixedString, debounce, isMac, keyCodes, noop, useSHA256, withHiddenFullscreen, withTooltipProvider };
|
|
307
307
|
|
|
308
|
-
//# sourceMappingURL=utils-
|
|
308
|
+
//# sourceMappingURL=utils-B-g7d_Jb.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils-D0c5VAyF.js","names":["Root"],"sources":["../src/utils/copyToClipboard.ts","../src/utils/createChangeInputEvent.ts","../src/constants/keyCodes.ts","../src/components/Tooltip/TooltipContent.tsx","../src/components/Tooltip/TooltipRoot.tsx","../src/components/Tooltip/TooltipTrigger.tsx","../src/components/Tooltip/Tooltip.tsx","../src/utils/decorators.tsx","../src/utils/createPrefixedString.ts","../src/utils/noop.ts","../src/utils/debounce.ts","../src/utils/isMac.ts","../src/utils/useSHA256.ts"],"sourcesContent":["/**\n * The async Clipboard API requires the document to be focused and rejects with\n * `NotAllowedError: Document is not focused` otherwise — which is the normal state\n * for a page inside an iframe that has not taken focus, such as Storybook's canvas\n * or an embedded preview. `execCommand` has no such requirement because it copies\n * the selection of a node we focus ourselves, so it covers that gap.\n */\nconst copyViaSelection = (text: string) => {\n const node = document.createElement('textarea');\n node.value = text;\n node.setAttribute('readonly', '');\n node.style.cssText = 'position:fixed;top:0;left:0;opacity:0';\n document.body.append(node);\n node.select();\n\n try {\n return document.execCommand('copy');\n } finally {\n node.remove();\n }\n};\n\nexport const copyToClipboard = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n } catch (error) {\n if (!copyViaSelection(text)) throw error;\n }\n};\n","import type { ChangeEvent } from 'react';\n\nexport const createChangeInputEvent = (input: HTMLInputElement) => {\n const changeEvent: ChangeEvent<HTMLInputElement> = {\n target: input,\n currentTarget: input,\n type: 'change',\n nativeEvent: new Event('change', { bubbles: true }),\n bubbles: true,\n cancelable: false,\n defaultPrevented: false,\n eventPhase: 2, // AT_TARGET\n isTrusted: false, // Synthetic events are not trusted\n preventDefault: () => {}, // Provide dummy functions if not needed\n isDefaultPrevented: () => false,\n stopPropagation: () => {},\n isPropagationStopped: () => false,\n persist: () => {},\n timeStamp: Date.now(),\n };\n\n Object.defineProperty(changeEvent, 'target', {\n value: input,\n writable: false,\n });\n\n return changeEvent;\n};\n","export const keyCodes = {\n ENTER: 'Enter',\n ESCAPE: 'Escape',\n SPACE: ' ',\n};\n","import type { ComponentProps } from 'react';\nimport { Content, Portal } from '@radix-ui/react-tooltip';\nimport type { VariantProps } from 'class-variance-authority';\nimport { cva } from 'class-variance-authority';\n\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nconst tooltipVariants = cva(\n [\n 'tailwindcss-preflight',\n 'tw:inline-block',\n 'tw:break-anywhere',\n 'tw:max-h-96',\n 'tw:overflow-y-auto',\n 'tw:z-[1060]',\n\n // legacy (dark) chrome — default\n 'tw:rounded',\n 'tw:bg-neutral-800',\n 'tw:text-white',\n\n // argo chrome overrides — semantic floating-panel tokens\n 'tw:data-[argo=true]:rounded-2xl',\n 'tw:data-[argo=true]:border',\n 'tw:data-[argo=true]:border-solid',\n 'tw:data-[argo=true]:border-border',\n 'tw:data-[argo=true]:bg-popover',\n 'tw:data-[argo=true]:text-popover-foreground',\n 'tw:data-[argo=true]:shadow-md',\n\n // argo open animation\n 'tw:data-[argo=true]:data-[state=delayed-open]:animate-in',\n 'tw:data-[argo=true]:data-[state=instant-open]:animate-in',\n 'tw:data-[argo=true]:data-[state=delayed-open]:fade-in-0',\n 'tw:data-[argo=true]:data-[state=instant-open]:fade-in-0',\n 'tw:data-[argo=true]:data-[state=delayed-open]:zoom-in-95',\n 'tw:data-[argo=true]:data-[state=instant-open]:zoom-in-95',\n\n // argo closed animation\n 'tw:data-[argo=true]:data-[state=closed]:animate-out',\n 'tw:data-[argo=true]:data-[state=closed]:fade-out-0',\n 'tw:data-[argo=true]:data-[state=closed]:zoom-out-95',\n\n // argo position animation\n 'tw:data-[argo=true]:data-[side=bottom]:slide-in-from-top-2',\n 'tw:data-[argo=true]:data-[side=left]:slide-in-from-right-2',\n 'tw:data-[argo=true]:data-[side=right]:slide-in-from-left-2',\n 'tw:data-[argo=true]:data-[side=top]:slide-in-from-bottom-2',\n ],\n {\n defaultVariants: {\n variant: 'action',\n },\n variants: {\n variant: {\n action: [\n 'tw:max-w-fit',\n 'tw:px-3',\n 'tw:py-2',\n\n 'tw:text-center',\n 'tw:text-xs',\n 'tw:font-medium',\n // Legacy chrome uppercases the action tooltip; the Keboola V2 brand\n // (`data-brand=\"keboola\"`) renders it in standard case instead.\n 'tw:uppercase',\n 'tw:tracking-wider',\n 'tw:[[data-brand=keboola]_&]:normal-case',\n 'tw:[[data-brand=keboola]_&]:tracking-normal',\n ],\n explanatory: [\n 'tw:max-w-80',\n 'tw:px-4',\n 'tw:py-3',\n 'tw:text-left',\n\n 'tw:text-sm',\n 'tw:font-normal',\n ],\n },\n },\n },\n);\n\ntype Props = {\n keepOpenOnPointerDownOutside?: boolean;\n placement?: ComponentProps<typeof Content>['side'];\n} & Omit<ComponentProps<typeof Content>, 'side'> &\n VariantProps<typeof tooltipVariants>;\n\nexport const TooltipContent = ({\n className,\n variant,\n keepOpenOnPointerDownOutside = false,\n children,\n onPointerDownOutside,\n sideOffset = 8,\n collisionPadding = 8,\n hideWhenDetached = true,\n placement = 'right',\n ...rest\n}: Props) => {\n const renderArgo = useArgoDesign();\n\n const handlePointerDownOutside: ComponentProps<typeof Content>['onPointerDownOutside'] = (\n event,\n ) => {\n if (keepOpenOnPointerDownOutside) event.preventDefault();\n onPointerDownOutside?.(event);\n };\n\n return (\n <Portal>\n <Content\n {...rest}\n // Marks the dark (non-argo) tooltip chrome so styles.css can invert\n // nested `.tw\\:prose` for contrast.\n data-tooltip-content={renderArgo ? undefined : true}\n data-argo={renderArgo}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n onPointerDownOutside={handlePointerDownOutside}\n className={tooltipVariants({ className, variant })}\n hideWhenDetached={hideWhenDetached}\n side={placement}\n >\n {children}\n </Content>\n </Portal>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Root } from '@radix-ui/react-tooltip';\n\ntype Props = ComponentProps<typeof Root>;\n\nconst DELAY_SHOW_TOOLTIP = 300;\n\nexport const TooltipRoot = ({ children, delayDuration = DELAY_SHOW_TOOLTIP, ...rest }: Props) => (\n <Root {...rest} delayDuration={delayDuration}>\n {children}\n </Root>\n);\n","import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport { Trigger } from '@radix-ui/react-tooltip';\n\nimport { cn } from '../../utils';\n\n/**\n * Radix stamps the tooltip's own open/closed `data-state` onto the trigger. Merged onto an\n * `asChild` child that keeps a `data-state` of its own — `ToggleGroup.Item`, `Switch`, a `Tabs`\n * trigger — it wins, because those primitives spread incoming props *after* their own attribute.\n * The child then silently loses every `data-[state=…]` style it has, which is usually the only\n * thing marking it as selected.\n *\n * The tooltip's trigger state is styled nowhere, so it is dropped before it reaches the child.\n */\nconst WithoutTooltipState = ({\n children,\n ...props\n // `Slot`'s own props, plus the one attribute this exists to remove: React's types declare no\n // `data-*`, so it has to be named to be destructured away.\n}: ComponentProps<typeof Slot> & { 'data-state'?: string }) => {\n const { 'data-state': _tooltipState, ...rest } = props;\n\n return <Slot {...rest}>{children}</Slot>;\n};\n\ntype Props = {\n keepOpenOnClick?: boolean;\n} & ComponentProps<typeof Trigger>;\n\nexport const TooltipTrigger = ({\n ref,\n children,\n className,\n keepOpenOnClick = false,\n onClick,\n onPointerDown,\n asChild,\n ...rest\n}: Props) => {\n const handleClick: ComponentProps<typeof Trigger>['onClick'] = (event) => {\n if (keepOpenOnClick) event.preventDefault();\n onClick?.(event);\n };\n\n const handlePointerDown: ComponentProps<typeof Trigger>['onPointerDown'] = (event) => {\n if (keepOpenOnClick) event.preventDefault();\n onPointerDown?.(event);\n };\n\n return (\n <Trigger\n {...rest}\n asChild\n ref={ref}\n className={cn('tailwindcss-preflight', className)}\n onClick={handleClick}\n onPointerDown={handlePointerDown}\n >\n {asChild ? (\n <WithoutTooltipState>{children}</WithoutTooltipState>\n ) : (\n // Default-mode trigger wraps children in a span so Radix has a\n // single DOM element to attach handlers to. `tailwindcss-preflight`\n // (merged in via Slot) activates Tailwind's preflight inside the\n // span, which sets `svg { display: block }` — without an inline-flex\n // container that would stack any bare Lucide icon onto its own\n // line. `tw:inline-flex tw:items-center` keeps icon + text aligned.\n <span className=\"tw:inline-flex tw:items-center\">{children}</span>\n )}\n </Trigger>\n );\n};\n","import { useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport type { Content, Trigger } from '@radix-ui/react-tooltip';\nimport { Provider } from '@radix-ui/react-tooltip';\n\nimport { keyCodes } from '../../constants/keyCodes';\n\nimport { TooltipContent } from './TooltipContent';\nimport { TooltipRoot } from './TooltipRoot';\nimport { TooltipTrigger } from './TooltipTrigger';\n\nconst ACTION_TOOLTIP_LIMIT = 30;\n\ntype TriggerProps = {\n triggerAsChild?: boolean;\n};\n\n/**\n * Props for `Tooltip`. `tooltip` is the popup content; `children` is the trigger element.\n * `variant` auto-resolves to `\"explanatory\"` for strings >30 chars, else `\"action\"`.\n */\nexport type Props = {\n /** Keep the tooltip visible when the user clicks the trigger (useful for click-to-copy feedback). */\n keepOpenOnTriggerClick?: boolean;\n /** Content rendered inside the tooltip. Plain text only — no interactive elements (use `HoverCard` or `Popover` for that). */\n tooltip: ReactNode;\n children: ReactNode;\n placement?: ComponentProps<typeof Content>['side'];\n /** Forcibly hide the tooltip regardless of hover state. */\n forceHide?: boolean;\n /** Forcibly show the tooltip regardless of hover state. Useful for guided-tour overlays. */\n forceShow?: boolean;\n /** Hover delay before the tooltip opens, in ms. Defaults to the shared 300ms. */\n delayDuration?: number;\n className?: string;\n} & TriggerProps &\n Pick<ComponentProps<typeof TooltipContent>, 'variant' | 'className'>;\n\n/** Re-export of Radix `Tooltip.Provider`. Mount once at the app root so tooltips share delay state. */\nexport const TooltipProvider = Provider;\n\n/**\n * Short plain-text label that appears on hover or focus.\n *\n * **When to use:** describing an icon-only `Button`, explaining a disabled control, or labelling a\n * truncated value. Plain text only — auto-switches to the longer `\"explanatory\"` variant when the string\n * exceeds 30 characters.\n * **When NOT to use:** for rich preview content (multiple lines, formatted text, structured data) use\n * `HoverCard`; for tooltips containing links or buttons use `Popover` (interactive elements break a11y\n * inside a `Tooltip`).\n * **Composition:** wrap any focusable element via `triggerAsChild` so the tooltip targets the underlying\n * native element. Mount `TooltipProvider` once at the app root.\n *\n * @see RECIPES.md#disabled-button-tooltip — for the disabled-button + tooltip pattern\n */\nexport const Tooltip = ({\n tooltip,\n children,\n className,\n keepOpenOnTriggerClick = false,\n variant,\n placement = 'right',\n forceHide = false,\n forceShow = false,\n delayDuration,\n // trigger props\n triggerAsChild = false,\n}: Props) => {\n const [open, setOpen] = useState(false);\n\n const resolvedVariant = (() => {\n if (!!variant) return variant;\n if (typeof tooltip === 'string' && tooltip.length > ACTION_TOOLTIP_LIMIT) return 'explanatory';\n\n return 'action';\n })();\n\n const isActionVariant = resolvedVariant === 'action';\n\n const handleKeyUp: ComponentProps<typeof Trigger>['onKeyUp'] = (event) => {\n if (![keyCodes.ENTER, keyCodes.SPACE].includes(event.key)) return;\n event.stopPropagation();\n };\n\n return (\n <TooltipRoot\n open={!!tooltip && (open || forceShow) && !forceHide}\n onOpenChange={setOpen}\n delayDuration={delayDuration}\n disableHoverableContent={isActionVariant}\n >\n <TooltipTrigger\n asChild={triggerAsChild}\n keepOpenOnClick={keepOpenOnTriggerClick}\n onKeyUp={handleKeyUp}\n >\n {children}\n </TooltipTrigger>\n\n <TooltipContent\n className={className}\n variant={resolvedVariant}\n placement={placement}\n keepOpenOnPointerDownOutside={keepOpenOnTriggerClick}\n >\n {tooltip}\n </TooltipContent>\n </TooltipRoot>\n );\n};\n\nTooltip.Root = TooltipRoot;\nTooltip.Content = TooltipContent;\nTooltip.Trigger = TooltipTrigger;\n","import type { ComponentType } from 'react';\n\nimport { TooltipProvider } from '../components/Tooltip';\n\nexport const withTooltipProvider = (Story: ComponentType) => (\n <TooltipProvider>\n <Story />\n </TooltipProvider>\n);\n\n// position:fixed only fills the Storybook iframe, not the browser window.\nexport const withHiddenFullscreen = (Story: ComponentType) => (\n <div className=\"tw:[&_[aria-label=Fullscreen]]:hidden\">\n <Story />\n </div>\n);\n","export const createPrefixedString = (prefix: string) => (literals: TemplateStringsArray) =>\n literals.reduce((acc, literal) => acc + literal, `${prefix}-`);\n","export const noop = () => void 0;\n","type DebouncedFn<T extends (...args: any[]) => void> = {\n (...args: Parameters<T>): void;\n cancel: () => void;\n};\n\nexport const debounce = <T extends (...args: any[]) => void>(\n fn: T,\n delay: number,\n): DebouncedFn<T> => {\n let timeoutId: ReturnType<typeof setTimeout>;\n const debounced = (...args: Parameters<T>) => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => fn(...args), delay);\n };\n debounced.cancel = () => clearTimeout(timeoutId);\n return debounced;\n};\n","// Platform detection\ntype NavigatorUAData = {\n platform: string;\n brands: { brand: string; version: string }[];\n mobile: boolean;\n};\n\nconst getIsMac = (): boolean => {\n // Modern approach using navigator.userAgentData\n if (typeof navigator !== 'undefined' && 'userAgentData' in navigator) {\n const platform = (navigator.userAgentData as NavigatorUAData).platform;\n\n if (typeof platform === 'string') {\n return platform.toLowerCase() === 'macos';\n }\n }\n\n if (typeof navigator !== 'undefined' && typeof navigator.platform === 'string') {\n return navigator.platform.toUpperCase().indexOf('MAC') >= 0;\n }\n\n // Server-side rendering fallback\n return false;\n};\n\nexport const isMac = getIsMac();\n","import { useEffect, useState } from 'react';\n\n// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\nconst sha256 = async (text: string) => {\n const msgUint8 = new TextEncoder().encode(text);\n const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');\n};\n\nexport const useSHA256 = (text?: string) => {\n const [hash, setHash] = useState('');\n\n useEffect(() => {\n if (!text) return;\n let cancelled = false;\n sha256(text).then((h) => {\n if (!cancelled) setHash(h);\n });\n return () => {\n cancelled = true;\n };\n }, [text]);\n\n // Empty input has no hash — derive it during render instead of syncing state\n // in the effect (avoids the extra render and a stale-value frame).\n return text ? hash : '';\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils-B-g7d_Jb.js","names":["Root"],"sources":["../src/utils/copyToClipboard.ts","../src/utils/createChangeInputEvent.ts","../src/constants/keyCodes.ts","../src/components/Tooltip/TooltipContent.tsx","../src/components/Tooltip/TooltipRoot.tsx","../src/components/Tooltip/TooltipTrigger.tsx","../src/components/Tooltip/Tooltip.tsx","../src/utils/decorators.tsx","../src/utils/createPrefixedString.ts","../src/utils/noop.ts","../src/utils/debounce.ts","../src/utils/isMac.ts","../src/utils/useSHA256.ts"],"sourcesContent":["/**\n * The async Clipboard API requires the document to be focused and rejects with\n * `NotAllowedError: Document is not focused` otherwise — which is the normal state\n * for a page inside an iframe that has not taken focus, such as Storybook's canvas\n * or an embedded preview. `execCommand` has no such requirement because it copies\n * the selection of a node we focus ourselves, so it covers that gap.\n */\nconst copyViaSelection = (text: string) => {\n const node = document.createElement('textarea');\n node.value = text;\n node.setAttribute('readonly', '');\n node.style.cssText = 'position:fixed;top:0;left:0;opacity:0';\n document.body.append(node);\n node.select();\n\n try {\n return document.execCommand('copy');\n } finally {\n node.remove();\n }\n};\n\nexport const copyToClipboard = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n } catch (error) {\n if (!copyViaSelection(text)) throw error;\n }\n};\n","import type { ChangeEvent } from 'react';\n\nexport const createChangeInputEvent = (input: HTMLInputElement) => {\n const changeEvent: ChangeEvent<HTMLInputElement> = {\n target: input,\n currentTarget: input,\n type: 'change',\n nativeEvent: new Event('change', { bubbles: true }),\n bubbles: true,\n cancelable: false,\n defaultPrevented: false,\n eventPhase: 2, // AT_TARGET\n isTrusted: false, // Synthetic events are not trusted\n preventDefault: () => {}, // Provide dummy functions if not needed\n isDefaultPrevented: () => false,\n stopPropagation: () => {},\n isPropagationStopped: () => false,\n persist: () => {},\n timeStamp: Date.now(),\n };\n\n Object.defineProperty(changeEvent, 'target', {\n value: input,\n writable: false,\n });\n\n return changeEvent;\n};\n","export const keyCodes = {\n ENTER: 'Enter',\n ESCAPE: 'Escape',\n SPACE: ' ',\n};\n","import type { ComponentProps } from 'react';\nimport { Content, Portal } from '@radix-ui/react-tooltip';\nimport type { VariantProps } from 'class-variance-authority';\nimport { cva } from 'class-variance-authority';\n\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nconst tooltipVariants = cva(\n [\n 'tailwindcss-preflight',\n 'tw:inline-block',\n 'tw:break-anywhere',\n 'tw:max-h-96',\n 'tw:overflow-y-auto',\n 'tw:z-[1060]',\n\n // legacy (dark) chrome — default\n 'tw:rounded',\n 'tw:bg-neutral-800',\n 'tw:text-white',\n\n // argo chrome overrides — semantic floating-panel tokens\n 'tw:data-[argo=true]:rounded-2xl',\n 'tw:data-[argo=true]:border',\n 'tw:data-[argo=true]:border-solid',\n 'tw:data-[argo=true]:border-border',\n 'tw:data-[argo=true]:bg-popover',\n 'tw:data-[argo=true]:text-popover-foreground',\n 'tw:data-[argo=true]:shadow-md',\n\n // argo open animation\n 'tw:data-[argo=true]:data-[state=delayed-open]:animate-in',\n 'tw:data-[argo=true]:data-[state=instant-open]:animate-in',\n 'tw:data-[argo=true]:data-[state=delayed-open]:fade-in-0',\n 'tw:data-[argo=true]:data-[state=instant-open]:fade-in-0',\n 'tw:data-[argo=true]:data-[state=delayed-open]:zoom-in-95',\n 'tw:data-[argo=true]:data-[state=instant-open]:zoom-in-95',\n\n // argo closed animation\n 'tw:data-[argo=true]:data-[state=closed]:animate-out',\n 'tw:data-[argo=true]:data-[state=closed]:fade-out-0',\n 'tw:data-[argo=true]:data-[state=closed]:zoom-out-95',\n\n // argo position animation\n 'tw:data-[argo=true]:data-[side=bottom]:slide-in-from-top-2',\n 'tw:data-[argo=true]:data-[side=left]:slide-in-from-right-2',\n 'tw:data-[argo=true]:data-[side=right]:slide-in-from-left-2',\n 'tw:data-[argo=true]:data-[side=top]:slide-in-from-bottom-2',\n ],\n {\n defaultVariants: {\n variant: 'action',\n },\n variants: {\n variant: {\n action: [\n 'tw:max-w-fit',\n 'tw:px-3',\n 'tw:py-2',\n\n 'tw:text-center',\n 'tw:text-xs',\n 'tw:font-medium',\n // Legacy chrome uppercases the action tooltip; the Keboola V2 brand\n // (`data-brand=\"keboola\"`) renders it in standard case instead.\n 'tw:uppercase',\n 'tw:tracking-wider',\n 'tw:[[data-brand=keboola]_&]:normal-case',\n 'tw:[[data-brand=keboola]_&]:tracking-normal',\n ],\n explanatory: [\n 'tw:max-w-80',\n 'tw:px-4',\n 'tw:py-3',\n 'tw:text-left',\n\n 'tw:text-sm',\n 'tw:font-normal',\n ],\n },\n },\n },\n);\n\ntype Props = {\n keepOpenOnPointerDownOutside?: boolean;\n placement?: ComponentProps<typeof Content>['side'];\n} & Omit<ComponentProps<typeof Content>, 'side'> &\n VariantProps<typeof tooltipVariants>;\n\nexport const TooltipContent = ({\n className,\n variant,\n keepOpenOnPointerDownOutside = false,\n children,\n onPointerDownOutside,\n sideOffset = 8,\n collisionPadding = 8,\n hideWhenDetached = true,\n placement = 'right',\n ...rest\n}: Props) => {\n const renderArgo = useArgoDesign();\n\n const handlePointerDownOutside: ComponentProps<typeof Content>['onPointerDownOutside'] = (\n event,\n ) => {\n if (keepOpenOnPointerDownOutside) event.preventDefault();\n onPointerDownOutside?.(event);\n };\n\n return (\n <Portal>\n <Content\n {...rest}\n // Marks the dark (non-argo) tooltip chrome so styles.css can invert\n // nested `.tw\\:prose` for contrast.\n data-tooltip-content={renderArgo ? undefined : true}\n data-argo={renderArgo}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n onPointerDownOutside={handlePointerDownOutside}\n className={tooltipVariants({ className, variant })}\n hideWhenDetached={hideWhenDetached}\n side={placement}\n >\n {children}\n </Content>\n </Portal>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Root } from '@radix-ui/react-tooltip';\n\ntype Props = ComponentProps<typeof Root>;\n\nconst DELAY_SHOW_TOOLTIP = 300;\n\nexport const TooltipRoot = ({ children, delayDuration = DELAY_SHOW_TOOLTIP, ...rest }: Props) => (\n <Root {...rest} delayDuration={delayDuration}>\n {children}\n </Root>\n);\n","import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport { Trigger } from '@radix-ui/react-tooltip';\n\nimport { cn } from '../../utils';\n\n/**\n * Radix stamps the tooltip's own open/closed `data-state` onto the trigger. Merged onto an\n * `asChild` child that keeps a `data-state` of its own — `ToggleGroup.Item`, `Switch`, a `Tabs`\n * trigger — it wins, because those primitives spread incoming props *after* their own attribute.\n * The child then silently loses every `data-[state=…]` style it has, which is usually the only\n * thing marking it as selected.\n *\n * The tooltip's trigger state is styled nowhere, so it is dropped before it reaches the child.\n */\nconst WithoutTooltipState = ({\n children,\n ...props\n // `Slot`'s own props, plus the one attribute this exists to remove: React's types declare no\n // `data-*`, so it has to be named to be destructured away.\n}: ComponentProps<typeof Slot> & { 'data-state'?: string }) => {\n const { 'data-state': _tooltipState, ...rest } = props;\n\n return <Slot {...rest}>{children}</Slot>;\n};\n\ntype Props = {\n keepOpenOnClick?: boolean;\n} & ComponentProps<typeof Trigger>;\n\nexport const TooltipTrigger = ({\n ref,\n children,\n className,\n keepOpenOnClick = false,\n onClick,\n onPointerDown,\n asChild,\n ...rest\n}: Props) => {\n const handleClick: ComponentProps<typeof Trigger>['onClick'] = (event) => {\n if (keepOpenOnClick) event.preventDefault();\n onClick?.(event);\n };\n\n const handlePointerDown: ComponentProps<typeof Trigger>['onPointerDown'] = (event) => {\n if (keepOpenOnClick) event.preventDefault();\n onPointerDown?.(event);\n };\n\n return (\n <Trigger\n {...rest}\n asChild\n ref={ref}\n className={cn('tailwindcss-preflight', className)}\n onClick={handleClick}\n onPointerDown={handlePointerDown}\n >\n {asChild ? (\n <WithoutTooltipState>{children}</WithoutTooltipState>\n ) : (\n // Default-mode trigger wraps children in a span so Radix has a\n // single DOM element to attach handlers to. `tailwindcss-preflight`\n // (merged in via Slot) activates Tailwind's preflight inside the\n // span, which sets `svg { display: block }` — without an inline-flex\n // container that would stack any bare Lucide icon onto its own\n // line. `tw:inline-flex tw:items-center` keeps icon + text aligned.\n <span className=\"tw:inline-flex tw:items-center\">{children}</span>\n )}\n </Trigger>\n );\n};\n","import { useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport type { Content, Trigger } from '@radix-ui/react-tooltip';\nimport { Provider } from '@radix-ui/react-tooltip';\n\nimport { keyCodes } from '../../constants/keyCodes';\n\nimport { TooltipContent } from './TooltipContent';\nimport { TooltipRoot } from './TooltipRoot';\nimport { TooltipTrigger } from './TooltipTrigger';\n\nconst ACTION_TOOLTIP_LIMIT = 30;\n\ntype TriggerProps = {\n triggerAsChild?: boolean;\n};\n\n/**\n * Props for `Tooltip`. `tooltip` is the popup content; `children` is the trigger element.\n * `variant` auto-resolves to `\"explanatory\"` for strings >30 chars, else `\"action\"`.\n */\nexport type Props = {\n /** Keep the tooltip visible when the user clicks the trigger (useful for click-to-copy feedback). */\n keepOpenOnTriggerClick?: boolean;\n /** Content rendered inside the tooltip. Plain text only — no interactive elements (use `HoverCard` or `Popover` for that). */\n tooltip: ReactNode;\n children: ReactNode;\n placement?: ComponentProps<typeof Content>['side'];\n /** Forcibly hide the tooltip regardless of hover state. */\n forceHide?: boolean;\n /** Forcibly show the tooltip regardless of hover state. Useful for guided-tour overlays. */\n forceShow?: boolean;\n /** Hover delay before the tooltip opens, in ms. Defaults to the shared 300ms. */\n delayDuration?: number;\n className?: string;\n} & TriggerProps &\n Pick<ComponentProps<typeof TooltipContent>, 'variant' | 'className'>;\n\n/** Re-export of Radix `Tooltip.Provider`. Mount once at the app root so tooltips share delay state. */\nexport const TooltipProvider = Provider;\n\n/**\n * Short plain-text label that appears on hover or focus.\n *\n * **When to use:** describing an icon-only `Button`, explaining a disabled control, or labelling a\n * truncated value. Plain text only — auto-switches to the longer `\"explanatory\"` variant when the string\n * exceeds 30 characters.\n * **When NOT to use:** for rich preview content (multiple lines, formatted text, structured data) use\n * `HoverCard`; for tooltips containing links or buttons use `Popover` (interactive elements break a11y\n * inside a `Tooltip`).\n * **Composition:** wrap any focusable element via `triggerAsChild` so the tooltip targets the underlying\n * native element. Mount `TooltipProvider` once at the app root.\n *\n * @see RECIPES.md#disabled-button-tooltip — for the disabled-button + tooltip pattern\n */\nexport const Tooltip = ({\n tooltip,\n children,\n className,\n keepOpenOnTriggerClick = false,\n variant,\n placement = 'right',\n forceHide = false,\n forceShow = false,\n delayDuration,\n // trigger props\n triggerAsChild = false,\n}: Props) => {\n const [open, setOpen] = useState(false);\n\n const resolvedVariant = (() => {\n if (!!variant) return variant;\n if (typeof tooltip === 'string' && tooltip.length > ACTION_TOOLTIP_LIMIT) return 'explanatory';\n\n return 'action';\n })();\n\n const isActionVariant = resolvedVariant === 'action';\n\n const handleKeyUp: ComponentProps<typeof Trigger>['onKeyUp'] = (event) => {\n if (![keyCodes.ENTER, keyCodes.SPACE].includes(event.key)) return;\n event.stopPropagation();\n };\n\n return (\n <TooltipRoot\n open={!!tooltip && (open || forceShow) && !forceHide}\n onOpenChange={setOpen}\n delayDuration={delayDuration}\n disableHoverableContent={isActionVariant}\n >\n <TooltipTrigger\n asChild={triggerAsChild}\n keepOpenOnClick={keepOpenOnTriggerClick}\n onKeyUp={handleKeyUp}\n >\n {children}\n </TooltipTrigger>\n\n <TooltipContent\n className={className}\n variant={resolvedVariant}\n placement={placement}\n keepOpenOnPointerDownOutside={keepOpenOnTriggerClick}\n >\n {tooltip}\n </TooltipContent>\n </TooltipRoot>\n );\n};\n\nTooltip.Root = TooltipRoot;\nTooltip.Content = TooltipContent;\nTooltip.Trigger = TooltipTrigger;\n","import type { ComponentType } from 'react';\n\nimport { TooltipProvider } from '../components/Tooltip';\n\nexport const withTooltipProvider = (Story: ComponentType) => (\n <TooltipProvider>\n <Story />\n </TooltipProvider>\n);\n\n// position:fixed only fills the Storybook iframe, not the browser window.\nexport const withHiddenFullscreen = (Story: ComponentType) => (\n <div className=\"tw:[&_[aria-label=Fullscreen]]:hidden\">\n <Story />\n </div>\n);\n","export const createPrefixedString = (prefix: string) => (literals: TemplateStringsArray) =>\n literals.reduce((acc, literal) => acc + literal, `${prefix}-`);\n","export const noop = () => void 0;\n","type DebouncedFn<T extends (...args: any[]) => void> = {\n (...args: Parameters<T>): void;\n cancel: () => void;\n};\n\nexport const debounce = <T extends (...args: any[]) => void>(\n fn: T,\n delay: number,\n): DebouncedFn<T> => {\n let timeoutId: ReturnType<typeof setTimeout>;\n const debounced = (...args: Parameters<T>) => {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => fn(...args), delay);\n };\n debounced.cancel = () => clearTimeout(timeoutId);\n return debounced;\n};\n","// Platform detection\ntype NavigatorUAData = {\n platform: string;\n brands: { brand: string; version: string }[];\n mobile: boolean;\n};\n\nconst getIsMac = (): boolean => {\n // Modern approach using navigator.userAgentData\n if (typeof navigator !== 'undefined' && 'userAgentData' in navigator) {\n const platform = (navigator.userAgentData as NavigatorUAData).platform;\n\n if (typeof platform === 'string') {\n return platform.toLowerCase() === 'macos';\n }\n }\n\n if (typeof navigator !== 'undefined' && typeof navigator.platform === 'string') {\n return navigator.platform.toUpperCase().indexOf('MAC') >= 0;\n }\n\n // Server-side rendering fallback\n return false;\n};\n\nexport const isMac = getIsMac();\n","import { useEffect, useState } from 'react';\n\n// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\nconst sha256 = async (text: string) => {\n const msgUint8 = new TextEncoder().encode(text);\n const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');\n};\n\nexport const useSHA256 = (text?: string) => {\n const [hash, setHash] = useState('');\n\n useEffect(() => {\n if (!text) return;\n let cancelled = false;\n sha256(text).then((h) => {\n if (!cancelled) setHash(h);\n });\n return () => {\n cancelled = true;\n };\n }, [text]);\n\n // Empty input has no hash — derive it during render instead of syncing state\n // in the effect (avoids the extra render and a stale-value frame).\n return text ? hash : '';\n};\n"],"mappings":"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"}
|
package/dist/vega.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ResolvedColorScheme } from "./types-BPcAjMG0.js";
|
|
2
|
+
import { Config } from "vega-lite";
|
|
3
|
+
//#region src/vega/useVegaTheme.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* {@link vegaTheme} for the scheme and brand currently painted on `<html>`,
|
|
6
|
+
* rebuilt whenever either changes.
|
|
7
|
+
*
|
|
8
|
+
* - The config holds resolved colour strings, not `var()` references, so a
|
|
9
|
+
* mounted chart would otherwise keep the palette it was first built with.
|
|
10
|
+
* - The `useThemeAttributes` snapshot is the memo key: its reference moves on a
|
|
11
|
+
* scheme or brand switch and stands still otherwise, and `scheme` comes out of
|
|
12
|
+
* the same read, so the colours can never be resolved under one scheme and
|
|
13
|
+
* memoized under the other.
|
|
14
|
+
* - Re-rendering is not enough on its own — a consumer that compiles a spec in
|
|
15
|
+
* an effect must depend on this config (or on `useThemeAttributes().cacheKey`)
|
|
16
|
+
* and re-render the chart.
|
|
17
|
+
*/
|
|
18
|
+
declare const useVegaTheme: () => Config;
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/vega/vegaTheme.d.ts
|
|
21
|
+
/**
|
|
22
|
+
* Scheme-following Vega-Lite config — the design system's chart look as a plain
|
|
23
|
+
* `Config`, for any consumer that compiles or renders a Vega-Lite spec.
|
|
24
|
+
*
|
|
25
|
+
* - `background: 'transparent'` drops vega's opaque white backdrop, so the page
|
|
26
|
+
* surface shows through in both schemes.
|
|
27
|
+
* - Axis/legend/header/title text and lines read the live semantic tokens, so a
|
|
28
|
+
* dark scheme (and a customer brand) recolour the chart chrome for free.
|
|
29
|
+
* - `range.category` is `--chart-1..5` in series order — the same decorative
|
|
30
|
+
* palette the recharts wrappers in `@keboola/design/charts` use — so a
|
|
31
|
+
* categorical encoding matches the rest of the platform's data-viz instead of
|
|
32
|
+
* falling back to vega's `tableau10`.
|
|
33
|
+
* - `range.ramp` puts the low end of a quantitative scale on `--accent` rather
|
|
34
|
+
* than vega's blue-only default, which keeps the pale end legible on a dark
|
|
35
|
+
* surface.
|
|
36
|
+
* - A range set on the spec's own scale still wins, which is how a Flint chart
|
|
37
|
+
* keeps the series colours it resolves during assembly.
|
|
38
|
+
* - Colours are resolved to concrete `rgb(R, G, B)` strings, not `var()`
|
|
39
|
+
* references: vega does its colour maths in JS and never consults the
|
|
40
|
+
* stylesheet. Rebuild the config when the scheme or brand changes —
|
|
41
|
+
* `useVegaTheme` does that for you.
|
|
42
|
+
*/
|
|
43
|
+
declare const vegaTheme: (scheme: ResolvedColorScheme) => Config;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { useVegaTheme, vegaTheme };
|
|
46
|
+
//# sourceMappingURL=vega.d.ts.map
|
package/dist/vega.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useThemeAttributes } from "./themeTokens-7T1AFLhq.js";
|
|
2
|
+
import { vegaTheme } from "./vegaTheme-FBXgAdHK.js";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
//#region src/vega/useVegaTheme.ts
|
|
5
|
+
/**
|
|
6
|
+
* {@link vegaTheme} for the scheme and brand currently painted on `<html>`,
|
|
7
|
+
* rebuilt whenever either changes.
|
|
8
|
+
*
|
|
9
|
+
* - The config holds resolved colour strings, not `var()` references, so a
|
|
10
|
+
* mounted chart would otherwise keep the palette it was first built with.
|
|
11
|
+
* - The `useThemeAttributes` snapshot is the memo key: its reference moves on a
|
|
12
|
+
* scheme or brand switch and stands still otherwise, and `scheme` comes out of
|
|
13
|
+
* the same read, so the colours can never be resolved under one scheme and
|
|
14
|
+
* memoized under the other.
|
|
15
|
+
* - Re-rendering is not enough on its own — a consumer that compiles a spec in
|
|
16
|
+
* an effect must depend on this config (or on `useThemeAttributes().cacheKey`)
|
|
17
|
+
* and re-render the chart.
|
|
18
|
+
*/
|
|
19
|
+
const useVegaTheme = () => {
|
|
20
|
+
const theme = useThemeAttributes();
|
|
21
|
+
return useMemo(() => vegaTheme(theme.scheme), [theme]);
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { useVegaTheme, vegaTheme };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=vega.js.map
|
package/dist/vega.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vega.js","names":[],"sources":["../src/vega/useVegaTheme.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { Config } from 'vega-lite';\n\nimport { useThemeAttributes } from '../components/ThemeProvider/useThemeAttributes';\n\nimport { vegaTheme } from './vegaTheme';\n\n/**\n * {@link vegaTheme} for the scheme and brand currently painted on `<html>`,\n * rebuilt whenever either changes.\n *\n * - The config holds resolved colour strings, not `var()` references, so a\n * mounted chart would otherwise keep the palette it was first built with.\n * - The `useThemeAttributes` snapshot is the memo key: its reference moves on a\n * scheme or brand switch and stands still otherwise, and `scheme` comes out of\n * the same read, so the colours can never be resolved under one scheme and\n * memoized under the other.\n * - Re-rendering is not enough on its own — a consumer that compiles a spec in\n * an effect must depend on this config (or on `useThemeAttributes().cacheKey`)\n * and re-render the chart.\n */\nexport const useVegaTheme = (): Config => {\n const theme = useThemeAttributes();\n\n // The whole snapshot is the memo key, not `theme.scheme`: its reference moves\n // when the scheme *or* the brand does, and a brand switch repaints every\n // `--*` value while leaving the scheme alone.\n return useMemo(() => vegaTheme(theme.scheme), [theme]);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,MAAa,qBAA6B;CACxC,MAAM,QAAQ,mBAAmB;CAKjC,OAAO,cAAc,UAAU,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC;AACvD"}
|