@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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InlineEdit-D4P0SvCB.js","names":[],"sources":["../src/blocks/InlineEdit/InlineEdit.tsx"],"sourcesContent":["import { useEffect, useId, useLayoutEffect, useRef, useState } from 'react';\nimport type { ChangeEvent, FocusEvent, KeyboardEvent, MouseEvent, ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Kbd, keys } from '../../components/Kbd';\nimport { Tooltip } from '../../components/Tooltip';\nimport { useAutosizeInput } from '../../hooks/useAutosizeInput';\nimport { Check, Loader2, X } from '../../icons';\nimport { cn } from '../../utils';\n\n/** A sized `fill` row at least this wide shows Save / Cancel as text; a narrower one as icons. */\nconst LABELLED_BUTTONS_MIN_WIDTH = 480;\n/** Below this a `multiline` field keeps the row and Save / Cancel move under it. */\nconst INLINE_BUTTONS_MIN_WIDTH = 320;\n/** How long the field and the buttons take to open and close. */\nconst EXPAND_MS = 200;\n\ntype Size = 'auto' | 'sm' | 'md' | 'lg' | 'title';\n\n/**\n * Box and button height per size; the font is always the surrounding one.\n *\n * - Buttons take the box's height, not the brand's own button height, so the row lines up.\n * - The box overhangs its line by the same amount it pads it, so the line box never changes.\n * - `auto` scales the icon buttons with the text instead of picking a fixed height.\n */\n// Class names are spelled out in full: Tailwind only generates the ones it can read here.\nconst SIZES = {\n auto: { box: 'tw:py-px tw:-my-[2px]', icon: 'icon-xs', label: 'medium', fit: '', iconFit: '' },\n sm: {\n box: 'tw:py-[max(1px,calc((1.5rem-1lh)/2-1px))] tw:-my-[max(2px,calc((1.5rem-1lh)/2))]',\n icon: 'icon-xs',\n label: 'small',\n fit: 'tw:h-6 tw:min-h-6 tw:max-h-6',\n iconFit: 'tw:size-6',\n },\n md: {\n box: 'tw:py-[max(1px,calc((2rem-1lh)/2-1px))] tw:-my-[max(2px,calc((2rem-1lh)/2))]',\n icon: 'icon-sm',\n label: 'small',\n fit: 'tw:h-8 tw:min-h-8 tw:max-h-8',\n iconFit: 'tw:size-8',\n },\n lg: {\n box: 'tw:py-[max(1px,calc((2.5rem-1lh)/2-1px))] tw:-my-[max(2px,calc((2.5rem-1lh)/2))]',\n icon: 'icon',\n label: 'medium',\n fit: 'tw:h-10 tw:min-h-10 tw:max-h-10',\n iconFit: 'tw:size-10',\n },\n title: {\n box: 'tw:py-[max(1px,calc((2.5rem-1lh)/2-1px))] tw:-my-[max(2px,calc((2.5rem-1lh)/2))]',\n icon: 'icon',\n label: 'medium',\n fit: 'tw:h-10 tw:min-h-10 tw:max-h-10',\n iconFit: 'tw:size-10',\n },\n} as const satisfies Record<\n Size,\n { box: string; icon: string; label: string; fit: string; iconFit: string }\n>;\n\n// One box in view and edit; only its colours change, so nothing moves and the change can animate.\n// - 1px border + 5px padding = the 6px the box shifts left, so the text stays where it was.\n// - A shift, not a negative margin: that would shrink the width a fit-content parent gives it.\n// - `leading-[inherit]` beats the 1.5 a Tooltip trigger's scoped preflight would set.\nconst BOX_CLASS = cn(\n 'tw:relative tw:-left-1.5 tw:rounded-md tw:border tw:px-[5px] tw:leading-[inherit]',\n 'tw:transition-[border-color,background-color,box-shadow] tw:duration-150 tw:ease-out',\n);\n\nconst VIEW_BOX_CLASS = cn(\n 'tw:border-transparent',\n 'tw:hover:border-input tw:hover:bg-muted-foreground/10',\n 'tw:has-[:focus-visible]:border-input tw:has-[:focus-visible]:bg-muted-foreground/10',\n);\n\n// The field takes the surrounding typography instead of the browser's form-control defaults.\nconst FIELD_CLASS = cn(\n 'tw:m-0 tw:block tw:border-0 tw:bg-transparent tw:p-0 tw:outline-hidden',\n 'tw:[font:inherit] tw:[letter-spacing:inherit] tw:[color:inherit]',\n 'tw:placeholder:text-muted-foreground',\n);\n\n// `auto` icon buttons scale with the text: 24px beside body copy, ~33px beside a page title.\nconst AUTO_ICON_BUTTON_CLASS = 'tw:size-[max(1.5rem,1.1em)] tw:text-[length:inherit]';\n\nconst ShortcutLabel = ({ label, shortcut }: { label: string; shortcut: string }) => (\n <span className=\"tw:inline-flex tw:items-center tw:gap-2\">\n {label}\n <Kbd variant=\"primary\">{shortcut}</Kbd>\n </span>\n);\n\n// Keeps focus in the field, so pressing a button never blurs it into an early save first.\nconst keepFieldFocus = (event: MouseEvent) => event.preventDefault();\n\ntype Props = {\n /** The text shown, and the draft while editing. */\n value: string;\n onChange: (value: string) => void;\n /** Enter, Save, or a blur with a valid change. */\n onSubmit: () => void;\n /** Escape, Cancel, or leaving the field with nothing changed. */\n onCancel: () => void;\n isEditing: boolean;\n /** Opens the editor from view mode; omit when the caller opens it some other way. */\n onEditStart?: () => void;\n /** Whether `value` differs from the saved value; nothing to save while false. */\n isChanged: boolean;\n /** A save is in flight: buttons and keys are held until it settles. */\n isSaving?: boolean;\n /** Why the draft can't be saved; disables Save and becomes its tooltip. */\n invalidReason?: string | null;\n /** Renders the value as plain text. */\n readOnly?: boolean;\n /** Fills the row while editing (default); `false` keeps the field as wide as its text. */\n fill?: boolean;\n /** Long text wraps and the field grows a line at a time; without it the field stays one line. */\n multiline?: boolean;\n /** Box height and buttons: sm 24, md 32, lg and title 40px, or `auto` to follow the text. */\n size?: Size;\n /** One line with an ellipsis in view mode; otherwise up to two lines. */\n truncate?: boolean;\n placeholder?: string;\n /** Tooltip on the value in view mode. */\n editTooltip?: ReactNode;\n tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';\n maxLength?: number;\n /** Accessible name of the field; defaults to `placeholder`. */\n 'aria-label'?: string;\n className?: string;\n};\n\n/**\n * Click-to-edit text: a page title, an entity name, a short label in a row.\n *\n * - The caller owns the draft and the editing flag, so it can validate, save and fail on its own terms.\n * - Enter saves a change and closes an unchanged edit; Escape cancels.\n * - Not for multi-paragraph or markdown text: use `MarkdownEditor`.\n */\nexport const InlineEdit = ({\n value,\n onChange,\n onSubmit,\n onCancel,\n isEditing,\n onEditStart,\n isChanged,\n isSaving = false,\n invalidReason = null,\n readOnly = false,\n fill = true,\n multiline = false,\n size = 'auto',\n truncate = false,\n placeholder = 'Click to edit',\n editTooltip = 'Click to edit',\n tooltipPlacement = 'top',\n maxLength,\n 'aria-label': ariaLabel,\n className,\n}: Props) => {\n const formRef = useRef<HTMLFormElement>(null);\n const viewButtonRef = useRef<HTMLButtonElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const wasEditingRef = useRef(isEditing);\n const reasonId = useId();\n const { inputRef, inputStyle, sizerElement } = useAutosizeInput({ value, placeholder });\n const [rowWidth, setRowWidth] = useState(0);\n const boxRef = useRef<HTMLDivElement>(null);\n const buttonsRef = useRef<HTMLDivElement>(null);\n const boxWidthRef = useRef(0);\n // The width sizer mounts on first hover or focus, before the first open, not with every row.\n const [isPrimed, setIsPrimed] = useState(false);\n // Focus returning after an edit doesn't pop \"Click to edit\"; it shows again once the user moves on.\n const [isTipQuiet, setIsTipQuiet] = useState(false);\n\n const isValid = !invalidReason;\n const canSave = isChanged && isValid && !isSaving;\n // Text labels only beside a sized box: next to small `auto` text a 40px label would tower.\n const showLabels = fill && size !== 'auto' && rowWidth >= LABELLED_BUTTONS_MIN_WIDTH;\n const stackButtons = fill && multiline && rowWidth > 0 && rowWidth < INLINE_BUTTONS_MIN_WIDTH;\n const sizing = SIZES[size];\n\n useEffect(() => {\n const wasEditing = wasEditingRef.current;\n wasEditingRef.current = isEditing;\n\n if (isEditing) {\n const field = textareaRef.current ?? inputRef.current;\n field?.focus();\n field?.setSelectionRange(field.value.length, field.value.length);\n return;\n }\n\n if (!wasEditing) return;\n // oxlint-disable-next-line react-x/set-state-in-effect -- the close is a prop change, seen only here\n setIsTipQuiet(true);\n // Closing the editor removed the focused field; hand focus back to the value, not to <body>.\n if (!document.activeElement || document.activeElement === document.body) {\n viewButtonRef.current?.focus();\n }\n }, [isEditing, inputRef]);\n\n // Tracks the box's width, so a toggle knows where its animation starts.\n useLayoutEffect(() => {\n const box = boxRef.current;\n if (!box || typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(() => {\n boxWidthRef.current = box.offsetWidth;\n });\n observer.observe(box);\n return () => observer.disconnect();\n }, []);\n\n // Grows the box from its text to the row and slides Save / Cancel open, then reverses both.\n // - Measured widths, not `fr` tracks: an `fr` track sized by its content doesn't transition.\n useLayoutEffect(() => {\n const box = boxRef.current;\n const buttons = buttonsRef.current;\n const from = boxWidthRef.current;\n if (!box || !buttons || !from) return;\n\n // A toggle mid-animation measures the box's own size, not the one the last animation holds.\n for (const running of box.getAnimations()) running.cancel();\n const to = box.offsetWidth;\n boxWidthRef.current = to;\n const reduceMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;\n if (reduceMotion || typeof box.animate !== 'function') return;\n\n const timing = { duration: EXPAND_MS, easing: 'ease-out' };\n if (from !== to) {\n // An open `fill` box is a growing flex item, which ignores `width`; `max-width` holds it.\n const property = fill && isEditing ? 'maxWidth' : 'width';\n const field = textareaRef.current;\n // One line while it grows, so the text doesn't wrap and unwrap as the box widens.\n if (field) field.style.whiteSpace = 'nowrap';\n const animation = box.animate(\n [{ [property]: `${from}px` }, { [property]: `${to}px` }],\n timing,\n );\n // A closing `fill` field holds its row until it has shrunk:\n // - `data-expanded` stays on until the animation ends;\n // - `data-settled` then marks that a rename closed here, so what the row hid fades back in.\n const heldRow = fill && !isEditing ? formRef.current : null;\n if (heldRow) heldRow.dataset.expanded = 'true';\n animation.onfinish = () => {\n if (field) field.style.whiteSpace = '';\n if (!heldRow) return;\n delete heldRow.dataset.expanded;\n heldRow.dataset.settled = 'true';\n };\n }\n\n // - Clips only sideways, so buttons taller than the line keep their borders.\n // - Open buttons aren't clipped at all, so their focus rings show.\n for (const running of buttons.getAnimations()) running.cancel();\n const buttonsWidth = `${buttons.scrollWidth}px`;\n buttons.style.overflowX = 'clip';\n buttons.animate(\n isEditing\n ? [{ maxWidth: '0px' }, { maxWidth: buttonsWidth }]\n : [{ maxWidth: buttonsWidth }, { maxWidth: '0px' }],\n timing,\n ).onfinish = () => {\n buttons.style.overflowX = '';\n };\n }, [isEditing, fill]);\n\n useLayoutEffect(() => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n\n const fitHeight = () => {\n textarea.style.height = 'auto';\n textarea.style.height = `${textarea.scrollHeight}px`;\n };\n fitHeight();\n if (typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(fitHeight);\n observer.observe(textarea);\n return () => observer.disconnect();\n }, [isEditing, value]);\n\n useLayoutEffect(() => {\n const form = formRef.current;\n if (!fill || !isEditing || !form) return;\n\n // Measured before paint, so the buttons never render at one size and settle at another.\n // `offsetWidth` is the layout width: a scale transform (an opening modal) doesn't change it.\n // oxlint-disable-next-line react-x/set-state-in-effect -- a layout read has to happen before paint\n const fitButtons = (width: number) => setRowWidth(width);\n fitButtons(form.offsetWidth);\n if (typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(() => fitButtons(form.offsetWidth));\n observer.observe(form);\n return () => observer.disconnect();\n }, [fill, isEditing]);\n\n if (readOnly) {\n return <span className={cn(truncate && 'tw:block tw:truncate', className)}>{value}</span>;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n event.stopPropagation();\n\n if (event.key === 'Escape') {\n event.preventDefault();\n if (!isSaving) onCancel();\n return;\n }\n\n if (event.key === 'Enter') {\n event.preventDefault();\n if (isSaving) return;\n if (!isChanged) onCancel();\n else if (isValid) onSubmit();\n }\n };\n\n const handleBlur = (event: FocusEvent<HTMLFormElement>) => {\n if (!isEditing || isSaving) return;\n // Focus left the window (resizing it, switching apps), not the field: keep editing.\n if (!document.hasFocus()) return;\n const next = event.relatedTarget;\n if (next instanceof Node && event.currentTarget.contains(next)) return;\n if (!isChanged) onCancel();\n else if (isValid) onSubmit();\n };\n\n const handleChange = (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n onChange(multiline ? event.target.value.replace(/[\\r\\n]+/g, ' ') : event.target.value);\n };\n\n const fieldProps = {\n value,\n placeholder,\n maxLength,\n readOnly: isSaving,\n 'aria-label': ariaLabel ?? placeholder,\n 'aria-invalid': !isValid || undefined,\n 'aria-describedby': invalidReason ? reasonId : undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n onKeyUp: (event: KeyboardEvent) => event.stopPropagation(),\n onClick: (event: MouseEvent) => event.stopPropagation(),\n };\n\n const saveTooltip = (() => {\n if (isSaving) return 'Saving…';\n if (!isChanged) return 'No changes to save';\n if (invalidReason) return invalidReason;\n return <ShortcutLabel label=\"Save\" shortcut={keys.enter.symbol} />;\n })();\n\n const iconButtonClass = size === 'auto' ? AUTO_ICON_BUTTON_CLASS : sizing.iconFit;\n // Labelled buttons match the box's height whatever the brand's own button height is.\n const labelButtonClass = sizing.fit;\n const buttonSize = showLabels ? sizing.label : sizing.icon;\n\n const view = (\n <Tooltip\n tooltip={editTooltip}\n placement={tooltipPlacement}\n forceHide={isTipQuiet}\n triggerAsChild\n >\n <button\n ref={viewButtonRef}\n type=\"button\"\n data-testid=\"inline-edit-trigger\"\n className={cn(\n 'tw:block tw:max-w-full tw:cursor-text tw:text-left tw:outline-hidden',\n 'tw:[font:inherit] tw:leading-[inherit] tw:[color:inherit]',\n // The whole box takes the click, not just the glyphs.\n 'tw:after:absolute tw:after:inset-0',\n truncate && 'tw:min-w-0 tw:truncate',\n )}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onEditStart?.();\n }}\n onBlur={() => setIsTipQuiet(false)}\n onPointerLeave={() => setIsTipQuiet(false)}\n >\n {value ? (\n <span className={cn(!truncate && !multiline && 'tw:line-clamp-2', 'tw:break-words')}>\n {value}\n </span>\n ) : (\n <span className=\"tw:text-muted-foreground\">{placeholder}</span>\n )}\n </button>\n </Tooltip>\n );\n\n const field = multiline ? (\n <textarea\n ref={textareaRef}\n rows={1}\n className={cn(FIELD_CLASS, 'tw:w-full tw:resize-none tw:overflow-hidden tw:break-words')}\n {...fieldProps}\n />\n ) : (\n <input\n ref={inputRef}\n type=\"text\"\n className={cn(FIELD_CLASS, fill ? 'tw:w-full' : 'tw:max-w-full')}\n style={fill ? undefined : inputStyle}\n {...fieldProps}\n />\n );\n\n const buttons = (\n <div\n className={cn(\n 'tw:flex tw:items-center tw:gap-1',\n // - The gap lives inside the collapsing track, so a closed field leaves no trailing space.\n // - Beside the field the row is one line tall, so taller buttons overhang it evenly.\n stackButtons ? 'tw:pt-2' : 'tw:h-[1lh] tw:pl-2',\n 'tw:transition-opacity tw:duration-200 tw:ease-out',\n isEditing ? 'tw:opacity-100' : 'tw:opacity-0',\n )}\n >\n <Tooltip tooltip={saveTooltip} placement=\"top\" triggerAsChild>\n <span className={cn('tw:inline-flex', !canSave && 'tw:cursor-not-allowed')}>\n <Button\n type=\"submit\"\n variant=\"primary\"\n size={buttonSize}\n aria-label={showLabels ? undefined : 'Save'}\n isLoading={!showLabels && isSaving}\n disabled={!canSave}\n onMouseDown={keepFieldFocus}\n className={cn(\n 'tw:transition-colors',\n showLabels ? labelButtonClass : iconButtonClass,\n !canSave && 'tw:pointer-events-none',\n )}\n >\n {showLabels ? (\n // The spinner overlays the label, so Save keeps its width and Cancel stays put.\n <>\n <span className={cn(isSaving && 'tw:invisible')}>Save</span>\n {isSaving && <Loader2 className=\"tw:absolute tw:size-4 tw:animate-spin\" />}\n </>\n ) : (\n <Check />\n )}\n </Button>\n </span>\n </Tooltip>\n <Tooltip\n tooltip={<ShortcutLabel label=\"Cancel\" shortcut=\"Esc\" />}\n placement=\"top\"\n triggerAsChild\n >\n <Button\n type=\"button\"\n variant=\"outline\"\n size={buttonSize}\n aria-label={showLabels ? undefined : 'Cancel'}\n disabled={isSaving}\n className={cn('tw:transition-colors', showLabels ? labelButtonClass : iconButtonClass)}\n onMouseDown={keepFieldFocus}\n onClick={(event) => {\n event.stopPropagation();\n onCancel();\n }}\n >\n {showLabels ? 'Cancel' : <X />}\n </Button>\n </Tooltip>\n </div>\n );\n\n return (\n <form\n ref={formRef}\n data-slot=\"inline-edit\"\n data-state={isEditing ? 'edit' : 'view'}\n data-expanded={(fill && isEditing) || undefined}\n aria-busy={isSaving || undefined}\n className={cn(\n 'tw:leading-[inherit]',\n // Top-aligned: Save / Cancel sit on the first line however many lines the text wraps to.\n fill && isEditing\n ? 'tw:flex tw:w-full tw:min-w-0 tw:items-start'\n : 'tw:inline-flex tw:max-w-full tw:items-center',\n // Only a wrapping title moves Save / Cancel under the field; one line keeps them beside it.\n fill && isEditing && multiline && 'tw:flex-wrap',\n truncate && !isEditing && 'tw:flex tw:min-w-0',\n className,\n )}\n onSubmit={(event) => {\n event.preventDefault();\n if (canSave) onSubmit();\n }}\n onBlur={handleBlur}\n // Escape on Save / Cancel cancels too; the field handles its own keys first.\n onKeyDown={(event) => {\n if (event.key !== 'Escape' || !isEditing) return;\n event.preventDefault();\n event.stopPropagation();\n if (!isSaving) onCancel();\n }}\n >\n <div\n ref={boxRef}\n onPointerEnter={() => setIsPrimed(true)}\n onFocus={() => setIsPrimed(true)}\n className={cn(\n BOX_CLASS,\n sizing.box,\n 'tw:min-w-0',\n fill && isEditing && 'tw:flex-1',\n fill && isEditing && multiline && 'tw:min-w-[min(100%,12rem)]',\n !isEditing && VIEW_BOX_CLASS,\n isEditing &&\n (isValid\n ? 'tw:border-ring tw:bg-input-background tw:ring-3 tw:ring-ring/25'\n : 'tw:border-destructive tw:bg-input-background tw:ring-3 tw:ring-destructive/20'),\n isEditing && !fill && !multiline && 'tw:inline-flex',\n )}\n >\n {isEditing ? field : view}\n {/* Measures from first hover, so the first open already knows the field's width. */}\n {!fill && !multiline && (isPrimed || isEditing) && (\n <span aria-hidden className=\"tw:absolute tw:size-0 tw:overflow-hidden\">\n {sizerElement}\n </span>\n )}\n </div>\n {isEditing && invalidReason && (\n <span id={reasonId} className=\"tw:sr-only\" aria-live=\"polite\">\n {invalidReason}\n </span>\n )}\n {/* Stays mounted, inert while closed, so it can slide shut after Save / Cancel. */}\n <div\n ref={buttonsRef}\n inert={!isEditing}\n aria-hidden={!isEditing || undefined}\n className={cn(\n fill ? 'tw:self-start' : 'tw:self-center',\n !isEditing && 'tw:max-w-0 tw:overflow-x-clip',\n stackButtons && isEditing && 'tw:basis-full',\n )}\n >\n {buttons}\n </div>\n </form>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InlineEdit-CXL0ZslO.js","names":[],"sources":["../src/blocks/InlineEdit/InlineEdit.tsx"],"sourcesContent":["import { useEffect, useId, useLayoutEffect, useRef, useState } from 'react';\nimport type { ChangeEvent, FocusEvent, KeyboardEvent, MouseEvent, ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Kbd, keys } from '../../components/Kbd';\nimport { Tooltip } from '../../components/Tooltip';\nimport { useAutosizeInput } from '../../hooks/useAutosizeInput';\nimport { Check, Loader2, X } from '../../icons';\nimport { cn } from '../../utils';\n\n/** A sized `fill` row at least this wide shows Save / Cancel as text; a narrower one as icons. */\nconst LABELLED_BUTTONS_MIN_WIDTH = 480;\n/** Below this a `multiline` field keeps the row and Save / Cancel move under it. */\nconst INLINE_BUTTONS_MIN_WIDTH = 320;\n/** How long the field and the buttons take to open and close. */\nconst EXPAND_MS = 200;\n\ntype Size = 'auto' | 'sm' | 'md' | 'lg' | 'title';\n\n/**\n * Box and button height per size; the font is always the surrounding one.\n *\n * - Buttons take the box's height, not the brand's own button height, so the row lines up.\n * - The box overhangs its line by the same amount it pads it, so the line box never changes.\n * - `auto` scales the icon buttons with the text instead of picking a fixed height.\n */\n// Class names are spelled out in full: Tailwind only generates the ones it can read here.\nconst SIZES = {\n auto: { box: 'tw:py-px tw:-my-[2px]', icon: 'icon-xs', label: 'medium', fit: '', iconFit: '' },\n sm: {\n box: 'tw:py-[max(1px,calc((1.5rem-1lh)/2-1px))] tw:-my-[max(2px,calc((1.5rem-1lh)/2))]',\n icon: 'icon-xs',\n label: 'small',\n fit: 'tw:h-6 tw:min-h-6 tw:max-h-6',\n iconFit: 'tw:size-6',\n },\n md: {\n box: 'tw:py-[max(1px,calc((2rem-1lh)/2-1px))] tw:-my-[max(2px,calc((2rem-1lh)/2))]',\n icon: 'icon-sm',\n label: 'small',\n fit: 'tw:h-8 tw:min-h-8 tw:max-h-8',\n iconFit: 'tw:size-8',\n },\n lg: {\n box: 'tw:py-[max(1px,calc((2.5rem-1lh)/2-1px))] tw:-my-[max(2px,calc((2.5rem-1lh)/2))]',\n icon: 'icon',\n label: 'medium',\n fit: 'tw:h-10 tw:min-h-10 tw:max-h-10',\n iconFit: 'tw:size-10',\n },\n title: {\n box: 'tw:py-[max(1px,calc((2.5rem-1lh)/2-1px))] tw:-my-[max(2px,calc((2.5rem-1lh)/2))]',\n icon: 'icon',\n label: 'medium',\n fit: 'tw:h-10 tw:min-h-10 tw:max-h-10',\n iconFit: 'tw:size-10',\n },\n} as const satisfies Record<\n Size,\n { box: string; icon: string; label: string; fit: string; iconFit: string }\n>;\n\n// One box in view and edit; only its colours change, so nothing moves and the change can animate.\n// - 1px border + 5px padding = the 6px the box shifts left, so the text stays where it was.\n// - A shift, not a negative margin: that would shrink the width a fit-content parent gives it.\n// - `leading-[inherit]` beats the 1.5 a Tooltip trigger's scoped preflight would set.\nconst BOX_CLASS = cn(\n 'tw:relative tw:-left-1.5 tw:rounded-md tw:border tw:px-[5px] tw:leading-[inherit]',\n 'tw:transition-[border-color,background-color,box-shadow] tw:duration-150 tw:ease-out',\n);\n\nconst VIEW_BOX_CLASS = cn(\n 'tw:border-transparent',\n 'tw:hover:border-input tw:hover:bg-muted-foreground/10',\n 'tw:has-[:focus-visible]:border-input tw:has-[:focus-visible]:bg-muted-foreground/10',\n);\n\n// The field takes the surrounding typography instead of the browser's form-control defaults.\nconst FIELD_CLASS = cn(\n 'tw:m-0 tw:block tw:border-0 tw:bg-transparent tw:p-0 tw:outline-hidden',\n 'tw:[font:inherit] tw:[letter-spacing:inherit] tw:[color:inherit]',\n 'tw:placeholder:text-muted-foreground',\n);\n\n// `auto` icon buttons scale with the text: 24px beside body copy, ~33px beside a page title.\nconst AUTO_ICON_BUTTON_CLASS = 'tw:size-[max(1.5rem,1.1em)] tw:text-[length:inherit]';\n\nconst ShortcutLabel = ({ label, shortcut }: { label: string; shortcut: string }) => (\n <span className=\"tw:inline-flex tw:items-center tw:gap-2\">\n {label}\n <Kbd variant=\"primary\">{shortcut}</Kbd>\n </span>\n);\n\n// Keeps focus in the field, so pressing a button never blurs it into an early save first.\nconst keepFieldFocus = (event: MouseEvent) => event.preventDefault();\n\ntype Props = {\n /** The text shown, and the draft while editing. */\n value: string;\n onChange: (value: string) => void;\n /** Enter, Save, or a blur with a valid change. */\n onSubmit: () => void;\n /** Escape, Cancel, or leaving the field with nothing changed. */\n onCancel: () => void;\n isEditing: boolean;\n /** Opens the editor from view mode; omit when the caller opens it some other way. */\n onEditStart?: () => void;\n /** Whether `value` differs from the saved value; nothing to save while false. */\n isChanged: boolean;\n /** A save is in flight: buttons and keys are held until it settles. */\n isSaving?: boolean;\n /** Why the draft can't be saved; disables Save and becomes its tooltip. */\n invalidReason?: string | null;\n /** Renders the value as plain text. */\n readOnly?: boolean;\n /** Fills the row while editing (default); `false` keeps the field as wide as its text. */\n fill?: boolean;\n /** Long text wraps and the field grows a line at a time; without it the field stays one line. */\n multiline?: boolean;\n /** Box height and buttons: sm 24, md 32, lg and title 40px, or `auto` to follow the text. */\n size?: Size;\n /** One line with an ellipsis in view mode; otherwise up to two lines. */\n truncate?: boolean;\n placeholder?: string;\n /** Tooltip on the value in view mode. */\n editTooltip?: ReactNode;\n tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';\n maxLength?: number;\n /** Accessible name of the field; defaults to `placeholder`. */\n 'aria-label'?: string;\n className?: string;\n};\n\n/**\n * Click-to-edit text: a page title, an entity name, a short label in a row.\n *\n * - The caller owns the draft and the editing flag, so it can validate, save and fail on its own terms.\n * - Enter saves a change and closes an unchanged edit; Escape cancels.\n * - Not for multi-paragraph or markdown text: use `MarkdownEditor`.\n */\nexport const InlineEdit = ({\n value,\n onChange,\n onSubmit,\n onCancel,\n isEditing,\n onEditStart,\n isChanged,\n isSaving = false,\n invalidReason = null,\n readOnly = false,\n fill = true,\n multiline = false,\n size = 'auto',\n truncate = false,\n placeholder = 'Click to edit',\n editTooltip = 'Click to edit',\n tooltipPlacement = 'top',\n maxLength,\n 'aria-label': ariaLabel,\n className,\n}: Props) => {\n const formRef = useRef<HTMLFormElement>(null);\n const viewButtonRef = useRef<HTMLButtonElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const wasEditingRef = useRef(isEditing);\n const reasonId = useId();\n const { inputRef, inputStyle, sizerElement } = useAutosizeInput({ value, placeholder });\n const [rowWidth, setRowWidth] = useState(0);\n const boxRef = useRef<HTMLDivElement>(null);\n const buttonsRef = useRef<HTMLDivElement>(null);\n const boxWidthRef = useRef(0);\n // The width sizer mounts on first hover or focus, before the first open, not with every row.\n const [isPrimed, setIsPrimed] = useState(false);\n // Focus returning after an edit doesn't pop \"Click to edit\"; it shows again once the user moves on.\n const [isTipQuiet, setIsTipQuiet] = useState(false);\n\n const isValid = !invalidReason;\n const canSave = isChanged && isValid && !isSaving;\n // Text labels only beside a sized box: next to small `auto` text a 40px label would tower.\n const showLabels = fill && size !== 'auto' && rowWidth >= LABELLED_BUTTONS_MIN_WIDTH;\n const stackButtons = fill && multiline && rowWidth > 0 && rowWidth < INLINE_BUTTONS_MIN_WIDTH;\n const sizing = SIZES[size];\n\n useEffect(() => {\n const wasEditing = wasEditingRef.current;\n wasEditingRef.current = isEditing;\n\n if (isEditing) {\n const field = textareaRef.current ?? inputRef.current;\n field?.focus();\n field?.setSelectionRange(field.value.length, field.value.length);\n return;\n }\n\n if (!wasEditing) return;\n // oxlint-disable-next-line react-x/set-state-in-effect -- the close is a prop change, seen only here\n setIsTipQuiet(true);\n // Closing the editor removed the focused field; hand focus back to the value, not to <body>.\n if (!document.activeElement || document.activeElement === document.body) {\n viewButtonRef.current?.focus();\n }\n }, [isEditing, inputRef]);\n\n // Tracks the box's width, so a toggle knows where its animation starts.\n useLayoutEffect(() => {\n const box = boxRef.current;\n if (!box || typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(() => {\n boxWidthRef.current = box.offsetWidth;\n });\n observer.observe(box);\n return () => observer.disconnect();\n }, []);\n\n // Grows the box from its text to the row and slides Save / Cancel open, then reverses both.\n // - Measured widths, not `fr` tracks: an `fr` track sized by its content doesn't transition.\n useLayoutEffect(() => {\n const box = boxRef.current;\n const buttons = buttonsRef.current;\n const from = boxWidthRef.current;\n if (!box || !buttons || !from) return;\n\n // A toggle mid-animation measures the box's own size, not the one the last animation holds.\n for (const running of box.getAnimations()) running.cancel();\n const to = box.offsetWidth;\n boxWidthRef.current = to;\n const reduceMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;\n if (reduceMotion || typeof box.animate !== 'function') return;\n\n const timing = { duration: EXPAND_MS, easing: 'ease-out' };\n if (from !== to) {\n // An open `fill` box is a growing flex item, which ignores `width`; `max-width` holds it.\n const property = fill && isEditing ? 'maxWidth' : 'width';\n const field = textareaRef.current;\n // One line while it grows, so the text doesn't wrap and unwrap as the box widens.\n if (field) field.style.whiteSpace = 'nowrap';\n const animation = box.animate(\n [{ [property]: `${from}px` }, { [property]: `${to}px` }],\n timing,\n );\n // A closing `fill` field holds its row until it has shrunk:\n // - `data-expanded` stays on until the animation ends;\n // - `data-settled` then marks that a rename closed here, so what the row hid fades back in.\n const heldRow = fill && !isEditing ? formRef.current : null;\n if (heldRow) heldRow.dataset.expanded = 'true';\n animation.onfinish = () => {\n if (field) field.style.whiteSpace = '';\n if (!heldRow) return;\n delete heldRow.dataset.expanded;\n heldRow.dataset.settled = 'true';\n };\n }\n\n // - Clips only sideways, so buttons taller than the line keep their borders.\n // - Open buttons aren't clipped at all, so their focus rings show.\n for (const running of buttons.getAnimations()) running.cancel();\n const buttonsWidth = `${buttons.scrollWidth}px`;\n buttons.style.overflowX = 'clip';\n buttons.animate(\n isEditing\n ? [{ maxWidth: '0px' }, { maxWidth: buttonsWidth }]\n : [{ maxWidth: buttonsWidth }, { maxWidth: '0px' }],\n timing,\n ).onfinish = () => {\n buttons.style.overflowX = '';\n };\n }, [isEditing, fill]);\n\n useLayoutEffect(() => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n\n const fitHeight = () => {\n textarea.style.height = 'auto';\n textarea.style.height = `${textarea.scrollHeight}px`;\n };\n fitHeight();\n if (typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(fitHeight);\n observer.observe(textarea);\n return () => observer.disconnect();\n }, [isEditing, value]);\n\n useLayoutEffect(() => {\n const form = formRef.current;\n if (!fill || !isEditing || !form) return;\n\n // Measured before paint, so the buttons never render at one size and settle at another.\n // `offsetWidth` is the layout width: a scale transform (an opening modal) doesn't change it.\n // oxlint-disable-next-line react-x/set-state-in-effect -- a layout read has to happen before paint\n const fitButtons = (width: number) => setRowWidth(width);\n fitButtons(form.offsetWidth);\n if (typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(() => fitButtons(form.offsetWidth));\n observer.observe(form);\n return () => observer.disconnect();\n }, [fill, isEditing]);\n\n if (readOnly) {\n return <span className={cn(truncate && 'tw:block tw:truncate', className)}>{value}</span>;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n event.stopPropagation();\n\n if (event.key === 'Escape') {\n event.preventDefault();\n if (!isSaving) onCancel();\n return;\n }\n\n if (event.key === 'Enter') {\n event.preventDefault();\n if (isSaving) return;\n if (!isChanged) onCancel();\n else if (isValid) onSubmit();\n }\n };\n\n const handleBlur = (event: FocusEvent<HTMLFormElement>) => {\n if (!isEditing || isSaving) return;\n // Focus left the window (resizing it, switching apps), not the field: keep editing.\n if (!document.hasFocus()) return;\n const next = event.relatedTarget;\n if (next instanceof Node && event.currentTarget.contains(next)) return;\n if (!isChanged) onCancel();\n else if (isValid) onSubmit();\n };\n\n const handleChange = (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n onChange(multiline ? event.target.value.replace(/[\\r\\n]+/g, ' ') : event.target.value);\n };\n\n const fieldProps = {\n value,\n placeholder,\n maxLength,\n readOnly: isSaving,\n 'aria-label': ariaLabel ?? placeholder,\n 'aria-invalid': !isValid || undefined,\n 'aria-describedby': invalidReason ? reasonId : undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n onKeyUp: (event: KeyboardEvent) => event.stopPropagation(),\n onClick: (event: MouseEvent) => event.stopPropagation(),\n };\n\n const saveTooltip = (() => {\n if (isSaving) return 'Saving…';\n if (!isChanged) return 'No changes to save';\n if (invalidReason) return invalidReason;\n return <ShortcutLabel label=\"Save\" shortcut={keys.enter.symbol} />;\n })();\n\n const iconButtonClass = size === 'auto' ? AUTO_ICON_BUTTON_CLASS : sizing.iconFit;\n // Labelled buttons match the box's height whatever the brand's own button height is.\n const labelButtonClass = sizing.fit;\n const buttonSize = showLabels ? sizing.label : sizing.icon;\n\n const view = (\n <Tooltip\n tooltip={editTooltip}\n placement={tooltipPlacement}\n forceHide={isTipQuiet}\n triggerAsChild\n >\n <button\n ref={viewButtonRef}\n type=\"button\"\n data-testid=\"inline-edit-trigger\"\n className={cn(\n 'tw:block tw:max-w-full tw:cursor-text tw:text-left tw:outline-hidden',\n 'tw:[font:inherit] tw:leading-[inherit] tw:[color:inherit]',\n // The whole box takes the click, not just the glyphs.\n 'tw:after:absolute tw:after:inset-0',\n truncate && 'tw:min-w-0 tw:truncate',\n )}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onEditStart?.();\n }}\n onBlur={() => setIsTipQuiet(false)}\n onPointerLeave={() => setIsTipQuiet(false)}\n >\n {value ? (\n <span className={cn(!truncate && !multiline && 'tw:line-clamp-2', 'tw:break-words')}>\n {value}\n </span>\n ) : (\n <span className=\"tw:text-muted-foreground\">{placeholder}</span>\n )}\n </button>\n </Tooltip>\n );\n\n const field = multiline ? (\n <textarea\n ref={textareaRef}\n rows={1}\n className={cn(FIELD_CLASS, 'tw:w-full tw:resize-none tw:overflow-hidden tw:break-words')}\n {...fieldProps}\n />\n ) : (\n <input\n ref={inputRef}\n type=\"text\"\n className={cn(FIELD_CLASS, fill ? 'tw:w-full' : 'tw:max-w-full')}\n style={fill ? undefined : inputStyle}\n {...fieldProps}\n />\n );\n\n const buttons = (\n <div\n className={cn(\n 'tw:flex tw:items-center tw:gap-1',\n // - The gap lives inside the collapsing track, so a closed field leaves no trailing space.\n // - Beside the field the row is one line tall, so taller buttons overhang it evenly.\n stackButtons ? 'tw:pt-2' : 'tw:h-[1lh] tw:pl-2',\n 'tw:transition-opacity tw:duration-200 tw:ease-out',\n isEditing ? 'tw:opacity-100' : 'tw:opacity-0',\n )}\n >\n <Tooltip tooltip={saveTooltip} placement=\"top\" triggerAsChild>\n <span className={cn('tw:inline-flex', !canSave && 'tw:cursor-not-allowed')}>\n <Button\n type=\"submit\"\n variant=\"primary\"\n size={buttonSize}\n aria-label={showLabels ? undefined : 'Save'}\n isLoading={!showLabels && isSaving}\n disabled={!canSave}\n onMouseDown={keepFieldFocus}\n className={cn(\n 'tw:transition-colors',\n showLabels ? labelButtonClass : iconButtonClass,\n !canSave && 'tw:pointer-events-none',\n )}\n >\n {showLabels ? (\n // The spinner overlays the label, so Save keeps its width and Cancel stays put.\n <>\n <span className={cn(isSaving && 'tw:invisible')}>Save</span>\n {isSaving && <Loader2 className=\"tw:absolute tw:size-4 tw:animate-spin\" />}\n </>\n ) : (\n <Check />\n )}\n </Button>\n </span>\n </Tooltip>\n <Tooltip\n tooltip={<ShortcutLabel label=\"Cancel\" shortcut=\"Esc\" />}\n placement=\"top\"\n triggerAsChild\n >\n <Button\n type=\"button\"\n variant=\"outline\"\n size={buttonSize}\n aria-label={showLabels ? undefined : 'Cancel'}\n disabled={isSaving}\n className={cn('tw:transition-colors', showLabels ? labelButtonClass : iconButtonClass)}\n onMouseDown={keepFieldFocus}\n onClick={(event) => {\n event.stopPropagation();\n onCancel();\n }}\n >\n {showLabels ? 'Cancel' : <X />}\n </Button>\n </Tooltip>\n </div>\n );\n\n return (\n <form\n ref={formRef}\n data-slot=\"inline-edit\"\n data-state={isEditing ? 'edit' : 'view'}\n data-expanded={(fill && isEditing) || undefined}\n aria-busy={isSaving || undefined}\n className={cn(\n 'tw:leading-[inherit]',\n // Top-aligned: Save / Cancel sit on the first line however many lines the text wraps to.\n fill && isEditing\n ? 'tw:flex tw:w-full tw:min-w-0 tw:items-start'\n : 'tw:inline-flex tw:max-w-full tw:items-center',\n // Only a wrapping title moves Save / Cancel under the field; one line keeps them beside it.\n fill && isEditing && multiline && 'tw:flex-wrap',\n truncate && !isEditing && 'tw:flex tw:min-w-0',\n className,\n )}\n onSubmit={(event) => {\n event.preventDefault();\n if (canSave) onSubmit();\n }}\n onBlur={handleBlur}\n // Escape on Save / Cancel cancels too; the field handles its own keys first.\n onKeyDown={(event) => {\n if (event.key !== 'Escape' || !isEditing) return;\n event.preventDefault();\n event.stopPropagation();\n if (!isSaving) onCancel();\n }}\n >\n <div\n ref={boxRef}\n onPointerEnter={() => setIsPrimed(true)}\n onFocus={() => setIsPrimed(true)}\n className={cn(\n BOX_CLASS,\n sizing.box,\n 'tw:min-w-0',\n fill && isEditing && 'tw:flex-1',\n fill && isEditing && multiline && 'tw:min-w-[min(100%,12rem)]',\n !isEditing && VIEW_BOX_CLASS,\n isEditing &&\n (isValid\n ? 'tw:border-ring tw:bg-input-background tw:ring-3 tw:ring-ring/25'\n : 'tw:border-destructive tw:bg-input-background tw:ring-3 tw:ring-destructive/20'),\n isEditing && !fill && !multiline && 'tw:inline-flex',\n )}\n >\n {isEditing ? field : view}\n {/* Measures from first hover, so the first open already knows the field's width. */}\n {!fill && !multiline && (isPrimed || isEditing) && (\n <span aria-hidden className=\"tw:absolute tw:size-0 tw:overflow-hidden\">\n {sizerElement}\n </span>\n )}\n </div>\n {isEditing && invalidReason && (\n <span id={reasonId} className=\"tw:sr-only\" aria-live=\"polite\">\n {invalidReason}\n </span>\n )}\n {/* Stays mounted, inert while closed, so it can slide shut after Save / Cancel. */}\n <div\n ref={buttonsRef}\n inert={!isEditing}\n aria-hidden={!isEditing || undefined}\n className={cn(\n fill ? 'tw:self-start' : 'tw:self-center',\n !isEditing && 'tw:max-w-0 tw:overflow-x-clip',\n stackButtons && isEditing && 'tw:basis-full',\n )}\n >\n {buttons}\n </div>\n </form>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { cn } from "./classNames-
|
|
2
|
-
import { Button } from "./Button-
|
|
1
|
+
import { cn } from "./classNames-DkX30VJU.js";
|
|
2
|
+
import { Button } from "./Button-DbvGzEDb.js";
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import TextareaAutosize from "react-textarea-autosize";
|
|
6
|
-
|
|
6
|
+
// src/components/InputGroup/InputGroupAddon.tsx
|
|
7
7
|
const addonVariants = cva([
|
|
8
8
|
"tw:flex",
|
|
9
9
|
"tw:items-center",
|
|
@@ -46,8 +46,7 @@ const InputGroupAddon = ({ children, align = "inline-start", className, ...props
|
|
|
46
46
|
})),
|
|
47
47
|
children
|
|
48
48
|
});
|
|
49
|
-
|
|
50
|
-
//#region src/components/InputGroup/InputGroupButton.tsx
|
|
49
|
+
// src/components/InputGroup/InputGroupButton.tsx
|
|
51
50
|
const InputGroupButton = ({ ref, className, tabIndex = -1, ...props }) => /* @__PURE__ */ jsx(Button, {
|
|
52
51
|
...props,
|
|
53
52
|
tabIndex,
|
|
@@ -56,21 +55,18 @@ const InputGroupButton = ({ ref, className, tabIndex = -1, ...props }) => /* @__
|
|
|
56
55
|
size: "icon-sm",
|
|
57
56
|
className: cn("tw:size-5", "tw:[&_svg]:text-muted-foreground", className)
|
|
58
57
|
});
|
|
59
|
-
|
|
60
|
-
//#region src/components/InputGroup/InputGroupInput.tsx
|
|
58
|
+
// src/components/InputGroup/InputGroupInput.tsx
|
|
61
59
|
const InputGroupInput = ({ ref, className, ...inputProps }) => /* @__PURE__ */ jsx("input", {
|
|
62
60
|
...inputProps,
|
|
63
61
|
ref,
|
|
64
62
|
className: cn("tw:flex-1", "tw:min-w-0", "tw:bg-transparent", "tw:outline-hidden", "tw:font-sans", "tw:text-sm", "tw:placeholder:text-neutral-400", "tw:placeholder:font-normal", "tw:disabled:cursor-not-allowed", className)
|
|
65
63
|
});
|
|
66
|
-
|
|
67
|
-
//#region src/components/InputGroup/InputGroupText.tsx
|
|
64
|
+
// src/components/InputGroup/InputGroupText.tsx
|
|
68
65
|
const InputGroupText = ({ className, ...props }) => /* @__PURE__ */ jsx("span", {
|
|
69
66
|
className: cn("tw:flex", "tw:items-center", "tw:gap-2", "tw:text-sm", "tw:text-muted-foreground", "tw:[&_svg]:pointer-events-none", "tw:[&_svg:not([class*=\"tw:size-\"])]:size-4", className),
|
|
70
67
|
...props
|
|
71
68
|
});
|
|
72
|
-
|
|
73
|
-
//#region src/components/InputGroup/InputGroupTextArea.tsx
|
|
69
|
+
// src/components/InputGroup/InputGroupTextArea.tsx
|
|
74
70
|
const InputGroupTextArea = ({ ref, className, onChange, onValueChange, value, defaultValue, onBlur, onValueBlur, disableResize = false, minRows = 1, maxRows = 4, ...props }) => {
|
|
75
71
|
const handleChange = (event) => {
|
|
76
72
|
onValueChange?.(event.target.value);
|
|
@@ -92,8 +88,7 @@ const InputGroupTextArea = ({ ref, className, onChange, onValueChange, value, de
|
|
|
92
88
|
className: cn("tw:w-full", "tw:bg-transparent", "tw:outline-hidden", "tw:px-4", "tw:font-sans", "tw:text-sm", "tw:placeholder:text-neutral-400", "tw:placeholder:font-normal", "tw:disabled:cursor-not-allowed", { "tw:resize-none": disableResize }, className)
|
|
93
89
|
});
|
|
94
90
|
};
|
|
95
|
-
|
|
96
|
-
//#region src/components/InputGroup/InputGroup.tsx
|
|
91
|
+
// src/components/InputGroup/InputGroup.tsx
|
|
97
92
|
const inputGroupVariants = cva([
|
|
98
93
|
"tailwindcss-preflight",
|
|
99
94
|
"tw:group",
|
|
@@ -186,7 +181,6 @@ InputGroup.Addon = InputGroupAddon;
|
|
|
186
181
|
InputGroup.Button = InputGroupButton;
|
|
187
182
|
InputGroup.TextArea = InputGroupTextArea;
|
|
188
183
|
InputGroup.Text = InputGroupText;
|
|
189
|
-
//#endregion
|
|
190
184
|
export { InputGroup };
|
|
191
185
|
|
|
192
|
-
//# sourceMappingURL=InputGroup-
|
|
186
|
+
//# sourceMappingURL=InputGroup-BWeanEo7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputGroup-CZv_7QlM.js","names":[],"sources":["../src/components/InputGroup/InputGroupAddon.tsx","../src/components/InputGroup/InputGroupButton.tsx","../src/components/InputGroup/InputGroupInput.tsx","../src/components/InputGroup/InputGroupText.tsx","../src/components/InputGroup/InputGroupTextArea.tsx","../src/components/InputGroup/InputGroup.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nimport { cn } from '../../utils';\n\n// Padding only fires when the addon actually has content — keeps an empty\n// `<Addon>{maybeNull}</Addon>` from carving 16px out of the input row.\nconst addonVariants = cva(\n [\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-1',\n\n // Default size for nested Lucide icons in prefix/suffix slots; callers can override on the icon.\n \"tw:[&_svg.lucide:not([class*='tw:size-'])]:size-4\",\n 'tw:[&_svg]:shrink-0',\n ],\n {\n defaultVariants: {\n align: 'inline-start',\n },\n variants: {\n align: {\n 'inline-start': ['tw:order-first', 'tw:shrink-0', 'tw:[&:not(:empty)]:pl-4'],\n 'inline-end': ['tw:order-last', 'tw:shrink-0', 'tw:[&:not(:empty)]:pr-4'],\n 'block-start': [\n 'tw:order-first',\n // `tw:w-full` needs to be empty-conditional too — when the addon\n // has no content the root stays in flex-row, and a 100%-wide\n // empty addon would claim half of the input row beside the input.\n 'tw:[&:not(:empty)]:w-full',\n 'tw:[&:not(:empty)]:px-4',\n 'tw:[&:not(:empty)]:py-1.5',\n ],\n 'block-end': [\n 'tw:order-last',\n 'tw:[&:not(:empty)]:w-full',\n 'tw:[&:not(:empty)]:px-4',\n 'tw:[&:not(:empty)]:py-1.5',\n ],\n },\n },\n },\n);\n\ntype Props = ComponentProps<'div'> & VariantProps<typeof addonVariants>;\n\nexport const InputGroupAddon = ({\n children,\n align = 'inline-start',\n className,\n ...props\n}: Props) => (\n <div {...props} data-align={align} className={cn(addonVariants({ align, className }))}>\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\n\ntype ButtonProps = ComponentProps<typeof Button>;\n\ntype Props = Omit<ButtonProps, 'size' | 'block' | 'variant'>;\n\nexport const InputGroupButton = ({ ref, className, tabIndex = -1, ...props }: Props) => (\n <Button\n {...props}\n tabIndex={tabIndex}\n ref={ref}\n variant=\"invisible\"\n size=\"icon-sm\"\n className={cn('tw:size-5', 'tw:[&_svg]:text-muted-foreground', className)}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'input'>;\n\nexport const InputGroupInput = ({ ref, className, ...inputProps }: Props) => (\n <input\n {...inputProps}\n ref={ref}\n className={cn(\n 'tw:flex-1',\n 'tw:min-w-0',\n 'tw:bg-transparent',\n 'tw:outline-hidden',\n\n // font\n 'tw:font-sans',\n 'tw:text-sm',\n\n // placeholder\n 'tw:placeholder:text-neutral-400',\n 'tw:placeholder:font-normal',\n\n // disabled\n 'tw:disabled:cursor-not-allowed',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'span'>;\n\nexport const InputGroupText = ({ className, ...props }: Props) => (\n <span\n className={cn(\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n 'tw:text-sm',\n 'tw:text-muted-foreground',\n 'tw:[&_svg]:pointer-events-none',\n 'tw:[&_svg:not([class*=\"tw:size-\"])]:size-4',\n className,\n )}\n {...props}\n />\n);\n","import type { ChangeEventHandler, ComponentProps, FocusEventHandler } from 'react';\nimport TextareaAutosize from 'react-textarea-autosize';\n\nimport { cn } from '../../utils';\n\ntype TextareaNativeProps = Omit<\n ComponentProps<typeof TextareaAutosize>,\n 'value' | 'defaultValue' | 'rows' | 'maxRows'\n>;\n\ntype Props = TextareaNativeProps & {\n value?: string | null;\n defaultValue?: string | null;\n onValueChange?: (value: string) => void;\n onValueBlur?: (value: string) => void;\n maxRows?: number | 'unlimited';\n disableResize?: boolean;\n};\n\nexport const InputGroupTextArea = ({\n ref,\n className,\n onChange,\n onValueChange,\n value,\n defaultValue,\n onBlur,\n onValueBlur,\n disableResize = false,\n minRows = 1,\n maxRows = 4,\n ...props\n}: Props) => {\n const handleChange: ChangeEventHandler<HTMLTextAreaElement> = (event) => {\n onValueChange?.(event.target.value);\n onChange?.(event);\n };\n\n const handleBlur: FocusEventHandler<HTMLTextAreaElement> = (event) => {\n onValueBlur?.(event.target.value);\n onBlur?.(event);\n };\n\n return (\n <TextareaAutosize\n {...props}\n ref={ref}\n value={value ?? undefined}\n defaultValue={defaultValue ?? undefined}\n onChange={handleChange}\n onBlur={handleBlur}\n minRows={minRows}\n maxRows={maxRows === 'unlimited' ? undefined : maxRows}\n className={cn(\n 'tw:w-full',\n 'tw:bg-transparent',\n 'tw:outline-hidden',\n 'tw:px-4',\n\n // font\n 'tw:font-sans',\n 'tw:text-sm',\n\n // placeholder\n 'tw:placeholder:text-neutral-400',\n 'tw:placeholder:font-normal',\n\n // disabled\n 'tw:disabled:cursor-not-allowed',\n {\n 'tw:resize-none': disableResize,\n },\n\n className,\n )}\n />\n );\n};\n","import type { ComponentPropsWithRef } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nimport { cn } from '../../utils';\n\nimport { InputGroupAddon } from './InputGroupAddon';\nimport { InputGroupButton } from './InputGroupButton';\nimport { InputGroupInput } from './InputGroupInput';\nimport { InputGroupText } from './InputGroupText';\nimport { InputGroupTextArea } from './InputGroupTextArea';\n\nconst inputGroupVariants = cva(\n [\n 'tailwindcss-preflight',\n 'tw:group',\n\n 'tw:overflow-hidden',\n 'tw:box-border',\n\n // positioning\n 'tw:flex',\n 'tw:items-center',\n // A flex item's default `min-width: auto` floors the group at its content's intrinsic width,\n // so a constrained row (several groups side by side) overflows rather than sharing the space.\n // The group clips its own content anyway, and the input inside already carries `min-w-0`.\n 'tw:min-w-0',\n\n 'tw:rounded-[var(--radius-lg,0.25rem)]',\n 'tw:border',\n 'tw:border-solid',\n 'tw:border-input',\n // A grey inset field, distinct from white containers.\n 'tw:bg-muted',\n 'tw:text-foreground',\n 'tw:transition',\n\n // focus\n 'tw:has-[:is(input,textarea):focus]:ring-4',\n\n // readonly — higher specificity than the focus border, so a readonly field never takes it.\n 'tw:has-[:is(input,textarea)[readonly]]:focus-within:ring-0',\n 'tw:has-[:is(input,textarea)[readonly]]:border-input',\n 'tw:has-[:is(input,textarea)[readonly]:focus]:border-input',\n\n // disabled\n 'tw:has-[:is(input,textarea):disabled]:cursor-not-allowed',\n 'tw:has-[:is(input,textarea):disabled]:opacity-disabled',\n\n // `aria-invalid` on the control surfaces the error chrome without a `state` prop.\n 'tw:has-[:is(input,textarea)[aria-invalid=true]]:border-destructive',\n 'tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:border-destructive',\n 'tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:ring-destructive/20',\n\n // textarea: top-align addons, allow vertical expansion, own its y-padding\n 'tw:has-[textarea]:items-start',\n\n 'tw:has-[[data-align=block-start]:not(:empty)]:flex-wrap',\n 'tw:has-[[data-align=block-end]:not(:empty)]:flex-wrap',\n 'tw:[&>input]:has-[[data-align=block-start]:not(:empty)]:w-auto',\n 'tw:[&>input]:has-[[data-align=block-start]:not(:empty)]:flex-1',\n 'tw:[&>input]:has-[[data-align=block-end]:not(:empty)]:w-auto',\n 'tw:[&>input]:has-[[data-align=block-end]:not(:empty)]:flex-1',\n\n 'tw:[&_input]:px-4',\n 'tw:[&>input]:has-[[data-align=inline-start]:not(:empty)]:pl-2',\n 'tw:[&>input]:has-[[data-align=inline-end]:not(:empty)]:pr-2',\n\n 'tw:[&_:is(input,textarea)]:py-2',\n 'tw:[&_:is(input,textarea)]:leading-[18px]',\n 'tw:[&_textarea]:!min-h-[calc(2.25rem-2px)]',\n ],\n {\n defaultVariants: {\n state: 'default',\n focusVariant: 'default',\n },\n compoundVariants: [\n {\n state: 'error',\n focusVariant: 'on',\n className: ['tw:!border-destructive', 'tw:!ring-destructive/20'],\n },\n {\n state: 'default',\n focusVariant: 'off',\n className: ['tw:has-[:is(input,textarea):focus]:border-input'],\n },\n ],\n variants: {\n focusVariant: {\n default: [],\n on: ['tw:!border-primary', 'tw:!ring-ring/50', 'tw:!ring-4'],\n off: ['tw:has-[:is(input,textarea):focus]:!ring-0'],\n },\n state: {\n default: [\n 'tw:has-[:is(input,textarea):focus]:border-primary',\n 'tw:has-[:is(input,textarea):focus]:ring-ring/50',\n ],\n error: [\n 'tw:border-destructive',\n 'tw:has-[:is(input,textarea):focus]:border-destructive',\n 'tw:has-[:is(input,textarea):focus]:ring-destructive/20',\n ],\n warning: [\n 'tw:border-warning-500',\n 'tw:has-[:is(input,textarea):focus]:border-warning-500',\n 'tw:has-[:is(input,textarea):focus]:ring-warning/20',\n ],\n },\n },\n },\n);\n\ntype Props = ComponentPropsWithRef<'div'> & VariantProps<typeof inputGroupVariants>;\n\nconst InputGroupRoot = ({ ref, children, state, focusVariant, className, ...props }: Props) => (\n <div {...props} ref={ref} className={cn(inputGroupVariants({ state, focusVariant, className }))}>\n {children}\n </div>\n);\n\nexport const InputGroup = InputGroupRoot as typeof InputGroupRoot & {\n Input: typeof InputGroupInput;\n Addon: typeof InputGroupAddon;\n Button: typeof InputGroupButton;\n TextArea: typeof InputGroupTextArea;\n Text: typeof InputGroupText;\n};\n\nInputGroup.Input = InputGroupInput;\nInputGroup.Addon = InputGroupAddon;\nInputGroup.Button = InputGroupButton;\nInputGroup.TextArea = InputGroupTextArea;\nInputGroup.Text = InputGroupText;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InputGroup-BWeanEo7.js","names":[],"sources":["../src/components/InputGroup/InputGroupAddon.tsx","../src/components/InputGroup/InputGroupButton.tsx","../src/components/InputGroup/InputGroupInput.tsx","../src/components/InputGroup/InputGroupText.tsx","../src/components/InputGroup/InputGroupTextArea.tsx","../src/components/InputGroup/InputGroup.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nimport { cn } from '../../utils';\n\n// Padding only fires when the addon actually has content — keeps an empty\n// `<Addon>{maybeNull}</Addon>` from carving 16px out of the input row.\nconst addonVariants = cva(\n [\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-1',\n\n // Default size for nested Lucide icons in prefix/suffix slots; callers can override on the icon.\n \"tw:[&_svg.lucide:not([class*='tw:size-'])]:size-4\",\n 'tw:[&_svg]:shrink-0',\n ],\n {\n defaultVariants: {\n align: 'inline-start',\n },\n variants: {\n align: {\n 'inline-start': ['tw:order-first', 'tw:shrink-0', 'tw:[&:not(:empty)]:pl-4'],\n 'inline-end': ['tw:order-last', 'tw:shrink-0', 'tw:[&:not(:empty)]:pr-4'],\n 'block-start': [\n 'tw:order-first',\n // `tw:w-full` needs to be empty-conditional too — when the addon\n // has no content the root stays in flex-row, and a 100%-wide\n // empty addon would claim half of the input row beside the input.\n 'tw:[&:not(:empty)]:w-full',\n 'tw:[&:not(:empty)]:px-4',\n 'tw:[&:not(:empty)]:py-1.5',\n ],\n 'block-end': [\n 'tw:order-last',\n 'tw:[&:not(:empty)]:w-full',\n 'tw:[&:not(:empty)]:px-4',\n 'tw:[&:not(:empty)]:py-1.5',\n ],\n },\n },\n },\n);\n\ntype Props = ComponentProps<'div'> & VariantProps<typeof addonVariants>;\n\nexport const InputGroupAddon = ({\n children,\n align = 'inline-start',\n className,\n ...props\n}: Props) => (\n <div {...props} data-align={align} className={cn(addonVariants({ align, className }))}>\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\n\ntype ButtonProps = ComponentProps<typeof Button>;\n\ntype Props = Omit<ButtonProps, 'size' | 'block' | 'variant'>;\n\nexport const InputGroupButton = ({ ref, className, tabIndex = -1, ...props }: Props) => (\n <Button\n {...props}\n tabIndex={tabIndex}\n ref={ref}\n variant=\"invisible\"\n size=\"icon-sm\"\n className={cn('tw:size-5', 'tw:[&_svg]:text-muted-foreground', className)}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'input'>;\n\nexport const InputGroupInput = ({ ref, className, ...inputProps }: Props) => (\n <input\n {...inputProps}\n ref={ref}\n className={cn(\n 'tw:flex-1',\n 'tw:min-w-0',\n 'tw:bg-transparent',\n 'tw:outline-hidden',\n\n // font\n 'tw:font-sans',\n 'tw:text-sm',\n\n // placeholder\n 'tw:placeholder:text-neutral-400',\n 'tw:placeholder:font-normal',\n\n // disabled\n 'tw:disabled:cursor-not-allowed',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'span'>;\n\nexport const InputGroupText = ({ className, ...props }: Props) => (\n <span\n className={cn(\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n 'tw:text-sm',\n 'tw:text-muted-foreground',\n 'tw:[&_svg]:pointer-events-none',\n 'tw:[&_svg:not([class*=\"tw:size-\"])]:size-4',\n className,\n )}\n {...props}\n />\n);\n","import type { ChangeEventHandler, ComponentProps, FocusEventHandler } from 'react';\nimport TextareaAutosize from 'react-textarea-autosize';\n\nimport { cn } from '../../utils';\n\ntype TextareaNativeProps = Omit<\n ComponentProps<typeof TextareaAutosize>,\n 'value' | 'defaultValue' | 'rows' | 'maxRows'\n>;\n\ntype Props = TextareaNativeProps & {\n value?: string | null;\n defaultValue?: string | null;\n onValueChange?: (value: string) => void;\n onValueBlur?: (value: string) => void;\n maxRows?: number | 'unlimited';\n disableResize?: boolean;\n};\n\nexport const InputGroupTextArea = ({\n ref,\n className,\n onChange,\n onValueChange,\n value,\n defaultValue,\n onBlur,\n onValueBlur,\n disableResize = false,\n minRows = 1,\n maxRows = 4,\n ...props\n}: Props) => {\n const handleChange: ChangeEventHandler<HTMLTextAreaElement> = (event) => {\n onValueChange?.(event.target.value);\n onChange?.(event);\n };\n\n const handleBlur: FocusEventHandler<HTMLTextAreaElement> = (event) => {\n onValueBlur?.(event.target.value);\n onBlur?.(event);\n };\n\n return (\n <TextareaAutosize\n {...props}\n ref={ref}\n value={value ?? undefined}\n defaultValue={defaultValue ?? undefined}\n onChange={handleChange}\n onBlur={handleBlur}\n minRows={minRows}\n maxRows={maxRows === 'unlimited' ? undefined : maxRows}\n className={cn(\n 'tw:w-full',\n 'tw:bg-transparent',\n 'tw:outline-hidden',\n 'tw:px-4',\n\n // font\n 'tw:font-sans',\n 'tw:text-sm',\n\n // placeholder\n 'tw:placeholder:text-neutral-400',\n 'tw:placeholder:font-normal',\n\n // disabled\n 'tw:disabled:cursor-not-allowed',\n {\n 'tw:resize-none': disableResize,\n },\n\n className,\n )}\n />\n );\n};\n","import type { ComponentPropsWithRef } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nimport { cn } from '../../utils';\n\nimport { InputGroupAddon } from './InputGroupAddon';\nimport { InputGroupButton } from './InputGroupButton';\nimport { InputGroupInput } from './InputGroupInput';\nimport { InputGroupText } from './InputGroupText';\nimport { InputGroupTextArea } from './InputGroupTextArea';\n\nconst inputGroupVariants = cva(\n [\n 'tailwindcss-preflight',\n 'tw:group',\n\n 'tw:overflow-hidden',\n 'tw:box-border',\n\n // positioning\n 'tw:flex',\n 'tw:items-center',\n // A flex item's default `min-width: auto` floors the group at its content's intrinsic width,\n // so a constrained row (several groups side by side) overflows rather than sharing the space.\n // The group clips its own content anyway, and the input inside already carries `min-w-0`.\n 'tw:min-w-0',\n\n 'tw:rounded-[var(--radius-lg,0.25rem)]',\n 'tw:border',\n 'tw:border-solid',\n 'tw:border-input',\n // A grey inset field, distinct from white containers.\n 'tw:bg-muted',\n 'tw:text-foreground',\n 'tw:transition',\n\n // focus\n 'tw:has-[:is(input,textarea):focus]:ring-4',\n\n // readonly — higher specificity than the focus border, so a readonly field never takes it.\n 'tw:has-[:is(input,textarea)[readonly]]:focus-within:ring-0',\n 'tw:has-[:is(input,textarea)[readonly]]:border-input',\n 'tw:has-[:is(input,textarea)[readonly]:focus]:border-input',\n\n // disabled\n 'tw:has-[:is(input,textarea):disabled]:cursor-not-allowed',\n 'tw:has-[:is(input,textarea):disabled]:opacity-disabled',\n\n // `aria-invalid` on the control surfaces the error chrome without a `state` prop.\n 'tw:has-[:is(input,textarea)[aria-invalid=true]]:border-destructive',\n 'tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:border-destructive',\n 'tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:ring-destructive/20',\n\n // textarea: top-align addons, allow vertical expansion, own its y-padding\n 'tw:has-[textarea]:items-start',\n\n 'tw:has-[[data-align=block-start]:not(:empty)]:flex-wrap',\n 'tw:has-[[data-align=block-end]:not(:empty)]:flex-wrap',\n 'tw:[&>input]:has-[[data-align=block-start]:not(:empty)]:w-auto',\n 'tw:[&>input]:has-[[data-align=block-start]:not(:empty)]:flex-1',\n 'tw:[&>input]:has-[[data-align=block-end]:not(:empty)]:w-auto',\n 'tw:[&>input]:has-[[data-align=block-end]:not(:empty)]:flex-1',\n\n 'tw:[&_input]:px-4',\n 'tw:[&>input]:has-[[data-align=inline-start]:not(:empty)]:pl-2',\n 'tw:[&>input]:has-[[data-align=inline-end]:not(:empty)]:pr-2',\n\n 'tw:[&_:is(input,textarea)]:py-2',\n 'tw:[&_:is(input,textarea)]:leading-[18px]',\n 'tw:[&_textarea]:!min-h-[calc(2.25rem-2px)]',\n ],\n {\n defaultVariants: {\n state: 'default',\n focusVariant: 'default',\n },\n compoundVariants: [\n {\n state: 'error',\n focusVariant: 'on',\n className: ['tw:!border-destructive', 'tw:!ring-destructive/20'],\n },\n {\n state: 'default',\n focusVariant: 'off',\n className: ['tw:has-[:is(input,textarea):focus]:border-input'],\n },\n ],\n variants: {\n focusVariant: {\n default: [],\n on: ['tw:!border-primary', 'tw:!ring-ring/50', 'tw:!ring-4'],\n off: ['tw:has-[:is(input,textarea):focus]:!ring-0'],\n },\n state: {\n default: [\n 'tw:has-[:is(input,textarea):focus]:border-primary',\n 'tw:has-[:is(input,textarea):focus]:ring-ring/50',\n ],\n error: [\n 'tw:border-destructive',\n 'tw:has-[:is(input,textarea):focus]:border-destructive',\n 'tw:has-[:is(input,textarea):focus]:ring-destructive/20',\n ],\n warning: [\n 'tw:border-warning-500',\n 'tw:has-[:is(input,textarea):focus]:border-warning-500',\n 'tw:has-[:is(input,textarea):focus]:ring-warning/20',\n ],\n },\n },\n },\n);\n\ntype Props = ComponentPropsWithRef<'div'> & VariantProps<typeof inputGroupVariants>;\n\nconst InputGroupRoot = ({ ref, children, state, focusVariant, className, ...props }: Props) => (\n <div {...props} ref={ref} className={cn(inputGroupVariants({ state, focusVariant, className }))}>\n {children}\n </div>\n);\n\nexport const InputGroup = InputGroupRoot as typeof InputGroupRoot & {\n Input: typeof InputGroupInput;\n Addon: typeof InputGroupAddon;\n Button: typeof InputGroupButton;\n TextArea: typeof InputGroupTextArea;\n Text: typeof InputGroupText;\n};\n\nInputGroup.Input = InputGroupInput;\nInputGroup.Addon = InputGroupAddon;\nInputGroup.Button = InputGroupButton;\nInputGroup.TextArea = InputGroupTextArea;\nInputGroup.Text = InputGroupText;\n"],"mappings":"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"}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { cn } from "./classNames-
|
|
2
|
-
import { isMac } from "./utils-
|
|
1
|
+
import { cn } from "./classNames-DkX30VJU.js";
|
|
2
|
+
import { isMac } from "./utils-DjFceY3H.js";
|
|
3
3
|
import { Children, Fragment } from "react";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
|
|
6
|
+
// src/components/Kbd/KbdSeparator.tsx
|
|
7
7
|
/** The `+` / `then` glue between two `Kbd` keys, in the muted chrome token. */
|
|
8
8
|
const KbdSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx("span", {
|
|
9
9
|
...props,
|
|
10
10
|
className: cn("tw:text-xs tw:text-muted-foreground", className)
|
|
11
11
|
});
|
|
12
|
-
|
|
13
|
-
//#region src/components/Kbd/KbdGroup.tsx
|
|
12
|
+
// src/components/Kbd/KbdGroup.tsx
|
|
14
13
|
const KbdGroup = ({ ref, className, children, separator, ...props }) => {
|
|
15
14
|
return /* @__PURE__ */ jsx("kbd", {
|
|
16
15
|
...props,
|
|
@@ -19,8 +18,7 @@ const KbdGroup = ({ ref, className, children, separator, ...props }) => {
|
|
|
19
18
|
children: separator ? Children.toArray(children).map((child, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && /* @__PURE__ */ jsx(KbdSeparator, { children: separator }), child] }, index)) : children
|
|
20
19
|
});
|
|
21
20
|
};
|
|
22
|
-
|
|
23
|
-
//#region src/components/Kbd/styles.ts
|
|
21
|
+
// src/components/Kbd/styles.ts
|
|
24
22
|
const kbdVariants = cva([
|
|
25
23
|
"tailwindcss-preflight",
|
|
26
24
|
"tw:pointer-events-none",
|
|
@@ -53,8 +51,7 @@ const kbdVariants = cva([
|
|
|
53
51
|
}
|
|
54
52
|
}
|
|
55
53
|
});
|
|
56
|
-
|
|
57
|
-
//#region src/components/Kbd/Kbd.tsx
|
|
54
|
+
// src/components/Kbd/Kbd.tsx
|
|
58
55
|
const Kbd = ({ children, className, variant, casing, ...rest }) => /* @__PURE__ */ jsx("kbd", {
|
|
59
56
|
...rest,
|
|
60
57
|
className: kbdVariants({
|
|
@@ -66,8 +63,7 @@ const Kbd = ({ children, className, variant, casing, ...rest }) => /* @__PURE__
|
|
|
66
63
|
});
|
|
67
64
|
Kbd.Group = KbdGroup;
|
|
68
65
|
Kbd.Separator = KbdSeparator;
|
|
69
|
-
|
|
70
|
-
//#region src/components/Kbd/keyboardKeys.ts
|
|
66
|
+
// src/components/Kbd/keyboardKeys.ts
|
|
71
67
|
const KEY_DEFINITIONS = {
|
|
72
68
|
mod: {
|
|
73
69
|
mac: {
|
|
@@ -116,7 +112,6 @@ const createKeyboardKeys = () => {
|
|
|
116
112
|
return keysObj;
|
|
117
113
|
};
|
|
118
114
|
const keys = createKeyboardKeys();
|
|
119
|
-
//#endregion
|
|
120
115
|
export { Kbd, kbdVariants, keys };
|
|
121
116
|
|
|
122
|
-
//# sourceMappingURL=Kbd-
|
|
117
|
+
//# sourceMappingURL=Kbd-BprYCICe.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Kbd-
|
|
1
|
+
{"version":3,"file":"Kbd-BprYCICe.js","names":[],"sources":["../src/components/Kbd/KbdSeparator.tsx","../src/components/Kbd/KbdGroup.tsx","../src/components/Kbd/styles.ts","../src/components/Kbd/Kbd.tsx","../src/components/Kbd/keyboardKeys.ts"],"sourcesContent":["import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'span'>;\n\n/** The `+` / `then` glue between two `Kbd` keys, in the muted chrome token. */\nexport const KbdSeparator = ({ className, ...props }: Props) => (\n <span {...props} className={cn('tw:text-xs tw:text-muted-foreground', className)} />\n);\n","import { Children, Fragment } from 'react';\nimport type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nimport { KbdSeparator } from './KbdSeparator';\n\ntype Props = { separator?: string } & ComponentProps<'kbd'>;\n\nexport const KbdGroup = ({ ref, className, children, separator, ...props }: Props) => {\n return (\n <kbd\n {...props}\n ref={ref}\n className={cn('tw:inline-flex', 'tw:items-center', 'tw:gap-1', className)}\n >\n {separator\n ? // oxlint-disable-next-line react-x/no-children-to-array\n Children.toArray(children).map((child, index) => (\n // oxlint-disable-next-line\n <Fragment key={index}>\n {index > 0 && <KbdSeparator>{separator}</KbdSeparator>}\n {child}\n </Fragment>\n ))\n : children}\n </kbd>\n );\n};\n","import { cva } from 'class-variance-authority';\n\nexport const kbdVariants = cva(\n [\n 'tailwindcss-preflight',\n // style\n 'tw:pointer-events-none',\n 'tw:w-fit',\n 'tw:h-5',\n 'tw:min-w-5',\n\n // layout\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:gap-1',\n 'tw:shrink-0',\n\n // spacing\n 'tw:px-1',\n 'tw:[&_svg:not([class*=\"size-\"])]:size-2.5',\n\n 'tw:text-xs',\n 'tw:font-medium',\n\n 'tw:rounded',\n ],\n {\n defaultVariants: {\n variant: 'default',\n casing: 'upper',\n },\n variants: {\n // Uppercase like a keycap; `as-written` for layout-printed labels, where the transform\n // changes glyph count (`ß` → `SS`).\n casing: {\n upper: 'tw:uppercase',\n 'as-written': '',\n },\n variant: {\n default: 'tw:bg-muted tw:text-muted-foreground',\n // Tooltip shortcut key.\n primary: 'tw:bg-muted tw:text-muted-foreground',\n },\n },\n },\n);\n","import type { ComponentProps } from 'react';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { KbdGroup } from './KbdGroup';\nimport { KbdSeparator } from './KbdSeparator';\nimport { kbdVariants } from './styles';\n\ntype Props = ComponentProps<'kbd'> & VariantProps<typeof kbdVariants>;\n\nexport const Kbd = ({ children, className, variant, casing, ...rest }: Props) => (\n <kbd {...rest} className={kbdVariants({ className, variant, casing })}>\n {children}\n </kbd>\n);\n\nKbd.Group = KbdGroup;\nKbd.Separator = KbdSeparator;\n","import { isMac } from '../../utils';\n\ntype KeyName = 'mod' | 'option' | 'shift' | 'enter';\ntype KeyRepresentation = { symbol: string; text: string };\n\ntype KeyDefinition = {\n mac: KeyRepresentation;\n windows: KeyRepresentation;\n};\n\nconst KEY_DEFINITIONS: Record<KeyName, KeyDefinition> = {\n mod: {\n mac: { symbol: '⌘', text: 'Command' },\n windows: { symbol: 'Ctrl', text: 'Ctrl' },\n },\n option: {\n mac: { symbol: '⌥', text: 'Option' },\n windows: { symbol: 'Alt', text: 'Alt' },\n },\n shift: {\n mac: { symbol: '⇧', text: 'Shift' },\n windows: { symbol: '⇧', text: 'Shift' },\n },\n enter: {\n mac: { symbol: '⏎', text: 'Enter' },\n windows: { symbol: '⏎', text: 'Enter' },\n },\n};\n\nconst createKeyboardKeys = () => {\n const keysObj: Record<KeyName, KeyRepresentation> = {} as Record<KeyName, KeyRepresentation>;\n\n for (const keyName of Object.keys(KEY_DEFINITIONS) as KeyName[]) {\n keysObj[keyName] = KEY_DEFINITIONS[keyName][isMac ? 'mac' : 'windows'];\n }\n\n return keysObj;\n};\n\nexport const keys = createKeyboardKeys();\n"],"mappings":";;;;;;;AAOA,MAAa,gBAAgB,EAAE,WAAW,GAAG,YAC3C,oBAAC,QAAD;CAAM,GAAI;CAAO,WAAW,GAAG,uCAAuC,SAAS;AAAI,CAAA;;ACCrF,MAAa,YAAY,EAAE,KAAK,WAAW,UAAU,WAAW,GAAG,YAAmB;CACpF,OACE,oBAAC,OAAD;EACE,GAAI;EACC;EACL,WAAW,GAAG,kBAAkB,mBAAmB,YAAY,SAAS;EAEvE,UAAA,YAEG,SAAS,QAAQ,QAAQ,CAAC,CAAC,KAAK,OAAO,UAErC,qBAAC,UAAD,EAAA,UAAA,CACG,QAAQ,KAAK,oBAAC,cAAD,EAAA,UAAe,UAAwB,CAAA,GACpD,KACO,EAAA,GAHK,KAGL,CACX,IACD;CACD,CAAA;AAET;;AC1BA,MAAa,cAAc,IACzB;CACE;CAEA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CAGA;CACA;CAEA;CACA;CAEA;AACF,GACA;CACE,iBAAiB;EACf,SAAS;EACT,QAAQ;CACV;CACA,UAAU;EAGR,QAAQ;GACN,OAAO;GACP,cAAc;EAChB;EACA,SAAS;GACP,SAAS;GAET,SAAS;EACX;CACF;AACF,CACF;;ACrCA,MAAa,OAAO,EAAE,UAAU,WAAW,SAAS,QAAQ,GAAG,WAC7D,oBAAC,OAAD;CAAK,GAAI;CAAM,WAAW,YAAY;EAAE;EAAW;EAAS;CAAO,CAAC;CACjE;AACE,CAAA;AAGP,IAAI,QAAQ;AACZ,IAAI,YAAY;;ACNhB,MAAM,kBAAkD;CACtD,KAAK;EACH,KAAK;GAAE,QAAQ;GAAK,MAAM;EAAU;EACpC,SAAS;GAAE,QAAQ;GAAQ,MAAM;EAAO;CAC1C;CACA,QAAQ;EACN,KAAK;GAAE,QAAQ;GAAK,MAAM;EAAS;EACnC,SAAS;GAAE,QAAQ;GAAO,MAAM;EAAM;CACxC;CACA,OAAO;EACL,KAAK;GAAE,QAAQ;GAAK,MAAM;EAAQ;EAClC,SAAS;GAAE,QAAQ;GAAK,MAAM;EAAQ;CACxC;CACA,OAAO;EACL,KAAK;GAAE,QAAQ;GAAK,MAAM;EAAQ;EAClC,SAAS;GAAE,QAAQ;GAAK,MAAM;EAAQ;CACxC;AACF;AAEA,MAAM,2BAA2B;CAC/B,MAAM,UAA8C,CAAC;CAErD,KAAK,MAAM,WAAW,OAAO,KAAK,eAAe,GAC/C,QAAQ,WAAW,gBAAgB,QAAQ,CAAC,QAAQ,QAAQ;CAG9D,OAAO;AACT;AAEA,MAAa,OAAO,mBAAmB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { findLiteralTermMatches } from "./findLiteralMatches-
|
|
1
|
+
import { findLiteralTermMatches } from "./findLiteralMatches-BaLZTPtx.js";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
|
-
|
|
4
|
+
// src/components/MarkedText/utils.ts
|
|
5
5
|
/**
|
|
6
6
|
* Splits `source` into alternating plain and marked runs.
|
|
7
7
|
*
|
|
@@ -43,8 +43,7 @@ const createMarkedParts = ({ mark, isCaseSensitive, source }) => {
|
|
|
43
43
|
});
|
|
44
44
|
return parts;
|
|
45
45
|
};
|
|
46
|
-
|
|
47
|
-
//#region src/components/MarkedText/MarkedText.tsx
|
|
46
|
+
// src/components/MarkedText/MarkedText.tsx
|
|
48
47
|
const MarkedText = ({ ref, source, mark, isCaseSensitive = false, ...spanProps }) => {
|
|
49
48
|
const parts = useMemo(() => createMarkedParts({
|
|
50
49
|
mark,
|
|
@@ -61,7 +60,6 @@ const MarkedText = ({ ref, source, mark, isCaseSensitive = false, ...spanProps }
|
|
|
61
60
|
children: parts.map(({ isMark, part }, index) => isMark ? /* @__PURE__ */ jsx("mark", { children: part }, index) : part)
|
|
62
61
|
});
|
|
63
62
|
};
|
|
64
|
-
//#endregion
|
|
65
63
|
export { MarkedText };
|
|
66
64
|
|
|
67
|
-
//# sourceMappingURL=MarkedText-
|
|
65
|
+
//# sourceMappingURL=MarkedText-BrganZ_V.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkedText-
|
|
1
|
+
{"version":3,"file":"MarkedText-BrganZ_V.js","names":[],"sources":["../src/components/MarkedText/utils.ts","../src/components/MarkedText/MarkedText.tsx"],"sourcesContent":["import { findLiteralTermMatches } from '../../utils/findLiteralMatches';\n\ntype MarkedPart = { isMark: boolean; part: string };\n\n/**\n * Splits `source` into alternating plain and marked runs.\n *\n * - Every space-separated term of `mark` highlights independently.\n * - Terms are matched as literal text, never compiled as a pattern — a pasted document is a valid\n * query, and tens of kilobytes of one exceed what V8 accepts as a regular expression.\n * - Overlapping or adjacent term matches merge into one marked run.\n * - A blank `mark` returns the whole source unmarked.\n */\nexport const createMarkedParts = ({\n mark,\n isCaseSensitive,\n source,\n}: {\n mark?: string;\n source: string;\n isCaseSensitive: boolean;\n}): MarkedPart[] => {\n if (!mark?.trim()) return [{ isMark: false, part: source }];\n\n const terms = [...new Set(mark.split(' '))].filter(Boolean);\n const matches = findLiteralTermMatches(source, terms, { isCaseSensitive }).sort(\n (a, b) => a.from - b.from,\n );\n\n const merged: { from: number; to: number }[] = [];\n for (const match of matches) {\n const last = merged.at(-1);\n if (last && match.from <= last.to) {\n last.to = Math.max(last.to, match.to);\n } else {\n merged.push(match);\n }\n }\n\n const parts: MarkedPart[] = [];\n let cursor = 0;\n for (const { from, to } of merged) {\n if (from > cursor) parts.push({ isMark: false, part: source.slice(cursor, from) });\n parts.push({ isMark: true, part: source.slice(from, to) });\n cursor = to;\n }\n if (cursor < source.length) parts.push({ isMark: false, part: source.slice(cursor) });\n\n return parts;\n};\n","import { useMemo } from 'react';\nimport type { ComponentProps } from 'react';\n\nimport { createMarkedParts } from './utils';\n\ntype Props = {\n source: string;\n className?: string;\n mark?: string;\n isCaseSensitive?: boolean;\n} & ComponentProps<'span'>;\n\nexport const MarkedText = ({ ref, source, mark, isCaseSensitive = false, ...spanProps }: Props) => {\n const parts = useMemo(\n () =>\n createMarkedParts({\n mark,\n source,\n isCaseSensitive,\n }),\n [isCaseSensitive, mark, source],\n );\n\n return (\n <span {...spanProps} ref={ref}>\n {/* oxlint-disable-next-line react/no-array-index-key */}\n {parts.map(({ isMark, part }, index) => (isMark ? <mark key={index}>{part}</mark> : part))}\n </span>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,qBAAqB,EAChC,MACA,iBACA,aAKkB;CAClB,IAAI,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC;EAAE,QAAQ;EAAO,MAAM;CAAO,CAAC;CAE1D,MAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,OAAO;CAC1D,MAAM,UAAU,uBAAuB,QAAQ,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,MACxE,GAAG,MAAM,EAAE,OAAO,EAAE,IACvB;CAEA,MAAM,SAAyC,CAAC;CAChD,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,OAAO,OAAO,GAAG,EAAE;EACzB,IAAI,QAAQ,MAAM,QAAQ,KAAK,IAC7B,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,EAAE;OAEpC,OAAO,KAAK,KAAK;CAErB;CAEA,MAAM,QAAsB,CAAC;CAC7B,IAAI,SAAS;CACb,KAAK,MAAM,EAAE,MAAM,QAAQ,QAAQ;EACjC,IAAI,OAAO,QAAQ,MAAM,KAAK;GAAE,QAAQ;GAAO,MAAM,OAAO,MAAM,QAAQ,IAAI;EAAE,CAAC;EACjF,MAAM,KAAK;GAAE,QAAQ;GAAM,MAAM,OAAO,MAAM,MAAM,EAAE;EAAE,CAAC;EACzD,SAAS;CACX;CACA,IAAI,SAAS,OAAO,QAAQ,MAAM,KAAK;EAAE,QAAQ;EAAO,MAAM,OAAO,MAAM,MAAM;CAAE,CAAC;CAEpF,OAAO;AACT;;ACrCA,MAAa,cAAc,EAAE,KAAK,QAAQ,MAAM,kBAAkB,OAAO,GAAG,gBAAuB;CACjG,MAAM,QAAQ,cAEV,kBAAkB;EAChB;EACA;EACA;CACF,CAAC,GACH;EAAC;EAAiB;EAAM;CAAM,CAChC;CAEA,OACE,oBAAC,QAAD;EAAM,GAAI;EAAgB;EAEvB,UAAA,MAAM,KAAK,EAAE,QAAQ,QAAQ,UAAW,SAAS,oBAAC,QAAD,EAAA,UAAmB,KAAW,GAAnB,KAAmB,IAAI,IAAK;CACrF,CAAA;AAEV"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { __exportAll } from "./rolldown-runtime-
|
|
1
|
+
import { __exportAll } from "./rolldown-runtime-BrwM56v-.js";
|
|
2
2
|
import { DiagramSkeleton } from "./internal/blocks/DiagramShared/DiagramSkeleton.js";
|
|
3
|
-
import { DiagramSource, makeResponsive } from "./svgTransforms-
|
|
4
|
-
import { ZoomableSvg } from "./ZoomableSvg-
|
|
5
|
-
import { useThemeAttributes } from "./themeTokens-
|
|
6
|
-
import { SERIES_TOKENS, createVegaColorResolver, tierTwoColour } from "./vegaTokens-
|
|
7
|
-
import { createSvgCache, diagramCacheKey } from "./svgCache-
|
|
3
|
+
import { DiagramSource, makeResponsive } from "./svgTransforms-BBxxO9T6.js";
|
|
4
|
+
import { ZoomableSvg } from "./ZoomableSvg-BRPGgaWJ.js";
|
|
5
|
+
import { useThemeAttributes } from "./themeTokens-B60cQtAY.js";
|
|
6
|
+
import { SERIES_TOKENS, createVegaColorResolver, tierTwoColour } from "./vegaTokens-DnCcy7JY.js";
|
|
7
|
+
import { createSvgCache, diagramCacheKey } from "./svgCache-BzvN_fgr.js";
|
|
8
8
|
import { useEffect, useState } from "react";
|
|
9
9
|
import { jsx } from "react/jsx-runtime";
|
|
10
10
|
import { PeleError, detectType, load, registered, render } from "pele/lazy";
|
|
11
|
-
|
|
11
|
+
// src/blocks/MermaidDiagram/peleTheme.ts
|
|
12
12
|
const DIAGRAM_FONT = "Inter, system-ui, sans-serif";
|
|
13
13
|
/**
|
|
14
14
|
* The `--pele-*` declarations for one scheme, as a `style` attribute fragment.
|
|
@@ -39,8 +39,7 @@ const peleThemeStyle = (scheme, from) => {
|
|
|
39
39
|
});
|
|
40
40
|
return Object.entries(vars).map(([name, value]) => `--pele-${name}:${value}`).join(";");
|
|
41
41
|
};
|
|
42
|
-
|
|
43
|
-
//#region src/blocks/MermaidDiagram/MermaidDiagram.tsx
|
|
42
|
+
// src/blocks/MermaidDiagram/MermaidDiagram.tsx
|
|
44
43
|
var MermaidDiagram_exports = /* @__PURE__ */ __exportAll({ MermaidDiagram: () => MermaidDiagram });
|
|
45
44
|
let lucidePack = null;
|
|
46
45
|
let lucidePromise = null;
|
|
@@ -193,7 +192,6 @@ const MermaidDiagram = ({ code, renderActions }) => {
|
|
|
193
192
|
if ("error" in outcome && (!outcome.truncated || gaveUpKey === cacheKey)) return /* @__PURE__ */ jsx(DiagramSource, { code });
|
|
194
193
|
return /* @__PURE__ */ jsx(DiagramSkeleton, {});
|
|
195
194
|
};
|
|
196
|
-
//#endregion
|
|
197
195
|
export { MermaidDiagram, MermaidDiagram_exports };
|
|
198
196
|
|
|
199
|
-
//# sourceMappingURL=MermaidDiagram-
|
|
197
|
+
//# sourceMappingURL=MermaidDiagram-E3azndPk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MermaidDiagram-Te-5gOCU.js","names":[],"sources":["../src/blocks/MermaidDiagram/peleTheme.ts","../src/blocks/MermaidDiagram/MermaidDiagram.tsx"],"sourcesContent":["import type { ResolvedColorScheme } from '../../components/ThemeProvider/types';\nimport { createVegaColorResolver, SERIES_TOKENS, tierTwoColour } from '../../vega/vegaTokens';\n\nexport const DIAGRAM_FONT = 'Inter, system-ui, sans-serif';\n\n/**\n * The `--pele-*` declarations for one scheme, as a `style` attribute fragment.\n *\n * - Resolved colours, not `var()` refs: an exported SVG or PNG has no page CSS to read.\n * - One `getComputedStyle` snapshot per call; never hoist — values follow scheme and brand.\n * - Series 6–8 are the charts' second tier, as in Flint charts.\n */\nexport const peleThemeStyle = (scheme: ResolvedColorScheme, from?: Element | null): string => {\n const token = createVegaColorResolver(scheme, from);\n const series = SERIES_TOKENS.map((name) => token(name));\n\n const vars: Record<string, string> = {\n bg: token('card'),\n fg: token('foreground'),\n muted: token('muted-foreground'),\n line: token('muted-foreground'),\n surface: token('muted'),\n 'surface-alt': token('accent'),\n border: token('border'),\n accent: token('primary'),\n critical: token('destructive'),\n error: token('destructive'),\n font: DIAGRAM_FONT,\n radius: '6px',\n };\n [...series, ...series.map((colour) => tierTwoColour(colour, scheme))]\n .slice(0, 8)\n .forEach((colour, index) => {\n vars[`series-${index + 1}`] = colour;\n });\n\n return Object.entries(vars)\n .map(([name, value]) => `--pele-${name}:${value}`)\n .join(';');\n};\n","import { useEffect, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport type { DiagramType, IconResolver } from 'pele/lazy';\nimport { detectType, load, PeleError, registered, render } from 'pele/lazy';\n\nimport type { ResolvedColorScheme } from '../../components/ThemeProvider/types';\nimport { useThemeAttributes } from '../../components/ThemeProvider/useThemeAttributes';\nimport { ZoomableSvg } from '../../components/ZoomableSvg';\nimport { DiagramSkeleton } from '../DiagramShared/DiagramSkeleton';\nimport { DiagramSource } from '../DiagramShared/DiagramSource';\nimport { createSvgCache, diagramCacheKey } from '../DiagramShared/svgCache';\nimport { makeResponsive } from '../DiagramShared/svgTransforms';\n\nimport { DIAGRAM_FONT, peleThemeStyle } from './peleTheme';\n\ntype IconPack = {\n icons: Record<string, { body: string }>;\n aliases?: Record<string, { parent: string }>;\n};\n\nlet lucidePack: IconPack | null = null;\nlet lucidePromise: Promise<void> | null = null;\n\n// The pack is a lazy local chunk, so no CDN fetch and it works under strict CSP.\nconst loadLucidePack = (): Promise<void> => {\n lucidePromise ??= import('@iconify-json/lucide/icons.json')\n .then((mod) => {\n lucidePack = mod.default;\n })\n .catch((err: unknown) => {\n lucidePromise = null;\n throw err;\n });\n return lucidePromise;\n};\n\n// `lucide:name` refs resolve to the pack's 24×24 stroke body, which is the frame Pele draws.\nconst lucideIcon: IconResolver = (ref) => {\n if (!lucidePack || !ref.startsWith('lucide:')) return null;\n const name = ref.slice('lucide:'.length);\n return (lucidePack.icons[name] ?? lucidePack.icons[lucidePack.aliases?.[name]?.parent ?? ''])\n ?.body;\n};\n\nconst usesLucide = (code: string): boolean => code.includes('lucide:');\n\nconst diagramType = (code: string): DiagramType | null => {\n try {\n return detectType(code);\n } catch (err) {\n console.debug('[MermaidDiagram] no diagram type detected:', err);\n return null;\n }\n};\n\n/**\n * Whether a render error means \"ran out of input\" rather than \"bad syntax\".\n *\n * - A syntax error at the last non-blank character or past it, as in every streaming frame.\n * - No type yet and at most one line after the preamble: the header itself is still arriving.\n * - Lower bound only: a real error on the last character shows as truncated until the grace period.\n */\n// Closed front matter and `%%` directive or comment lines before the type header.\nconst PREAMBLE = /^(?:\\s*---\\n[\\s\\S]*?\\n---[^\\S\\n]*(?:\\n|$)|[^\\S\\n]*%%.*(?:\\n|$)|\\s*\\n)*/;\n\nconst isHeaderArriving = (code: string): boolean => {\n const rest = code.replace(PREAMBLE, '');\n // Front matter whose closing `---` has not arrived yet.\n if (/^\\s*---\\n/.test(rest)) return true;\n return !rest.trim().includes('\\n');\n};\n\nconst isTruncatedDiagram = (err: unknown, code: string): boolean => {\n if (!(err instanceof PeleError)) return false;\n if (err.code === 'unsupported-diagram') return isHeaderArriving(code);\n if (err.code !== 'syntax') return false;\n const tail = code\n .split('\\n')\n .slice(err.line - 1)\n .join('\\n');\n return tail.slice(Math.max(err.column - 1, 0)).trim().length <= 1;\n};\n\n// Longer than the gap between streamed chunks, short enough for an abandoned stream.\nconst TRUNCATION_GRACE_MS = 2_000;\n\nconst svgCache = createSvgCache();\n\n// Every streamed frame shares one theme, so its palette is read once per theme key.\nlet lastTheme = { key: '', style: '' };\nconst themeStyleFor = (themeKey: string, scheme: ResolvedColorScheme, scope: Element | null) => {\n if (lastTheme.key !== themeKey) {\n lastTheme = { key: themeKey, style: peleThemeStyle(scheme, scope) };\n }\n return lastTheme.style;\n};\n\ntype Outcome =\n | { svg: string }\n | { error: unknown; truncated: boolean }\n | { loading: DiagramType | null };\n\ntype Theme = { key: string; scheme: ResolvedColorScheme; scope: Element | null };\n\n/**\n * The diagram for `code`, rendered synchronously.\n *\n * 1. A cached SVG for this code and theme.\n * 2. `loading` while the diagram type's chunk or the icon pack is not loaded yet.\n * 3. A fresh render, or the error Pele threw.\n */\nconst renderNow = (code: string, theme: Theme): Outcome => {\n const cacheKey = diagramCacheKey(code, theme.key);\n const cached = svgCache.get(cacheKey);\n if (cached) return { svg: cached };\n const type = diagramType(code);\n if ((type !== null && !registered(type)) || (usesLucide(code) && lucidePack === null)) {\n return { loading: type };\n }\n try {\n const { svg } = render(code, { fontFamily: DIAGRAM_FONT, icons: lucideIcon });\n const themed = makeResponsive(svg, themeStyleFor(theme.key, theme.scheme, theme.scope));\n svgCache.set(cacheKey, themed);\n return { svg: themed };\n } catch (error) {\n return { error, truncated: isTruncatedDiagram(error, code) };\n }\n};\n\ntype Props = {\n /** Mermaid source. */\n code: string;\n /** Extra toolbar controls forwarded to `ZoomableSvg`; receives the sanitized SVG. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const MermaidDiagram = ({ code, renderActions }: Props) => {\n // - Scheme and key come from one read, so a palette is never cached under the wrong scheme.\n // - `scope` is the element tokens are read off (`null` = `<html>`) and is part of `themeKey`.\n const { scheme, cacheKey: themeKey, scope } = useThemeAttributes();\n const cacheKey = diagramCacheKey(code, themeKey);\n\n const [state, setState] = useState(() => ({\n key: cacheKey,\n outcome: renderNow(code, { key: themeKey, scheme, scope }),\n }));\n const [gaveUpKey, setGaveUpKey] = useState<string | null>(null);\n\n // Render-phase reset avoids a one-frame flash of the previous diagram.\n if (state.key !== cacheKey) {\n setState({ key: cacheKey, outcome: renderNow(code, { key: themeKey, scheme, scope }) });\n }\n const { outcome } = state;\n\n useEffect(() => {\n if (!('loading' in outcome)) return;\n let cancelled = false;\n Promise.all([load(outcome.loading), usesLucide(code) ? loadLucidePack() : null])\n .then(() => renderNow(code, { key: themeKey, scheme, scope }))\n .catch((error: unknown) => ({ error, truncated: false }))\n .then((next) => {\n if (!cancelled) setState({ key: cacheKey, outcome: next });\n });\n return () => {\n cancelled = true;\n };\n }, [outcome, code, cacheKey, themeKey, scheme, scope]);\n\n useEffect(() => {\n if (!('error' in outcome)) return;\n if (!outcome.truncated) {\n console.error('[MermaidDiagram] render failed:', outcome.error);\n return;\n }\n // A streaming diagram is truncated at almost every frame; one that stops arriving shows its source.\n const timer = setTimeout(() => setGaveUpKey(cacheKey), TRUNCATION_GRACE_MS);\n return () => clearTimeout(timer);\n }, [outcome, cacheKey]);\n\n if ('svg' in outcome) {\n return (\n <ZoomableSvg\n key={code}\n html={outcome.svg}\n copyText={`\\`\\`\\`mermaid\\n${code}\\n\\`\\`\\``}\n className=\"tw:my-3\"\n renderActions={renderActions}\n />\n );\n }\n\n if ('error' in outcome && (!outcome.truncated || gaveUpKey === cacheKey)) {\n return <DiagramSource code={code} />;\n }\n\n return <DiagramSkeleton />;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MermaidDiagram-E3azndPk.js","names":[],"sources":["../src/blocks/MermaidDiagram/peleTheme.ts","../src/blocks/MermaidDiagram/MermaidDiagram.tsx"],"sourcesContent":["import type { ResolvedColorScheme } from '../../components/ThemeProvider/types';\nimport { createVegaColorResolver, SERIES_TOKENS, tierTwoColour } from '../../vega/vegaTokens';\n\nexport const DIAGRAM_FONT = 'Inter, system-ui, sans-serif';\n\n/**\n * The `--pele-*` declarations for one scheme, as a `style` attribute fragment.\n *\n * - Resolved colours, not `var()` refs: an exported SVG or PNG has no page CSS to read.\n * - One `getComputedStyle` snapshot per call; never hoist — values follow scheme and brand.\n * - Series 6–8 are the charts' second tier, as in Flint charts.\n */\nexport const peleThemeStyle = (scheme: ResolvedColorScheme, from?: Element | null): string => {\n const token = createVegaColorResolver(scheme, from);\n const series = SERIES_TOKENS.map((name) => token(name));\n\n const vars: Record<string, string> = {\n bg: token('card'),\n fg: token('foreground'),\n muted: token('muted-foreground'),\n line: token('muted-foreground'),\n surface: token('muted'),\n 'surface-alt': token('accent'),\n border: token('border'),\n accent: token('primary'),\n critical: token('destructive'),\n error: token('destructive'),\n font: DIAGRAM_FONT,\n radius: '6px',\n };\n [...series, ...series.map((colour) => tierTwoColour(colour, scheme))]\n .slice(0, 8)\n .forEach((colour, index) => {\n vars[`series-${index + 1}`] = colour;\n });\n\n return Object.entries(vars)\n .map(([name, value]) => `--pele-${name}:${value}`)\n .join(';');\n};\n","import { useEffect, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport type { DiagramType, IconResolver } from 'pele/lazy';\nimport { detectType, load, PeleError, registered, render } from 'pele/lazy';\n\nimport type { ResolvedColorScheme } from '../../components/ThemeProvider/types';\nimport { useThemeAttributes } from '../../components/ThemeProvider/useThemeAttributes';\nimport { ZoomableSvg } from '../../components/ZoomableSvg';\nimport { DiagramSkeleton } from '../DiagramShared/DiagramSkeleton';\nimport { DiagramSource } from '../DiagramShared/DiagramSource';\nimport { createSvgCache, diagramCacheKey } from '../DiagramShared/svgCache';\nimport { makeResponsive } from '../DiagramShared/svgTransforms';\n\nimport { DIAGRAM_FONT, peleThemeStyle } from './peleTheme';\n\ntype IconPack = {\n icons: Record<string, { body: string }>;\n aliases?: Record<string, { parent: string }>;\n};\n\nlet lucidePack: IconPack | null = null;\nlet lucidePromise: Promise<void> | null = null;\n\n// The pack is a lazy local chunk, so no CDN fetch and it works under strict CSP.\nconst loadLucidePack = (): Promise<void> => {\n lucidePromise ??= import('@iconify-json/lucide/icons.json')\n .then((mod) => {\n lucidePack = mod.default;\n })\n .catch((err: unknown) => {\n lucidePromise = null;\n throw err;\n });\n return lucidePromise;\n};\n\n// `lucide:name` refs resolve to the pack's 24×24 stroke body, which is the frame Pele draws.\nconst lucideIcon: IconResolver = (ref) => {\n if (!lucidePack || !ref.startsWith('lucide:')) return null;\n const name = ref.slice('lucide:'.length);\n return (lucidePack.icons[name] ?? lucidePack.icons[lucidePack.aliases?.[name]?.parent ?? ''])\n ?.body;\n};\n\nconst usesLucide = (code: string): boolean => code.includes('lucide:');\n\nconst diagramType = (code: string): DiagramType | null => {\n try {\n return detectType(code);\n } catch (err) {\n console.debug('[MermaidDiagram] no diagram type detected:', err);\n return null;\n }\n};\n\n/**\n * Whether a render error means \"ran out of input\" rather than \"bad syntax\".\n *\n * - A syntax error at the last non-blank character or past it, as in every streaming frame.\n * - No type yet and at most one line after the preamble: the header itself is still arriving.\n * - Lower bound only: a real error on the last character shows as truncated until the grace period.\n */\n// Closed front matter and `%%` directive or comment lines before the type header.\nconst PREAMBLE = /^(?:\\s*---\\n[\\s\\S]*?\\n---[^\\S\\n]*(?:\\n|$)|[^\\S\\n]*%%.*(?:\\n|$)|\\s*\\n)*/;\n\nconst isHeaderArriving = (code: string): boolean => {\n const rest = code.replace(PREAMBLE, '');\n // Front matter whose closing `---` has not arrived yet.\n if (/^\\s*---\\n/.test(rest)) return true;\n return !rest.trim().includes('\\n');\n};\n\nconst isTruncatedDiagram = (err: unknown, code: string): boolean => {\n if (!(err instanceof PeleError)) return false;\n if (err.code === 'unsupported-diagram') return isHeaderArriving(code);\n if (err.code !== 'syntax') return false;\n const tail = code\n .split('\\n')\n .slice(err.line - 1)\n .join('\\n');\n return tail.slice(Math.max(err.column - 1, 0)).trim().length <= 1;\n};\n\n// Longer than the gap between streamed chunks, short enough for an abandoned stream.\nconst TRUNCATION_GRACE_MS = 2_000;\n\nconst svgCache = createSvgCache();\n\n// Every streamed frame shares one theme, so its palette is read once per theme key.\nlet lastTheme = { key: '', style: '' };\nconst themeStyleFor = (themeKey: string, scheme: ResolvedColorScheme, scope: Element | null) => {\n if (lastTheme.key !== themeKey) {\n lastTheme = { key: themeKey, style: peleThemeStyle(scheme, scope) };\n }\n return lastTheme.style;\n};\n\ntype Outcome =\n | { svg: string }\n | { error: unknown; truncated: boolean }\n | { loading: DiagramType | null };\n\ntype Theme = { key: string; scheme: ResolvedColorScheme; scope: Element | null };\n\n/**\n * The diagram for `code`, rendered synchronously.\n *\n * 1. A cached SVG for this code and theme.\n * 2. `loading` while the diagram type's chunk or the icon pack is not loaded yet.\n * 3. A fresh render, or the error Pele threw.\n */\nconst renderNow = (code: string, theme: Theme): Outcome => {\n const cacheKey = diagramCacheKey(code, theme.key);\n const cached = svgCache.get(cacheKey);\n if (cached) return { svg: cached };\n const type = diagramType(code);\n if ((type !== null && !registered(type)) || (usesLucide(code) && lucidePack === null)) {\n return { loading: type };\n }\n try {\n const { svg } = render(code, { fontFamily: DIAGRAM_FONT, icons: lucideIcon });\n const themed = makeResponsive(svg, themeStyleFor(theme.key, theme.scheme, theme.scope));\n svgCache.set(cacheKey, themed);\n return { svg: themed };\n } catch (error) {\n return { error, truncated: isTruncatedDiagram(error, code) };\n }\n};\n\ntype Props = {\n /** Mermaid source. */\n code: string;\n /** Extra toolbar controls forwarded to `ZoomableSvg`; receives the sanitized SVG. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const MermaidDiagram = ({ code, renderActions }: Props) => {\n // - Scheme and key come from one read, so a palette is never cached under the wrong scheme.\n // - `scope` is the element tokens are read off (`null` = `<html>`) and is part of `themeKey`.\n const { scheme, cacheKey: themeKey, scope } = useThemeAttributes();\n const cacheKey = diagramCacheKey(code, themeKey);\n\n const [state, setState] = useState(() => ({\n key: cacheKey,\n outcome: renderNow(code, { key: themeKey, scheme, scope }),\n }));\n const [gaveUpKey, setGaveUpKey] = useState<string | null>(null);\n\n // Render-phase reset avoids a one-frame flash of the previous diagram.\n if (state.key !== cacheKey) {\n setState({ key: cacheKey, outcome: renderNow(code, { key: themeKey, scheme, scope }) });\n }\n const { outcome } = state;\n\n useEffect(() => {\n if (!('loading' in outcome)) return;\n let cancelled = false;\n Promise.all([load(outcome.loading), usesLucide(code) ? loadLucidePack() : null])\n .then(() => renderNow(code, { key: themeKey, scheme, scope }))\n .catch((error: unknown) => ({ error, truncated: false }))\n .then((next) => {\n if (!cancelled) setState({ key: cacheKey, outcome: next });\n });\n return () => {\n cancelled = true;\n };\n }, [outcome, code, cacheKey, themeKey, scheme, scope]);\n\n useEffect(() => {\n if (!('error' in outcome)) return;\n if (!outcome.truncated) {\n console.error('[MermaidDiagram] render failed:', outcome.error);\n return;\n }\n // A streaming diagram is truncated at almost every frame; one that stops arriving shows its source.\n const timer = setTimeout(() => setGaveUpKey(cacheKey), TRUNCATION_GRACE_MS);\n return () => clearTimeout(timer);\n }, [outcome, cacheKey]);\n\n if ('svg' in outcome) {\n return (\n <ZoomableSvg\n key={code}\n html={outcome.svg}\n copyText={`\\`\\`\\`mermaid\\n${code}\\n\\`\\`\\``}\n className=\"tw:my-3\"\n renderActions={renderActions}\n />\n );\n }\n\n if ('error' in outcome && (!outcome.truncated || gaveUpKey === cacheKey)) {\n return <DiagramSource code={code} />;\n }\n\n return <DiagramSkeleton />;\n};\n"],"mappings":"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"}
|