@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs-
|
|
1
|
+
{"version":3,"file":"Tabs-l72-WuhK.js","names":[],"sources":["../src/components/Tabs/styles.ts","../src/components/Tabs/TabsList.tsx","../src/components/Tabs/TabsTrigger.tsx","../src/components/Tabs/Tabs.tsx","../src/components/Tabs/TabsContent.tsx"],"sourcesContent":["// Directional resets (border-t-0/border-x-0), NOT border-0: under Tailwind v4 a\n// consumer app's `border-0` utility can land after design's compiled bottom-border in\n// the shared `utilities` layer and zero its width (same layer + specificity → source\n// order wins), dropping the line. With directional resets, only the bottom-border\n// utility (`border-b` on the wrapper, `border-b-[3px]` on the trigger) sets the bottom.\nexport const tabsListWrapperClass =\n 'tw:shrink-0 tw:border-t-0 tw:border-x-0 tw:border-b tw:border-solid tw:border-border';\n\nexport const tabsListClass = 'tw:flex tw:gap-8 tw:shrink-0 tw:w-max';\n\nexport const tabsTriggerGroupClass =\n 'tw:group/tab-trigger-group tw:flex tw:shrink-0 tw:items-center';\n\n// The focus ring is **inset**, not an outline. `TabsList` wraps the row in a horizontal\n// `ScrollArea`, whose viewport is `overflow-y: hidden`, and a trigger is exactly as tall as that\n// viewport — so there is 0px of slack for anything painted outside the border box, and a focus\n// outline (the browser's, or a host app's global rule) gets cropped on the top and bottom edges,\n// plus the left edge on the first trigger. Painting inside the box cannot be clipped by any\n// ancestor. Owning the affordance here is also what stops the consumer's global rule applying.\nexport const tabsTriggerClass =\n 'tw:focus-visible:outline-hidden tw:focus-visible:ring-2 tw:focus-visible:ring-inset tw:focus-visible:ring-ring tw:flex tw:justify-center tw:items-center tw:gap-1.5 tw:bg-transparent tw:shrink-0 tw:border-t-0 tw:border-x-0 tw:border-b-[3px] tw:border-solid tw:border-transparent tw:pt-2.5 tw:pb-5 tw:px-0 tw:m-0 tw:font-medium tw:leading-5 tw:text-muted-foreground tw:text-base tw:data-[state=active]:text-primary tw:data-[state=active]:border-primary tw:data-[disabled]:text-muted-foreground tw:data-[disabled]:opacity-50 tw:data-[disabled]:cursor-not-allowed tw:group-hover/tab-trigger-group:enabled:text-primary tw:group-hover/tab-trigger-group:enabled:border-primary tw:group-hover/tab-trigger-group:enabled:cursor-pointer';\n\nexport const tabsTriggerCompactClass = 'tw:text-sm tw:pb-4';\n","import * as RadixTabs from '@radix-ui/react-tabs';\n\nimport { cn } from '../../utils';\nimport { ScrollArea } from '../ScrollArea';\n\nimport { tabsListClass, tabsListWrapperClass } from './styles';\n\ntype Props = Omit<RadixTabs.TabsListProps, 'asChild'>;\n\nexport const TabsList = ({ className, children, ...rest }: Props) => (\n <ScrollArea orientation=\"horizontal\" className={tabsListWrapperClass}>\n <RadixTabs.List {...rest} data-slot=\"tabs-list\" className={cn(tabsListClass, className)}>\n {children}\n </RadixTabs.List>\n </ScrollArea>\n);\n","import * as RadixTabs from '@radix-ui/react-tabs';\n\nimport { cn } from '../../utils';\n\nimport { tabsTriggerClass, tabsTriggerCompactClass } from './styles';\n\ntype Props = Omit<RadixTabs.TabsTriggerProps, 'asChild'> & {\n compact?: boolean;\n};\n\nexport const TabsTrigger = ({ className, compact = false, ...rest }: Props) => (\n <RadixTabs.Trigger\n data-slot=\"tabs-trigger\"\n {...rest}\n className={cn(tabsTriggerClass, compact && tabsTriggerCompactClass, className)}\n />\n);\n","import type { ReactNode } from 'react';\nimport * as RadixTabs from '@radix-ui/react-tabs';\n\nimport { X } from '../../icons';\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\n\nimport { tabsTriggerGroupClass } from './styles';\nimport { TabsList } from './TabsList';\nimport { TabsTrigger } from './TabsTrigger';\n\nexport type Trigger<T extends string> = {\n value: T;\n title: ReactNode;\n onClose?: (value: T) => void;\n} & Omit<RadixTabs.TabsTriggerProps, 'title' | 'asChild'>;\n\ntype Props<T extends string> = {\n triggers: readonly Trigger<T>[];\n compact?: boolean;\n children: ReactNode;\n defaultValue?: string;\n onValueChange?: (value: T) => void;\n rootClassName?: string;\n listClassName?: string;\n triggerClassName?: string;\n triggerGroupClassName?: string;\n} & Omit<RadixTabs.TabsProps, 'onValueChange'>;\n\nexport const Tabs = <T extends string>({\n triggers,\n compact = false,\n children,\n defaultValue,\n onValueChange,\n rootClassName,\n listClassName,\n triggerClassName,\n triggerGroupClassName,\n ...rest\n}: Props<T>) => (\n <RadixTabs.Root\n {...rest}\n data-slot=\"tabs-root\"\n className={cn('tw:flex tw:flex-col tw:gap-6', rootClassName)}\n defaultValue={defaultValue ?? triggers[0]?.value}\n onValueChange={onValueChange as (value: string) => void}\n >\n <TabsList className={listClassName}>\n {triggers.map(({ value, title, onClose, className: callerClassName, ...triggerRest }) => (\n <div\n key={value}\n className={cn(tabsTriggerGroupClass, triggerGroupClassName)}\n data-slot=\"tabs-trigger-group\"\n >\n <TabsTrigger\n value={value}\n compact={compact}\n {...triggerRest}\n className={cn(triggerClassName, callerClassName)}\n >\n {title}\n </TabsTrigger>\n {onClose && (\n <Button\n type=\"button\"\n variant=\"inline\"\n size=\"icon-3xs\"\n disabled={triggerRest.disabled}\n onClick={() => onClose(value)}\n onMouseDown={(e) => e.preventDefault()}\n className=\"tw:!size-8 tw:opacity-0 tw:duration-200 tw:focus-visible:opacity-100 tw:group-focus-within/tab-trigger-group:opacity-100 tw:group-hover/tab-trigger-group:opacity-100\"\n aria-label={typeof title === 'string' ? `Close ${title}` : 'Close tab'}\n >\n <X className=\"tw:size-4\" />\n </Button>\n )}\n </div>\n ))}\n </TabsList>\n {children}\n </RadixTabs.Root>\n);\n","import * as RadixTabs from '@radix-ui/react-tabs';\n\nexport const TabsContent = (props: RadixTabs.TabsContentProps) => (\n <RadixTabs.Content data-slot=\"tabs-content\" tabIndex={-1} {...props} />\n);\n"],"mappings":";;;;;;;AAKA,MAAa,uBACX;AAEF,MAAa,gBAAgB;AAE7B,MAAa,wBACX;AAQF,MAAa,mBACX;;;ACXF,MAAa,YAAY,EAAE,WAAW,UAAU,GAAG,WACjD,oBAAC,YAAD;CAAY,aAAY;CAAa,WAAW;CAC9C,UAAA,oBAAC,UAAU,MAAX;EAAgB,GAAI;EAAM,aAAU;EAAY,WAAW,GAAG,eAAe,SAAS;EACnF;CACa,CAAA;AACN,CAAA;;;ACJd,MAAa,eAAe,EAAE,WAAW,UAAU,OAAO,GAAG,WAC3D,oBAAC,UAAU,SAAX;CACE,aAAU;CACV,GAAI;CACJ,WAAW,GAAG,kBAAkB,WAAA,sBAAoC,SAAS;AAC9E,CAAA;;;ACcH,MAAa,QAA0B,EACrC,UACA,UAAU,OACV,UACA,cACA,eACA,eACA,eACA,kBACA,uBACA,GAAG,WAEH,qBAAC,UAAU,MAAX;CACE,GAAI;CACJ,aAAU;CACV,WAAW,GAAG,gCAAgC,aAAa;CAC3D,cAAc,gBAAgB,SAAS,EAAE,EAAE;CAC5B;CALjB,UAAA,CAOE,oBAAC,UAAD;EAAU,WAAW;EAClB,UAAA,SAAS,KAAK,EAAE,OAAO,OAAO,SAAS,WAAW,iBAAiB,GAAG,kBACrE,qBAAC,OAAD;GAEE,WAAW,GAAG,uBAAuB,qBAAqB;GAC1D,aAAU;GAHZ,UAAA,CAKE,oBAAC,aAAD;IACS;IACE;IACT,GAAI;IACJ,WAAW,GAAG,kBAAkB,eAAe;IAE9C,UAAA;GACU,CAAA,GACZ,WACC,oBAAC,QAAD;IACE,MAAK;IACL,SAAQ;IACR,MAAK;IACL,UAAU,YAAY;IACtB,eAAe,QAAQ,KAAK;IAC5B,cAAc,MAAM,EAAE,eAAe;IACrC,WAAU;IACV,cAAY,OAAO,UAAU,WAAW,SAAS,UAAU;IAE3D,UAAA,oBAAC,GAAD,EAAG,WAAU,YAAa,CAAA;GACpB,CAAA,CAEP;EA1BE,GAAA,KA0BF,CACN;CACO,CAAA,GACT,QACa;;;;AC/ElB,MAAa,eAAe,UAC1B,oBAAC,UAAU,SAAX;CAAmB,aAAU;CAAe,UAAU;CAAI,GAAI;AAAQ,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { createChangeInputEvent, createPrefixedString } from "./utils-
|
|
2
|
+
import { createChangeInputEvent, createPrefixedString } from "./utils-B-g7d_Jb.js";
|
|
3
3
|
import { mergeRefs } from "./internal/utils/mergeRefs.js";
|
|
4
4
|
import { X } from "./icons-Cek151jC.js";
|
|
5
|
-
import { InputGroup } from "./InputGroup-
|
|
5
|
+
import { InputGroup } from "./InputGroup-D7zlmqPB.js";
|
|
6
6
|
import { useControllableState } from "./useControllableState-M6494mCT.js";
|
|
7
7
|
import { useRef } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -107,4 +107,4 @@ const TextInput = ({ ref: forwardedRef, state = "default", sizing = "default", c
|
|
|
107
107
|
//#endregion
|
|
108
108
|
export { TextInput };
|
|
109
109
|
|
|
110
|
-
//# sourceMappingURL=TextInput-
|
|
110
|
+
//# sourceMappingURL=TextInput-DhdRk8qm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput-
|
|
1
|
+
{"version":3,"file":"TextInput-DhdRk8qm.js","names":[],"sources":["../src/blocks/TextInput/utils.ts","../src/blocks/TextInput/TextInput.tsx"],"sourcesContent":["import { createPrefixedString } from '../../utils';\n\nexport const genInputTestId = (prefix: string = '') => {\n const ps = createPrefixedString(prefix);\n return {\n toString: () => prefix,\n inputWrapper: ps`input-wrapper`,\n input: ps`input`,\n clearButton: ps`clear-button`,\n };\n};\n","import { useRef } from 'react';\nimport type {\n ChangeEventHandler,\n ComponentProps,\n ComponentRef,\n FocusEventHandler,\n MouseEventHandler,\n ReactNode,\n} from 'react';\n\nimport { InputGroup } from '../../components/InputGroup';\nimport { useControllableState } from '../../hooks/useControllableState';\nimport { X } from '../../icons';\nimport { cn, createChangeInputEvent, mergeRefs } from '../../utils';\n\nimport { genInputTestId } from './utils';\n\ntype InputGroupProps = Pick<\n ComponentProps<typeof InputGroup>,\n 'variant' | 'focusVariant' | 'sizing' | 'state'\n>;\n\ntype OwnProps = {\n prefix?: ReactNode;\n rightSuffix?: ReactNode;\n rightSuffixVariant?: 'addon' | 'default';\n leftSuffix?: ReactNode;\n allowClear?: boolean;\n onClear?: () => void;\n testId?: string;\n value?: string | null;\n defaultValue?: string | null;\n /** Called with the unwrapped string value on every change. For the raw event use `onChange`. */\n onValueChange?: (value: string) => void;\n /** Called with the unwrapped string value on blur. For the raw event use `onBlur`. */\n onValueBlur?: (value: string) => void;\n type?: 'text' | 'email' | 'password' | 'datetime-local' | 'date';\n};\n\n/**\n * Props for `TextInput`. Combines `InputGroup` chrome (variant / sizing / state / focusVariant) with\n * input-specific slots (`prefix`, `leftSuffix`, `rightSuffix`, `allowClear`) and a string-typed\n * `value` / `defaultValue` plus convenience `onValueChange` / `onValueBlur` callbacks. `null` /\n * `undefined` are coerced to empty strings.\n */\nexport type Props = InputGroupProps &\n OwnProps &\n Omit<ComponentProps<'input'>, 'prefix' | 'value' | 'defaultValue' | 'type' | 'accept' | 'step'>;\n\nconst sanitizeTextInputValue = (value: string | null | undefined) => {\n if (typeof value === 'string' && value.trim() === '') return '';\n return value;\n};\n\n/**\n * Standard text input with a string-only API, built on `InputGroup` chrome — addons, clear button,\n * sizing, focus variants. The default choice for a bare text input.\n *\n * **When to use:** any plain text / email / password / date-input field outside `useAppForm`. Pair with\n * `onValueChange` instead of unwrapping `event.target.value` from `onChange`.\n * **When NOT to use:** for fields inside a labelled group use `FormGroup.TextInput`; for forms with\n * validation use `useAppForm` + `field.TextField`; for search use `SearchInput`.\n * **Composition:** wrap in a `FormGroup` for shared error / help-text state, or render directly inside\n * page layouts. Chrome resolves from the active brand automatically: a modern brand always renders argo\n * (any `variant` is ignored), while `variant` only tunes the legacy-brand chrome.\n */\nexport const TextInput = ({\n ref: forwardedRef,\n state = 'default',\n sizing = 'default',\n className,\n prefix = null,\n rightSuffix = null,\n rightSuffixVariant = 'default',\n leftSuffix = null,\n allowClear = false,\n onClear,\n disabled = false,\n testId: prefixTestId = '',\n autoFocus = false,\n id,\n name,\n variant,\n readOnly,\n type = 'text',\n focusVariant = 'default',\n onChange,\n onBlur,\n onValueChange,\n onValueBlur,\n value: valueProp,\n defaultValue,\n ...inputProps\n}: Props) => {\n const inputRef = useRef<ComponentRef<'input'>>(null);\n\n const [value, setValue] = useControllableState<string>({\n // `undefined` stays uncontrolled; any provided value (incl. `null`) is controlled and coerced\n // to a string. Whitespace-only input collapses to '' via `sanitizeTextInputValue`.\n prop: valueProp === undefined ? undefined : (sanitizeTextInputValue(valueProp) ?? ''),\n defaultProp: sanitizeTextInputValue(defaultValue) ?? '',\n onChange: onValueChange,\n });\n\n const testId = genInputTestId(prefixTestId);\n const isClearButtonVisible = (!!value && !disabled && !readOnly) || !!onClear;\n\n const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n setValue(event.target.value);\n onChange?.(event);\n };\n\n const handleBlur: FocusEventHandler<HTMLInputElement> = (event) => {\n onValueBlur?.(event.target.value);\n onBlur?.(event);\n };\n\n const handleClear: MouseEventHandler<HTMLButtonElement> = () => {\n if (inputRef.current === null) return;\n inputRef.current.value = ''; // keep the DOM node in sync before firing the synthetic change\n inputRef.current.focus();\n onClear?.();\n handleChange(createChangeInputEvent(inputRef.current));\n };\n\n return (\n <InputGroup\n state={state}\n variant={variant}\n sizing={sizing}\n focusVariant={focusVariant}\n className={className}\n data-testid={testId.inputWrapper}\n >\n {prefix && <InputGroup.Addon align=\"inline-start\">{prefix}</InputGroup.Addon>}\n\n <InputGroup.Input\n {...inputProps}\n value={value}\n autoFocus={autoFocus}\n type={type}\n onChange={handleChange}\n onBlur={handleBlur}\n ref={mergeRefs(forwardedRef ?? null, inputRef)}\n disabled={disabled}\n id={id}\n name={name}\n readOnly={readOnly}\n data-testid={testId.input}\n />\n\n {(leftSuffix || allowClear || rightSuffix) && (\n <InputGroup.Addon align=\"inline-end\">\n {leftSuffix}\n {allowClear && isClearButtonVisible && (\n <InputGroup.Button\n aria-label=\"Clear\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={handleClear}\n data-testid={testId.clearButton}\n >\n <X className=\"tw:size-4\" />\n </InputGroup.Button>\n )}\n {rightSuffix && (\n <div\n className={cn({\n 'tw:whitespace-nowrap tw:bg-muted tw:px-4 tw:-mr-4 tw:py-2.5':\n rightSuffixVariant === 'addon',\n })}\n >\n {rightSuffix}\n </div>\n )}\n </InputGroup.Addon>\n )}\n </InputGroup>\n );\n};\n"],"mappings":";;;;;;;;;AAEA,MAAa,kBAAkB,SAAiB,OAAO;CACrD,MAAM,KAAK,qBAAqB,MAAM;CACtC,OAAO;EACL,gBAAgB;EAChB,cAAc,EAAE;EAChB,OAAO,EAAE;EACT,aAAa,EAAE;CACjB;AACF;;;ACuCA,MAAM,0BAA0B,UAAqC;CACnE,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,IAAI,OAAO;CAC7D,OAAO;AACT;;;;;;;;;;;;;AAcA,MAAa,aAAa,EACxB,KAAK,cACL,QAAQ,WACR,SAAS,WACT,WACA,SAAS,MACT,cAAc,MACd,qBAAqB,WACrB,aAAa,MACb,aAAa,OACb,SACA,WAAW,OACX,QAAQ,eAAe,IACvB,YAAY,OACZ,IACA,MACA,SACA,UACA,OAAO,QACP,eAAe,WACf,UACA,QACA,eACA,aACA,OAAO,WACP,cACA,GAAG,iBACQ;CACX,MAAM,WAAW,OAA8B,IAAI;CAEnD,MAAM,CAAC,OAAO,YAAY,qBAA6B;EAGrD,MAAM,cAAc,KAAA,IAAY,KAAA,IAAa,uBAAuB,SAAS,KAAK;EAClF,aAAa,uBAAuB,YAAY,KAAK;EACrD,UAAU;CACZ,CAAC;CAED,MAAM,SAAS,eAAe,YAAY;CAC1C,MAAM,uBAAwB,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,YAAa,CAAC,CAAC;CAEtE,MAAM,gBAAsD,UAAU;EACpE,SAAS,MAAM,OAAO,KAAK;EAC3B,WAAW,KAAK;CAClB;CAEA,MAAM,cAAmD,UAAU;EACjE,cAAc,MAAM,OAAO,KAAK;EAChC,SAAS,KAAK;CAChB;CAEA,MAAM,oBAA0D;EAC9D,IAAI,SAAS,YAAY,MAAM;EAC/B,SAAS,QAAQ,QAAQ;EACzB,SAAS,QAAQ,MAAM;EACvB,UAAU;EACV,aAAa,uBAAuB,SAAS,OAAO,CAAC;CACvD;CAEA,OACE,qBAAC,YAAD;EACS;EACE;EACD;EACM;EACH;EACX,eAAa,OAAO;EANtB,UAAA;GAQG,UAAU,oBAAC,WAAW,OAAZ;IAAkB,OAAM;IAAgB,UAAA;GAAyB,CAAA;GAE5E,oBAAC,WAAW,OAAZ;IACE,GAAI;IACG;IACI;IACL;IACN,UAAU;IACV,QAAQ;IACR,KAAK,UAAU,gBAAgB,MAAM,QAAQ;IACnC;IACN;IACE;IACI;IACV,eAAa,OAAO;GACrB,CAAA;IAEC,cAAc,cAAc,gBAC5B,qBAAC,WAAW,OAAZ;IAAkB,OAAM;IAAxB,UAAA;KACG;KACA,cAAc,wBACb,oBAAC,WAAW,QAAZ;MACE,cAAW;MACX,cAAc,MAAM,EAAE,eAAe;MACrC,SAAS;MACT,eAAa,OAAO;MAEpB,UAAA,oBAAC,GAAD,EAAG,WAAU,YAAa,CAAA;KACT,CAAA;KAEpB,eACC,oBAAC,OAAD;MACE,WAAW,GAAG,EACZ,+DACE,uBAAuB,QAC3B,CAAC;MAEA,UAAA;KACE,CAAA;IAES;;EAEV;;AAEhB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { TooltipProvider } from "./utils-
|
|
2
|
-
import { DEFAULT_BRANDS,
|
|
3
|
-
import {
|
|
1
|
+
import { TooltipProvider } from "./utils-B-g7d_Jb.js";
|
|
2
|
+
import { DEFAULT_BRANDS, createCssVars, createTheme, defaultBrand } from "./defaults-CTfvj2KB.js";
|
|
3
|
+
import { ThemeContext } from "./context-BrNtMc1H.js";
|
|
4
|
+
import { useBrandState, useColorSchemeState } from "./useColorSchemeState-BJEk6esG.js";
|
|
4
5
|
import { useInsertionEffect, useMemo } from "react";
|
|
5
6
|
import { brandSchema, exampleCustomer, keboola as keboola$1, keboolaLegacySidebar as keboolaLegacySidebar$1, keboolaLegacyTopnav as keboolaLegacyTopnav$1 } from "@keboola/brand-registry";
|
|
6
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -200,4 +201,4 @@ const ThemeProvider = ({ defaultScheme, scheme, onSchemeChange, defaultBrandId,
|
|
|
200
201
|
//#endregion
|
|
201
202
|
export { ThemeProvider, brandSchema, exampleCustomer, keboola$1 as keboola, keboolaLegacySidebar$1 as keboolaLegacySidebar, keboolaLegacyTopnav$1 as keboolaLegacyTopnav };
|
|
202
203
|
|
|
203
|
-
//# sourceMappingURL=ThemeProvider-
|
|
204
|
+
//# sourceMappingURL=ThemeProvider-DZfGdf1v.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeProvider-QncUrfJn.js","names":[],"sources":["../src/components/ThemeProvider/AIGradientSvg.tsx","../src/components/ThemeProvider/useThemeTokens.ts","../src/components/ThemeProvider/ThemeProvider.tsx"],"sourcesContent":["export const AIGradientsSvg = () => (\n <svg width=\"0\" height=\"0\" style={{ position: 'absolute', visibility: 'hidden' }}>\n <defs>\n {/*aigradient-600*/}\n <linearGradient id=\"aigradient-600\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#61E4FF\" />\n <stop offset=\"50%\" stopColor=\"#1F8FFF\" />\n <stop offset=\"100%\" stopColor=\"#7C5CFF\" />\n </linearGradient>\n\n {/*aigradient-700*/}\n <linearGradient id=\"aigradient-700\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#075fb8\" />\n <stop offset=\"100%\" stopColor=\"#5b2cb8\" />\n </linearGradient>\n </defs>\n </svg>\n);\n","import { useInsertionEffect } from 'react';\n\nimport type {\n BrandTheme,\n Colors,\n Gradient,\n Motion,\n Radii,\n Shadows,\n Spacing,\n Typography,\n} from '@keboola/brand-registry';\n\nimport type { ResolvedColorScheme } from './types';\nimport { createCssVars } from './utils';\n\nexport type ThemeTokens = {\n colors?: Colors;\n typography?: Typography;\n radii?: Radii;\n shadows?: Shadows;\n spacing?: Spacing;\n motion?: Motion;\n gradient?: Gradient;\n};\n\nexport const brandThemeToTokens = (\n theme: BrandTheme,\n scheme: ResolvedColorScheme,\n): ThemeTokens => ({\n colors: scheme === 'dark' ? theme.colorsDark : theme.colors,\n typography: theme.typography,\n radii: theme.radii,\n // Scheme-independent — the same values apply in light and dark.\n shadows: theme.shadows,\n spacing: theme.spacing,\n motion: theme.motion,\n gradient: theme.gradient,\n});\n\nexport const tokensToCssVars = ({\n colors,\n typography,\n radii,\n shadows,\n spacing,\n motion,\n gradient,\n}: ThemeTokens): Record<string, string> => {\n const vars = createCssVars();\n\n vars.set('--background', colors?.background);\n vars.set('--foreground', colors?.foreground);\n vars.set('--muted', colors?.muted);\n vars.set('--muted-foreground', colors?.mutedForeground);\n vars.set('--border', colors?.border);\n vars.set('--input', colors?.input);\n vars.set('--input-background', colors?.inputBackground);\n vars.set('--ring', colors?.ring);\n vars.set('--ring-offset', colors?.ringOffset);\n vars.set('--primary', colors?.primary);\n vars.set('--primary-foreground', colors?.primaryForeground);\n vars.set('--secondary', colors?.secondary);\n vars.set('--secondary-foreground', colors?.secondaryForeground);\n vars.set('--accent', colors?.accent);\n vars.set('--accent-foreground', colors?.accentForeground);\n vars.set('--card', colors?.card);\n vars.set('--card-foreground', colors?.cardForeground);\n vars.set('--popover', colors?.popover);\n vars.set('--popover-foreground', colors?.popoverForeground);\n vars.set('--destructive', colors?.destructive);\n vars.set('--destructive-foreground', colors?.destructiveForeground);\n vars.set('--success', colors?.success);\n vars.set('--success-foreground', colors?.successForeground);\n vars.set('--warning', colors?.warning);\n vars.set('--warning-foreground', colors?.warningForeground);\n vars.set('--info', colors?.info);\n vars.set('--info-foreground', colors?.infoForeground);\n\n vars.set('--chart-1', colors?.chart?.chart1);\n vars.set('--chart-2', colors?.chart?.chart2);\n vars.set('--chart-3', colors?.chart?.chart3);\n vars.set('--chart-4', colors?.chart?.chart4);\n vars.set('--chart-5', colors?.chart?.chart5);\n\n vars.set('--sidebar', colors?.sidebar?.sidebar);\n vars.set('--sidebar-foreground', colors?.sidebar?.sidebarForeground);\n vars.set('--sidebar-primary', colors?.sidebar?.sidebarPrimary);\n vars.set('--sidebar-primary-foreground', colors?.sidebar?.sidebarPrimaryForeground);\n vars.set('--sidebar-accent', colors?.sidebar?.sidebarAccent);\n vars.set('--sidebar-accent-foreground', colors?.sidebar?.sidebarAccentForeground);\n vars.set('--sidebar-border', colors?.sidebar?.sidebarBorder);\n vars.set('--sidebar-ring', colors?.sidebar?.sidebarRing);\n\n /**\n * TYPOGRAPHY\n */\n vars.set('--font-sans', typography?.fontFamily?.trim() || undefined);\n vars.set('--font-display', typography?.fontDisplay?.trim() || undefined);\n vars.set('--font-mono', typography?.fontMono?.trim() || undefined);\n\n // Chrome font-weight slots — read by Tailwind's `fontWeight` scale.\n vars.set('--font-weight-normal', typography?.weight?.normal);\n vars.set('--font-weight-medium', typography?.weight?.medium);\n vars.set('--font-weight-semibold', typography?.weight?.semibold);\n vars.set('--font-weight-bold', typography?.weight?.bold);\n\n // Chrome tracking — behind Button/Badge `tracking-chrome`.\n vars.set('--letter-spacing-chrome', typography?.letterSpacing?.chrome);\n\n // Type scale — display/heading/body steps read by `text-display/heading/body`.\n vars.set('--type-display-size', typography?.typeScale?.display?.size);\n vars.set('--type-display-weight', typography?.typeScale?.display?.weight);\n vars.set('--type-display-leading', typography?.typeScale?.display?.leading);\n vars.set('--type-display-tracking', typography?.typeScale?.display?.tracking);\n vars.set('--type-heading-size', typography?.typeScale?.heading?.size);\n vars.set('--type-heading-weight', typography?.typeScale?.heading?.weight);\n vars.set('--type-heading-leading', typography?.typeScale?.heading?.leading);\n vars.set('--type-heading-tracking', typography?.typeScale?.heading?.tracking);\n vars.set('--type-body-size', typography?.typeScale?.body?.size);\n vars.set('--type-body-weight', typography?.typeScale?.body?.weight);\n vars.set('--type-body-leading', typography?.typeScale?.body?.leading);\n vars.set('--type-body-tracking', typography?.typeScale?.body?.tracking);\n\n vars.set('--radius-sm', radii?.sm);\n vars.set('--radius-md', radii?.md);\n vars.set('--radius-lg', radii?.lg);\n\n /**\n * ELEVATION / DENSITY / MOTION / GRADIENT\n */\n vars.set('--shadow-sm', shadows?.sm);\n vars.set('--shadow-md', shadows?.md);\n vars.set('--shadow-lg', shadows?.lg);\n vars.set('--shadow-lift', shadows?.lift);\n\n vars.set('--space-gutter', spacing?.gutter);\n vars.set('--space-inset', spacing?.inset);\n\n vars.set('--motion-duration', motion?.duration);\n vars.set('--motion-easing', motion?.easing);\n\n vars.set('--gradient-brand', gradient?.brand);\n\n return vars.expose();\n};\n\nconst setTokens = (node: HTMLElement, vars: Record<string, string>) => {\n for (const [name, value] of Object.entries(vars)) {\n node.style.setProperty(name, value);\n }\n};\n\nconst removeTokens = (node: HTMLElement, vars: Record<string, string>) => {\n for (const name of Object.keys(vars)) {\n node.style.removeProperty(name);\n }\n};\n\nexport const useThemeTokens = (tokens: ThemeTokens) => {\n // Insertion effect: runs before the DOM mutates and before any (descendant)\n // layout effect measures token-dependent geometry. Write-only, so it fits the\n // hook's constraints. Only the brand's overrides are set; unset slots fall\n // through to the stylesheet's `:root` / `[data-theme='dark']` defaults.\n useInsertionEffect(() => {\n if (typeof document === 'undefined') return;\n const root = document.documentElement;\n const vars = tokensToCssVars(tokens);\n\n setTokens(root, vars);\n\n return () => removeTokens(root, vars);\n }, [tokens]);\n};\n","import { type ReactNode, useMemo } from 'react';\n\nimport type { Brand } from '@keboola/brand-registry';\n\nimport { TooltipProvider } from '../Tooltip';\n\nimport { AIGradientsSvg } from './AIGradientSvg';\nimport { ThemeContext, type ThemeContextValue } from './context';\nimport { DEFAULT_BRANDS, defaultBrand } from './defaults';\nimport { type UseBrandOptions, useBrandState } from './useBrandState';\nimport { type UseColorSchemeOptions, useColorSchemeState } from './useColorSchemeState';\nimport { brandThemeToTokens, useThemeTokens } from './useThemeTokens';\nimport { createTheme } from './utils';\n\ntype Props = UseColorSchemeOptions &\n UseBrandOptions & {\n /** Brands this provider knows about; the active brand id resolves against these. */\n brands?: readonly Brand[];\n children: ReactNode;\n };\n\nexport const ThemeProvider = ({\n defaultScheme,\n scheme,\n onSchemeChange,\n defaultBrandId,\n brandId,\n onBrandIdChange,\n brands = DEFAULT_BRANDS,\n children,\n}: Props) => {\n const colorSchemeState = useColorSchemeState({\n defaultScheme,\n scheme,\n onSchemeChange,\n });\n\n const brandState = useBrandState({\n defaultBrandId,\n brandId,\n onBrandIdChange,\n });\n\n // Resolve the active brand; an unknown id (incl. the default sentinel) falls\n // back to `defaultBrand`, whose empty theme injects nothing so the stylesheet\n // defaults apply.\n const brand = useMemo(\n () => brands.find((item) => item.id === brandState.brandId) ?? defaultBrand,\n [brands, brandState.brandId],\n );\n const themes = useMemo(() => brands.map(createTheme), [brands]);\n const currentTheme = useMemo(() => createTheme(brand), [brand]);\n\n // Only the brand's overrides for the resolved scheme are injected; every slot\n // it omits (including a missing dark palette) falls through to the stylesheet's\n // `:root` / `[data-theme='dark']` defaults — so dark mode works for any brand.\n const themeTokens = useMemo(\n () => brandThemeToTokens(brand.theme, colorSchemeState.resolvedScheme),\n [brand, colorSchemeState.resolvedScheme],\n );\n\n useThemeTokens(themeTokens);\n\n const { scheme: activeScheme, resolvedScheme, setScheme } = colorSchemeState;\n const { brandId: activeBrandId, setBrand } = brandState;\n const context = useMemo<ThemeContextValue>(\n () => ({\n scheme: activeScheme,\n resolvedScheme,\n setScheme,\n brandId: activeBrandId,\n setBrand,\n themes,\n currentTheme,\n }),\n [activeScheme, resolvedScheme, setScheme, activeBrandId, setBrand, themes, currentTheme],\n );\n\n return (\n <ThemeContext value={context}>\n <AIGradientsSvg />\n <TooltipProvider>{children}</TooltipProvider>\n </ThemeContext>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ThemeProvider-DZfGdf1v.js","names":[],"sources":["../src/components/ThemeProvider/AIGradientSvg.tsx","../src/components/ThemeProvider/useThemeTokens.ts","../src/components/ThemeProvider/ThemeProvider.tsx"],"sourcesContent":["export const AIGradientsSvg = () => (\n <svg width=\"0\" height=\"0\" style={{ position: 'absolute', visibility: 'hidden' }}>\n <defs>\n {/*aigradient-600*/}\n <linearGradient id=\"aigradient-600\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#61E4FF\" />\n <stop offset=\"50%\" stopColor=\"#1F8FFF\" />\n <stop offset=\"100%\" stopColor=\"#7C5CFF\" />\n </linearGradient>\n\n {/*aigradient-700*/}\n <linearGradient id=\"aigradient-700\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor=\"#075fb8\" />\n <stop offset=\"100%\" stopColor=\"#5b2cb8\" />\n </linearGradient>\n </defs>\n </svg>\n);\n","import { useInsertionEffect } from 'react';\n\nimport type {\n BrandTheme,\n Colors,\n Gradient,\n Motion,\n Radii,\n Shadows,\n Spacing,\n Typography,\n} from '@keboola/brand-registry';\n\nimport type { ResolvedColorScheme } from './types';\nimport { createCssVars } from './utils';\n\nexport type ThemeTokens = {\n colors?: Colors;\n typography?: Typography;\n radii?: Radii;\n shadows?: Shadows;\n spacing?: Spacing;\n motion?: Motion;\n gradient?: Gradient;\n};\n\nexport const brandThemeToTokens = (\n theme: BrandTheme,\n scheme: ResolvedColorScheme,\n): ThemeTokens => ({\n colors: scheme === 'dark' ? theme.colorsDark : theme.colors,\n typography: theme.typography,\n radii: theme.radii,\n // Scheme-independent — the same values apply in light and dark.\n shadows: theme.shadows,\n spacing: theme.spacing,\n motion: theme.motion,\n gradient: theme.gradient,\n});\n\nexport const tokensToCssVars = ({\n colors,\n typography,\n radii,\n shadows,\n spacing,\n motion,\n gradient,\n}: ThemeTokens): Record<string, string> => {\n const vars = createCssVars();\n\n vars.set('--background', colors?.background);\n vars.set('--foreground', colors?.foreground);\n vars.set('--muted', colors?.muted);\n vars.set('--muted-foreground', colors?.mutedForeground);\n vars.set('--border', colors?.border);\n vars.set('--input', colors?.input);\n vars.set('--input-background', colors?.inputBackground);\n vars.set('--ring', colors?.ring);\n vars.set('--ring-offset', colors?.ringOffset);\n vars.set('--primary', colors?.primary);\n vars.set('--primary-foreground', colors?.primaryForeground);\n vars.set('--secondary', colors?.secondary);\n vars.set('--secondary-foreground', colors?.secondaryForeground);\n vars.set('--accent', colors?.accent);\n vars.set('--accent-foreground', colors?.accentForeground);\n vars.set('--card', colors?.card);\n vars.set('--card-foreground', colors?.cardForeground);\n vars.set('--popover', colors?.popover);\n vars.set('--popover-foreground', colors?.popoverForeground);\n vars.set('--destructive', colors?.destructive);\n vars.set('--destructive-foreground', colors?.destructiveForeground);\n vars.set('--success', colors?.success);\n vars.set('--success-foreground', colors?.successForeground);\n vars.set('--warning', colors?.warning);\n vars.set('--warning-foreground', colors?.warningForeground);\n vars.set('--info', colors?.info);\n vars.set('--info-foreground', colors?.infoForeground);\n\n vars.set('--chart-1', colors?.chart?.chart1);\n vars.set('--chart-2', colors?.chart?.chart2);\n vars.set('--chart-3', colors?.chart?.chart3);\n vars.set('--chart-4', colors?.chart?.chart4);\n vars.set('--chart-5', colors?.chart?.chart5);\n\n vars.set('--sidebar', colors?.sidebar?.sidebar);\n vars.set('--sidebar-foreground', colors?.sidebar?.sidebarForeground);\n vars.set('--sidebar-primary', colors?.sidebar?.sidebarPrimary);\n vars.set('--sidebar-primary-foreground', colors?.sidebar?.sidebarPrimaryForeground);\n vars.set('--sidebar-accent', colors?.sidebar?.sidebarAccent);\n vars.set('--sidebar-accent-foreground', colors?.sidebar?.sidebarAccentForeground);\n vars.set('--sidebar-border', colors?.sidebar?.sidebarBorder);\n vars.set('--sidebar-ring', colors?.sidebar?.sidebarRing);\n\n /**\n * TYPOGRAPHY\n */\n vars.set('--font-sans', typography?.fontFamily?.trim() || undefined);\n vars.set('--font-display', typography?.fontDisplay?.trim() || undefined);\n vars.set('--font-mono', typography?.fontMono?.trim() || undefined);\n\n // Chrome font-weight slots — read by Tailwind's `fontWeight` scale.\n vars.set('--font-weight-normal', typography?.weight?.normal);\n vars.set('--font-weight-medium', typography?.weight?.medium);\n vars.set('--font-weight-semibold', typography?.weight?.semibold);\n vars.set('--font-weight-bold', typography?.weight?.bold);\n\n // Chrome tracking — behind Button/Badge `tracking-chrome`.\n vars.set('--letter-spacing-chrome', typography?.letterSpacing?.chrome);\n\n // Type scale — display/heading/body steps read by `text-display/heading/body`.\n vars.set('--type-display-size', typography?.typeScale?.display?.size);\n vars.set('--type-display-weight', typography?.typeScale?.display?.weight);\n vars.set('--type-display-leading', typography?.typeScale?.display?.leading);\n vars.set('--type-display-tracking', typography?.typeScale?.display?.tracking);\n vars.set('--type-heading-size', typography?.typeScale?.heading?.size);\n vars.set('--type-heading-weight', typography?.typeScale?.heading?.weight);\n vars.set('--type-heading-leading', typography?.typeScale?.heading?.leading);\n vars.set('--type-heading-tracking', typography?.typeScale?.heading?.tracking);\n vars.set('--type-body-size', typography?.typeScale?.body?.size);\n vars.set('--type-body-weight', typography?.typeScale?.body?.weight);\n vars.set('--type-body-leading', typography?.typeScale?.body?.leading);\n vars.set('--type-body-tracking', typography?.typeScale?.body?.tracking);\n\n vars.set('--radius-sm', radii?.sm);\n vars.set('--radius-md', radii?.md);\n vars.set('--radius-lg', radii?.lg);\n\n /**\n * ELEVATION / DENSITY / MOTION / GRADIENT\n */\n vars.set('--shadow-sm', shadows?.sm);\n vars.set('--shadow-md', shadows?.md);\n vars.set('--shadow-lg', shadows?.lg);\n vars.set('--shadow-lift', shadows?.lift);\n\n vars.set('--space-gutter', spacing?.gutter);\n vars.set('--space-inset', spacing?.inset);\n\n vars.set('--motion-duration', motion?.duration);\n vars.set('--motion-easing', motion?.easing);\n\n vars.set('--gradient-brand', gradient?.brand);\n\n return vars.expose();\n};\n\nconst setTokens = (node: HTMLElement, vars: Record<string, string>) => {\n for (const [name, value] of Object.entries(vars)) {\n node.style.setProperty(name, value);\n }\n};\n\nconst removeTokens = (node: HTMLElement, vars: Record<string, string>) => {\n for (const name of Object.keys(vars)) {\n node.style.removeProperty(name);\n }\n};\n\nexport const useThemeTokens = (tokens: ThemeTokens) => {\n // Insertion effect: runs before the DOM mutates and before any (descendant)\n // layout effect measures token-dependent geometry. Write-only, so it fits the\n // hook's constraints. Only the brand's overrides are set; unset slots fall\n // through to the stylesheet's `:root` / `[data-theme='dark']` defaults.\n useInsertionEffect(() => {\n if (typeof document === 'undefined') return;\n const root = document.documentElement;\n const vars = tokensToCssVars(tokens);\n\n setTokens(root, vars);\n\n return () => removeTokens(root, vars);\n }, [tokens]);\n};\n","import { type ReactNode, useMemo } from 'react';\n\nimport type { Brand } from '@keboola/brand-registry';\n\nimport { TooltipProvider } from '../Tooltip';\n\nimport { AIGradientsSvg } from './AIGradientSvg';\nimport { ThemeContext, type ThemeContextValue } from './context';\nimport { DEFAULT_BRANDS, defaultBrand } from './defaults';\nimport { type UseBrandOptions, useBrandState } from './useBrandState';\nimport { type UseColorSchemeOptions, useColorSchemeState } from './useColorSchemeState';\nimport { brandThemeToTokens, useThemeTokens } from './useThemeTokens';\nimport { createTheme } from './utils';\n\ntype Props = UseColorSchemeOptions &\n UseBrandOptions & {\n /** Brands this provider knows about; the active brand id resolves against these. */\n brands?: readonly Brand[];\n children: ReactNode;\n };\n\nexport const ThemeProvider = ({\n defaultScheme,\n scheme,\n onSchemeChange,\n defaultBrandId,\n brandId,\n onBrandIdChange,\n brands = DEFAULT_BRANDS,\n children,\n}: Props) => {\n const colorSchemeState = useColorSchemeState({\n defaultScheme,\n scheme,\n onSchemeChange,\n });\n\n const brandState = useBrandState({\n defaultBrandId,\n brandId,\n onBrandIdChange,\n });\n\n // Resolve the active brand; an unknown id (incl. the default sentinel) falls\n // back to `defaultBrand`, whose empty theme injects nothing so the stylesheet\n // defaults apply.\n const brand = useMemo(\n () => brands.find((item) => item.id === brandState.brandId) ?? defaultBrand,\n [brands, brandState.brandId],\n );\n const themes = useMemo(() => brands.map(createTheme), [brands]);\n const currentTheme = useMemo(() => createTheme(brand), [brand]);\n\n // Only the brand's overrides for the resolved scheme are injected; every slot\n // it omits (including a missing dark palette) falls through to the stylesheet's\n // `:root` / `[data-theme='dark']` defaults — so dark mode works for any brand.\n const themeTokens = useMemo(\n () => brandThemeToTokens(brand.theme, colorSchemeState.resolvedScheme),\n [brand, colorSchemeState.resolvedScheme],\n );\n\n useThemeTokens(themeTokens);\n\n const { scheme: activeScheme, resolvedScheme, setScheme } = colorSchemeState;\n const { brandId: activeBrandId, setBrand } = brandState;\n const context = useMemo<ThemeContextValue>(\n () => ({\n scheme: activeScheme,\n resolvedScheme,\n setScheme,\n brandId: activeBrandId,\n setBrand,\n themes,\n currentTheme,\n }),\n [activeScheme, resolvedScheme, setScheme, activeBrandId, setBrand, themes, currentTheme],\n );\n\n return (\n <ThemeContext value={context}>\n <AIGradientsSvg />\n <TooltipProvider>{children}</TooltipProvider>\n </ThemeContext>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ScrollArea } from "./internal/components/ScrollArea.js";
|
|
2
2
|
import { Toggle } from "./internal/components/Toggle.js";
|
|
3
|
-
import { Popover } from "./Popover-
|
|
3
|
+
import { Popover } from "./Popover-DsbI2HKu.js";
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/TimePicker/utils.ts
|
|
@@ -95,4 +95,4 @@ const TimePicker = ({ align = "end", alignOffset = -18, children, defaultOpen, d
|
|
|
95
95
|
//#endregion
|
|
96
96
|
export { TimePicker, formatTime, pad, parseTime };
|
|
97
97
|
|
|
98
|
-
//# sourceMappingURL=TimePicker-
|
|
98
|
+
//# sourceMappingURL=TimePicker-B6d2rAbX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimePicker-
|
|
1
|
+
{"version":3,"file":"TimePicker-B6d2rAbX.js","names":[],"sources":["../src/components/TimePicker/utils.ts","../src/components/TimePicker/TimePicker.tsx"],"sourcesContent":["export const pad = (n: number) => n.toString().padStart(2, '0');\n\n/** The \"HH:mm\" shape `parseTime` parses back. */\nexport const formatTime = (hour: number, minute: number) => `${pad(hour)}:${pad(minute)}`;\n\nexport const parseTime = (time?: string | null) => {\n if (!time) return { hour: null, minute: null };\n\n const match = /^(\\d{1,2}):(\\d{1,2})$/.exec(time.trim());\n if (!match) return { hour: null, minute: null };\n\n const hour = Number(match[1]);\n const minute = Number(match[2]);\n if (\n Number.isNaN(hour) ||\n Number.isNaN(minute) ||\n hour < 0 ||\n hour > 23 ||\n minute < 0 ||\n minute > 59\n )\n return { hour: null, minute: null };\n\n return { hour, minute };\n};\n\nexport const scrollToSelected = (viewport: HTMLDivElement | null) => {\n if (!viewport) return;\n // Defer scroll until after the popover open animation completes and layout is calculated\n requestAnimationFrame(() => {\n const selected = viewport.querySelector('[aria-pressed=\"true\"]');\n selected?.scrollIntoView({ block: 'center' });\n });\n};\n","import { useState } from 'react';\nimport type { ReactNode } from 'react';\nimport type { PopoverContentProps, PopoverProps } from '@radix-ui/react-popover';\n\nimport { Popover } from '../Popover';\nimport { ScrollArea } from '../ScrollArea';\nimport { Toggle } from '../Toggle';\n\nimport { formatTime, pad, parseTime, scrollToSelected } from './utils';\n\nconst HOURS = Array.from({ length: 24 }, (_, i) => i);\nconst MINUTES = Array.from({ length: 60 }, (_, i) => i);\n\ntype Props = {\n children?: ReactNode;\n defaultSelected?: string | null;\n selected?: string | null;\n onSelect?: (time: string) => void;\n} & Pick<PopoverProps, 'open' | 'onOpenChange' | 'defaultOpen'> &\n Pick<PopoverContentProps, 'align' | 'alignOffset' | 'sideOffset'>;\n\nexport const TimePicker = ({\n align = 'end',\n alignOffset = -18,\n children,\n defaultOpen,\n defaultSelected,\n onOpenChange,\n onSelect,\n open,\n selected,\n sideOffset = 12,\n}: Props) => {\n const [internalSelected, setInternalSelected] = useState<string | null>(defaultSelected ?? null);\n\n const isControlled = selected !== undefined;\n const currentValue = isControlled ? selected : internalSelected;\n\n const parsed = parseTime(currentValue);\n const hour = parsed.hour ?? null;\n const minute = parsed.minute ?? null;\n\n const handleSelect = (time: string) => {\n if (!isControlled) {\n setInternalSelected(time);\n }\n onSelect?.(time);\n };\n\n const handleHourSelect = (h: number) => {\n handleSelect(formatTime(h, minute ?? 0));\n };\n\n const handleMinuteSelect = (m: number) => {\n handleSelect(formatTime(hour ?? 0, m));\n };\n\n return (\n <Popover defaultOpen={defaultOpen} onOpenChange={onOpenChange} open={open}>\n <Popover.Trigger asChild>{children}</Popover.Trigger>\n <Popover.Content\n align={align}\n alignOffset={alignOffset}\n sideOffset={sideOffset}\n className=\"tw:flex tw:flex-row\"\n >\n <ScrollArea type=\"always\" ref={scrollToSelected} viewPortClassName=\"tw:h-60 tw:p-3\">\n {HOURS.map((value) => (\n <Toggle\n key={value}\n variant=\"ghost\"\n className=\"tw:size-10 tw:p-0\"\n pressed={value === hour}\n onPressedChange={() => handleHourSelect(value)}\n >\n {pad(value)}\n </Toggle>\n ))}\n </ScrollArea>\n\n <ScrollArea type=\"always\" ref={scrollToSelected} viewPortClassName=\"tw:h-60 tw:p-3\">\n {MINUTES.map((value) => (\n <Toggle\n key={value}\n variant=\"ghost\"\n className=\"tw:size-10 tw:p-0\"\n pressed={value === minute}\n onPressedChange={() => handleMinuteSelect(value)}\n >\n {pad(value)}\n </Toggle>\n ))}\n </ScrollArea>\n </Popover.Content>\n </Popover>\n );\n};\n"],"mappings":";;;;;;AAAA,MAAa,OAAO,MAAc,EAAE,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG;;AAG9D,MAAa,cAAc,MAAc,WAAmB,GAAG,IAAI,IAAI,EAAE,GAAG,IAAI,MAAM;AAEtF,MAAa,aAAa,SAAyB;CACjD,IAAI,CAAC,MAAM,OAAO;EAAE,MAAM;EAAM,QAAQ;CAAK;CAE7C,MAAM,QAAQ,wBAAwB,KAAK,KAAK,KAAK,CAAC;CACtD,IAAI,CAAC,OAAO,OAAO;EAAE,MAAM;EAAM,QAAQ;CAAK;CAE9C,MAAM,OAAO,OAAO,MAAM,EAAE;CAC5B,MAAM,SAAS,OAAO,MAAM,EAAE;CAC9B,IACE,OAAO,MAAM,IAAI,KACjB,OAAO,MAAM,MAAM,KACnB,OAAO,KACP,OAAO,MACP,SAAS,KACT,SAAS,IAET,OAAO;EAAE,MAAM;EAAM,QAAQ;CAAK;CAEpC,OAAO;EAAE;EAAM;CAAO;AACxB;AAEA,MAAa,oBAAoB,aAAoC;CACnE,IAAI,CAAC,UAAU;CAEf,4BAA4B;EAE1B,SAD0B,cAAc,yBACjC,CAAC,EAAE,eAAe,EAAE,OAAO,SAAS,CAAC;CAC9C,CAAC;AACH;;;ACvBA,MAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,CAAC;AACpD,MAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,CAAC;AAUtD,MAAa,cAAc,EACzB,QAAQ,OACR,cAAc,KACd,UACA,aACA,iBACA,cACA,UACA,MACA,UACA,aAAa,SACF;CACX,MAAM,CAAC,kBAAkB,uBAAuB,SAAwB,mBAAmB,IAAI;CAE/F,MAAM,eAAe,aAAa,KAAA;CAGlC,MAAM,SAAS,UAFM,eAAe,WAAW,gBAEV;CACrC,MAAM,OAAO,OAAO,QAAQ;CAC5B,MAAM,SAAS,OAAO,UAAU;CAEhC,MAAM,gBAAgB,SAAiB;EACrC,IAAI,CAAC,cACH,oBAAoB,IAAI;EAE1B,WAAW,IAAI;CACjB;CAEA,MAAM,oBAAoB,MAAc;EACtC,aAAa,WAAW,GAAG,UAAU,CAAC,CAAC;CACzC;CAEA,MAAM,sBAAsB,MAAc;EACxC,aAAa,WAAW,QAAQ,GAAG,CAAC,CAAC;CACvC;CAEA,OACE,qBAAC,SAAD;EAAsB;EAA2B;EAAoB;EAArE,UAAA,CACE,oBAAC,QAAQ,SAAT;GAAiB,SAAA;GAAS;EAA0B,CAAA,GACpD,qBAAC,QAAQ,SAAT;GACS;GACM;GACD;GACZ,WAAU;GAJZ,UAAA,CAME,oBAAC,YAAD;IAAY,MAAK;IAAS,KAAK;IAAkB,mBAAkB;IAChE,UAAA,MAAM,KAAK,UACV,oBAAC,QAAD;KAEE,SAAQ;KACR,WAAU;KACV,SAAS,UAAU;KACnB,uBAAuB,iBAAiB,KAAK;KAE5C,UAAA,IAAI,KAAK;IACJ,GAPD,KAOC,CACT;GACS,CAAA,GAEZ,oBAAC,YAAD;IAAY,MAAK;IAAS,KAAK;IAAkB,mBAAkB;IAChE,UAAA,QAAQ,KAAK,UACZ,oBAAC,QAAD;KAEE,SAAQ;KACR,WAAU;KACV,SAAS,UAAU;KACnB,uBAAuB,mBAAmB,KAAK;KAE9C,UAAA,IAAI,KAAK;IACJ,GAPD,KAOC,CACT;GACS,CAAA,CACG;EACV,CAAA,CAAA;;AAEb"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toast as toast$1 } from "./toast-
|
|
1
|
+
import { toast as toast$1 } from "./toast-BweSoKn3.js";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import { Toaster } from "sonner";
|
|
@@ -46,4 +46,4 @@ const Toaster$1 = ({ gap = 12, visibleToasts = 5, ...props }) => /* @__PURE__ */
|
|
|
46
46
|
//#endregion
|
|
47
47
|
export { Toaster$1 as Toaster, useNotification };
|
|
48
48
|
|
|
49
|
-
//# sourceMappingURL=Toast-
|
|
49
|
+
//# sourceMappingURL=Toast-CxXUulYN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toast-
|
|
1
|
+
{"version":3,"file":"Toast-CxXUulYN.js","names":["toast","Toaster","SonnerToaster"],"sources":["../src/components/Toast/useNotification.tsx","../src/components/Toast/Toaster.tsx"],"sourcesContent":["import { useEffect } from 'react';\n\nimport { toast } from './toast';\n\ntype Props = {\n enabled?: boolean;\n} & Parameters<typeof toast>[0];\n\n/**\n * Declarative notification component built on top of sonner/toast.\n *\n * Use `Notification` for persistent, system-driven messages that require user acknowledgment\n * (e.g., trial expiration warnings, upgrade prompts, billing alerts).\n * The notification stays visible until the user dismisses it or the component unmounts.\n *\n * Use `toast()` for transient feedback after a user action\n * (e.g., \"Saved\", \"Copied\", \"Deleted\") that auto-dismisses after a few seconds.\n */\nexport const useNotification = ({ enabled = true, ...toastOptions }: Props) => {\n useEffect(() => {\n if (!enabled) return;\n let toastId: string | number | undefined;\n const frameId = requestAnimationFrame(() => {\n toastId = toast({ ...toastOptions, duration: toastOptions.duration ?? Infinity });\n });\n\n return () => {\n cancelAnimationFrame(frameId);\n toast.dismiss(toastId);\n };\n // oxlint-disable-next-line react/exhaustive-deps -- we only want to trigger this effect when enabled changes, not when other toast options change\n }, [enabled]);\n};\n","import type { ComponentProps, PointerEvent } from 'react';\nimport { Toaster as SonnerToaster } from 'sonner';\n\ntype ToasterProps = ComponentProps<typeof SonnerToaster>;\n\nconst DEFAULT_STYLES = {\n '--width': '512px', // match max-w-lg\n} as React.CSSProperties;\n\nconst stopPropagation = (event: PointerEvent) => event.stopPropagation();\n\nexport const Toaster = ({ gap = 12, visibleToasts = 5, ...props }: ToasterProps) => (\n // Wrapper prevents toast clicks from reaching Radix Dialog's DismissableLayer,\n // which would otherwise close the modal on any \"outside\" pointer event.\n // oxlint-disable-next-line jsx-a11y/no-static-element-interactions\n <div onPointerDown={stopPropagation}>\n <SonnerToaster\n {...props}\n gap={gap}\n visibleToasts={visibleToasts}\n className=\"tw:pointer-events-auto tw:flex tw:w-full tw:max-w-lg tw:justify-center\"\n style={DEFAULT_STYLES}\n />\n </div>\n);\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAa,mBAAmB,EAAE,UAAU,MAAM,GAAG,mBAA0B;CAC7E,gBAAgB;EACd,IAAI,CAAC,SAAS;EACd,IAAI;EACJ,MAAM,UAAU,4BAA4B;GAC1C,UAAUA,QAAM;IAAE,GAAG;IAAc,UAAU,aAAa,YAAY;GAAS,CAAC;EAClF,CAAC;EAED,aAAa;GACX,qBAAqB,OAAO;GAC5B,QAAM,QAAQ,OAAO;EACvB;CAEF,GAAG,CAAC,OAAO,CAAC;AACd;;;AC3BA,MAAM,iBAAiB,EACrB,WAAW,QACb;AAEA,MAAM,mBAAmB,UAAwB,MAAM,gBAAgB;AAEvE,MAAaC,aAAW,EAAE,MAAM,IAAI,gBAAgB,GAAG,GAAG,YAIxD,oBAAC,OAAD;CAAK,eAAe;CAClB,UAAA,oBAACC,SAAD;EACE,GAAI;EACC;EACU;EACf,WAAU;EACV,OAAO;CACR,CAAA;AACE,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { Tooltip } from "./utils-
|
|
2
|
+
import { Tooltip } from "./utils-B-g7d_Jb.js";
|
|
3
3
|
import { Maximize2, Minimize2 } from "./icons-Cek151jC.js";
|
|
4
|
-
import { Button } from "./Button-
|
|
5
|
-
import { ClipboardButton } from "./ClipboardButton-
|
|
4
|
+
import { Button } from "./Button-CPsEQuTN.js";
|
|
5
|
+
import { ClipboardButton } from "./ClipboardButton-CQ6Aewpg.js";
|
|
6
6
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { createPortal } from "react-dom";
|
|
@@ -245,4 +245,4 @@ const svgToPngBlob = async (svg, background) => {
|
|
|
245
245
|
//#endregion
|
|
246
246
|
export { ZoomableSvg, svgToPngBlob, toSvgFileContent };
|
|
247
247
|
|
|
248
|
-
//# sourceMappingURL=ZoomableSvg-
|
|
248
|
+
//# sourceMappingURL=ZoomableSvg-CNIzRHKH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZoomableSvg-CZEu6sAq.js","names":[],"sources":["../src/components/ZoomableSvg/ZoomableSvg.tsx","../src/components/ZoomableSvg/exportSvg.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport DOMPurify from 'dompurify';\n\nimport { ClipboardButton } from '../../blocks/ClipboardButton';\nimport { Maximize2, Minimize2 } from '../../icons';\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\nimport { Tooltip } from '../Tooltip';\n\nconst MIN_SCALE = 0.5;\nconst MAX_SCALE = 3;\nconst ZOOM_STEP = 0.1;\n\ntype Props = {\n /** Raw SVG markup. Sanitized internally with DOMPurify (SVG profile) before rendering, so it is\n * safe even when it originates from user/LLM-controlled content. Non-SVG HTML is stripped. */\n html: string;\n copyText?: string;\n className?: string;\n /**\n * Opt in to keeping `<foreignObject>` elements through sanitization. Off by\n * default — the SVG profile drops `<foreignObject>` so no HTML subtree can\n * survive. Only enable when the caller pre-flattens each `<foreignObject>` to\n * bare text (the SVG profile still strips any HTML children even when the\n * element itself is allowed). `MermaidDiagram` sets this for node/icon labels.\n */\n allowForeignObject?: boolean;\n /**\n * Extra toolbar controls, rendered between the copy and fullscreen buttons.\n *\n * Injected rather than built in, so export behaviour — filenames,\n * rasterization, error reporting — stays with the consumer and this component\n * keeps shipping in the lazy `@keboola/design/mermaid` chunk with no download\n * dependencies of its own. Pass `ExportMenu` here. Receives the sanitized\n * SVG so an exporter writes exactly what is on screen.\n */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const ZoomableSvg = ({\n html,\n copyText,\n className,\n allowForeignObject,\n renderActions,\n}: Props) => {\n const safeHtml = useMemo(\n () =>\n DOMPurify.sanitize(html, {\n USE_PROFILES: { svg: true, svgFilters: true },\n ...(allowForeignObject ? { ADD_TAGS: ['foreignObject'] } : {}),\n }),\n [html, allowForeignObject],\n );\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [scale, setScale] = useState(1);\n const [translate, setTranslate] = useState({ x: 0, y: 0 });\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n useEffect(() => {\n if (!isFullscreen) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n setIsFullscreen(false);\n }\n };\n document.addEventListener('keydown', onKeyDown, { capture: true });\n return () => document.removeEventListener('keydown', onKeyDown, { capture: true });\n }, [isFullscreen]);\n\n const dragRef = useRef<{\n startX: number;\n startY: number;\n startTx: number;\n startTy: number;\n } | null>(null);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n const delta = e.deltaY > 0 ? -ZOOM_STEP : ZOOM_STEP;\n setScale((s) => Math.min(MAX_SCALE, Math.max(MIN_SCALE, s + delta)));\n };\n\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n // Re-bind when toggling fullscreen: the portal/inline switch remounts the\n // container element, so the listener must attach to the new node.\n }, [isFullscreen]);\n\n const didDragRef = useRef(false);\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (e.button !== 0) return;\n e.preventDefault();\n didDragRef.current = false;\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n startTx: translate.x,\n startTy: translate.y,\n };\n },\n [translate],\n );\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!dragRef.current) return;\n didDragRef.current = true;\n setTranslate({\n x: dragRef.current.startTx + e.clientX - dragRef.current.startX,\n y: dragRef.current.startTy + e.clientY - dragRef.current.startY,\n });\n }, []);\n\n const handleMouseUp = useCallback(() => {\n dragRef.current = null;\n }, []);\n\n const handleReset = useCallback(() => {\n setScale(1);\n setTranslate({ x: 0, y: 0 });\n }, []);\n\n const isZoomed = Math.abs(scale - 1) > 0.001 || translate.x !== 0 || translate.y !== 0;\n\n const handleClick = useCallback((e: React.MouseEvent) => {\n if (didDragRef.current) {\n e.stopPropagation();\n }\n }, []);\n\n const stopPropagation = useCallback((e: React.SyntheticEvent) => {\n e.stopPropagation();\n }, []);\n\n const diagramContent = (\n <div\n role=\"presentation\"\n className={cn('tw:group/zoom tw:relative', isFullscreen && 'tw:h-full')}\n onClick={handleClick}\n >\n <div\n role=\"presentation\"\n ref={containerRef}\n className={cn(\n 'tw:overflow-hidden tw:cursor-grab tw:active:cursor-grabbing tw:p-3',\n isFullscreen && 'tw:h-full',\n )}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n >\n <div\n className={cn(\n 'tw:flex tw:justify-center tw:origin-center',\n isFullscreen && 'tw:h-full tw:[&>svg]:h-full',\n )}\n style={{ transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})` }}\n dangerouslySetInnerHTML={{ __html: safeHtml }}\n />\n </div>\n <div\n role=\"presentation\"\n // `focus-within` as well as hover: the toolbar is opacity-0 but still in\n // the tab order, so without this a keyboard user tabs through invisible\n // controls with no visible focus ring.\n className=\"tw:absolute tw:right-1 tw:top-1 tw:flex tw:gap-1 tw:opacity-0 tw:transition-opacity tw:focus-within:opacity-100 tw:group-hover/zoom:opacity-100\"\n onClick={stopPropagation}\n >\n {isZoomed && (\n <Tooltip tooltip=\"Reset zoom\" placement=\"top\" triggerAsChild>\n <Button size=\"small\" variant=\"outline\" onClick={handleReset}>\n Reset\n </Button>\n </Tooltip>\n )}\n {copyText && (\n <ClipboardButton text={copyText} tooltip=\"Copy code\" size=\"icon-sm\" variant=\"outline\" />\n )}\n {renderActions?.(safeHtml)}\n <Tooltip\n tooltip={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n placement=\"top\"\n triggerAsChild\n >\n <Button\n size=\"icon-sm\"\n variant=\"outline\"\n aria-label={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n onClick={() => setIsFullscreen((f) => !f)}\n >\n {isFullscreen ? (\n <Minimize2 className=\"tw:size-4\" />\n ) : (\n <Maximize2 className=\"tw:size-4\" />\n )}\n </Button>\n </Tooltip>\n </div>\n </div>\n );\n\n if (isFullscreen) {\n return createPortal(\n <div\n role=\"presentation\"\n data-testid=\"zoomable-svg-fullscreen\"\n /**\n * Stacking contract for this overlay, which portals to `document.body`.\n *\n * - Sits at z-1051, the Modal/Sheet band: above page chrome.\n * - Stays *below* the floating-panel layer (z-1055: DropdownMenu,\n * Popover, Select, Combobox), which portals to `document.body` too —\n * an overlay above it hides any menu opened from the toolbar.\n * - `Tooltip` (z-1060) renders above, as it does over a Modal.\n * - `SpotlightBackdrop` (z-1056) dims this overlay rather than sitting\n * under it — by design, since it deliberately covers the portalled\n * surface tier so a tour's dim can't be punched through.\n * - An app may clamp poppers into this same band, making it a tie that\n * DOM order settles; Radix mounts its portal after this one.\n */\n className=\"tw:fixed tw:inset-0 tw:z-[1051] tw:bg-muted tw:p-4 tailwindcss-preflight\"\n onClick={stopPropagation}\n >\n {diagramContent}\n </div>,\n document.body,\n );\n }\n\n return (\n <div\n className={cn(\n 'tw:overflow-hidden tw:rounded-md tw:border tw:border-border tw:bg-muted',\n className,\n )}\n >\n {diagramContent}\n </div>\n );\n};\n","const PNG_SCALE = 2;\n\n// The root `<svg …>` tag, so the namespace check looks only at its attributes.\n// A plain `includes('xmlns=')` would also match a nested element or body text,\n// and would miss `xmlns = \"…\"` — adding a second declaration, which parsers\n// reject outright with \"Attribute xmlns redefined\".\nconst ROOT_SVG_TAG = /^<svg\\b[^>]*>/i;\nconst HAS_DEFAULT_NAMESPACE = /\\bxmlns\\s*=/i;\n\n// A standalone SVG file needs the namespace declaration; mermaid's inline output\n// omits it because an inline <svg> inherits it from the host document.\n// Trim before matching: the anchored `^<svg` misses markup that arrives with a\n// leading newline or indentation, which would emit a standalone file with no\n// namespace — unopenable in an image viewer.\nconst withSvgNamespace = (svg: string) => {\n const trimmed = svg.trim();\n const rootTag = trimmed.match(ROOT_SVG_TAG)?.[0];\n\n if (!rootTag || HAS_DEFAULT_NAMESPACE.test(rootTag)) return trimmed;\n\n return trimmed.replace(/^<svg\\b/i, '<svg xmlns=\"http://www.w3.org/2000/svg\"');\n};\n\nexport const toSvgFileContent = (svg: string) =>\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${withSvgNamespace(svg).trim()}\\n`;\n\n// A single decimal number: `12`, `12.5`, `.5`. Deliberately stricter than\n// `[\\d.]+`, which also matches `1.2.3` — and `parseFloat` truncates that to\n// `1.2` rather than rejecting it, so a malformed value would pass as a plausible\n// one.\nconst NUMBER = String.raw`\\d+(?:\\.\\d+)?|\\.\\d+`;\n\n// `parseFloat` happily reads a relative length as a number — `\"100%\"` becomes\n// `100`, `\"2em\"` becomes `2` — and `makeResponsive` sets `width=\"100%\"` on every\n// mermaid root, so an SVG with no usable viewBox would rasterize 100px wide with\n// no error. Accept only a unitless number or an explicit `px`.\nconst PIXEL_LENGTH = new RegExp(String.raw`^\\s*(?:${NUMBER})(?:px)?\\s*$`, 'i');\n\nconst parsePixelLength = (value: string | null): number | null => {\n if (!PIXEL_LENGTH.test(value ?? '')) return null;\n\n const parsed = Number.parseFloat(value ?? '');\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n};\n\nexport const parseSvgSize = (svg: string) => {\n const doc = new DOMParser().parseFromString(withSvgNamespace(svg), 'image/svg+xml');\n const element = doc.documentElement;\n\n const viewBox = element\n .getAttribute('viewBox')\n ?.split(/[\\s,]+/)\n .map(Number);\n // `> 0`, not truthiness: a negative extent is accepted by a truthy check, and\n // negative canvas dimensions silently fall back to the 300x150 default — an\n // export at the wrong size with no error. Falling through to width/height is\n // the better answer, since those are usually still valid.\n if (viewBox?.length === 4 && viewBox.every((value) => Number.isFinite(value))) {\n const [, , width, height] = viewBox;\n if (width !== undefined && height !== undefined && width > 0 && height > 0) {\n return { width, height };\n }\n }\n\n const width = parsePixelLength(element.getAttribute('width'));\n const height = parsePixelLength(element.getAttribute('height'));\n\n return width !== null && height !== null ? { width, height } : null;\n};\n\n// Resolve the themed page background so the exported PNG follows the active\n// brand and color scheme instead of a frozen literal. Falls back to `white`\n// (a CSS keyword, not a brand-locked hex) when the token is unset.\n//\n// The token holds Tailwind's bare channel triplet (\"249 250 251\") so utilities\n// can add an alpha. Canvas `fillStyle` rejects that form *silently* and keeps\n// its previous value (black), so wrap it back into rgb() before use.\nconst CHANNEL_TRIPLET = new RegExp(String.raw`^(?:${NUMBER})\\s+(?:${NUMBER})\\s+(?:${NUMBER})$`);\n\nexport const toCanvasColor = (token: string) => {\n const trimmed = token.trim();\n if (!trimmed) return 'white';\n\n // Only wrap a well-formed triplet. A malformed one (`1.2.3 4 5`) would produce\n // an invalid `rgb()` that `fillStyle` rejects silently, painting the PNG on\n // whatever colour was set before — passing it through unwrapped at least lets\n // a genuine CSS color value work.\n return CHANNEL_TRIPLET.test(trimmed) ? `rgb(${trimmed})` : trimmed;\n};\n\nconst resolveBackground = () =>\n toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue('--color-background'));\n\n/**\n * Rasterize SVG markup to a PNG blob at 2x for legible text.\n *\n * The SVG is loaded as a data URL rather than a blob URL: an <img> loading SVG\n * is treated as a foreign resource, so a blob URL would taint the canvas and\n * make toBlob throw a SecurityError. A background is painted first because a\n * transparent PNG reads as unusable when pasted into a slide deck.\n */\nexport const svgToPngBlob = async (svg: string, background?: string): Promise<Blob> => {\n const size = parseSvgSize(svg);\n if (!size) throw new Error('Cannot determine diagram dimensions.');\n\n const encoded = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(toSvgFileContent(svg))}`;\n\n const image = new Image();\n image.decoding = 'sync';\n await new Promise<void>((resolve, reject) => {\n image.onload = () => resolve();\n image.onerror = () => reject(new Error('Failed to load the diagram for export.'));\n image.src = encoded;\n });\n\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(size.width * PNG_SCALE);\n canvas.height = Math.round(size.height * PNG_SCALE);\n\n const context = canvas.getContext('2d');\n if (!context) throw new Error('Canvas is unavailable in this browser.');\n\n context.fillStyle = background ?? resolveBackground();\n context.fillRect(0, 0, canvas.width, canvas.height);\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n\n return new Promise<Blob>((resolve, reject) => {\n canvas.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error('Failed to encode the PNG.'))),\n 'image/png',\n );\n });\n};\n"],"mappings":";;;;;;;;;;AAWA,MAAM,YAAY;AAClB,MAAM,YAAY;AAClB,MAAM,YAAY;AA4BlB,MAAa,eAAe,EAC1B,MACA,UACA,WACA,oBACA,oBACW;CACX,MAAM,WAAW,cAEb,UAAU,SAAS,MAAM;EACvB,cAAc;GAAE,KAAK;GAAM,YAAY;EAAK;EAC5C,GAAI,qBAAqB,EAAE,UAAU,CAAC,eAAe,EAAE,IAAI,CAAC;CAC9D,CAAC,GACH,CAAC,MAAM,kBAAkB,CAC3B;CAEA,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CACpC,MAAM,CAAC,WAAW,gBAAgB,SAAS;EAAE,GAAG;EAAG,GAAG;CAAE,CAAC;CACzD,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CAEtD,gBAAgB;EACd,IAAI,CAAC,cAAc;EACnB,MAAM,aAAa,MAAqB;GACtC,IAAI,EAAE,QAAQ,UAAU;IACtB,EAAE,gBAAgB;IAClB,gBAAgB,KAAK;GACvB;EACF;EACA,SAAS,iBAAiB,WAAW,WAAW,EAAE,SAAS,KAAK,CAAC;EACjE,aAAa,SAAS,oBAAoB,WAAW,WAAW,EAAE,SAAS,KAAK,CAAC;CACnF,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,UAAU,OAKN,IAAI;CAEd,gBAAgB;EACd,MAAM,KAAK,aAAa;EACxB,IAAI,CAAC,IAAI;EAET,MAAM,WAAW,MAAkB;GACjC,IAAI,CAAC,EAAE,WAAW,CAAC,EAAE,SAAS;GAC9B,EAAE,eAAe;GACjB,MAAM,QAAQ,EAAE,SAAS,IAAI,MAAa;GAC1C,UAAU,MAAM,KAAK,IAAI,WAAW,KAAK,IAAI,WAAW,IAAI,KAAK,CAAC,CAAC;EACrE;EAEA,GAAG,iBAAiB,SAAS,SAAS,EAAE,SAAS,MAAM,CAAC;EACxD,aAAa,GAAG,oBAAoB,SAAS,OAAO;CAGtD,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,aAAa,OAAO,KAAK;CAE/B,MAAM,kBAAkB,aACrB,MAAwB;EACvB,IAAI,EAAE,WAAW,GAAG;EACpB,EAAE,eAAe;EACjB,WAAW,UAAU;EACrB,QAAQ,UAAU;GAChB,QAAQ,EAAE;GACV,QAAQ,EAAE;GACV,SAAS,UAAU;GACnB,SAAS,UAAU;EACrB;CACF,GACA,CAAC,SAAS,CACZ;CAEA,MAAM,kBAAkB,aAAa,MAAwB;EAC3D,IAAI,CAAC,QAAQ,SAAS;EACtB,WAAW,UAAU;EACrB,aAAa;GACX,GAAG,QAAQ,QAAQ,UAAU,EAAE,UAAU,QAAQ,QAAQ;GACzD,GAAG,QAAQ,QAAQ,UAAU,EAAE,UAAU,QAAQ,QAAQ;EAC3D,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,gBAAgB,kBAAkB;EACtC,QAAQ,UAAU;CACpB,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,kBAAkB;EACpC,SAAS,CAAC;EACV,aAAa;GAAE,GAAG;GAAG,GAAG;EAAE,CAAC;CAC7B,GAAG,CAAC,CAAC;CAEL,MAAM,WAAW,KAAK,IAAI,QAAQ,CAAC,IAAI,QAAS,UAAU,MAAM,KAAK,UAAU,MAAM;CAErF,MAAM,cAAc,aAAa,MAAwB;EACvD,IAAI,WAAW,SACb,EAAE,gBAAgB;CAEtB,GAAG,CAAC,CAAC;CAEL,MAAM,kBAAkB,aAAa,MAA4B;EAC/D,EAAE,gBAAgB;CACpB,GAAG,CAAC,CAAC;CAEL,MAAM,iBACJ,qBAAC,OAAD;EACE,MAAK;EACL,WAAW,GAAG,6BAA6B,gBAAgB,WAAW;EACtE,SAAS;EAHX,UAAA,CAKE,oBAAC,OAAD;GACE,MAAK;GACL,KAAK;GACL,WAAW,GACT,sEACA,gBAAgB,WAClB;GACA,aAAa;GACb,aAAa;GACb,WAAW;GACX,cAAc;GAEd,UAAA,oBAAC,OAAD;IACE,WAAW,GACT,8CACA,gBAAgB,6BAClB;IACA,OAAO,EAAE,WAAW,aAAa,UAAU,EAAE,MAAM,UAAU,EAAE,YAAY,MAAM,GAAG;IACpF,yBAAyB,EAAE,QAAQ,SAAS;GAC7C,CAAA;EACE,CAAA,GACL,qBAAC,OAAD;GACE,MAAK;GAIL,WAAU;GACV,SAAS;GANX,UAAA;IAQG,YACC,oBAAC,SAAD;KAAS,SAAQ;KAAa,WAAU;KAAM,gBAAA;KAC5C,UAAA,oBAAC,QAAD;MAAQ,MAAK;MAAQ,SAAQ;MAAU,SAAS;MAAa,UAAA;KAErD,CAAA;IACD,CAAA;IAEV,YACC,oBAAC,iBAAD;KAAiB,MAAM;KAAU,SAAQ;KAAY,MAAK;KAAU,SAAQ;IAAW,CAAA;IAExF,gBAAgB,QAAQ;IACzB,oBAAC,SAAD;KACE,SAAS,eAAe,oBAAoB;KAC5C,WAAU;KACV,gBAAA;KAEA,UAAA,oBAAC,QAAD;MACE,MAAK;MACL,SAAQ;MACR,cAAY,eAAe,oBAAoB;MAC/C,eAAe,iBAAiB,MAAM,CAAC,CAAC;MAEvC,UAAA,eACC,oBAAC,WAAD,EAAW,WAAU,YAAa,CAAA,IAElC,oBAAC,WAAD,EAAW,WAAU,YAAa,CAAA;KAE9B,CAAA;IACD,CAAA;GACN;EACF,CAAA,CAAA;;CAGP,IAAI,cACF,OAAO,aACL,oBAAC,OAAD;EACE,MAAK;EACL,eAAY;;;;;;;;;;;;;;;EAeZ,WAAU;EACV,SAAS;EAER,UAAA;CACE,CAAA,GACL,SAAS,IACX;CAGF,OACE,oBAAC,OAAD;EACE,WAAW,GACT,2EACA,SACF;EAEC,UAAA;CACE,CAAA;AAET;;;AC3PA,MAAM,YAAY;AAMlB,MAAM,eAAe;AACrB,MAAM,wBAAwB;AAO9B,MAAM,oBAAoB,QAAgB;CACxC,MAAM,UAAU,IAAI,KAAK;CACzB,MAAM,UAAU,QAAQ,MAAM,YAAY,CAAC,GAAG;CAE9C,IAAI,CAAC,WAAW,sBAAsB,KAAK,OAAO,GAAG,OAAO;CAE5D,OAAO,QAAQ,QAAQ,YAAY,2CAAyC;AAC9E;AAEA,MAAa,oBAAoB,QAC/B,2CAA2C,iBAAiB,GAAG,CAAC,CAAC,KAAK,EAAE;AAM1E,MAAM,SAAS,OAAO,GAAG;AAMzB,MAAM,eAAe,IAAI,OAAO,OAAO,GAAG,UAAU,OAAO,eAAe,GAAG;AAE7E,MAAM,oBAAoB,UAAwC;CAChE,IAAI,CAAC,aAAa,KAAK,SAAS,EAAE,GAAG,OAAO;CAE5C,MAAM,SAAS,OAAO,WAAW,SAAS,EAAE;CAE5C,OAAO,OAAO,SAAS,MAAM,KAAK,SAAS,IAAI,SAAS;AAC1D;AAEA,MAAa,gBAAgB,QAAgB;CAE3C,MAAM,UADM,IAAI,UAAU,CAAC,CAAC,gBAAgB,iBAAiB,GAAG,GAAG,eACjD,CAAC,CAAC;CAEpB,MAAM,UAAU,QACb,aAAa,SAAS,CAAC,EACtB,MAAM,QAAQ,CAAC,CAChB,IAAI,MAAM;CAKb,IAAI,SAAS,WAAW,KAAK,QAAQ,OAAO,UAAU,OAAO,SAAS,KAAK,CAAC,GAAG;EAC7E,MAAM,KAAK,OAAO,UAAU;EAC5B,IAAI,UAAU,KAAA,KAAa,WAAW,KAAA,KAAa,QAAQ,KAAK,SAAS,GACvE,OAAO;GAAE;GAAO;EAAO;CAE3B;CAEA,MAAM,QAAQ,iBAAiB,QAAQ,aAAa,OAAO,CAAC;CAC5D,MAAM,SAAS,iBAAiB,QAAQ,aAAa,QAAQ,CAAC;CAE9D,OAAO,UAAU,QAAQ,WAAW,OAAO;EAAE;EAAO;CAAO,IAAI;AACjE;AASA,MAAM,kBAAkB,IAAI,OAAO,OAAO,GAAG,OAAO,OAAO,SAAS,OAAO,SAAS,OAAO,GAAG;AAE9F,MAAa,iBAAiB,UAAkB;CAC9C,MAAM,UAAU,MAAM,KAAK;CAC3B,IAAI,CAAC,SAAS,OAAO;CAMrB,OAAO,gBAAgB,KAAK,OAAO,IAAI,OAAO,QAAQ,KAAK;AAC7D;AAEA,MAAM,0BACJ,cAAc,iBAAiB,SAAS,eAAe,CAAC,CAAC,iBAAiB,oBAAoB,CAAC;;;;;;;;;AAUjG,MAAa,eAAe,OAAO,KAAa,eAAuC;CACrF,MAAM,OAAO,aAAa,GAAG;CAC7B,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,sCAAsC;CAEjE,MAAM,UAAU,oCAAoC,mBAAmB,iBAAiB,GAAG,CAAC;CAE5F,MAAM,QAAQ,IAAI,MAAM;CACxB,MAAM,WAAW;CACjB,MAAM,IAAI,SAAe,SAAS,WAAW;EAC3C,MAAM,eAAe,QAAQ;EAC7B,MAAM,gBAAgB,uBAAO,IAAI,MAAM,wCAAwC,CAAC;EAChF,MAAM,MAAM;CACd,CAAC;CAED,MAAM,SAAS,SAAS,cAAc,QAAQ;CAC9C,OAAO,QAAQ,KAAK,MAAM,KAAK,QAAQ,SAAS;CAChD,OAAO,SAAS,KAAK,MAAM,KAAK,SAAS,SAAS;CAElD,MAAM,UAAU,OAAO,WAAW,IAAI;CACtC,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,wCAAwC;CAEtE,QAAQ,YAAY,cAAc,kBAAkB;CACpD,QAAQ,SAAS,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;CAClD,QAAQ,UAAU,OAAO,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;CAE1D,OAAO,IAAI,SAAe,SAAS,WAAW;EAC5C,OAAO,QACJ,SAAU,OAAO,QAAQ,IAAI,IAAI,uBAAO,IAAI,MAAM,2BAA2B,CAAC,GAC/E,WACF;CACF,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"ZoomableSvg-CNIzRHKH.js","names":[],"sources":["../src/components/ZoomableSvg/ZoomableSvg.tsx","../src/components/ZoomableSvg/exportSvg.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport DOMPurify from 'dompurify';\n\nimport { ClipboardButton } from '../../blocks/ClipboardButton';\nimport { Maximize2, Minimize2 } from '../../icons';\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\nimport { Tooltip } from '../Tooltip';\n\nconst MIN_SCALE = 0.5;\nconst MAX_SCALE = 3;\nconst ZOOM_STEP = 0.1;\n\ntype Props = {\n /** Raw SVG markup. Sanitized internally with DOMPurify (SVG profile) before rendering, so it is\n * safe even when it originates from user/LLM-controlled content. Non-SVG HTML is stripped. */\n html: string;\n copyText?: string;\n className?: string;\n /**\n * Opt in to keeping `<foreignObject>` elements through sanitization. Off by\n * default — the SVG profile drops `<foreignObject>` so no HTML subtree can\n * survive. Only enable when the caller pre-flattens each `<foreignObject>` to\n * bare text (the SVG profile still strips any HTML children even when the\n * element itself is allowed). `MermaidDiagram` sets this for node/icon labels.\n */\n allowForeignObject?: boolean;\n /**\n * Extra toolbar controls, rendered between the copy and fullscreen buttons.\n *\n * Injected rather than built in, so export behaviour — filenames,\n * rasterization, error reporting — stays with the consumer and this component\n * keeps shipping in the lazy `@keboola/design/mermaid` chunk with no download\n * dependencies of its own. Pass `ExportMenu` here. Receives the sanitized\n * SVG so an exporter writes exactly what is on screen.\n */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const ZoomableSvg = ({\n html,\n copyText,\n className,\n allowForeignObject,\n renderActions,\n}: Props) => {\n const safeHtml = useMemo(\n () =>\n DOMPurify.sanitize(html, {\n USE_PROFILES: { svg: true, svgFilters: true },\n ...(allowForeignObject ? { ADD_TAGS: ['foreignObject'] } : {}),\n }),\n [html, allowForeignObject],\n );\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [scale, setScale] = useState(1);\n const [translate, setTranslate] = useState({ x: 0, y: 0 });\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n useEffect(() => {\n if (!isFullscreen) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n setIsFullscreen(false);\n }\n };\n document.addEventListener('keydown', onKeyDown, { capture: true });\n return () => document.removeEventListener('keydown', onKeyDown, { capture: true });\n }, [isFullscreen]);\n\n const dragRef = useRef<{\n startX: number;\n startY: number;\n startTx: number;\n startTy: number;\n } | null>(null);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n const delta = e.deltaY > 0 ? -ZOOM_STEP : ZOOM_STEP;\n setScale((s) => Math.min(MAX_SCALE, Math.max(MIN_SCALE, s + delta)));\n };\n\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n // Re-bind when toggling fullscreen: the portal/inline switch remounts the\n // container element, so the listener must attach to the new node.\n }, [isFullscreen]);\n\n const didDragRef = useRef(false);\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (e.button !== 0) return;\n e.preventDefault();\n didDragRef.current = false;\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n startTx: translate.x,\n startTy: translate.y,\n };\n },\n [translate],\n );\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!dragRef.current) return;\n didDragRef.current = true;\n setTranslate({\n x: dragRef.current.startTx + e.clientX - dragRef.current.startX,\n y: dragRef.current.startTy + e.clientY - dragRef.current.startY,\n });\n }, []);\n\n const handleMouseUp = useCallback(() => {\n dragRef.current = null;\n }, []);\n\n const handleReset = useCallback(() => {\n setScale(1);\n setTranslate({ x: 0, y: 0 });\n }, []);\n\n const isZoomed = Math.abs(scale - 1) > 0.001 || translate.x !== 0 || translate.y !== 0;\n\n const handleClick = useCallback((e: React.MouseEvent) => {\n if (didDragRef.current) {\n e.stopPropagation();\n }\n }, []);\n\n const stopPropagation = useCallback((e: React.SyntheticEvent) => {\n e.stopPropagation();\n }, []);\n\n const diagramContent = (\n <div\n role=\"presentation\"\n className={cn('tw:group/zoom tw:relative', isFullscreen && 'tw:h-full')}\n onClick={handleClick}\n >\n <div\n role=\"presentation\"\n ref={containerRef}\n className={cn(\n 'tw:overflow-hidden tw:cursor-grab tw:active:cursor-grabbing tw:p-3',\n isFullscreen && 'tw:h-full',\n )}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n >\n <div\n className={cn(\n 'tw:flex tw:justify-center tw:origin-center',\n isFullscreen && 'tw:h-full tw:[&>svg]:h-full',\n )}\n style={{ transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})` }}\n dangerouslySetInnerHTML={{ __html: safeHtml }}\n />\n </div>\n <div\n role=\"presentation\"\n // `focus-within` as well as hover: the toolbar is opacity-0 but still in\n // the tab order, so without this a keyboard user tabs through invisible\n // controls with no visible focus ring.\n className=\"tw:absolute tw:right-1 tw:top-1 tw:flex tw:gap-1 tw:opacity-0 tw:transition-opacity tw:focus-within:opacity-100 tw:group-hover/zoom:opacity-100\"\n onClick={stopPropagation}\n >\n {isZoomed && (\n <Tooltip tooltip=\"Reset zoom\" placement=\"top\" triggerAsChild>\n <Button size=\"small\" variant=\"outline\" onClick={handleReset}>\n Reset\n </Button>\n </Tooltip>\n )}\n {copyText && (\n <ClipboardButton text={copyText} tooltip=\"Copy code\" size=\"icon-sm\" variant=\"outline\" />\n )}\n {renderActions?.(safeHtml)}\n <Tooltip\n tooltip={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n placement=\"top\"\n triggerAsChild\n >\n <Button\n size=\"icon-sm\"\n variant=\"outline\"\n aria-label={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n onClick={() => setIsFullscreen((f) => !f)}\n >\n {isFullscreen ? (\n <Minimize2 className=\"tw:size-4\" />\n ) : (\n <Maximize2 className=\"tw:size-4\" />\n )}\n </Button>\n </Tooltip>\n </div>\n </div>\n );\n\n if (isFullscreen) {\n return createPortal(\n <div\n role=\"presentation\"\n data-testid=\"zoomable-svg-fullscreen\"\n /**\n * Stacking contract for this overlay, which portals to `document.body`.\n *\n * - Sits at z-1051, the Modal/Sheet band: above page chrome.\n * - Stays *below* the floating-panel layer (z-1055: DropdownMenu,\n * Popover, Select, Combobox), which portals to `document.body` too —\n * an overlay above it hides any menu opened from the toolbar.\n * - `Tooltip` (z-1060) renders above, as it does over a Modal.\n * - `SpotlightBackdrop` (z-1056) dims this overlay rather than sitting\n * under it — by design, since it deliberately covers the portalled\n * surface tier so a tour's dim can't be punched through.\n * - An app may clamp poppers into this same band, making it a tie that\n * DOM order settles; Radix mounts its portal after this one.\n */\n className=\"tw:fixed tw:inset-0 tw:z-[1051] tw:bg-muted tw:p-4 tailwindcss-preflight\"\n onClick={stopPropagation}\n >\n {diagramContent}\n </div>,\n document.body,\n );\n }\n\n return (\n <div\n className={cn(\n 'tw:overflow-hidden tw:rounded-md tw:border tw:border-border tw:bg-muted',\n className,\n )}\n >\n {diagramContent}\n </div>\n );\n};\n","const PNG_SCALE = 2;\n\n// The root `<svg …>` tag, so the namespace check looks only at its attributes.\n// A plain `includes('xmlns=')` would also match a nested element or body text,\n// and would miss `xmlns = \"…\"` — adding a second declaration, which parsers\n// reject outright with \"Attribute xmlns redefined\".\nconst ROOT_SVG_TAG = /^<svg\\b[^>]*>/i;\nconst HAS_DEFAULT_NAMESPACE = /\\bxmlns\\s*=/i;\n\n// A standalone SVG file needs the namespace declaration; mermaid's inline output\n// omits it because an inline <svg> inherits it from the host document.\n// Trim before matching: the anchored `^<svg` misses markup that arrives with a\n// leading newline or indentation, which would emit a standalone file with no\n// namespace — unopenable in an image viewer.\nconst withSvgNamespace = (svg: string) => {\n const trimmed = svg.trim();\n const rootTag = trimmed.match(ROOT_SVG_TAG)?.[0];\n\n if (!rootTag || HAS_DEFAULT_NAMESPACE.test(rootTag)) return trimmed;\n\n return trimmed.replace(/^<svg\\b/i, '<svg xmlns=\"http://www.w3.org/2000/svg\"');\n};\n\nexport const toSvgFileContent = (svg: string) =>\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${withSvgNamespace(svg).trim()}\\n`;\n\n// A single decimal number: `12`, `12.5`, `.5`. Deliberately stricter than\n// `[\\d.]+`, which also matches `1.2.3` — and `parseFloat` truncates that to\n// `1.2` rather than rejecting it, so a malformed value would pass as a plausible\n// one.\nconst NUMBER = String.raw`\\d+(?:\\.\\d+)?|\\.\\d+`;\n\n// `parseFloat` happily reads a relative length as a number — `\"100%\"` becomes\n// `100`, `\"2em\"` becomes `2` — and `makeResponsive` sets `width=\"100%\"` on every\n// mermaid root, so an SVG with no usable viewBox would rasterize 100px wide with\n// no error. Accept only a unitless number or an explicit `px`.\nconst PIXEL_LENGTH = new RegExp(String.raw`^\\s*(?:${NUMBER})(?:px)?\\s*$`, 'i');\n\nconst parsePixelLength = (value: string | null): number | null => {\n if (!PIXEL_LENGTH.test(value ?? '')) return null;\n\n const parsed = Number.parseFloat(value ?? '');\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n};\n\nexport const parseSvgSize = (svg: string) => {\n const doc = new DOMParser().parseFromString(withSvgNamespace(svg), 'image/svg+xml');\n const element = doc.documentElement;\n\n const viewBox = element\n .getAttribute('viewBox')\n ?.split(/[\\s,]+/)\n .map(Number);\n // `> 0`, not truthiness: a negative extent is accepted by a truthy check, and\n // negative canvas dimensions silently fall back to the 300x150 default — an\n // export at the wrong size with no error. Falling through to width/height is\n // the better answer, since those are usually still valid.\n if (viewBox?.length === 4 && viewBox.every((value) => Number.isFinite(value))) {\n const [, , width, height] = viewBox;\n if (width !== undefined && height !== undefined && width > 0 && height > 0) {\n return { width, height };\n }\n }\n\n const width = parsePixelLength(element.getAttribute('width'));\n const height = parsePixelLength(element.getAttribute('height'));\n\n return width !== null && height !== null ? { width, height } : null;\n};\n\n// Resolve the themed page background so the exported PNG follows the active\n// brand and color scheme instead of a frozen literal. Falls back to `white`\n// (a CSS keyword, not a brand-locked hex) when the token is unset.\n//\n// The token holds Tailwind's bare channel triplet (\"249 250 251\") so utilities\n// can add an alpha. Canvas `fillStyle` rejects that form *silently* and keeps\n// its previous value (black), so wrap it back into rgb() before use.\nconst CHANNEL_TRIPLET = new RegExp(String.raw`^(?:${NUMBER})\\s+(?:${NUMBER})\\s+(?:${NUMBER})$`);\n\nexport const toCanvasColor = (token: string) => {\n const trimmed = token.trim();\n if (!trimmed) return 'white';\n\n // Only wrap a well-formed triplet. A malformed one (`1.2.3 4 5`) would produce\n // an invalid `rgb()` that `fillStyle` rejects silently, painting the PNG on\n // whatever colour was set before — passing it through unwrapped at least lets\n // a genuine CSS color value work.\n return CHANNEL_TRIPLET.test(trimmed) ? `rgb(${trimmed})` : trimmed;\n};\n\nconst resolveBackground = () =>\n toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue('--color-background'));\n\n/**\n * Rasterize SVG markup to a PNG blob at 2x for legible text.\n *\n * The SVG is loaded as a data URL rather than a blob URL: an <img> loading SVG\n * is treated as a foreign resource, so a blob URL would taint the canvas and\n * make toBlob throw a SecurityError. A background is painted first because a\n * transparent PNG reads as unusable when pasted into a slide deck.\n */\nexport const svgToPngBlob = async (svg: string, background?: string): Promise<Blob> => {\n const size = parseSvgSize(svg);\n if (!size) throw new Error('Cannot determine diagram dimensions.');\n\n const encoded = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(toSvgFileContent(svg))}`;\n\n const image = new Image();\n image.decoding = 'sync';\n await new Promise<void>((resolve, reject) => {\n image.onload = () => resolve();\n image.onerror = () => reject(new Error('Failed to load the diagram for export.'));\n image.src = encoded;\n });\n\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(size.width * PNG_SCALE);\n canvas.height = Math.round(size.height * PNG_SCALE);\n\n const context = canvas.getContext('2d');\n if (!context) throw new Error('Canvas is unavailable in this browser.');\n\n context.fillStyle = background ?? resolveBackground();\n context.fillRect(0, 0, canvas.width, canvas.height);\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n\n return new Promise<Blob>((resolve, reject) => {\n canvas.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error('Failed to encode the PNG.'))),\n 'image/png',\n );\n });\n};\n"],"mappings":"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"}
|
|
@@ -1,35 +1,5 @@
|
|
|
1
|
+
import { DEFAULT_COLOR_SCHEME, defaultTheme } from "./defaults-CTfvj2KB.js";
|
|
1
2
|
import { createContext, use } from "react";
|
|
2
|
-
import { keboolaLegacySidebar, keboolaLegacyTopnav } from "@keboola/brand-registry";
|
|
3
|
-
//#region src/components/ThemeProvider/utils.ts
|
|
4
|
-
const createTheme = (brand) => ({
|
|
5
|
-
id: brand.id,
|
|
6
|
-
name: brand.name,
|
|
7
|
-
shell: brand.shell,
|
|
8
|
-
logo: brand.logo
|
|
9
|
-
});
|
|
10
|
-
const createCssVars = () => {
|
|
11
|
-
const vars = {};
|
|
12
|
-
return {
|
|
13
|
-
set: (name, value) => {
|
|
14
|
-
if (value !== void 0) vars[name] = value;
|
|
15
|
-
},
|
|
16
|
-
expose: () => ({ ...vars })
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region src/components/ThemeProvider/defaults.ts
|
|
21
|
-
const keboolaLegacyIds = [keboolaLegacySidebar.id, keboolaLegacyTopnav.id];
|
|
22
|
-
const DEFAULT_COLOR_SCHEME = "light";
|
|
23
|
-
const DEFAULT_BRAND_ID = "design-system";
|
|
24
|
-
const defaultBrand = {
|
|
25
|
-
id: DEFAULT_BRAND_ID,
|
|
26
|
-
name: "Design System",
|
|
27
|
-
shell: "sidebar",
|
|
28
|
-
theme: {}
|
|
29
|
-
};
|
|
30
|
-
const defaultTheme = createTheme(defaultBrand);
|
|
31
|
-
const DEFAULT_BRANDS = [];
|
|
32
|
-
//#endregion
|
|
33
3
|
//#region src/components/ThemeProvider/context.tsx
|
|
34
4
|
const noop = () => void 0;
|
|
35
5
|
const defaultContext = {
|
|
@@ -57,6 +27,6 @@ const useTheme = () => use(ThemeContext);
|
|
|
57
27
|
const ArgoDesignContext = createContext(true);
|
|
58
28
|
const useArgoDesign = () => use(ArgoDesignContext);
|
|
59
29
|
//#endregion
|
|
60
|
-
export { ArgoDesignContext,
|
|
30
|
+
export { ArgoDesignContext, ThemeContext, useArgoDesign, useTheme };
|
|
61
31
|
|
|
62
|
-
//# sourceMappingURL=context-
|
|
32
|
+
//# sourceMappingURL=context-BrNtMc1H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-BrNtMc1H.js","names":[],"sources":["../src/components/ThemeProvider/context.tsx"],"sourcesContent":["import { createContext, use } from 'react';\n\nimport { DEFAULT_COLOR_SCHEME, defaultTheme } from './defaults';\nimport type { Theme } from './types';\nimport type { useBrandState } from './useBrandState';\nimport type { useColorSchemeState } from './useColorSchemeState';\n\nexport type ThemeContextValue = ReturnType<typeof useColorSchemeState> &\n ReturnType<typeof useBrandState> & {\n themes: Theme[];\n currentTheme: Theme;\n };\n\nconst noop = () => void 0;\n\nconst defaultContext: ThemeContextValue = {\n scheme: DEFAULT_COLOR_SCHEME,\n resolvedScheme: DEFAULT_COLOR_SCHEME,\n setScheme: noop,\n brandId: defaultTheme.id,\n setBrand: noop,\n\n themes: [defaultTheme],\n currentTheme: defaultTheme,\n};\n\nexport const ThemeContext = createContext(defaultContext);\n\nexport const useTheme = () => use(ThemeContext);\n\n/**\n * TEMPORARY — kbc-ui-internal only.\n *\n * Flags whether the subtree renders the argo design language. Defaults to argo\n * (`true`) — the modern default; legacy chrome is the exception. It exists\n * solely to bridge kbc-ui while its chrome is migrated off the legacy design\n * language: kbc-ui provides `false` for legacy brands/surfaces (see its\n * `AppThemeProvider`) and reads it via `useArgoDesign`. `ThemeProvider` does\n * not set it — argo is decoupled from the brand. Once every kbc-ui surface has\n * been migrated, this context and its hook can be deleted.\n */\nexport const ArgoDesignContext = createContext<boolean>(true);\n\nexport const useArgoDesign = () => use(ArgoDesignContext);\n"],"mappings":";;;AAaA,MAAM,aAAa,KAAK;AAExB,MAAM,iBAAoC;CACxC,QAAQ;CACR,gBAAgB;CAChB,WAAW;CACX,SAAS,aAAa;CACtB,UAAU;CAEV,QAAQ,CAAC,YAAY;CACrB,cAAc;AAChB;AAEA,MAAa,eAAe,cAAc,cAAc;AAExD,MAAa,iBAAiB,IAAI,YAAY;;;;;;;;;;;;AAa9C,MAAa,oBAAoB,cAAuB,IAAI;AAE5D,MAAa,sBAAsB,IAAI,iBAAiB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { keboolaLegacySidebar, keboolaLegacyTopnav } from "@keboola/brand-registry";
|
|
2
|
+
//#region src/components/ThemeProvider/utils.ts
|
|
3
|
+
const createTheme = (brand) => ({
|
|
4
|
+
id: brand.id,
|
|
5
|
+
name: brand.name,
|
|
6
|
+
shell: brand.shell,
|
|
7
|
+
logo: brand.logo
|
|
8
|
+
});
|
|
9
|
+
const createCssVars = () => {
|
|
10
|
+
const vars = {};
|
|
11
|
+
return {
|
|
12
|
+
set: (name, value) => {
|
|
13
|
+
if (value !== void 0) vars[name] = value;
|
|
14
|
+
},
|
|
15
|
+
expose: () => ({ ...vars })
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/components/ThemeProvider/defaults.ts
|
|
20
|
+
const keboolaLegacyIds = [keboolaLegacySidebar.id, keboolaLegacyTopnav.id];
|
|
21
|
+
const DEFAULT_COLOR_SCHEME = "light";
|
|
22
|
+
const DEFAULT_BRAND_ID = "design-system";
|
|
23
|
+
const defaultBrand = {
|
|
24
|
+
id: DEFAULT_BRAND_ID,
|
|
25
|
+
name: "Design System",
|
|
26
|
+
shell: "sidebar",
|
|
27
|
+
theme: {}
|
|
28
|
+
};
|
|
29
|
+
const defaultTheme = createTheme(defaultBrand);
|
|
30
|
+
const DEFAULT_BRANDS = [];
|
|
31
|
+
//#endregion
|
|
32
|
+
export { DEFAULT_BRANDS, DEFAULT_BRAND_ID, DEFAULT_COLOR_SCHEME, createCssVars, createTheme, defaultBrand, defaultTheme, keboolaLegacyIds };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=defaults-CTfvj2KB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults-CTfvj2KB.js","names":[],"sources":["../src/components/ThemeProvider/utils.ts","../src/components/ThemeProvider/defaults.ts"],"sourcesContent":["import type { Brand } from '@keboola/brand-registry';\n\nimport type { Theme } from './types';\n\nexport const createTheme = (brand: Brand): Theme => ({\n id: brand.id,\n name: brand.name,\n shell: brand.shell,\n logo: brand.logo,\n});\n\nexport type CssVars = {\n set: (name: string, value: string | undefined) => void;\n expose: () => Record<string, string>;\n};\n\nexport const createCssVars = (): CssVars => {\n const vars: Record<string, string> = {};\n return {\n set: (name, value) => {\n if (value !== undefined) vars[name] = value;\n },\n expose: () => ({ ...vars }),\n };\n};\n","import type { Brand } from '@keboola/brand-registry';\nimport { keboolaLegacySidebar, keboolaLegacyTopnav } from '@keboola/brand-registry';\n\nimport type { ResolvedColorScheme } from './types';\nimport { createTheme } from './utils';\n\nexport const keboolaLegacyIds = [keboolaLegacySidebar.id, keboolaLegacyTopnav.id];\nexport const DEFAULT_COLOR_SCHEME: ResolvedColorScheme = 'light';\n\n// Sentinel active-brand id that maps to no registry brand. It resolves to\n// `defaultBrand` below, whose empty theme injects nothing — so the design-system\n// stylesheet defaults (`:root` / `[data-theme='dark']`) provide every token.\nexport const DEFAULT_BRAND_ID = 'design-system';\n\n// The \"no brand\" fallback: an empty theme → no CSS vars injected → the\n// stylesheet defaults win. Its shell/name still drive AppShell + switcher label.\nexport const defaultBrand: Brand = {\n id: DEFAULT_BRAND_ID,\n name: 'Design System',\n shell: 'sidebar',\n theme: {},\n};\nexport const defaultTheme = createTheme(defaultBrand);\n\nexport const DEFAULT_BRANDS: Brand[] = [];\n"],"mappings":";;AAIA,MAAa,eAAe,WAAyB;CACnD,IAAI,MAAM;CACV,MAAM,MAAM;CACZ,OAAO,MAAM;CACb,MAAM,MAAM;AACd;AAOA,MAAa,sBAA+B;CAC1C,MAAM,OAA+B,CAAC;CACtC,OAAO;EACL,MAAM,MAAM,UAAU;GACpB,IAAI,UAAU,KAAA,GAAW,KAAK,QAAQ;EACxC;EACA,eAAe,EAAE,GAAG,KAAK;CAC3B;AACF;;;AClBA,MAAa,mBAAmB,CAAC,qBAAqB,IAAI,oBAAoB,EAAE;AAChF,MAAa,uBAA4C;AAKzD,MAAa,mBAAmB;AAIhC,MAAa,eAAsB;CACjC,IAAI;CACJ,MAAM;CACN,OAAO;CACP,OAAO,CAAC;AACV;AACA,MAAa,eAAe,YAAY,YAAY;AAEpD,MAAa,iBAA0B,CAAC"}
|
package/dist/editors.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./types-BPcAjMG0.js";
|
|
2
|
+
import { ChangeClassification, FieldItemProps, MergeConflict } from "./FieldItem-vhIJW4pj.js";
|
|
2
3
|
import { ComponentProps, ReactNode } from "react";
|
|
3
4
|
import { CompletionSource } from "@codemirror/autocomplete";
|
|
4
5
|
import { EditorView } from "@codemirror/view";
|
|
@@ -108,6 +109,15 @@ type Props$3 = {
|
|
|
108
109
|
* gets variables spelled the way the rest of the platform writes them.
|
|
109
110
|
*/
|
|
110
111
|
variables?: EditorVariable[];
|
|
112
|
+
/**
|
|
113
|
+
* Whether the completion popup runs at all.
|
|
114
|
+
*
|
|
115
|
+
* - `false` silences every source, the *language's* own vocabulary included.
|
|
116
|
+
* - For a field highlighted as a language nobody authors there: pasted `.env` and a
|
|
117
|
+
* cURL command sit in shell mode for its colours, and shell's `ls`, `sudo`, `vim`
|
|
118
|
+
* are noise over content we cannot predict.
|
|
119
|
+
*/
|
|
120
|
+
withCompletions?: boolean;
|
|
111
121
|
extraKeys?: Record<string, () => void>;
|
|
112
122
|
withToggleCommentHint?: boolean;
|
|
113
123
|
withAutofocus?: boolean;
|
|
@@ -132,7 +142,7 @@ type Props$3 = {
|
|
|
132
142
|
readOnly?: boolean;
|
|
133
143
|
onChange: (value: string) => void;
|
|
134
144
|
});
|
|
135
|
-
declare const CodeEditor: ({ value, previousValue, onChange, variant, mode, placeholder, ariaLabel, ariaLabelledBy, ariaDescribedBy, ariaInvalid, ariaRequired, allowBlankDocument, onBlur, searchQuery, searchMatchIndex, readOnly, inputLocked, autocompletions, completionSource, variables, extraKeys, withToggleCommentHint, withAutofocus, withLineNumbers, withLineWrapping, withCollapseUnchanged, withCopyButton, completeAny, help, helpPostfix, renderAdditionalButtons, className }: Props$3) => import("react/jsx-runtime").JSX.Element;
|
|
145
|
+
declare const CodeEditor: ({ value, previousValue, onChange, variant, mode, placeholder, ariaLabel, ariaLabelledBy, ariaDescribedBy, ariaInvalid, ariaRequired, allowBlankDocument, onBlur, searchQuery, searchMatchIndex, readOnly, inputLocked, autocompletions, completionSource, variables, withCompletions, extraKeys, withToggleCommentHint, withAutofocus, withLineNumbers, withLineWrapping, withCollapseUnchanged, withCopyButton, completeAny, help, helpPostfix, renderAdditionalButtons, className }: Props$3) => import("react/jsx-runtime").JSX.Element;
|
|
136
146
|
//#endregion
|
|
137
147
|
//#region src/components/CodeEditor/highlighting.d.ts
|
|
138
148
|
type HighlightedLines = {
|