@keboola/design 15.0.0 → 16.0.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 +6 -5
- package/CHANGELOG.md +94 -0
- package/COMPONENT-API.md +62 -61
- package/dist/{AIKit-CaAW4GLx.js → AIKit-Cf5plya2.js} +381 -224
- package/dist/AIKit-Cf5plya2.js.map +1 -0
- package/dist/{Alert-Chz6KZ7e.js → Alert-DziS8n1H.js} +12 -19
- package/dist/{Alert-Chz6KZ7e.js.map → Alert-DziS8n1H.js.map} +1 -1
- package/dist/{AlertModal-D4AtpvLS.js → AlertModal-De04fFoy.js} +16 -26
- package/dist/AlertModal-De04fFoy.js.map +1 -0
- package/dist/{AppShell-C8V1KRr_.js → AppShell-BUa3U7-e.js} +6 -9
- package/dist/{AppShell-C8V1KRr_.js.map → AppShell-BUa3U7-e.js.map} +1 -1
- package/dist/{AutoSaveTextarea-BbMhC5Aq.js → AutoSaveTextarea-CXHOQSun.js} +4 -5
- package/dist/{AutoSaveTextarea-BbMhC5Aq.js.map → AutoSaveTextarea-CXHOQSun.js.map} +1 -1
- package/dist/{Badge-5GHIsgRS.js → Badge-CFRhducL.js} +18 -23
- package/dist/Badge-CFRhducL.js.map +1 -0
- package/dist/{BrandEditor-CTGtQUFZ.js → BrandEditor-hiLBX7az.js} +16 -23
- package/dist/{BrandEditor-CTGtQUFZ.js.map → BrandEditor-hiLBX7az.js.map} +1 -1
- package/dist/{BrandLogo-DkESE19K.js → BrandLogo-Dn7hhp2c.js} +4 -5
- package/dist/{BrandLogo-DkESE19K.js.map → BrandLogo-Dn7hhp2c.js.map} +1 -1
- package/dist/{Breadcrumb-B2YSNON4.js → Breadcrumb-uGFEIjFF.js} +17 -28
- package/dist/{Breadcrumb-B2YSNON4.js.map → Breadcrumb-uGFEIjFF.js.map} +1 -1
- package/dist/{Button-BNkyYU8u.js → Button-DbvGzEDb.js} +24 -20
- package/dist/Button-DbvGzEDb.js.map +1 -0
- package/dist/{Calendar-BnKi1kPu.js → Calendar-lJBTETbk.js} +752 -905
- package/dist/Calendar-lJBTETbk.js.map +1 -0
- package/dist/{Card-DxjGiqH8.js → Card-VIPfOVW5.js} +8 -14
- package/dist/{Card-DxjGiqH8.js.map → Card-VIPfOVW5.js.map} +1 -1
- package/dist/{Checkbox-CHDDJyAA.js → Checkbox-B2jLlyaO.js} +6 -8
- package/dist/{Checkbox-CHDDJyAA.js.map → Checkbox-B2jLlyaO.js.map} +1 -1
- package/dist/{Clipboard-DlwVZS1P.js → Clipboard-fAkDdpEu.js} +4 -5
- package/dist/{Clipboard-DlwVZS1P.js.map → Clipboard-fAkDdpEu.js.map} +1 -1
- package/dist/{ClipboardButton-B1Hr_n_Z.js → ClipboardButton-71Ugbl8c.js} +6 -8
- package/dist/{ClipboardButton-B1Hr_n_Z.js.map → ClipboardButton-71Ugbl8c.js.map} +1 -1
- package/dist/{CodeEditor-DVSPdfdo.js → CodeEditor-D_b-ZCng.js} +19 -31
- package/dist/{CodeEditor-DVSPdfdo.js.map → CodeEditor-D_b-ZCng.js.map} +1 -1
- package/dist/{Collapsible-DD4xTL75.js → Collapsible-zsXk4Vpp.js} +5 -8
- package/dist/{Collapsible-DD4xTL75.js.map → Collapsible-zsXk4Vpp.js.map} +1 -1
- package/dist/{ColorInput-B_eZIu39.js → ColorInput-Cjr1jkvy.js} +9 -12
- package/dist/{ColorInput-B_eZIu39.js.map → ColorInput-Cjr1jkvy.js.map} +1 -1
- package/dist/{ColorModeSwitch-B6UEzG0H.js → ColorModeSwitch-CuPYnJ2V.js} +5 -6
- package/dist/{ColorModeSwitch-B6UEzG0H.js.map → ColorModeSwitch-CuPYnJ2V.js.map} +1 -1
- package/dist/{Combobox-CaKqgstG.js → Combobox-DYjvYgl3.js} +38 -67
- package/dist/Combobox-DYjvYgl3.js.map +1 -0
- package/dist/{Command-DhXmqFLT.js → Command-BcTb6GsR.js} +14 -24
- package/dist/{Command-DhXmqFLT.js.map → Command-BcTb6GsR.js.map} +1 -1
- package/dist/{CopyField-D0Pg4Z0R.js → CopyField-CnwAvQz9.js} +16 -28
- package/dist/{CopyField-D0Pg4Z0R.js.map → CopyField-CnwAvQz9.js.map} +1 -1
- package/dist/{DateInput-BgbMDJkm.js → DateInput-DJNX7Vdx.js} +8 -10
- package/dist/{DateInput-BgbMDJkm.js.map → DateInput-DJNX7Vdx.js.map} +1 -1
- package/dist/{DatePicker-BXpDRo-R.js → DatePicker-CI59gF3S.js} +4 -5
- package/dist/{DatePicker-BXpDRo-R.js.map → DatePicker-CI59gF3S.js.map} +1 -1
- package/dist/{DateRangeInput-BW0-_jV0.js → DateRangeInput-B3g8cyS0.js} +8 -10
- package/dist/{DateRangeInput-BW0-_jV0.js.map → DateRangeInput-B3g8cyS0.js.map} +1 -1
- package/dist/{DateRangePicker-C4-DoWac.js → DateRangePicker-48yOB2qV.js} +9 -10
- package/dist/{DateRangePicker-C4-DoWac.js.map → DateRangePicker-48yOB2qV.js.map} +1 -1
- package/dist/{DiffView-Dy4z-n-1.js → DiffView-DITZdVbh.js} +7 -12
- package/dist/{DiffView-Dy4z-n-1.js.map → DiffView-DITZdVbh.js.map} +1 -1
- package/dist/{DropdownMenu-CcVbZ_5u.js → DropdownMenu-Ba9atqDa.js} +21 -37
- package/dist/DropdownMenu-Ba9atqDa.js.map +1 -0
- package/dist/{FieldBox-BrxLkY9C.js → FieldBox-DdSdJ3ZN.js} +6 -10
- package/dist/{FieldBox-BrxLkY9C.js.map → FieldBox-DdSdJ3ZN.js.map} +1 -1
- package/dist/{FieldItem-BHUqgSO1.js → FieldItem-D7eCMfMB.js} +6 -8
- package/dist/{FieldItem-BHUqgSO1.js.map → FieldItem-D7eCMfMB.js.map} +1 -1
- package/dist/{FieldItem-CPN1xjN5.d.ts → FieldItem-fqm3CNR8.d.ts} +7 -6
- package/dist/{FileUpload-BYFONpEl.js → FileUpload-DskvxhAr.js} +25 -45
- package/dist/{FileUpload-BYFONpEl.js.map → FileUpload-DskvxhAr.js.map} +1 -1
- package/dist/{Form-CAofWyMI.js → Form-BUNW7nlt.js} +24 -38
- package/dist/{Form-CAofWyMI.js.map → Form-BUNW7nlt.js.map} +1 -1
- package/dist/{FormGroup-V5kIgQRN.js → FormGroup-QJB21LKp.js} +12 -20
- package/dist/{FormGroup-V5kIgQRN.js.map → FormGroup-QJB21LKp.js.map} +1 -1
- package/dist/{FullScreenModal-DAvvlGOz.js → FullScreenModal-RzY5XxiG.js} +8 -12
- package/dist/{FullScreenModal-DAvvlGOz.js.map → FullScreenModal-RzY5XxiG.js.map} +1 -1
- package/dist/HoverCard-OGWKRXJ7.js +24 -0
- package/dist/HoverCard-OGWKRXJ7.js.map +1 -0
- package/dist/{InlineEdit-D4P0SvCB.js → InlineEdit-CXL0ZslO.js} +7 -8
- package/dist/{InlineEdit-D4P0SvCB.js.map → InlineEdit-CXL0ZslO.js.map} +1 -1
- package/dist/{InputGroup-CZv_7QlM.js → InputGroup-BWeanEo7.js} +9 -15
- package/dist/{InputGroup-CZv_7QlM.js.map → InputGroup-BWeanEo7.js.map} +1 -1
- package/dist/{Kbd-CflKthfu.js → Kbd-BprYCICe.js} +8 -13
- package/dist/{Kbd-CflKthfu.js.map → Kbd-BprYCICe.js.map} +1 -1
- package/dist/{MarkedText-DlmlJO0u.js → MarkedText-BrganZ_V.js} +4 -6
- package/dist/{MarkedText-DlmlJO0u.js.map → MarkedText-BrganZ_V.js.map} +1 -1
- package/dist/{MermaidDiagram-Te-5gOCU.js → MermaidDiagram-E3azndPk.js} +9 -11
- package/dist/{MermaidDiagram-Te-5gOCU.js.map → MermaidDiagram-E3azndPk.js.map} +1 -1
- package/dist/{Modal-CbUz-5YH.js → Modal-Cf_kPEBW.js} +14 -22
- package/dist/Modal-Cf_kPEBW.js.map +1 -0
- package/dist/{ModalTitle-cy0Ht9VY.js → ModalTitle-7vgpfc6B.js} +6 -9
- package/dist/ModalTitle-7vgpfc6B.js.map +1 -0
- package/dist/{MultiActionButtonGroup-Dzig87s1.js → MultiActionButtonGroup-8WQwL4UQ.js} +6 -8
- package/dist/{MultiActionButtonGroup-Dzig87s1.js.map → MultiActionButtonGroup-8WQwL4UQ.js.map} +1 -1
- package/dist/{Navbar-DHUS7XiU.js → Navbar-CRjxVboE.js} +13 -22
- package/dist/{Navbar-DHUS7XiU.js.map → Navbar-CRjxVboE.js.map} +1 -1
- package/dist/{OtpInput-CY8yCaJk.js → OtpInput-C5plPzGU.js} +7 -11
- package/dist/{OtpInput-CY8yCaJk.js.map → OtpInput-C5plPzGU.js.map} +1 -1
- package/dist/{PageHeader-CL1A6jFM.js → PageHeader-DosMyar2.js} +6 -10
- package/dist/{PageHeader-CL1A6jFM.js.map → PageHeader-DosMyar2.js.map} +1 -1
- package/dist/{PageLayout-C9aXTpqV.js → PageLayout-LcvJccOW.js} +5 -8
- package/dist/{PageLayout-C9aXTpqV.js.map → PageLayout-LcvJccOW.js.map} +1 -1
- package/dist/{PageToolbar-DJ5tdYla.js → PageToolbar-By2HznxO.js} +8 -10
- package/dist/{PageToolbar-DJ5tdYla.js.map → PageToolbar-By2HznxO.js.map} +1 -1
- package/dist/{Pagination-D27x5KmH.js → Pagination-DrXTrvfD.js} +11 -18
- package/dist/{Pagination-D27x5KmH.js.map → Pagination-DrXTrvfD.js.map} +1 -1
- package/dist/{Popconfirm-DwLCYNaF.js → Popconfirm-BJuDOHdv.js} +46 -25
- package/dist/Popconfirm-BJuDOHdv.js.map +1 -0
- package/dist/{Popover-DtUDwUVO.js → Popover-DhOPlWgF.js} +5 -7
- package/dist/Popover-DhOPlWgF.js.map +1 -0
- package/dist/{RadioGroup-B0TwHjBb.js → RadioGroup-B9oC8P15.js} +12 -18
- package/dist/{RadioGroup-B0TwHjBb.js.map → RadioGroup-B9oC8P15.js.map} +1 -1
- package/dist/{Resizable-D8zs0kcq.js → Resizable-Co-L3qg7.js} +4 -6
- package/dist/{Resizable-D8zs0kcq.js.map → Resizable-Co-L3qg7.js.map} +1 -1
- package/dist/{Search-vyZwGKMU.js → Search-OgaNjqQM.js} +26 -21
- package/dist/Search-OgaNjqQM.js.map +1 -0
- package/dist/{SearchInput-DyYXyw3u.js → SearchInput-eLS-uvOn.js} +18 -29
- package/dist/SearchInput-eLS-uvOn.js.map +1 -0
- package/dist/{SectionNav-tLK3iF6c.js → SectionNav-L81iJBo3.js} +11 -14
- package/dist/{SectionNav-tLK3iF6c.js.map → SectionNav-L81iJBo3.js.map} +1 -1
- package/dist/{Select-B22hB_-w.js → Select-DRdkdzBp.js} +29 -26
- package/dist/Select-DRdkdzBp.js.map +1 -0
- package/dist/{Sheet-0TWKTqid.js → Sheet-DVb4XoJ5.js} +13 -20
- package/dist/Sheet-DVb4XoJ5.js.map +1 -0
- package/dist/{Sidebar-C5hdANBU.js → Sidebar-DYvodJWN.js} +43 -75
- package/dist/{Sidebar-C5hdANBU.js.map → Sidebar-DYvodJWN.js.map} +1 -1
- package/dist/{Slider-DrcsM8_G.js → Slider-B9IskDxf.js} +8 -12
- package/dist/{Slider-DrcsM8_G.js.map → Slider-B9IskDxf.js.map} +1 -1
- package/dist/{Stepper-CQrUPVFL.js → Stepper-D7VspVEt.js} +11 -19
- package/dist/{Stepper-CQrUPVFL.js.map → Stepper-D7VspVEt.js.map} +1 -1
- package/dist/{Switch-DccpSpzC.js → Switch-DONWW7ju.js} +4 -6
- package/dist/{Switch-DccpSpzC.js.map → Switch-DONWW7ju.js.map} +1 -1
- package/dist/{Table-CilEvpMq.js → Table-BwgBm3hJ.js} +12 -21
- package/dist/{Table-CilEvpMq.js.map → Table-BwgBm3hJ.js.map} +1 -1
- package/dist/{Tabs-Ck4uWf8U.js → Tabs-DmJB4l_N.js} +9 -14
- package/dist/{Tabs-Ck4uWf8U.js.map → Tabs-DmJB4l_N.js.map} +1 -1
- package/dist/{TextInput-CR0_USaY.js → TextInput--1CfZybC.js} +8 -10
- package/dist/TextInput--1CfZybC.js.map +1 -0
- package/dist/{ThemeProvider-BTK7AL-T.js → ThemeProvider-BCHllN7d.js} +8 -13
- package/dist/{ThemeProvider-BTK7AL-T.js.map → ThemeProvider-BCHllN7d.js.map} +1 -1
- package/dist/{TimePicker-CoRpiEM3.js → TimePicker-CCV3SOw5.js} +4 -6
- package/dist/{TimePicker-CoRpiEM3.js.map → TimePicker-CCV3SOw5.js.map} +1 -1
- package/dist/{Timeline-DUXgByUE.js → Timeline-EMOpTLAT.js} +8 -13
- package/dist/{Timeline-DUXgByUE.js.map → Timeline-EMOpTLAT.js.map} +1 -1
- package/dist/{Toast-937n7n8i.js → Toast-BOTINeTX.js} +4 -6
- package/dist/{Toast-937n7n8i.js.map → Toast-BOTINeTX.js.map} +1 -1
- package/dist/{ToggleAllTooltip-DEjbWFoj.js → ToggleAllTooltip-BFmA6TXf.js} +4 -6
- package/dist/{ToggleAllTooltip-DEjbWFoj.js.map → ToggleAllTooltip-BFmA6TXf.js.map} +1 -1
- package/dist/{ToggleGroup-BOz1yyz6.js → ToggleGroup-DsDS7k70.js} +3 -4
- package/dist/{ToggleGroup-BOz1yyz6.js.map → ToggleGroup-DsDS7k70.js.map} +1 -1
- package/dist/{Workbench-CxgNCs3I.js → Workbench-4s0xP6XU.js} +18 -32
- package/dist/{Workbench-CxgNCs3I.js.map → Workbench-4s0xP6XU.js.map} +1 -1
- package/dist/{ZoomableSvg-DnFXo2L4.js → ZoomableSvg-BRPGgaWJ.js} +9 -11
- package/dist/{ZoomableSvg-DnFXo2L4.js.map → ZoomableSvg-BRPGgaWJ.js.map} +1 -1
- package/dist/charts.d.ts +0 -16
- package/dist/charts.js +10 -19
- package/dist/charts.js.map +1 -1
- package/dist/{classNames-DcGnTh2N.js → classNames-DkX30VJU.js} +2 -3
- package/dist/{classNames-DcGnTh2N.js.map → classNames-DkX30VJU.js.map} +1 -1
- package/dist/editors.d.ts +2 -16
- package/dist/editors.js +16 -26
- package/dist/editors.js.map +1 -1
- package/dist/{findLiteralMatches-DgGLzyG0.js → findLiteralMatches-BaLZTPtx.js} +2 -3
- package/dist/{findLiteralMatches-DgGLzyG0.js.map → findLiteralMatches-BaLZTPtx.js.map} +1 -1
- package/dist/flint.d.ts +0 -2
- package/dist/flint.js +10 -14
- package/dist/flint.js.map +1 -1
- package/dist/{highlightCode-D354tCXO.js → highlightCode-2spZP7ZA.js} +2 -3
- package/dist/{highlightCode-D354tCXO.js.map → highlightCode-2spZP7ZA.js.map} +1 -1
- package/dist/{icons-ZIeZXXS7.js → icons-DDR9dFSr.js} +21 -40
- package/dist/{icons-ZIeZXXS7.js.map → icons-DDR9dFSr.js.map} +1 -1
- package/dist/icons.d.ts +1 -1
- package/dist/icons.js +1 -2
- package/dist/{index-D-itZ3VP.d.ts → index-BljYaTWL.d.ts} +1 -39
- package/dist/index.d.ts +452 -1296
- package/dist/index.js +76 -74
- package/dist/internal/blocks/AIKit.js +1 -2
- package/dist/internal/blocks/AppShell.js +1 -2
- package/dist/internal/blocks/AuthLayout.js +3 -4
- package/dist/internal/blocks/AutoSaveTextarea.js +1 -2
- package/dist/internal/blocks/BrandEditor.js +1 -2
- package/dist/internal/blocks/ChartPanel.js +3 -4
- package/dist/internal/blocks/ChipEditor.js +6 -7
- package/dist/internal/blocks/ClipboardButton.js +1 -2
- package/dist/internal/blocks/ColorInput.js +1 -2
- package/dist/internal/blocks/ColorModeSwitch.js +1 -2
- package/dist/internal/blocks/Command.js +1 -2
- package/dist/internal/blocks/CopyField.js +1 -2
- package/dist/internal/blocks/DashboardHero.js +2 -3
- package/dist/internal/blocks/DateInput.js +1 -2
- package/dist/internal/blocks/DateRangeInput.js +1 -2
- package/dist/internal/blocks/DiagramShared/DiagramSkeleton.js +1 -2
- package/dist/internal/blocks/EmptyConfigurationActionCard.js +2 -3
- package/dist/internal/blocks/EmptyState.js +1 -2
- package/dist/internal/blocks/ErrorState.js +1 -2
- package/dist/internal/blocks/ExportMenu.js +5 -6
- package/dist/internal/blocks/FacebookButton.js +3 -4
- package/dist/internal/blocks/Form/connectors/ComboboxField.js +3 -4
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +2 -3
- package/dist/internal/blocks/Form.js +3 -2
- package/dist/internal/blocks/FormGroup.js +1 -2
- package/dist/internal/blocks/GoogleButton.js +3 -4
- package/dist/internal/blocks/InlineEdit.js +1 -2
- package/dist/internal/blocks/MicrosoftButton.js +3 -4
- package/dist/internal/blocks/MultiActionButtonGroup.js +1 -2
- package/dist/internal/blocks/MultiCombobox.js +7 -8
- package/dist/internal/blocks/NumberInput.js +2 -3
- package/dist/internal/blocks/OtpInput.js +1 -2
- package/dist/internal/blocks/PageHeader.js +1 -2
- package/dist/internal/blocks/PageLayout.js +1 -2
- package/dist/internal/blocks/PageToolbar.js +1 -2
- package/dist/internal/blocks/PasswordInput.js +5 -6
- package/dist/internal/blocks/SearchInput.js +1 -2
- package/dist/internal/blocks/SearchInputWithNavigation.js +6 -7
- package/dist/internal/blocks/SectionNav.js +1 -2
- package/dist/internal/blocks/SplitButton.js +4 -5
- package/dist/internal/blocks/StatCard.js +4 -6
- package/dist/internal/blocks/StatCard.js.map +1 -1
- package/dist/internal/blocks/TextInput.js +1 -2
- package/dist/internal/blocks/Textarea.js +3 -4
- package/dist/internal/blocks/TimeInput.js +6 -7
- package/dist/internal/components/Alert.js +1 -2
- package/dist/internal/components/AlertModal.js +1 -2
- package/dist/internal/components/Avatar.js +3 -4
- package/dist/internal/components/Badge.js +1 -2
- package/dist/internal/components/BrandLogo.js +1 -2
- package/dist/internal/components/Breadcrumb.js +1 -2
- package/dist/internal/components/Button.js +1 -2
- package/dist/internal/components/ButtonGroup.js +2 -3
- package/dist/internal/components/Calendar.js +1 -2
- package/dist/internal/components/Card.js +1 -2
- package/dist/internal/components/Checkbox.js +1 -2
- package/dist/internal/components/Clipboard.js +1 -2
- package/dist/internal/components/Collapsible.js +1 -2
- package/dist/internal/components/CollapsiblePanel.js +5 -6
- package/dist/internal/components/Combobox.js +1 -2
- package/dist/internal/components/DatePicker.js +1 -2
- package/dist/internal/components/DateRangePicker.js +1 -2
- package/dist/internal/components/DiffView.js +1 -2
- package/dist/internal/components/DotsLoader.js +2 -3
- package/dist/internal/components/DropdownMenu.js +1 -2
- package/dist/internal/components/EmptySearchContent.js +1 -2
- package/dist/internal/components/FileUpload.js +1 -2
- package/dist/internal/components/FullScreenModal.js +1 -2
- package/dist/internal/components/HelpBlock.js +1 -2
- package/dist/internal/components/HoverCard.js +1 -2
- package/dist/internal/components/InputGroup.js +1 -2
- package/dist/internal/components/Kbd.js +1 -2
- package/dist/internal/components/Label.js +2 -3
- package/dist/internal/components/Link.js +2 -3
- package/dist/internal/components/MarkedText.js +1 -2
- package/dist/internal/components/MergeEditor/ConflictStatus/ConflictStatusIndicator.js +3 -4
- package/dist/internal/components/MergeEditor/PaneHeader.js +1 -2
- package/dist/internal/components/MergeEditor/constants.js +1 -2
- package/dist/internal/components/MergeEditor/useMergeDiff.js +1 -2
- package/dist/internal/components/Modal.js +1 -2
- package/dist/internal/components/Navbar.js +1 -2
- package/dist/internal/components/Pagination.js +1 -2
- package/dist/internal/components/PanelWithDetails.js +4 -5
- package/dist/internal/components/Popconfirm.js +1 -2
- package/dist/internal/components/Popover.js +1 -2
- package/dist/internal/components/Progress.js +2 -3
- package/dist/internal/components/RadioGroup.js +1 -2
- package/dist/internal/components/Resizable.js +1 -2
- package/dist/internal/components/ScrollArea.js +3 -5
- package/dist/internal/components/ScrollArea.js.map +1 -1
- package/dist/internal/components/Search.js +1 -2
- package/dist/internal/components/Select.js +1 -2
- package/dist/internal/components/Separator.js +2 -3
- package/dist/internal/components/Sheet.js +1 -2
- package/dist/internal/components/Sidebar.js +1 -2
- package/dist/internal/components/Skeleton/Skeleton.js +2 -3
- package/dist/internal/components/Skeleton/SkeletonList.js +2 -3
- package/dist/internal/components/Slider.js +1 -2
- package/dist/internal/components/SpotlightBackdrop.js +3 -5
- package/dist/internal/components/SpotlightBackdrop.js.map +1 -1
- package/dist/internal/components/Stepper.js +1 -2
- package/dist/internal/components/Switch.js +1 -2
- package/dist/internal/components/Table.js +1 -2
- package/dist/internal/components/Tabs.js +1 -2
- package/dist/internal/components/ThemeProvider.js +2 -2
- package/dist/internal/components/TimePicker.js +1 -2
- package/dist/internal/components/Timeline.js +1 -2
- package/dist/internal/components/Toast.js +2 -2
- package/dist/internal/components/Toggle.js +2 -3
- package/dist/internal/components/ToggleGroup.js +1 -2
- package/dist/internal/components/Tooltip.js +1 -2
- package/dist/internal/components/Truncated.js +3 -4
- package/dist/internal/components/Workbench.js +1 -2
- package/dist/internal/components/ZoomableSvg.js +1 -2
- package/dist/internal/hooks/useAltDigitHotkey.js +1 -2
- package/dist/internal/hooks/useAutosizeInput.js +1 -2
- package/dist/internal/hooks/useScrollbarPosition.js +2 -3
- package/dist/internal/hooks/useStableCallback.js +1 -2
- package/dist/internal/hooks/useTimeout.js +18 -0
- package/dist/internal/hooks/useTimeout.js.map +1 -0
- package/dist/internal/utils/accessibleName.js +1 -2
- package/dist/internal/utils/mergeRefs.js +1 -2
- package/dist/internal/utils.js +3 -3
- package/dist/markdown-editor.d.ts +0 -4
- package/dist/markdown-editor.js +30 -49
- package/dist/markdown-editor.js.map +1 -1
- package/dist/mermaid.d.ts +0 -2
- package/dist/mermaid.js +1 -2
- package/dist/rjsf.d.ts +0 -8
- package/dist/rjsf.js +47 -78
- package/dist/rjsf.js.map +1 -1
- package/dist/{rolldown-runtime-Bdc48AWt.js → rolldown-runtime-BrwM56v-.js} +2 -3
- package/dist/{styles-T8xwr0sR.js → styles-BXXXosW_.js} +2 -3
- package/dist/{styles-T8xwr0sR.js.map → styles-BXXXosW_.js.map} +1 -1
- package/dist/{styles-DxazJ8Mz.js → styles-nwtCRF7y.js} +2 -3
- package/dist/{styles-DxazJ8Mz.js.map → styles-nwtCRF7y.js.map} +1 -1
- package/dist/styles.css +1 -1
- package/dist/{svgCache-Dhmbe-7i.js → svgCache-BzvN_fgr.js} +2 -3
- package/dist/{svgCache-Dhmbe-7i.js.map → svgCache-BzvN_fgr.js.map} +1 -1
- package/dist/{svgTransforms-Hnvev3Vs.js → svgTransforms-BBxxO9T6.js} +4 -6
- package/dist/{svgTransforms-Hnvev3Vs.js.map → svgTransforms-BBxxO9T6.js.map} +1 -1
- package/dist/testing.d.ts +0 -2
- package/dist/testing.js +2 -3
- package/dist/{themeScopeContext-CEVXbYvZ.js → themeScopeContext-BZGPdyG8.js} +6 -11
- package/dist/{themeScopeContext-CEVXbYvZ.js.map → themeScopeContext-BZGPdyG8.js.map} +1 -1
- package/dist/{themeTokens-DCeb62ap.js → themeTokens-B60cQtAY.js} +4 -6
- package/dist/{themeTokens-DCeb62ap.js.map → themeTokens-B60cQtAY.js.map} +1 -1
- package/dist/{toast-Y3cTMBW8.js → toast-Dzj1EFOb.js} +10 -17
- package/dist/{toast-Y3cTMBW8.js.map → toast-Dzj1EFOb.js.map} +1 -1
- package/dist/{types-BPcAjMG0.d.ts → types-CsZuwfxc.d.ts} +1 -3
- package/dist/{useControllableState-CUYXMsfz.js → useControllableState-BCvUOC6G.js} +2 -3
- package/dist/{useControllableState-CUYXMsfz.js.map → useControllableState-BCvUOC6G.js.map} +1 -1
- package/dist/{useElement-D-RjrGa4.js → useElement-Dcoo9Jlr.js} +2 -3
- package/dist/{useElement-D-RjrGa4.js.map → useElement-Dcoo9Jlr.js.map} +1 -1
- package/dist/{useMergeDiff-CvowEXJ1.js → useMergeDiff-DFIATaTw.js} +3 -5
- package/dist/{useMergeDiff-CvowEXJ1.js.map → useMergeDiff-DFIATaTw.js.map} +1 -1
- package/dist/{utils-DwC9u0tM.js → utils-DjFceY3H.js} +18 -34
- package/dist/utils-DjFceY3H.js.map +1 -0
- package/dist/vega.d.ts +1 -5
- package/dist/vega.js +3 -4
- package/dist/{vegaTheme-ISwGXvof.js → vegaTheme-BcTNRmVS.js} +3 -4
- package/dist/{vegaTheme-ISwGXvof.js.map → vegaTheme-BcTNRmVS.js.map} +1 -1
- package/dist/{vegaTokens-DCkvpIVE.js → vegaTokens-DnCcy7JY.js} +3 -4
- package/dist/{vegaTokens-DCkvpIVE.js.map → vegaTokens-DnCcy7JY.js.map} +1 -1
- package/package.json +40 -40
- package/src/styles.css +70 -4
- package/src/theme.css +117 -11
- package/dist/AIKit-CaAW4GLx.js.map +0 -1
- package/dist/AlertModal-D4AtpvLS.js.map +0 -1
- package/dist/Badge-5GHIsgRS.js.map +0 -1
- package/dist/Button-BNkyYU8u.js.map +0 -1
- package/dist/Calendar-BnKi1kPu.js.map +0 -1
- package/dist/Combobox-CaKqgstG.js.map +0 -1
- package/dist/DropdownMenu-CcVbZ_5u.js.map +0 -1
- package/dist/HoverCard-Cv5rmvJq.js +0 -26
- package/dist/HoverCard-Cv5rmvJq.js.map +0 -1
- package/dist/Modal-CbUz-5YH.js.map +0 -1
- package/dist/ModalTitle-cy0Ht9VY.js.map +0 -1
- package/dist/Popconfirm-DwLCYNaF.js.map +0 -1
- package/dist/Popover-DtUDwUVO.js.map +0 -1
- package/dist/Search-vyZwGKMU.js.map +0 -1
- package/dist/SearchInput-DyYXyw3u.js.map +0 -1
- package/dist/Select-B22hB_-w.js.map +0 -1
- package/dist/Sheet-0TWKTqid.js.map +0 -1
- package/dist/TextInput-CR0_USaY.js.map +0 -1
- package/dist/utils-DwC9u0tM.js.map +0 -1
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { cn } from "./classNames-
|
|
2
|
-
import { useControllableState } from "./useControllableState-
|
|
3
|
-
import { Collapsible } from "./Collapsible-
|
|
1
|
+
import { cn } from "./classNames-DkX30VJU.js";
|
|
2
|
+
import { useControllableState } from "./useControllableState-BCvUOC6G.js";
|
|
3
|
+
import { Collapsible } from "./Collapsible-zsXk4Vpp.js";
|
|
4
4
|
import { createContext, use, useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { Slot } from "@radix-ui/react-slot";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/components/Workbench/constants.ts
|
|
8
8
|
const DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM = 2.75;
|
|
9
9
|
const DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX = 320;
|
|
10
10
|
const MIN_WORKBENCH_PANEL_HEIGHT_IN_PX = 120;
|
|
11
11
|
const WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO = .8;
|
|
12
|
-
|
|
13
|
-
//#region src/components/Workbench/context.ts
|
|
12
|
+
// src/components/Workbench/context.ts
|
|
14
13
|
const createWorkbenchActions = (setState) => ({
|
|
15
14
|
expand: () => setState((state) => state === "collapsed" ? "expanded" : state),
|
|
16
15
|
collapse: () => setState("collapsed"),
|
|
@@ -29,29 +28,25 @@ const useWorkbench = () => {
|
|
|
29
28
|
if (context === null) throw new Error("Workbench compound components must be rendered inside <Workbench>.");
|
|
30
29
|
return context;
|
|
31
30
|
};
|
|
32
|
-
|
|
33
|
-
//#region src/components/Workbench/WorkbenchBar/WorkbenchBarEnd.tsx
|
|
31
|
+
// src/components/Workbench/WorkbenchBar/WorkbenchBarEnd.tsx
|
|
34
32
|
const WorkbenchBarEnd = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
35
33
|
...props,
|
|
36
34
|
"data-slot": "workbench-bar-end",
|
|
37
35
|
className: cn("tw:col-start-3", "tw:row-start-1", "tw:flex", "tw:items-center", "tw:justify-end", "tw:gap-2", className)
|
|
38
36
|
});
|
|
39
|
-
|
|
40
|
-
//#region src/components/Workbench/WorkbenchBar/WorkbenchBarMiddle.tsx
|
|
37
|
+
// src/components/Workbench/WorkbenchBar/WorkbenchBarMiddle.tsx
|
|
41
38
|
const WorkbenchBarMiddle = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
42
39
|
...props,
|
|
43
40
|
"data-slot": "workbench-bar-middle",
|
|
44
41
|
className: cn("tw:col-start-2", "tw:row-start-1", "tw:flex", "tw:items-center", "tw:justify-center", "tw:gap-2", className)
|
|
45
42
|
});
|
|
46
|
-
|
|
47
|
-
//#region src/components/Workbench/WorkbenchBar/WorkbenchBarStart.tsx
|
|
43
|
+
// src/components/Workbench/WorkbenchBar/WorkbenchBarStart.tsx
|
|
48
44
|
const WorkbenchBarStart = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
49
45
|
...props,
|
|
50
46
|
"data-slot": "workbench-bar-start",
|
|
51
47
|
className: cn("tw:col-start-1", "tw:row-start-1", "tw:flex", "tw:items-center", "tw:gap-2", className)
|
|
52
48
|
});
|
|
53
|
-
|
|
54
|
-
//#region src/components/Workbench/WorkbenchBar/WorkbenchBar.tsx
|
|
49
|
+
// src/components/Workbench/WorkbenchBar/WorkbenchBar.tsx
|
|
55
50
|
const WorkbenchBar = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
56
51
|
"data-workbench-slot": "bar",
|
|
57
52
|
className: cn("tw:grid", "tw:grid-cols-[auto_1fr_auto]", "tw:items-center", "tw:gap-x-2", "tw:h-(--workbench-bar-height)", "tw:shrink-0", "tw:pointer-events-auto", "tw:border-t", "tw:border-sidebar-border", "tw:bg-sidebar", "tw:px-3", "tw:text-xs", className),
|
|
@@ -61,8 +56,7 @@ const WorkbenchBar = ({ className, children, ...props }) => /* @__PURE__ */ jsx(
|
|
|
61
56
|
WorkbenchBar.Start = WorkbenchBarStart;
|
|
62
57
|
WorkbenchBar.Middle = WorkbenchBarMiddle;
|
|
63
58
|
WorkbenchBar.End = WorkbenchBarEnd;
|
|
64
|
-
|
|
65
|
-
//#region src/components/Workbench/WorkbenchFullScreenTrigger.tsx
|
|
59
|
+
// src/components/Workbench/WorkbenchFullScreenTrigger.tsx
|
|
66
60
|
const WorkbenchFullScreenTrigger = ({ asChild = false, onClick, ...props }) => {
|
|
67
61
|
const { state, toggleFullScreen } = useWorkbench();
|
|
68
62
|
const isFullScreen = state === "full-screen";
|
|
@@ -79,8 +73,7 @@ const WorkbenchFullScreenTrigger = ({ asChild = false, onClick, ...props }) => {
|
|
|
79
73
|
onClick: handleClick
|
|
80
74
|
});
|
|
81
75
|
};
|
|
82
|
-
|
|
83
|
-
//#region src/components/Workbench/WorkbenchPanel/WorkbenchPanelResizeHandle.tsx
|
|
76
|
+
// src/components/Workbench/WorkbenchPanel/WorkbenchPanelResizeHandle.tsx
|
|
84
77
|
const getMaxHeight = (panel) => {
|
|
85
78
|
const hostTop = panel.offsetParent?.getBoundingClientRect().top ?? 0;
|
|
86
79
|
return Math.max(panel.getBoundingClientRect().bottom - hostTop, 120);
|
|
@@ -179,8 +172,7 @@ const WorkbenchPanelResizeHandle = ({ panelRef }) => {
|
|
|
179
172
|
})
|
|
180
173
|
});
|
|
181
174
|
};
|
|
182
|
-
|
|
183
|
-
//#region src/components/Workbench/WorkbenchPanel/WorkbenchPanel.tsx
|
|
175
|
+
// src/components/Workbench/WorkbenchPanel/WorkbenchPanel.tsx
|
|
184
176
|
const clearRadixMeasurementTransitionBlock = (panel) => {
|
|
185
177
|
if (panel) panel.style.transitionDuration = "";
|
|
186
178
|
};
|
|
@@ -199,8 +191,7 @@ const WorkbenchPanel = ({ className, children, ...props }) => {
|
|
|
199
191
|
})]
|
|
200
192
|
});
|
|
201
193
|
};
|
|
202
|
-
|
|
203
|
-
//#region src/components/Workbench/WorkbenchPanel/WorkbenchPanelActions.tsx
|
|
194
|
+
// src/components/Workbench/WorkbenchPanel/WorkbenchPanelActions.tsx
|
|
204
195
|
const WorkbenchPanelActions = ({ className, asChild = false, ...props }) => {
|
|
205
196
|
return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
|
|
206
197
|
...props,
|
|
@@ -208,29 +199,25 @@ const WorkbenchPanelActions = ({ className, asChild = false, ...props }) => {
|
|
|
208
199
|
className: cn("tw:col-start-2", "tw:row-start-1", "tw:flex", "tw:items-center", "tw:gap-2", className)
|
|
209
200
|
});
|
|
210
201
|
};
|
|
211
|
-
|
|
212
|
-
//#region src/components/Workbench/WorkbenchPanel/WorkbenchPanelContent.tsx
|
|
202
|
+
// src/components/Workbench/WorkbenchPanel/WorkbenchPanelContent.tsx
|
|
213
203
|
const WorkbenchPanelContent = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
214
204
|
className: cn("tw:min-h-0", "tw:flex-1", "tw:overflow-auto", className),
|
|
215
205
|
...props,
|
|
216
206
|
children
|
|
217
207
|
});
|
|
218
|
-
|
|
219
|
-
//#region src/components/Workbench/WorkbenchPanel/WorkbenchPanelHeader.tsx
|
|
208
|
+
// src/components/Workbench/WorkbenchPanel/WorkbenchPanelHeader.tsx
|
|
220
209
|
const WorkbenchPanelHeader = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
221
210
|
className: cn("tw:grid", "tw:grid-cols-[1fr_auto]", "tw:items-center", "tw:gap-x-2", "tw:shrink-0", "tw:bg-sidebar", "tw:px-3", "tw:py-2", "tw:text-xs", className),
|
|
222
211
|
...props,
|
|
223
212
|
children
|
|
224
213
|
});
|
|
225
|
-
|
|
226
|
-
//#region src/components/Workbench/WorkbenchPanel/WorkbenchPanelTitle.tsx
|
|
214
|
+
// src/components/Workbench/WorkbenchPanel/WorkbenchPanelTitle.tsx
|
|
227
215
|
const WorkbenchPanelTitle = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
228
216
|
...props,
|
|
229
217
|
"data-slot": "workbench-panel-title",
|
|
230
218
|
className: cn("tw:col-start-1", "tw:flex", "tw:items-center", "tw:text-sm", "tw:font-semibold", "tw:text-foreground", className)
|
|
231
219
|
});
|
|
232
|
-
|
|
233
|
-
//#region src/components/Workbench/Workbench.tsx
|
|
220
|
+
// src/components/Workbench/Workbench.tsx
|
|
234
221
|
const Workbench = ({ className, children, state: stateProp, defaultState = "collapsed", onStateChange, barHeight = DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM, panelHeight: panelHeightProp, defaultPanelHeight = 320, onPanelHeightChange }) => {
|
|
235
222
|
const [state, setState] = useControllableState({
|
|
236
223
|
prop: stateProp,
|
|
@@ -289,7 +276,6 @@ Workbench.PanelActions = WorkbenchPanelActions;
|
|
|
289
276
|
Workbench.PanelContent = WorkbenchPanelContent;
|
|
290
277
|
Workbench.Trigger = Collapsible.Trigger;
|
|
291
278
|
Workbench.FullScreenTrigger = WorkbenchFullScreenTrigger;
|
|
292
|
-
//#endregion
|
|
293
279
|
export { DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM, DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX, Workbench, useWorkbench };
|
|
294
280
|
|
|
295
|
-
//# sourceMappingURL=Workbench-
|
|
281
|
+
//# sourceMappingURL=Workbench-4s0xP6XU.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Workbench-CxgNCs3I.js","names":[],"sources":["../src/components/Workbench/constants.ts","../src/components/Workbench/context.ts","../src/components/Workbench/WorkbenchBar/WorkbenchBarEnd.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBarMiddle.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBarStart.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBar.tsx","../src/components/Workbench/WorkbenchFullScreenTrigger.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelResizeHandle.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanel.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelActions.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelContent.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelHeader.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelTitle.tsx","../src/components/Workbench/Workbench.tsx"],"sourcesContent":["export const DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM = 2.75;\n\nexport const MIN_WORKBENCH_BAR_HEIGHT_IN_REM = 1;\n\nexport const DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX = 320;\n\nexport const MIN_WORKBENCH_PANEL_HEIGHT_IN_PX = 120;\n\nexport const WORKBENCH_PANEL_RESIZE_STEP_IN_PX = 24;\n\nexport const WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO = 0.8;\n","import { createContext, use } from 'react';\nimport type { Dispatch, SetStateAction } from 'react';\n\n/**\n * Full screen is a mode of the open panel, not a flag beside it — as two booleans the fourth\n * combination (collapsed *and* full screen) is expressible but meaningless.\n */\nexport type WorkbenchState = 'collapsed' | 'expanded' | 'full-screen';\n\ntype WorkbenchActions = {\n expand: () => void;\n collapse: () => void;\n toggleExpanded: () => void;\n enterFullScreen: () => void;\n exitFullScreen: () => void;\n toggleFullScreen: () => void;\n};\n\ntype WorkbenchContextValue = WorkbenchActions & {\n state: WorkbenchState;\n setState: Dispatch<SetStateAction<WorkbenchState>>;\n panelHeight: number;\n setPanelHeight: Dispatch<SetStateAction<number>>;\n isResizing: boolean;\n setIsResizing: (isResizing: boolean) => void;\n};\n\nexport const createWorkbenchActions = (\n setState: Dispatch<SetStateAction<WorkbenchState>>,\n): WorkbenchActions => ({\n // Opening an already-open panel leaves full screen alone.\n expand: () => setState((state) => (state === 'collapsed' ? 'expanded' : state)),\n collapse: () => setState('collapsed'),\n toggleExpanded: () => setState((state) => (state === 'collapsed' ? 'expanded' : 'collapsed')),\n\n enterFullScreen: () => setState('full-screen'),\n // Exiting returns to the open panel, never to a closed one — this is a restore, not a collapse.\n exitFullScreen: () => setState((state) => (state === 'full-screen' ? 'expanded' : state)),\n toggleFullScreen: () =>\n setState((state) => (state === 'full-screen' ? 'expanded' : 'full-screen')),\n});\n\nexport const WorkbenchContext = createContext<WorkbenchContextValue | null>(null);\n\n/**\n * The parts sit at arbitrary depth under `<Workbench>` — a trigger lives inside the panel header,\n * three levels down — so the state travels by context rather than props.\n */\nexport const useWorkbench = (): WorkbenchContextValue => {\n const context = use(WorkbenchContext);\n\n if (context === null) {\n throw new Error('Workbench compound components must be rendered inside <Workbench>.');\n }\n\n return context;\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarEnd = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-end\"\n className={cn(\n // grid placement\n 'tw:col-start-3',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-end',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarMiddle = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-middle\"\n className={cn(\n // grid placement\n 'tw:col-start-2',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarStart = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-start\"\n className={cn(\n // grid placement\n 'tw:col-start-1',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\nimport { WorkbenchBarEnd } from './WorkbenchBarEnd';\nimport { WorkbenchBarMiddle } from './WorkbenchBarMiddle';\nimport { WorkbenchBarStart } from './WorkbenchBarStart';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBar = ({ className, children, ...props }: Props) => (\n <div\n // Marked so a floating surface (kbc-ui's Kai widget) can measure the dock; the root's rect is the bar alone.\n data-workbench-slot=\"bar\"\n className={cn(\n // layout\n 'tw:grid',\n 'tw:grid-cols-[auto_1fr_auto]',\n 'tw:items-center',\n 'tw:gap-x-2',\n\n // sizing\n 'tw:h-(--workbench-bar-height)',\n 'tw:shrink-0',\n 'tw:pointer-events-auto',\n\n // surface\n 'tw:border-t',\n 'tw:border-sidebar-border',\n 'tw:bg-sidebar',\n\n // spacing\n 'tw:px-3',\n\n // typography\n 'tw:text-xs',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n\nWorkbenchBar.Start = WorkbenchBarStart;\nWorkbenchBar.Middle = WorkbenchBarMiddle;\nWorkbenchBar.End = WorkbenchBarEnd;\n","import type { ComponentProps, MouseEvent } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { useWorkbench } from './context';\n\ntype Props = ComponentProps<'button'> & {\n asChild?: boolean;\n};\n\nexport const WorkbenchFullScreenTrigger = ({ asChild = false, onClick, ...props }: Props) => {\n const { state, toggleFullScreen } = useWorkbench();\n const isFullScreen = state === 'full-screen';\n const Comp = asChild ? Slot : 'button';\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.defaultPrevented) {\n toggleFullScreen();\n }\n };\n\n return (\n <Comp\n {...(asChild ? {} : { type: 'button' as const })}\n {...props}\n data-slot=\"workbench-full-screen-trigger\"\n data-state={isFullScreen ? 'on' : 'off'}\n onClick={handleClick}\n />\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { KeyboardEvent, PointerEvent, RefObject } from 'react';\n\nimport { cn } from '../../../utils';\nimport {\n MIN_WORKBENCH_PANEL_HEIGHT_IN_PX,\n WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO,\n WORKBENCH_PANEL_RESIZE_STEP_IN_PX,\n} from '../constants';\nimport { useWorkbench } from '../context';\n\ntype Props = {\n panelRef: RefObject<HTMLDivElement | null>;\n};\n\nconst getMaxHeight = (panel: HTMLDivElement) => {\n const hostTop = panel.offsetParent?.getBoundingClientRect().top ?? 0;\n\n return Math.max(panel.getBoundingClientRect().bottom - hostTop, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX);\n};\n\nconst clampHeight = (height: number, panel: HTMLDivElement) =>\n Math.min(Math.max(height, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX), getMaxHeight(panel));\n\nexport const WorkbenchPanelResizeHandle = ({ panelRef }: Props) => {\n const {\n state,\n panelHeight,\n setPanelHeight,\n isResizing,\n setIsResizing,\n enterFullScreen,\n exitFullScreen,\n } = useWorkbench();\n const grabOffsetRef = useRef(0);\n const previousStateRef = useRef(state);\n const isFullScreenRequestedRef = useRef(state === 'full-screen');\n const enteredFullScreenByDragRef = useRef(false);\n const exitedFullScreenByDragRef = useRef(false);\n\n useEffect(() => {\n if (!isResizing) return;\n\n const { body } = document;\n const { cursor, userSelect } = body.style;\n\n body.style.cursor = 'ns-resize';\n body.style.userSelect = 'none';\n\n return () => {\n body.style.cursor = cursor;\n body.style.userSelect = userSelect;\n };\n }, [isResizing]);\n\n useEffect(() => {\n const previous = previousStateRef.current;\n const panel = panelRef.current;\n\n previousStateRef.current = state;\n isFullScreenRequestedRef.current = state === 'full-screen';\n\n if (previous !== 'full-screen' || state !== 'expanded' || !panel) return;\n\n const draggedIntoFullScreen = enteredFullScreenByDragRef.current;\n const draggedOutOfFullScreen = exitedFullScreenByDragRef.current;\n\n enteredFullScreenByDragRef.current = false;\n exitedFullScreenByDragRef.current = false;\n\n if (!draggedIntoFullScreen || draggedOutOfFullScreen) return;\n\n setPanelHeight(\n clampHeight(getMaxHeight(panel) * WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO, panel),\n );\n }, [state, panelRef, setPanelHeight]);\n\n const applyHeight = (height: number, panel: HTMLDivElement) => {\n const isFullScreen = isFullScreenRequestedRef.current;\n\n if (height >= getMaxHeight(panel)) {\n if (!isFullScreen) {\n isFullScreenRequestedRef.current = true;\n enteredFullScreenByDragRef.current = true;\n enterFullScreen();\n }\n\n return;\n }\n\n if (isFullScreen) {\n isFullScreenRequestedRef.current = false;\n exitedFullScreenByDragRef.current = true;\n exitFullScreen();\n }\n\n setPanelHeight(Math.max(height, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX));\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (event.button !== 0 || !panel) return;\n\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n grabOffsetRef.current = panel.getBoundingClientRect().top - event.clientY;\n setIsResizing(true);\n };\n\n const handlePointerMove = (event: PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (!panel || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n\n const top = event.clientY + grabOffsetRef.current;\n\n applyHeight(panel.getBoundingClientRect().bottom - top, panel);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (!panel) return;\n\n const step = event.shiftKey\n ? WORKBENCH_PANEL_RESIZE_STEP_IN_PX * 4\n : WORKBENCH_PANEL_RESIZE_STEP_IN_PX;\n const delta = event.key === 'ArrowUp' ? step : event.key === 'ArrowDown' ? -step : 0;\n\n if (delta === 0) return;\n\n event.preventDefault();\n applyHeight(\n (isFullScreenRequestedRef.current ? getMaxHeight(panel) : panelHeight) + delta,\n panel,\n );\n };\n\n return (\n <div\n role=\"separator\"\n aria-orientation=\"horizontal\"\n aria-label=\"Resize panel\"\n aria-valuenow={Math.round(panelHeight)}\n aria-valuemin={MIN_WORKBENCH_PANEL_HEIGHT_IN_PX}\n tabIndex={0}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onLostPointerCapture={() => setIsResizing(false)}\n onKeyDown={handleKeyDown}\n className={cn(\n // group\n 'tw:group/workbench-resize',\n\n // positioning — the panel is the positioned ancestor\n 'tw:absolute',\n 'tw:inset-x-0',\n 'tw:top-0',\n 'tw:z-10',\n\n // sizing\n 'tw:h-2',\n\n // layout — the whole strip grabs, only the pill shows\n 'tw:flex',\n 'tw:justify-center',\n\n // affordance\n 'tw:cursor-ns-resize',\n 'tw:touch-none',\n\n // focus\n 'tw:outline-none',\n )}\n >\n <span\n className={cn(\n // layout — hangs below the strip so the pill sits clear of the top edge, and\n // grabs there too since the events bubble to the strip\n 'tw:flex',\n 'tw:h-3',\n 'tw:w-16',\n 'tw:items-end',\n 'tw:justify-center',\n )}\n >\n <span\n className={cn(\n // sizing\n 'tw:h-1.5',\n 'tw:w-16',\n\n // surface\n 'tw:rounded-full',\n 'tw:bg-input',\n 'tw:transition-colors',\n 'tw:group-hover/workbench-resize:bg-muted-foreground',\n 'tw:group-focus-visible/workbench-resize:bg-muted-foreground',\n 'tw:group-data-[workbench-resizing=true]/workbench:bg-muted-foreground',\n )}\n />\n </span>\n </div>\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { ComponentProps, CSSProperties } from 'react';\n\nimport { cn } from '../../../utils';\nimport { Collapsible } from '../../Collapsible';\n\nimport { WorkbenchPanelResizeHandle } from './WorkbenchPanelResizeHandle';\n\ntype Props = ComponentProps<'div'>;\n\nconst clearRadixMeasurementTransitionBlock = (panel: HTMLDivElement | null) => {\n if (panel) panel.style.transitionDuration = '';\n};\n\nexport const WorkbenchPanel = ({ className, children, ...props }: Props) => {\n const panelRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => clearRadixMeasurementTransitionBlock(panelRef.current), []);\n\n return (\n <Collapsible.Content\n ref={panelRef}\n // See `WorkbenchBar` — the other half of the dock's measurable area.\n data-workbench-slot=\"panel\"\n style={{ '--workbench-panel-shadow': '0 -8px 24px -6px rgb(0 0 0 / 0.08)' } as CSSProperties}\n className={cn(\n // positioning — against the host, which must be a positioned element\n 'tw:absolute',\n 'tw:inset-x-0',\n 'tw:bottom-(--workbench-bar-height)',\n 'tw:pointer-events-auto',\n\n // height — the drag-controlled var, capped at the space above the bar so the panel\n // never covers it, whatever height was dragged or restored\n 'tw:h-(--workbench-panel-height)',\n 'tw:max-h-[calc(100%-var(--workbench-bar-height))]',\n 'tw:group-data-[workbench-state=full-screen]/workbench:h-[calc(100%-var(--workbench-bar-height))]',\n\n // height transition\n 'tw:transition-[height]',\n 'tw:duration-200',\n 'tw:ease-out',\n 'tw:group-data-[workbench-resizing=true]/workbench:transition-none',\n\n // surface\n 'tw:border-x',\n 'tw:border-t',\n 'tw:border-border',\n\n // clipping\n 'tw:overflow-hidden',\n\n // raised edge\n 'tw:group-not-data-[workbench-state=full-screen]/workbench:rounded-t-2xl',\n 'tw:group-not-data-[workbench-state=full-screen]/workbench:shadow-(--workbench-panel-shadow)',\n )}\n >\n <WorkbenchPanelResizeHandle panelRef={panelRef} />\n\n <div\n className={cn(\n // layout\n 'tw:flex',\n 'tw:flex-col',\n 'tw:h-full',\n\n // surface\n 'tw:bg-background',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </Collapsible.Content>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'> & {\n asChild?: boolean;\n};\n\nexport const WorkbenchPanelActions = ({ className, asChild = false, ...props }: Props) => {\n const Comp = asChild ? Slot : 'div';\n\n return (\n <Comp\n {...props}\n data-slot=\"workbench-panel-actions\"\n className={cn(\n // grid placement\n 'tw:col-start-2',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelContent = ({ className, children, ...props }: Props) => (\n <div\n className={cn(\n // layout\n 'tw:min-h-0',\n 'tw:flex-1',\n 'tw:overflow-auto',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelHeader = ({ className, children, ...props }: Props) => (\n <div\n className={cn(\n // layout\n 'tw:grid',\n 'tw:grid-cols-[1fr_auto]',\n 'tw:items-center',\n 'tw:gap-x-2',\n\n // sizing\n 'tw:shrink-0',\n\n // surface\n 'tw:bg-sidebar',\n\n // spacing\n 'tw:px-3',\n 'tw:py-2',\n\n // typography\n 'tw:text-xs',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelTitle = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-panel-title\"\n className={cn(\n // grid placement\n 'tw:col-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n\n // typography\n 'tw:text-sm',\n 'tw:font-semibold',\n 'tw:text-foreground',\n\n className,\n )}\n />\n);\n","import { useMemo, useState } from 'react';\nimport type { CSSProperties, ReactNode } from 'react';\n\nimport { useControllableState } from '../../hooks/useControllableState';\nimport { cn } from '../../utils';\nimport { Collapsible } from '../Collapsible';\n\nimport {\n DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM,\n DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX,\n MIN_WORKBENCH_BAR_HEIGHT_IN_REM,\n MIN_WORKBENCH_PANEL_HEIGHT_IN_PX,\n} from './constants';\nimport type { WorkbenchState } from './context';\nimport { createWorkbenchActions, WorkbenchContext } from './context';\nimport {\n WorkbenchBar,\n WorkbenchBarEnd,\n WorkbenchBarMiddle,\n WorkbenchBarStart,\n} from './WorkbenchBar';\nimport { WorkbenchFullScreenTrigger } from './WorkbenchFullScreenTrigger';\nimport {\n WorkbenchPanel,\n WorkbenchPanelActions,\n WorkbenchPanelContent,\n WorkbenchPanelHeader,\n WorkbenchPanelTitle,\n} from './WorkbenchPanel';\n\ntype Props = {\n className?: string;\n children: ReactNode;\n state?: WorkbenchState;\n defaultState?: WorkbenchState;\n onStateChange?: (state: WorkbenchState) => void;\n barHeight?: number;\n panelHeight?: number;\n defaultPanelHeight?: number;\n onPanelHeightChange?: (panelHeight: number) => void;\n};\n\nexport const Workbench = ({\n className,\n children,\n state: stateProp,\n defaultState = 'collapsed',\n onStateChange,\n barHeight = DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM,\n panelHeight: panelHeightProp,\n defaultPanelHeight = DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX,\n onPanelHeightChange,\n}: Props) => {\n const [state, setState] = useControllableState<WorkbenchState>({\n prop: stateProp,\n defaultProp: defaultState,\n onChange: onStateChange,\n });\n const [panelHeight, setPanelHeight] = useControllableState<number>({\n prop: panelHeightProp,\n defaultProp: defaultPanelHeight,\n onChange: onPanelHeightChange,\n });\n const [isResizing, setIsResizing] = useState(false);\n\n const actions = useMemo(() => createWorkbenchActions(setState), [setState]);\n const value = useMemo(\n () => ({\n state,\n setState,\n panelHeight,\n setPanelHeight,\n isResizing,\n setIsResizing,\n ...actions,\n }),\n [state, setState, panelHeight, setPanelHeight, isResizing, actions],\n );\n\n const clampedBarHeight = Math.max(barHeight, MIN_WORKBENCH_BAR_HEIGHT_IN_REM);\n const clampedPanelHeight = Math.max(panelHeight, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX);\n\n return (\n <WorkbenchContext value={value}>\n <Collapsible\n open={state !== 'collapsed'}\n onOpenChange={(open) => setState(open ? 'expanded' : 'collapsed')}\n data-workbench-state={state}\n data-workbench-resizing={isResizing ? 'true' : undefined}\n style={\n {\n '--workbench-bar-height': `${clampedBarHeight}rem`,\n '--workbench-panel-height': `${clampedPanelHeight}px`,\n } as CSSProperties\n }\n className={cn(\n // reset\n 'tailwindcss-preflight',\n\n // group\n 'tw:group/workbench',\n\n // positioning — above the chrome layer (`z-50`) *and* above a `Sidebar` in\n // `expand-on-hover`, which takes `z-51` to float over content; the dock outranks both.\n // Overlays (Modal / Sheet / Popover / Tooltip) live at 1051+, so they still win.\n 'tw:z-[52]',\n\n // layout\n 'tw:shrink-0',\n\n className,\n )}\n >\n {children}\n </Collapsible>\n </WorkbenchContext>\n );\n};\n\nWorkbench.Bar = WorkbenchBar;\nWorkbench.BarStart = WorkbenchBarStart;\nWorkbench.BarMiddle = WorkbenchBarMiddle;\nWorkbench.BarEnd = WorkbenchBarEnd;\n\nWorkbench.Panel = WorkbenchPanel;\nWorkbench.PanelHeader = WorkbenchPanelHeader;\nWorkbench.PanelTitle = WorkbenchPanelTitle;\nWorkbench.PanelActions = WorkbenchPanelActions;\nWorkbench.PanelContent = WorkbenchPanelContent;\n\nWorkbench.Trigger = Collapsible.Trigger;\nWorkbench.FullScreenTrigger = WorkbenchFullScreenTrigger;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Workbench-4s0xP6XU.js","names":[],"sources":["../src/components/Workbench/constants.ts","../src/components/Workbench/context.ts","../src/components/Workbench/WorkbenchBar/WorkbenchBarEnd.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBarMiddle.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBarStart.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBar.tsx","../src/components/Workbench/WorkbenchFullScreenTrigger.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelResizeHandle.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanel.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelActions.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelContent.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelHeader.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelTitle.tsx","../src/components/Workbench/Workbench.tsx"],"sourcesContent":["export const DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM = 2.75;\n\nexport const MIN_WORKBENCH_BAR_HEIGHT_IN_REM = 1;\n\nexport const DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX = 320;\n\nexport const MIN_WORKBENCH_PANEL_HEIGHT_IN_PX = 120;\n\nexport const WORKBENCH_PANEL_RESIZE_STEP_IN_PX = 24;\n\nexport const WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO = 0.8;\n","import { createContext, use } from 'react';\nimport type { Dispatch, SetStateAction } from 'react';\n\n/**\n * Full screen is a mode of the open panel, not a flag beside it — as two booleans the fourth\n * combination (collapsed *and* full screen) is expressible but meaningless.\n */\nexport type WorkbenchState = 'collapsed' | 'expanded' | 'full-screen';\n\ntype WorkbenchActions = {\n expand: () => void;\n collapse: () => void;\n toggleExpanded: () => void;\n enterFullScreen: () => void;\n exitFullScreen: () => void;\n toggleFullScreen: () => void;\n};\n\ntype WorkbenchContextValue = WorkbenchActions & {\n state: WorkbenchState;\n setState: Dispatch<SetStateAction<WorkbenchState>>;\n panelHeight: number;\n setPanelHeight: Dispatch<SetStateAction<number>>;\n isResizing: boolean;\n setIsResizing: (isResizing: boolean) => void;\n};\n\nexport const createWorkbenchActions = (\n setState: Dispatch<SetStateAction<WorkbenchState>>,\n): WorkbenchActions => ({\n // Opening an already-open panel leaves full screen alone.\n expand: () => setState((state) => (state === 'collapsed' ? 'expanded' : state)),\n collapse: () => setState('collapsed'),\n toggleExpanded: () => setState((state) => (state === 'collapsed' ? 'expanded' : 'collapsed')),\n\n enterFullScreen: () => setState('full-screen'),\n // Exiting returns to the open panel, never to a closed one — this is a restore, not a collapse.\n exitFullScreen: () => setState((state) => (state === 'full-screen' ? 'expanded' : state)),\n toggleFullScreen: () =>\n setState((state) => (state === 'full-screen' ? 'expanded' : 'full-screen')),\n});\n\nexport const WorkbenchContext = createContext<WorkbenchContextValue | null>(null);\n\n/**\n * The parts sit at arbitrary depth under `<Workbench>` — a trigger lives inside the panel header,\n * three levels down — so the state travels by context rather than props.\n */\nexport const useWorkbench = (): WorkbenchContextValue => {\n const context = use(WorkbenchContext);\n\n if (context === null) {\n throw new Error('Workbench compound components must be rendered inside <Workbench>.');\n }\n\n return context;\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarEnd = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-end\"\n className={cn(\n // grid placement\n 'tw:col-start-3',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-end',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarMiddle = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-middle\"\n className={cn(\n // grid placement\n 'tw:col-start-2',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarStart = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-start\"\n className={cn(\n // grid placement\n 'tw:col-start-1',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\nimport { WorkbenchBarEnd } from './WorkbenchBarEnd';\nimport { WorkbenchBarMiddle } from './WorkbenchBarMiddle';\nimport { WorkbenchBarStart } from './WorkbenchBarStart';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBar = ({ className, children, ...props }: Props) => (\n <div\n // Marked so a floating surface (kbc-ui's Kai widget) can measure the dock; the root's rect is the bar alone.\n data-workbench-slot=\"bar\"\n className={cn(\n // layout\n 'tw:grid',\n 'tw:grid-cols-[auto_1fr_auto]',\n 'tw:items-center',\n 'tw:gap-x-2',\n\n // sizing\n 'tw:h-(--workbench-bar-height)',\n 'tw:shrink-0',\n 'tw:pointer-events-auto',\n\n // surface\n 'tw:border-t',\n 'tw:border-sidebar-border',\n 'tw:bg-sidebar',\n\n // spacing\n 'tw:px-3',\n\n // typography\n 'tw:text-xs',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n\nWorkbenchBar.Start = WorkbenchBarStart;\nWorkbenchBar.Middle = WorkbenchBarMiddle;\nWorkbenchBar.End = WorkbenchBarEnd;\n","import type { ComponentProps, MouseEvent } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { useWorkbench } from './context';\n\ntype Props = ComponentProps<'button'> & {\n asChild?: boolean;\n};\n\nexport const WorkbenchFullScreenTrigger = ({ asChild = false, onClick, ...props }: Props) => {\n const { state, toggleFullScreen } = useWorkbench();\n const isFullScreen = state === 'full-screen';\n const Comp = asChild ? Slot : 'button';\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.defaultPrevented) {\n toggleFullScreen();\n }\n };\n\n return (\n <Comp\n {...(asChild ? {} : { type: 'button' as const })}\n {...props}\n data-slot=\"workbench-full-screen-trigger\"\n data-state={isFullScreen ? 'on' : 'off'}\n onClick={handleClick}\n />\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { KeyboardEvent, PointerEvent, RefObject } from 'react';\n\nimport { cn } from '../../../utils';\nimport {\n MIN_WORKBENCH_PANEL_HEIGHT_IN_PX,\n WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO,\n WORKBENCH_PANEL_RESIZE_STEP_IN_PX,\n} from '../constants';\nimport { useWorkbench } from '../context';\n\ntype Props = {\n panelRef: RefObject<HTMLDivElement | null>;\n};\n\nconst getMaxHeight = (panel: HTMLDivElement) => {\n const hostTop = panel.offsetParent?.getBoundingClientRect().top ?? 0;\n\n return Math.max(panel.getBoundingClientRect().bottom - hostTop, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX);\n};\n\nconst clampHeight = (height: number, panel: HTMLDivElement) =>\n Math.min(Math.max(height, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX), getMaxHeight(panel));\n\nexport const WorkbenchPanelResizeHandle = ({ panelRef }: Props) => {\n const {\n state,\n panelHeight,\n setPanelHeight,\n isResizing,\n setIsResizing,\n enterFullScreen,\n exitFullScreen,\n } = useWorkbench();\n const grabOffsetRef = useRef(0);\n const previousStateRef = useRef(state);\n const isFullScreenRequestedRef = useRef(state === 'full-screen');\n const enteredFullScreenByDragRef = useRef(false);\n const exitedFullScreenByDragRef = useRef(false);\n\n useEffect(() => {\n if (!isResizing) return;\n\n const { body } = document;\n const { cursor, userSelect } = body.style;\n\n body.style.cursor = 'ns-resize';\n body.style.userSelect = 'none';\n\n return () => {\n body.style.cursor = cursor;\n body.style.userSelect = userSelect;\n };\n }, [isResizing]);\n\n useEffect(() => {\n const previous = previousStateRef.current;\n const panel = panelRef.current;\n\n previousStateRef.current = state;\n isFullScreenRequestedRef.current = state === 'full-screen';\n\n if (previous !== 'full-screen' || state !== 'expanded' || !panel) return;\n\n const draggedIntoFullScreen = enteredFullScreenByDragRef.current;\n const draggedOutOfFullScreen = exitedFullScreenByDragRef.current;\n\n enteredFullScreenByDragRef.current = false;\n exitedFullScreenByDragRef.current = false;\n\n if (!draggedIntoFullScreen || draggedOutOfFullScreen) return;\n\n setPanelHeight(\n clampHeight(getMaxHeight(panel) * WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO, panel),\n );\n }, [state, panelRef, setPanelHeight]);\n\n const applyHeight = (height: number, panel: HTMLDivElement) => {\n const isFullScreen = isFullScreenRequestedRef.current;\n\n if (height >= getMaxHeight(panel)) {\n if (!isFullScreen) {\n isFullScreenRequestedRef.current = true;\n enteredFullScreenByDragRef.current = true;\n enterFullScreen();\n }\n\n return;\n }\n\n if (isFullScreen) {\n isFullScreenRequestedRef.current = false;\n exitedFullScreenByDragRef.current = true;\n exitFullScreen();\n }\n\n setPanelHeight(Math.max(height, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX));\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (event.button !== 0 || !panel) return;\n\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n grabOffsetRef.current = panel.getBoundingClientRect().top - event.clientY;\n setIsResizing(true);\n };\n\n const handlePointerMove = (event: PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (!panel || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n\n const top = event.clientY + grabOffsetRef.current;\n\n applyHeight(panel.getBoundingClientRect().bottom - top, panel);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (!panel) return;\n\n const step = event.shiftKey\n ? WORKBENCH_PANEL_RESIZE_STEP_IN_PX * 4\n : WORKBENCH_PANEL_RESIZE_STEP_IN_PX;\n const delta = event.key === 'ArrowUp' ? step : event.key === 'ArrowDown' ? -step : 0;\n\n if (delta === 0) return;\n\n event.preventDefault();\n applyHeight(\n (isFullScreenRequestedRef.current ? getMaxHeight(panel) : panelHeight) + delta,\n panel,\n );\n };\n\n return (\n <div\n role=\"separator\"\n aria-orientation=\"horizontal\"\n aria-label=\"Resize panel\"\n aria-valuenow={Math.round(panelHeight)}\n aria-valuemin={MIN_WORKBENCH_PANEL_HEIGHT_IN_PX}\n tabIndex={0}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onLostPointerCapture={() => setIsResizing(false)}\n onKeyDown={handleKeyDown}\n className={cn(\n // group\n 'tw:group/workbench-resize',\n\n // positioning — the panel is the positioned ancestor\n 'tw:absolute',\n 'tw:inset-x-0',\n 'tw:top-0',\n 'tw:z-10',\n\n // sizing\n 'tw:h-2',\n\n // layout — the whole strip grabs, only the pill shows\n 'tw:flex',\n 'tw:justify-center',\n\n // affordance\n 'tw:cursor-ns-resize',\n 'tw:touch-none',\n\n // focus\n 'tw:outline-none',\n )}\n >\n <span\n className={cn(\n // layout — hangs below the strip so the pill sits clear of the top edge, and\n // grabs there too since the events bubble to the strip\n 'tw:flex',\n 'tw:h-3',\n 'tw:w-16',\n 'tw:items-end',\n 'tw:justify-center',\n )}\n >\n <span\n className={cn(\n // sizing\n 'tw:h-1.5',\n 'tw:w-16',\n\n // surface\n 'tw:rounded-full',\n 'tw:bg-input',\n 'tw:transition-colors',\n 'tw:group-hover/workbench-resize:bg-muted-foreground',\n 'tw:group-focus-visible/workbench-resize:bg-muted-foreground',\n 'tw:group-data-[workbench-resizing=true]/workbench:bg-muted-foreground',\n )}\n />\n </span>\n </div>\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { ComponentProps, CSSProperties } from 'react';\n\nimport { cn } from '../../../utils';\nimport { Collapsible } from '../../Collapsible';\n\nimport { WorkbenchPanelResizeHandle } from './WorkbenchPanelResizeHandle';\n\ntype Props = ComponentProps<'div'>;\n\nconst clearRadixMeasurementTransitionBlock = (panel: HTMLDivElement | null) => {\n if (panel) panel.style.transitionDuration = '';\n};\n\nexport const WorkbenchPanel = ({ className, children, ...props }: Props) => {\n const panelRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => clearRadixMeasurementTransitionBlock(panelRef.current), []);\n\n return (\n <Collapsible.Content\n ref={panelRef}\n // See `WorkbenchBar` — the other half of the dock's measurable area.\n data-workbench-slot=\"panel\"\n style={{ '--workbench-panel-shadow': '0 -8px 24px -6px rgb(0 0 0 / 0.08)' } as CSSProperties}\n className={cn(\n // positioning — against the host, which must be a positioned element\n 'tw:absolute',\n 'tw:inset-x-0',\n 'tw:bottom-(--workbench-bar-height)',\n 'tw:pointer-events-auto',\n\n // height — the drag-controlled var, capped at the space above the bar so the panel\n // never covers it, whatever height was dragged or restored\n 'tw:h-(--workbench-panel-height)',\n 'tw:max-h-[calc(100%-var(--workbench-bar-height))]',\n 'tw:group-data-[workbench-state=full-screen]/workbench:h-[calc(100%-var(--workbench-bar-height))]',\n\n // height transition\n 'tw:transition-[height]',\n 'tw:duration-200',\n 'tw:ease-out',\n 'tw:group-data-[workbench-resizing=true]/workbench:transition-none',\n\n // surface\n 'tw:border-x',\n 'tw:border-t',\n 'tw:border-border',\n\n // clipping\n 'tw:overflow-hidden',\n\n // raised edge\n 'tw:group-not-data-[workbench-state=full-screen]/workbench:rounded-t-2xl',\n 'tw:group-not-data-[workbench-state=full-screen]/workbench:shadow-(--workbench-panel-shadow)',\n )}\n >\n <WorkbenchPanelResizeHandle panelRef={panelRef} />\n\n <div\n className={cn(\n // layout\n 'tw:flex',\n 'tw:flex-col',\n 'tw:h-full',\n\n // surface\n 'tw:bg-background',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </Collapsible.Content>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'> & {\n asChild?: boolean;\n};\n\nexport const WorkbenchPanelActions = ({ className, asChild = false, ...props }: Props) => {\n const Comp = asChild ? Slot : 'div';\n\n return (\n <Comp\n {...props}\n data-slot=\"workbench-panel-actions\"\n className={cn(\n // grid placement\n 'tw:col-start-2',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelContent = ({ className, children, ...props }: Props) => (\n <div\n className={cn(\n // layout\n 'tw:min-h-0',\n 'tw:flex-1',\n 'tw:overflow-auto',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelHeader = ({ className, children, ...props }: Props) => (\n <div\n className={cn(\n // layout\n 'tw:grid',\n 'tw:grid-cols-[1fr_auto]',\n 'tw:items-center',\n 'tw:gap-x-2',\n\n // sizing\n 'tw:shrink-0',\n\n // surface\n 'tw:bg-sidebar',\n\n // spacing\n 'tw:px-3',\n 'tw:py-2',\n\n // typography\n 'tw:text-xs',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelTitle = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-panel-title\"\n className={cn(\n // grid placement\n 'tw:col-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n\n // typography\n 'tw:text-sm',\n 'tw:font-semibold',\n 'tw:text-foreground',\n\n className,\n )}\n />\n);\n","import { useMemo, useState } from 'react';\nimport type { CSSProperties, ReactNode } from 'react';\n\nimport { useControllableState } from '../../hooks/useControllableState';\nimport { cn } from '../../utils';\nimport { Collapsible } from '../Collapsible';\n\nimport {\n DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM,\n DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX,\n MIN_WORKBENCH_BAR_HEIGHT_IN_REM,\n MIN_WORKBENCH_PANEL_HEIGHT_IN_PX,\n} from './constants';\nimport type { WorkbenchState } from './context';\nimport { createWorkbenchActions, WorkbenchContext } from './context';\nimport {\n WorkbenchBar,\n WorkbenchBarEnd,\n WorkbenchBarMiddle,\n WorkbenchBarStart,\n} from './WorkbenchBar';\nimport { WorkbenchFullScreenTrigger } from './WorkbenchFullScreenTrigger';\nimport {\n WorkbenchPanel,\n WorkbenchPanelActions,\n WorkbenchPanelContent,\n WorkbenchPanelHeader,\n WorkbenchPanelTitle,\n} from './WorkbenchPanel';\n\ntype Props = {\n className?: string;\n children: ReactNode;\n state?: WorkbenchState;\n defaultState?: WorkbenchState;\n onStateChange?: (state: WorkbenchState) => void;\n barHeight?: number;\n panelHeight?: number;\n defaultPanelHeight?: number;\n onPanelHeightChange?: (panelHeight: number) => void;\n};\n\nexport const Workbench = ({\n className,\n children,\n state: stateProp,\n defaultState = 'collapsed',\n onStateChange,\n barHeight = DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM,\n panelHeight: panelHeightProp,\n defaultPanelHeight = DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX,\n onPanelHeightChange,\n}: Props) => {\n const [state, setState] = useControllableState<WorkbenchState>({\n prop: stateProp,\n defaultProp: defaultState,\n onChange: onStateChange,\n });\n const [panelHeight, setPanelHeight] = useControllableState<number>({\n prop: panelHeightProp,\n defaultProp: defaultPanelHeight,\n onChange: onPanelHeightChange,\n });\n const [isResizing, setIsResizing] = useState(false);\n\n const actions = useMemo(() => createWorkbenchActions(setState), [setState]);\n const value = useMemo(\n () => ({\n state,\n setState,\n panelHeight,\n setPanelHeight,\n isResizing,\n setIsResizing,\n ...actions,\n }),\n [state, setState, panelHeight, setPanelHeight, isResizing, actions],\n );\n\n const clampedBarHeight = Math.max(barHeight, MIN_WORKBENCH_BAR_HEIGHT_IN_REM);\n const clampedPanelHeight = Math.max(panelHeight, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX);\n\n return (\n <WorkbenchContext value={value}>\n <Collapsible\n open={state !== 'collapsed'}\n onOpenChange={(open) => setState(open ? 'expanded' : 'collapsed')}\n data-workbench-state={state}\n data-workbench-resizing={isResizing ? 'true' : undefined}\n style={\n {\n '--workbench-bar-height': `${clampedBarHeight}rem`,\n '--workbench-panel-height': `${clampedPanelHeight}px`,\n } as CSSProperties\n }\n className={cn(\n // reset\n 'tailwindcss-preflight',\n\n // group\n 'tw:group/workbench',\n\n // positioning — above the chrome layer (`z-50`) *and* above a `Sidebar` in\n // `expand-on-hover`, which takes `z-51` to float over content; the dock outranks both.\n // Overlays (Modal / Sheet / Popover / Tooltip) live on `z-overlay` and above, so they still win.\n 'tw:z-[52]',\n\n // layout\n 'tw:shrink-0',\n\n className,\n )}\n >\n {children}\n </Collapsible>\n </WorkbenchContext>\n );\n};\n\nWorkbench.Bar = WorkbenchBar;\nWorkbench.BarStart = WorkbenchBarStart;\nWorkbench.BarMiddle = WorkbenchBarMiddle;\nWorkbench.BarEnd = WorkbenchBarEnd;\n\nWorkbench.Panel = WorkbenchPanel;\nWorkbench.PanelHeader = WorkbenchPanelHeader;\nWorkbench.PanelTitle = WorkbenchPanelTitle;\nWorkbench.PanelActions = WorkbenchPanelActions;\nWorkbench.PanelContent = WorkbenchPanelContent;\n\nWorkbench.Trigger = Collapsible.Trigger;\nWorkbench.FullScreenTrigger = WorkbenchFullScreenTrigger;\n"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { cn } from "./classNames-
|
|
2
|
-
import { Tooltip } from "./utils-
|
|
3
|
-
import { Maximize2, Minimize2 } from "./icons-
|
|
4
|
-
import { Button } from "./Button-
|
|
5
|
-
import { ClipboardButton } from "./ClipboardButton-
|
|
1
|
+
import { cn } from "./classNames-DkX30VJU.js";
|
|
2
|
+
import { Tooltip } from "./utils-DjFceY3H.js";
|
|
3
|
+
import { Maximize2, Minimize2 } from "./icons-DDR9dFSr.js";
|
|
4
|
+
import { Button } from "./Button-DbvGzEDb.js";
|
|
5
|
+
import { ClipboardButton } from "./ClipboardButton-71Ugbl8c.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";
|
|
9
9
|
import DOMPurify from "dompurify";
|
|
10
|
-
|
|
10
|
+
// src/components/ZoomableSvg/exportSvg.ts
|
|
11
11
|
const PNG_SCALE = 2;
|
|
12
12
|
const ROOT_SVG_TAG = /^<svg\b[^>]*>/i;
|
|
13
13
|
const HAS_DEFAULT_NAMESPACE = /\bxmlns\s*=/i;
|
|
@@ -80,8 +80,7 @@ const svgToPngBlob = async (svg, background) => {
|
|
|
80
80
|
canvas.toBlob((blob) => blob ? resolve(blob) : reject(/* @__PURE__ */ new Error("Failed to encode the PNG.")), "image/png");
|
|
81
81
|
});
|
|
82
82
|
};
|
|
83
|
-
|
|
84
|
-
//#region src/components/ZoomableSvg/ZoomableSvg.tsx
|
|
83
|
+
// src/components/ZoomableSvg/ZoomableSvg.tsx
|
|
85
84
|
const MIN_SCALE = .5;
|
|
86
85
|
const MAX_SCALE = 3;
|
|
87
86
|
const ZOOM_STEP = .1;
|
|
@@ -223,7 +222,7 @@ const ZoomableSvg = ({ html, copyText, className, allowForeignObject, allowUse,
|
|
|
223
222
|
if (isFullscreen) return createPortal(/* @__PURE__ */ jsx("div", {
|
|
224
223
|
role: "presentation",
|
|
225
224
|
"data-testid": "zoomable-svg-fullscreen",
|
|
226
|
-
className: "tw:fixed tw:inset-0 tw:z-
|
|
225
|
+
className: "tw:fixed tw:inset-0 tw:z-overlay tw:bg-muted tw:p-4 tailwindcss-preflight",
|
|
227
226
|
onClick: stopPropagation,
|
|
228
227
|
children: diagramContent
|
|
229
228
|
}), document.body);
|
|
@@ -232,7 +231,6 @@ const ZoomableSvg = ({ html, copyText, className, allowForeignObject, allowUse,
|
|
|
232
231
|
children: diagramContent
|
|
233
232
|
});
|
|
234
233
|
};
|
|
235
|
-
//#endregion
|
|
236
234
|
export { ZoomableSvg, svgToPngBlob, toSvgFileContent };
|
|
237
235
|
|
|
238
|
-
//# sourceMappingURL=ZoomableSvg-
|
|
236
|
+
//# sourceMappingURL=ZoomableSvg-BRPGgaWJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZoomableSvg-DnFXo2L4.js","names":[],"sources":["../src/components/ZoomableSvg/exportSvg.ts","../src/components/ZoomableSvg/ZoomableSvg.tsx"],"sourcesContent":["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; inline diagram output may\n// omit 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// diagram 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","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; DOMPurify-sanitized (SVG profile), so user/LLM content is safe. */\n html: string;\n copyText?: string;\n className?: string;\n /** Keep `<foreignObject>` through sanitization; its HTML children are still stripped.\n * Enable only when each one is pre-flattened to bare text. */\n allowForeignObject?: boolean;\n /** Keep `<use>` through sanitization. Enable only when every `href` is already a `#` reference. */\n allowUse?: boolean;\n /** Extra toolbar controls (e.g. `ExportMenu`) between copy and fullscreen; receives the\n * sanitized SVG. Injected so this lazy chunk carries no export dependencies. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const ZoomableSvg = ({\n html,\n copyText,\n className,\n allowForeignObject,\n allowUse,\n renderActions,\n}: Props) => {\n const safeHtml = useMemo(\n () =>\n DOMPurify.sanitize(html, {\n USE_PROFILES: { svg: true, svgFilters: true },\n ADD_TAGS: [...(allowForeignObject ? ['foreignObject'] : []), ...(allowUse ? ['use'] : [])],\n }),\n [html, allowForeignObject, allowUse],\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` too: the opacity-0 toolbar is still in the tab order.\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 // z-1051 (Modal band): must stay below floating panels (z-1055) or toolbar menus hide.\n // Tooltip (z-1060) and SpotlightBackdrop (z-1056) sit above it by design.\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"],"mappings":";;;;;;;;;;AAAA,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;;;AC1HA,MAAM,YAAY;AAClB,MAAM,YAAY;AAClB,MAAM,YAAY;AAiBlB,MAAa,eAAe,EAC1B,MACA,UACA,WACA,oBACA,UACA,oBACW;CACX,MAAM,WAAW,cAEb,UAAU,SAAS,MAAM;EACvB,cAAc;GAAE,KAAK;GAAM,YAAY;EAAK;EAC5C,UAAU,CAAC,GAAI,qBAAqB,CAAC,eAAe,IAAI,CAAC,GAAI,GAAI,WAAW,CAAC,KAAK,IAAI,CAAC,CAAE;CAC3F,CAAC,GACH;EAAC;EAAM;EAAoB;CAAQ,CACrC;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;GAEL,WAAU;GACV,SAAS;GAJX,UAAA;IAMG,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;EAGZ,WAAU;EACV,SAAS;EAER,UAAA;CACE,CAAA,GACL,SAAS,IACX;CAGF,OACE,oBAAC,OAAD;EACE,WAAW,GACT,2EACA,SACF;EAEC,UAAA;CACE,CAAA;AAET"}
|
|
1
|
+
{"version":3,"file":"ZoomableSvg-BRPGgaWJ.js","names":[],"sources":["../src/components/ZoomableSvg/exportSvg.ts","../src/components/ZoomableSvg/ZoomableSvg.tsx"],"sourcesContent":["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; inline diagram output may\n// omit 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// diagram 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","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; DOMPurify-sanitized (SVG profile), so user/LLM content is safe. */\n html: string;\n copyText?: string;\n className?: string;\n /** Keep `<foreignObject>` through sanitization; its HTML children are still stripped.\n * Enable only when each one is pre-flattened to bare text. */\n allowForeignObject?: boolean;\n /** Keep `<use>` through sanitization. Enable only when every `href` is already a `#` reference. */\n allowUse?: boolean;\n /** Extra toolbar controls (e.g. `ExportMenu`) between copy and fullscreen; receives the\n * sanitized SVG. Injected so this lazy chunk carries no export dependencies. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const ZoomableSvg = ({\n html,\n copyText,\n className,\n allowForeignObject,\n allowUse,\n renderActions,\n}: Props) => {\n const safeHtml = useMemo(\n () =>\n DOMPurify.sanitize(html, {\n USE_PROFILES: { svg: true, svgFilters: true },\n ADD_TAGS: [...(allowForeignObject ? ['foreignObject'] : []), ...(allowUse ? ['use'] : [])],\n }),\n [html, allowForeignObject, allowUse],\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` too: the opacity-0 toolbar is still in the tab order.\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 // `z-overlay`: a toolbar menu opened later paints over it.\n // Tooltip (z-1060) and SpotlightBackdrop (z-1056) sit above it by design.\n className=\"tw:fixed tw:inset-0 tw:z-overlay 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"],"mappings":"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"}
|
package/dist/charts.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ComponentProps, ReactElement } from "react";
|
|
2
2
|
import { Tooltip } from "recharts";
|
|
3
|
-
//#region src/blocks/Charts/ChartContainer.d.ts
|
|
4
3
|
/** A length that recharts' `<ResponsiveContainer>` accepts: px number or `"NN%"`. */
|
|
5
4
|
type ChartDimension = number | `${number}%`;
|
|
6
5
|
type ChartContainerProps = Omit<ComponentProps<'div'>, 'children'> & {
|
|
@@ -13,8 +12,6 @@ type ChartContainerProps = Omit<ComponentProps<'div'>, 'children'> & {
|
|
|
13
12
|
};
|
|
14
13
|
/** Responsive frame that themes the chart's axis, grid and cursor with semantic tokens via CSS. */
|
|
15
14
|
declare const ChartContainer: ({ height, width, className, children, ...props }: ChartContainerProps) => import("react").JSX.Element;
|
|
16
|
-
//#endregion
|
|
17
|
-
//#region src/blocks/Charts/ChartTooltip.d.ts
|
|
18
15
|
type TooltipPayloadEntry = {
|
|
19
16
|
name?: string | number;
|
|
20
17
|
value?: string | number;
|
|
@@ -43,14 +40,10 @@ type ChartTooltipProps = ComponentProps<typeof Tooltip> & {
|
|
|
43
40
|
* Each chart mounts one by default; pass `showTooltip={false}` on the chart to omit.
|
|
44
41
|
*/
|
|
45
42
|
declare const ChartTooltip: ({ valueFormatter, ...props }: ChartTooltipProps) => import("react").JSX.Element;
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/blocks/Charts/theme.d.ts
|
|
48
43
|
/** Number of the semantic chart token (`1`–`5`) a series maps to. */
|
|
49
44
|
type ChartColorToken = 1 | 2 | 3 | 4 | 5;
|
|
50
45
|
/** The CSS color for a 0-based series `index`, wrapping around the palette. */
|
|
51
46
|
declare const chartTokenColor: (index: number) => string;
|
|
52
|
-
//#endregion
|
|
53
|
-
//#region src/blocks/Charts/types.d.ts
|
|
54
47
|
/** A single row of chart data — an object keyed by the axis + series keys. */
|
|
55
48
|
type ChartDatum = Record<string, string | number | null | undefined>;
|
|
56
49
|
/**
|
|
@@ -106,8 +99,6 @@ type CartesianChartProps = {
|
|
|
106
99
|
valueFormatter?: (value: number) => string;
|
|
107
100
|
className?: string;
|
|
108
101
|
};
|
|
109
|
-
//#endregion
|
|
110
|
-
//#region src/blocks/Charts/LineChart.d.ts
|
|
111
102
|
type LineChartProps = CartesianChartProps & {
|
|
112
103
|
/**
|
|
113
104
|
* Y-axis `[min, max]`; defaults to a zero baseline. Line-only: a truncated baseline misstates
|
|
@@ -122,8 +113,6 @@ type LineChartProps = CartesianChartProps & {
|
|
|
122
113
|
* - Mounts its own {@link ChartContainer}.
|
|
123
114
|
*/
|
|
124
115
|
declare const LineChart: ({ data, xKey, series, height, width, className, ...chrome }: LineChartProps) => import("react").JSX.Element;
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/blocks/Charts/BarChart.d.ts
|
|
127
116
|
type BarChartProps = CartesianChartProps & {
|
|
128
117
|
/** Stack the series into a single bar per category. Defaults to grouped. */
|
|
129
118
|
stacked?: boolean;
|
|
@@ -138,8 +127,6 @@ type BarChartProps = CartesianChartProps & {
|
|
|
138
127
|
* <BarChart data={data} xKey="month" series={[{ dataKey: 'revenue' }]} />
|
|
139
128
|
*/
|
|
140
129
|
declare const BarChart: ({ data, xKey, series, height, width, className, stacked, ...chrome }: BarChartProps) => import("react").JSX.Element;
|
|
141
|
-
//#endregion
|
|
142
|
-
//#region src/blocks/Charts/AreaChart.d.ts
|
|
143
130
|
type AreaChartProps = CartesianChartProps & {
|
|
144
131
|
/** Stack the series into a cumulative area. Defaults to overlaid. */
|
|
145
132
|
stacked?: boolean;
|
|
@@ -154,8 +141,6 @@ type AreaChartProps = CartesianChartProps & {
|
|
|
154
141
|
* <AreaChart data={data} xKey="month" series={[{ dataKey: 'revenue' }]} />
|
|
155
142
|
*/
|
|
156
143
|
declare const AreaChart: ({ data, xKey, series, height, width, className, stacked, ...chrome }: AreaChartProps) => import("react").JSX.Element;
|
|
157
|
-
//#endregion
|
|
158
|
-
//#region src/blocks/Charts/PieChart.d.ts
|
|
159
144
|
type PieChartProps = {
|
|
160
145
|
/** The rows to plot — one sector per row. */
|
|
161
146
|
data: ChartDatum[];
|
|
@@ -187,6 +172,5 @@ type PieChartProps = {
|
|
|
187
172
|
* <PieChart data={data} nameKey="engine" dataKey="rows" innerRadius="60%" />
|
|
188
173
|
*/
|
|
189
174
|
declare const PieChart: ({ data, nameKey, dataKey, innerRadius, height, width, className, showLegend, showTooltip, valueFormatter }: PieChartProps) => import("react").JSX.Element;
|
|
190
|
-
//#endregion
|
|
191
175
|
export { AreaChart, type AreaChartProps, BarChart, type BarChartProps, type CartesianChartProps, type ChartAxisDomain, type ChartAxisLowerBound, type ChartAxisUpperBound, type ChartColorToken, ChartContainer, type ChartContainerProps, type ChartDatum, type ChartDimension, type ChartSeries, ChartTooltip, ChartTooltipContent, type ChartTooltipProps, LineChart, type LineChartProps, PieChart, type PieChartProps, chartTokenColor };
|
|
192
176
|
//# sourceMappingURL=charts.d.ts.map
|
package/dist/charts.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { cn } from "./classNames-
|
|
1
|
+
import { cn } from "./classNames-DkX30VJU.js";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Area, AreaChart as AreaChart$1, Bar, BarChart as BarChart$1, CartesianGrid, Cell, Legend, Line, LineChart as LineChart$1, Pie, PieChart as PieChart$1, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
|
4
|
-
|
|
4
|
+
// src/blocks/Charts/ChartContainer.tsx
|
|
5
5
|
/** Responsive frame that themes the chart's axis, grid and cursor with semantic tokens via CSS. */
|
|
6
6
|
const ChartContainer = ({ height = 300, width = "100%", className, children, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
7
7
|
className: cn("tw:text-xs", "tw:[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground", "tw:[&_.recharts-polar-angle-axis-tick_text]:fill-muted-foreground", "tw:[&_.recharts-label]:fill-muted-foreground", "tw:[&_.recharts-legend-item-text]:!text-muted-foreground", "tw:[&_.recharts-cartesian-grid_line]:stroke-border/60", "tw:[&_.recharts-cartesian-axis-line]:stroke-border", "tw:[&_.recharts-cartesian-axis-tick-line]:stroke-border", "tw:[&_.recharts-curve.recharts-tooltip-cursor]:stroke-border", "tw:[&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted/60", "tw:[&_.recharts-surface]:outline-hidden", className),
|
|
@@ -12,8 +12,7 @@ const ChartContainer = ({ height = 300, width = "100%", className, children, ...
|
|
|
12
12
|
children
|
|
13
13
|
})
|
|
14
14
|
});
|
|
15
|
-
|
|
16
|
-
//#region src/blocks/Charts/ChartTooltip.tsx
|
|
15
|
+
// src/blocks/Charts/ChartTooltip.tsx
|
|
17
16
|
/**
|
|
18
17
|
* Brand-themed tooltip body. Surfaces (background, border, text) resolve from
|
|
19
18
|
* semantic tokens, and each series swatch reuses the recharts-provided series
|
|
@@ -61,8 +60,7 @@ const ChartTooltip = ({ valueFormatter, ...props }) => /* @__PURE__ */ jsx(Toolt
|
|
|
61
60
|
content: /* @__PURE__ */ jsx(ChartTooltipContent, { valueFormatter }),
|
|
62
61
|
...props
|
|
63
62
|
});
|
|
64
|
-
|
|
65
|
-
//#region src/blocks/Charts/format.ts
|
|
63
|
+
// src/blocks/Charts/format.ts
|
|
66
64
|
/**
|
|
67
65
|
* Apply a numeric `valueFormatter` safely. recharts hands axis ticks and
|
|
68
66
|
* tooltip payload values as `string | number | null | undefined`, and partial
|
|
@@ -77,8 +75,7 @@ const formatValue = (value, valueFormatter) => {
|
|
|
77
75
|
if (!Number.isFinite(num)) return "";
|
|
78
76
|
return valueFormatter ? valueFormatter(num) : String(num);
|
|
79
77
|
};
|
|
80
|
-
|
|
81
|
-
//#region src/blocks/Charts/cartesian.tsx
|
|
78
|
+
// src/blocks/Charts/cartesian.tsx
|
|
82
79
|
const AXIS_PROPS = {
|
|
83
80
|
tickLine: false,
|
|
84
81
|
axisLine: false,
|
|
@@ -108,8 +105,7 @@ const cartesianChrome = ({ xKey, showGrid = true, showYAxis = true, showLegend =
|
|
|
108
105
|
showTooltip && /* @__PURE__ */ jsx(ChartTooltip, { valueFormatter: valueFormatter ? (value) => formatValue(value, valueFormatter) : void 0 }),
|
|
109
106
|
showLegend && /* @__PURE__ */ jsx(Legend, { wrapperStyle: { fontSize: 11 } })
|
|
110
107
|
] });
|
|
111
|
-
|
|
112
|
-
//#region src/blocks/Charts/theme.ts
|
|
108
|
+
// src/blocks/Charts/theme.ts
|
|
113
109
|
/**
|
|
114
110
|
* Chart series colors, from the `--chart-1` … `--chart-5` CSS variables only.
|
|
115
111
|
*
|
|
@@ -124,8 +120,7 @@ const chartTokenColor = (index) => {
|
|
|
124
120
|
};
|
|
125
121
|
/** Resolve an explicit token (1–5) or fall back to the series position. */
|
|
126
122
|
const resolveSeriesColor = (index, token) => chartTokenColor(token ? token - 1 : index);
|
|
127
|
-
|
|
128
|
-
//#region src/blocks/Charts/LineChart.tsx
|
|
123
|
+
// src/blocks/Charts/LineChart.tsx
|
|
129
124
|
/**
|
|
130
125
|
* A themed multi-series line chart.
|
|
131
126
|
*
|
|
@@ -166,8 +161,7 @@ const LineChart = ({ data, xKey, series, height, width, className, ...chrome })
|
|
|
166
161
|
})]
|
|
167
162
|
})
|
|
168
163
|
});
|
|
169
|
-
|
|
170
|
-
//#region src/blocks/Charts/BarChart.tsx
|
|
164
|
+
// src/blocks/Charts/BarChart.tsx
|
|
171
165
|
/**
|
|
172
166
|
* A themed multi-series bar chart. Series colors come from the semantic
|
|
173
167
|
* `--chart-*` palette (by order, or pinned via `series[].color`), which
|
|
@@ -207,8 +201,7 @@ const BarChart = ({ data, xKey, series, height, width, className, stacked = fals
|
|
|
207
201
|
}, s.dataKey))]
|
|
208
202
|
})
|
|
209
203
|
});
|
|
210
|
-
|
|
211
|
-
//#region src/blocks/Charts/AreaChart.tsx
|
|
204
|
+
// src/blocks/Charts/AreaChart.tsx
|
|
212
205
|
/**
|
|
213
206
|
* Themed multi-series area chart.
|
|
214
207
|
*
|
|
@@ -249,8 +242,7 @@ const AreaChart = ({ data, xKey, series, height, width, className, stacked = fal
|
|
|
249
242
|
})]
|
|
250
243
|
})
|
|
251
244
|
});
|
|
252
|
-
|
|
253
|
-
//#region src/blocks/Charts/PieChart.tsx
|
|
245
|
+
// src/blocks/Charts/PieChart.tsx
|
|
254
246
|
/**
|
|
255
247
|
* A themed pie / donut chart. Each sector cycles through the semantic
|
|
256
248
|
* `--chart-*` palette, which follows the active color scheme and the
|
|
@@ -278,7 +270,6 @@ const PieChart = ({ data, nameKey, dataKey, innerRadius = 0, height, width, clas
|
|
|
278
270
|
})
|
|
279
271
|
] })
|
|
280
272
|
});
|
|
281
|
-
//#endregion
|
|
282
273
|
export { AreaChart, BarChart, ChartContainer, ChartTooltip, ChartTooltipContent, LineChart, PieChart, chartTokenColor };
|
|
283
274
|
|
|
284
275
|
//# sourceMappingURL=charts.js.map
|