@keboola/design 11.9.0 → 12.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 +34 -8
- package/CHANGELOG.md +155 -0
- package/COMPONENT-API.md +337 -289
- package/README.md +11 -1
- package/dist/{AIKit-ELIsegJz.js → AIKit-BD4r7ff-.js} +404 -243
- package/dist/AIKit-BD4r7ff-.js.map +1 -0
- package/dist/{Alert-BsIM_oFK.js → Alert-UI-CIs-1.js} +16 -16
- package/dist/Alert-UI-CIs-1.js.map +1 -0
- package/dist/{AlertModal-BGJdaRRj.js → AlertModal-Th2khjPi.js} +5 -5
- package/dist/AlertModal-Th2khjPi.js.map +1 -0
- package/dist/{AppShell-DRgJxpXW.js → AppShell-WSQabK8r.js} +15 -52
- package/dist/AppShell-WSQabK8r.js.map +1 -0
- package/dist/{AutoSaveTextarea-BeuWuszr.js → AutoSaveTextarea-C5iIr2Ts.js} +2 -2
- package/dist/{AutoSaveTextarea-BeuWuszr.js.map → AutoSaveTextarea-C5iIr2Ts.js.map} +1 -1
- package/dist/{Badge-o5jURtpB.js → Badge-DIjhwPvh.js} +4 -9
- package/dist/Badge-DIjhwPvh.js.map +1 -0
- package/dist/{BrandEditor-BsTBM3s6.js → BrandEditor-BU23Vl8V.js} +7 -7
- package/dist/{BrandEditor-BsTBM3s6.js.map → BrandEditor-BU23Vl8V.js.map} +1 -1
- package/dist/{BrandLogo-CoKBk4MI.js → BrandLogo-CKpVSZb6.js} +4 -4
- package/dist/BrandLogo-CKpVSZb6.js.map +1 -0
- package/dist/{Breadcrumb-xqEUxfwn.js → Breadcrumb-p9HtMLCc.js} +8 -14
- package/dist/Breadcrumb-p9HtMLCc.js.map +1 -0
- package/dist/{Button-DsRrU5F1.js → Button-Ca4Q3VJU.js} +31 -13
- package/dist/Button-Ca4Q3VJU.js.map +1 -0
- package/dist/{Calendar-cG5NIJ4O.js → Calendar-DFtmZzbF.js} +99 -99
- package/dist/Calendar-DFtmZzbF.js.map +1 -0
- package/dist/{Card-Dyo7055Q.js → Card-Cr9MBNHu.js} +4 -4
- package/dist/Card-Cr9MBNHu.js.map +1 -0
- package/dist/{Checkbox-Dq5fPNrO.js → Checkbox-8yIIgY7g.js} +4 -4
- package/dist/Checkbox-8yIIgY7g.js.map +1 -0
- package/dist/{Clipboard-BZitKiSA.js → Clipboard-_xf6hMDD.js} +2 -2
- package/dist/{Clipboard-BZitKiSA.js.map → Clipboard-_xf6hMDD.js.map} +1 -1
- package/dist/{ClipboardButton-KHQnPEh_.js → ClipboardButton-DHa1trtI.js} +4 -4
- package/dist/{ClipboardButton-KHQnPEh_.js.map → ClipboardButton-DHa1trtI.js.map} +1 -1
- package/dist/{CodeEditor-BJKJXA0c.js → CodeEditor-BSo-oLFG.js} +55 -165
- package/dist/CodeEditor-BSo-oLFG.js.map +1 -0
- package/dist/{ColorInput-Bj3dfPFA.js → ColorInput-DSMqrs2-.js} +12 -27
- package/dist/ColorInput-DSMqrs2-.js.map +1 -0
- package/dist/{ColorModeSwitch-CWt-DZGC.js → ColorModeSwitch-D7EuWyJz.js} +7 -17
- package/dist/ColorModeSwitch-D7EuWyJz.js.map +1 -0
- package/dist/Combobox-CxRAYOBt.js +1069 -0
- package/dist/Combobox-CxRAYOBt.js.map +1 -0
- package/dist/{Command-BDU3C1gg.js → Command-BU_cVurn.js} +4 -4
- package/dist/{Command-BDU3C1gg.js.map → Command-BU_cVurn.js.map} +1 -1
- package/dist/{CopyField-BHRQUyuF.js → CopyField-6_c-NdLO.js} +17 -53
- package/dist/{CopyField-BHRQUyuF.js.map → CopyField-6_c-NdLO.js.map} +1 -1
- package/dist/{DateInput-B6N8g0ra.js → DateInput-DyEErfJf.js} +6 -6
- package/dist/{DateInput-B6N8g0ra.js.map → DateInput-DyEErfJf.js.map} +1 -1
- package/dist/{DatePicker-nA8YdE84.js → DatePicker-CtSa9b3V.js} +3 -3
- package/dist/{DatePicker-nA8YdE84.js.map → DatePicker-CtSa9b3V.js.map} +1 -1
- package/dist/{DateRangeInput-7M9Z4cVO.js → DateRangeInput-Dg7-VUd9.js} +10 -14
- package/dist/DateRangeInput-Dg7-VUd9.js.map +1 -0
- package/dist/{DateRangePicker-DjSUFjh4.js → DateRangePicker-BoPnh4aH.js} +9 -13
- package/dist/DateRangePicker-BoPnh4aH.js.map +1 -0
- package/dist/DiffView-ppTIzh2h.js.map +1 -1
- package/dist/{DropdownMenu-CgVwhDvl.js → DropdownMenu-gRM-A8qU.js} +3 -3
- package/dist/DropdownMenu-gRM-A8qU.js.map +1 -0
- package/dist/{FieldItem-DZGIdiXE.js → FieldItem-2wMXQ0Qw.js} +12 -25
- package/dist/FieldItem-2wMXQ0Qw.js.map +1 -0
- package/dist/{FieldItem-vhIJW4pj.d.ts → FieldItem-CPN1xjN5.d.ts} +11 -25
- package/dist/{FileUpload-DYQCTGjU.js → FileUpload-C83tXuE2.js} +11 -16
- package/dist/{FileUpload-DYQCTGjU.js.map → FileUpload-C83tXuE2.js.map} +1 -1
- package/dist/{Form-CcK7dRrC.js → Form-95rVLfX8.js} +15 -23
- package/dist/{Form-CcK7dRrC.js.map → Form-95rVLfX8.js.map} +1 -1
- package/dist/{FormGroup-DR_gZ25-.js → FormGroup-CmNiAtU6.js} +11 -17
- package/dist/FormGroup-CmNiAtU6.js.map +1 -0
- package/dist/{FullScreenModal-CN9nAs72.js → FullScreenModal-CD7mYeTz.js} +15 -29
- package/dist/FullScreenModal-CD7mYeTz.js.map +1 -0
- package/dist/{HoverCard-B9ZMJxjn.js → HoverCard-B8OKu9XZ.js} +2 -2
- package/dist/{HoverCard-B9ZMJxjn.js.map → HoverCard-B8OKu9XZ.js.map} +1 -1
- package/dist/{InputGroup-Do8K2hvD.js → InputGroup-B4QOPxHl.js} +11 -13
- package/dist/InputGroup-B4QOPxHl.js.map +1 -0
- package/dist/{Kbd-LCFMumoq.js → Kbd-J4n1J6i4.js} +23 -13
- package/dist/Kbd-J4n1J6i4.js.map +1 -0
- package/dist/{MarkedText-DNGEUVWc.js → MarkedText-DlmlJO0u.js} +2 -2
- package/dist/{MarkedText-DNGEUVWc.js.map → MarkedText-DlmlJO0u.js.map} +1 -1
- package/dist/{MermaidDiagram-ZG0iiDV_.js → MermaidDiagram-BQvz6bhv.js} +16 -34
- package/dist/MermaidDiagram-BQvz6bhv.js.map +1 -0
- package/dist/{Modal-I3VWk2oo.js → Modal-Driyqs_N.js} +17 -34
- package/dist/Modal-Driyqs_N.js.map +1 -0
- package/dist/{ModalTitle-CeLM_mX9.js → ModalTitle-BxopkIoQ.js} +3 -3
- package/dist/ModalTitle-BxopkIoQ.js.map +1 -0
- package/dist/{MultiActionButtonGroup-CYZ8IgSf.js → MultiActionButtonGroup-BPnmzBtw.js} +3 -3
- package/dist/{MultiActionButtonGroup-CYZ8IgSf.js.map → MultiActionButtonGroup-BPnmzBtw.js.map} +1 -1
- package/dist/{Navbar-Liy1TPI7.js → Navbar-B_DNpv5s.js} +9 -13
- package/dist/{Navbar-Liy1TPI7.js.map → Navbar-B_DNpv5s.js.map} +1 -1
- package/dist/{OtpInput-CbbymqYs.js → OtpInput-I8B8Vjdl.js} +2 -2
- package/dist/{OtpInput-CbbymqYs.js.map → OtpInput-I8B8Vjdl.js.map} +1 -1
- package/dist/{PageHeader-Q3IpCnQd.js → PageHeader-CgfyXpf1.js} +13 -26
- package/dist/PageHeader-CgfyXpf1.js.map +1 -0
- package/dist/{PageLayout-DSVM-ASz.js → PageLayout-DiAAILuS.js} +12 -20
- package/dist/PageLayout-DiAAILuS.js.map +1 -0
- package/dist/{PageToolbar-BKVJiDAL.js → PageToolbar-DOAtAnfL.js} +12 -42
- package/dist/PageToolbar-DOAtAnfL.js.map +1 -0
- package/dist/{Pagination-C_b7Xhey.js → Pagination-LaSg-5cl.js} +3 -3
- package/dist/{Pagination-C_b7Xhey.js.map → Pagination-LaSg-5cl.js.map} +1 -1
- package/dist/{Popconfirm-5pBzT_HQ.js → Popconfirm-SLz0zodk.js} +3 -3
- package/dist/{Popconfirm-5pBzT_HQ.js.map → Popconfirm-SLz0zodk.js.map} +1 -1
- package/dist/{Popover-BEbQrC_P.js → Popover-CEk915I1.js} +4 -3
- package/dist/Popover-CEk915I1.js.map +1 -0
- package/dist/{RadioGroup-Byc2mym4.js → RadioGroup-CBPRLRN0.js} +4 -4
- package/dist/{RadioGroup-Byc2mym4.js.map → RadioGroup-CBPRLRN0.js.map} +1 -1
- package/dist/{Search-Dhig_hPD.js → Search-DmkQo716.js} +3 -3
- package/dist/{Search-Dhig_hPD.js.map → Search-DmkQo716.js.map} +1 -1
- package/dist/{SearchInput-92r2bkA7.js → SearchInput-CEfQDNl3.js} +8 -13
- package/dist/SearchInput-CEfQDNl3.js.map +1 -0
- package/dist/{SectionNav-CNLJsiVG.js → SectionNav-B_qf0AXi.js} +10 -42
- package/dist/SectionNav-B_qf0AXi.js.map +1 -0
- package/dist/{Select-DV3Hak_l.js → Select-ByRvkZ3D.js} +8 -11
- package/dist/{Select-DV3Hak_l.js.map → Select-ByRvkZ3D.js.map} +1 -1
- package/dist/{Sheet-OparjIi-.js → Sheet-C-yXk5Da.js} +5 -9
- package/dist/Sheet-C-yXk5Da.js.map +1 -0
- package/dist/{Sidebar-CLEbBtNY.js → Sidebar-Ds0E6PbR.js} +16 -33
- package/dist/Sidebar-Ds0E6PbR.js.map +1 -0
- package/dist/{Slider-DLclvRws.js → Slider-DWdu9NuM.js} +3 -3
- package/dist/{Slider-DLclvRws.js.map → Slider-DWdu9NuM.js.map} +1 -1
- package/dist/{Stepper-C8sm9ZFM.js → Stepper-BLkLhfnd.js} +6 -9
- package/dist/{Stepper-C8sm9ZFM.js.map → Stepper-BLkLhfnd.js.map} +1 -1
- package/dist/{Switch-B0WdGSjz.js → Switch-DZvNePOm.js} +2 -2
- package/dist/{Switch-B0WdGSjz.js.map → Switch-DZvNePOm.js.map} +1 -1
- package/dist/{Table-CvYuTuNU.js → Table-BaVT5Tkn.js} +6 -11
- package/dist/{Table-CvYuTuNU.js.map → Table-BaVT5Tkn.js.map} +1 -1
- package/dist/{Tabs-eB974xJf.js → Tabs-Dt9oLYHC.js} +3 -3
- package/dist/{Tabs-eB974xJf.js.map → Tabs-Dt9oLYHC.js.map} +1 -1
- package/dist/{TextInput-CFTf4Cz1.js → TextInput-CDG2XpBl.js} +10 -14
- package/dist/TextInput-CDG2XpBl.js.map +1 -0
- package/dist/{ThemeProvider-DAmNn9Sd.js → ThemeProvider-DXsxFg1U.js} +13 -31
- package/dist/ThemeProvider-DXsxFg1U.js.map +1 -0
- package/dist/{TimePicker-BGeqc-Ed.js → TimePicker-CDGYrRxi.js} +2 -2
- package/dist/{TimePicker-BGeqc-Ed.js.map → TimePicker-CDGYrRxi.js.map} +1 -1
- package/dist/{Timeline-C8-wnRRr.js → Timeline-B-I6sb0M.js} +2 -2
- package/dist/{Timeline-C8-wnRRr.js.map → Timeline-B-I6sb0M.js.map} +1 -1
- package/dist/{Toast-Dr6Uw7ao.js → Toast-PfQf3vj-.js} +2 -2
- package/dist/{Toast-Dr6Uw7ao.js.map → Toast-PfQf3vj-.js.map} +1 -1
- package/dist/{Workbench-UR2FBC7I.js → Workbench-DmZzpkj7.js} +2 -2
- package/dist/{Workbench-UR2FBC7I.js.map → Workbench-DmZzpkj7.js.map} +1 -1
- package/dist/{ZoomableSvg-BZlk3PFJ.js → ZoomableSvg-BzXVfgnI.js} +5 -19
- package/dist/ZoomableSvg-BzXVfgnI.js.map +1 -0
- package/dist/charts.d.ts +21 -52
- package/dist/charts.js +13 -39
- package/dist/charts.js.map +1 -1
- package/dist/{context-D7X470dy.js → context-U293r3v-.js} +5 -9
- package/dist/context-U293r3v-.js.map +1 -0
- package/dist/editors.d.ts +27 -124
- package/dist/editors.js +29 -71
- package/dist/editors.js.map +1 -1
- package/dist/{findLiteralMatches-BGBw8Vbl.js → findLiteralMatches-DgGLzyG0.js} +8 -20
- package/dist/findLiteralMatches-DgGLzyG0.js.map +1 -0
- package/dist/flint.d.ts +3 -6
- package/dist/flint.js +31 -80
- package/dist/flint.js.map +1 -1
- package/dist/{icons-Cek151jC.js → icons-wcA70iQx.js} +105 -2
- package/dist/icons-wcA70iQx.js.map +1 -0
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +2 -2
- package/dist/{index-m-kQEWiY.d.ts → index-B7k-09i1.d.ts} +14 -2
- package/dist/index.d.ts +1151 -1838
- package/dist/index.js +68 -67
- package/dist/internal/blocks/AIKit.js +2 -2
- package/dist/internal/blocks/AppShell.js +1 -1
- package/dist/internal/blocks/AuthLayout.js +7 -27
- package/dist/internal/blocks/AuthLayout.js.map +1 -1
- package/dist/internal/blocks/AutoSaveTextarea.js +1 -1
- package/dist/internal/blocks/BrandEditor.js +1 -1
- package/dist/internal/blocks/ChartPanel.js +4 -8
- package/dist/internal/blocks/ChartPanel.js.map +1 -1
- package/dist/internal/blocks/ChipEditor.js +13 -21
- package/dist/internal/blocks/ChipEditor.js.map +1 -1
- package/dist/internal/blocks/ClipboardButton.js +1 -1
- package/dist/internal/blocks/ColorInput.js +1 -1
- package/dist/internal/blocks/ColorModeSwitch.js +1 -1
- package/dist/internal/blocks/Command.js +1 -1
- package/dist/internal/blocks/CopyField.js +1 -1
- package/dist/internal/blocks/DashboardHero.js +4 -7
- package/dist/internal/blocks/DashboardHero.js.map +1 -1
- package/dist/internal/blocks/DateInput.js +1 -1
- package/dist/internal/blocks/DateRangeInput.js +1 -1
- package/dist/internal/blocks/EmptyConfigurationActionCard.js +1 -1
- package/dist/internal/blocks/EmptyState.js +5 -9
- package/dist/internal/blocks/EmptyState.js.map +1 -1
- package/dist/internal/blocks/ErrorState.js +5 -9
- package/dist/internal/blocks/ErrorState.js.map +1 -1
- package/dist/internal/blocks/ExportMenu.js +6 -10
- package/dist/internal/blocks/ExportMenu.js.map +1 -1
- package/dist/internal/blocks/Form/connectors/ComboboxField.js +40 -0
- package/dist/internal/blocks/Form/connectors/ComboboxField.js.map +1 -0
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +5 -22
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js.map +1 -1
- package/dist/internal/blocks/Form.js +1 -1
- package/dist/internal/blocks/FormGroup.js +1 -1
- package/dist/internal/blocks/GoogleButton.js +1 -1
- package/dist/internal/blocks/MicrosoftButton.js +1 -1
- package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
- package/dist/internal/blocks/MultiCombobox.js +161 -154
- package/dist/internal/blocks/MultiCombobox.js.map +1 -1
- package/dist/internal/blocks/NumberInput.js +1 -1
- package/dist/internal/blocks/OtpInput.js +1 -1
- package/dist/internal/blocks/PageHeader.js +1 -1
- package/dist/internal/blocks/PageLayout.js +1 -1
- package/dist/internal/blocks/PageToolbar.js +1 -1
- package/dist/internal/blocks/PasswordInput.js +4 -4
- package/dist/internal/blocks/PasswordInput.js.map +1 -1
- package/dist/internal/blocks/SearchInput.js +1 -1
- package/dist/internal/blocks/SearchInputWithNavigation.js +4 -4
- package/dist/internal/blocks/SectionNav.js +1 -1
- package/dist/internal/blocks/SplitButton.js +3 -3
- package/dist/internal/blocks/StatCard.js +4 -8
- package/dist/internal/blocks/StatCard.js.map +1 -1
- package/dist/internal/blocks/TextInput.js +1 -1
- package/dist/internal/blocks/Textarea.js +2 -2
- package/dist/internal/blocks/TimeInput.js +5 -5
- package/dist/internal/blocks/TimeInput.js.map +1 -1
- package/dist/internal/components/Alert.js +1 -1
- package/dist/internal/components/AlertModal.js +1 -1
- package/dist/internal/components/Avatar.js +1 -1
- package/dist/internal/components/Badge.js +1 -1
- package/dist/internal/components/BrandLogo.js +1 -1
- package/dist/internal/components/Breadcrumb.js +1 -1
- package/dist/internal/components/Button.js +1 -1
- package/dist/internal/components/ButtonGroup.js.map +1 -1
- package/dist/internal/components/Calendar.js +1 -1
- package/dist/internal/components/Card.js +1 -1
- package/dist/internal/components/Checkbox.js +1 -1
- package/dist/internal/components/Clipboard.js +1 -1
- package/dist/internal/components/CollapsiblePanel.js +2 -2
- package/dist/internal/components/Combobox.js +2 -2
- package/dist/internal/components/DatePicker.js +1 -1
- package/dist/internal/components/DateRangePicker.js +1 -1
- package/dist/internal/components/DropdownMenu.js +1 -1
- package/dist/internal/components/FileUpload.js +1 -1
- package/dist/internal/components/FullScreenModal.js +1 -1
- package/dist/internal/components/HoverCard.js +1 -1
- package/dist/internal/components/InputGroup.js +1 -1
- package/dist/internal/components/Kbd.js +1 -1
- package/dist/internal/components/MarkedText.js +1 -1
- package/dist/internal/components/MergeEditor/ConflictStatus/ConflictStatusIndicator.js +1 -1
- package/dist/internal/components/Modal.js +1 -1
- package/dist/internal/components/Navbar.js +1 -1
- package/dist/internal/components/Pagination.js +1 -1
- package/dist/internal/components/PanelWithDetails.js +1 -1
- package/dist/internal/components/Popconfirm.js +1 -1
- package/dist/internal/components/Popover.js +1 -1
- package/dist/internal/components/RadioGroup.js +1 -1
- package/dist/internal/components/Search.js +1 -1
- package/dist/internal/components/Select.js +1 -1
- package/dist/internal/components/Separator.js.map +1 -1
- package/dist/internal/components/Sheet.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Skeleton/Skeleton.js +5 -9
- package/dist/internal/components/Skeleton/Skeleton.js.map +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/SpotlightBackdrop.js +3 -8
- package/dist/internal/components/SpotlightBackdrop.js.map +1 -1
- package/dist/internal/components/StatusDot.js +8 -15
- package/dist/internal/components/StatusDot.js.map +1 -1
- package/dist/internal/components/Stepper.js +1 -1
- package/dist/internal/components/Switch.js +1 -1
- package/dist/internal/components/Table.js +1 -1
- package/dist/internal/components/Tabs.js +1 -1
- package/dist/internal/components/ThemeProvider.js +3 -3
- package/dist/internal/components/TimePicker.js +1 -1
- package/dist/internal/components/Timeline.js +1 -1
- package/dist/internal/components/Toast.js +2 -2
- package/dist/internal/components/Tooltip.js +1 -1
- package/dist/internal/components/Truncated.js +4 -8
- package/dist/internal/components/Truncated.js.map +1 -1
- package/dist/internal/components/Workbench.js +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/hooks/useScrollbarPosition.js +1 -1
- package/dist/internal/hooks/useStableCallback.js +4 -13
- package/dist/internal/hooks/useStableCallback.js.map +1 -1
- package/dist/internal/utils.js +2 -2
- package/dist/markdown-editor.d.ts +15 -37
- package/dist/markdown-editor.js +17 -23
- package/dist/markdown-editor.js.map +1 -1
- package/dist/mermaid.d.ts +4 -6
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.d.ts +9 -19
- package/dist/rjsf.js +44 -84
- package/dist/rjsf.js.map +1 -1
- package/dist/{styles-BAFscjSV.js → styles-gzcjOyKv.js} +6 -6
- package/dist/styles-gzcjOyKv.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/svgTransforms-Dw2hRA-i.js +51 -0
- package/dist/svgTransforms-Dw2hRA-i.js.map +1 -0
- package/dist/testing.d.ts +3 -10
- package/dist/testing.js +5 -12
- package/dist/testing.js.map +1 -1
- package/dist/themeTokens-7DEab0kp.js +31 -0
- package/dist/themeTokens-7DEab0kp.js.map +1 -0
- package/dist/{toast-DIC0iNRf.js → toast-CyXEdaCZ.js} +3 -3
- package/dist/toast-CyXEdaCZ.js.map +1 -0
- package/dist/{themeScopeContext-D7fSyb06.js → useColorSchemeState-Cw4MCXUs.js} +14 -14
- package/dist/useColorSchemeState-Cw4MCXUs.js.map +1 -0
- package/dist/{useControllableState-M6494mCT.js → useControllableState-CUYXMsfz.js} +3 -7
- package/dist/useControllableState-CUYXMsfz.js.map +1 -0
- package/dist/useElement-D-RjrGa4.js +21 -0
- package/dist/useElement-D-RjrGa4.js.map +1 -0
- package/dist/useThemeAttributes-B199Regy.js +67 -0
- package/dist/useThemeAttributes-B199Regy.js.map +1 -0
- package/dist/{utils-BW4AE8VP.js → utils-Bd28bWgm.js} +31 -26
- package/dist/utils-Bd28bWgm.js.map +1 -0
- package/dist/vega.d.ts +8 -30
- package/dist/vega.js +5 -13
- package/dist/vega.js.map +1 -1
- package/dist/{vegaTheme-CSvFEMBl.js → vegaTheme-VQMWTlBw.js} +7 -21
- package/dist/vegaTheme-VQMWTlBw.js.map +1 -0
- package/package.json +10 -9
- package/src/styles.css +120 -14
- package/src/theme.css +126 -6
- package/dist/AIKit-ELIsegJz.js.map +0 -1
- package/dist/Alert-BsIM_oFK.js.map +0 -1
- package/dist/AlertModal-BGJdaRRj.js.map +0 -1
- package/dist/AppShell-DRgJxpXW.js.map +0 -1
- package/dist/Badge-o5jURtpB.js.map +0 -1
- package/dist/BrandLogo-CoKBk4MI.js.map +0 -1
- package/dist/Breadcrumb-xqEUxfwn.js.map +0 -1
- package/dist/Button-DsRrU5F1.js.map +0 -1
- package/dist/Calendar-cG5NIJ4O.js.map +0 -1
- package/dist/Card-Dyo7055Q.js.map +0 -1
- package/dist/Checkbox-Dq5fPNrO.js.map +0 -1
- package/dist/CodeEditor-BJKJXA0c.js.map +0 -1
- package/dist/ColorInput-Bj3dfPFA.js.map +0 -1
- package/dist/ColorModeSwitch-CWt-DZGC.js.map +0 -1
- package/dist/Combobox-D8PrEqTG.js +0 -619
- package/dist/Combobox-D8PrEqTG.js.map +0 -1
- package/dist/DateRangeInput-7M9Z4cVO.js.map +0 -1
- package/dist/DateRangePicker-DjSUFjh4.js.map +0 -1
- package/dist/DropdownMenu-CgVwhDvl.js.map +0 -1
- package/dist/FieldItem-DZGIdiXE.js.map +0 -1
- package/dist/FormGroup-DR_gZ25-.js.map +0 -1
- package/dist/FullScreenModal-CN9nAs72.js.map +0 -1
- package/dist/InputGroup-Do8K2hvD.js.map +0 -1
- package/dist/Kbd-LCFMumoq.js.map +0 -1
- package/dist/MermaidDiagram-ZG0iiDV_.js.map +0 -1
- package/dist/Modal-I3VWk2oo.js.map +0 -1
- package/dist/ModalTitle-CeLM_mX9.js.map +0 -1
- package/dist/PageHeader-Q3IpCnQd.js.map +0 -1
- package/dist/PageLayout-DSVM-ASz.js.map +0 -1
- package/dist/PageToolbar-BKVJiDAL.js.map +0 -1
- package/dist/Popover-BEbQrC_P.js.map +0 -1
- package/dist/SearchInput-92r2bkA7.js.map +0 -1
- package/dist/SectionNav-CNLJsiVG.js.map +0 -1
- package/dist/Sheet-OparjIi-.js.map +0 -1
- package/dist/Sidebar-CLEbBtNY.js.map +0 -1
- package/dist/TextInput-CFTf4Cz1.js.map +0 -1
- package/dist/ThemeProvider-DAmNn9Sd.js.map +0 -1
- package/dist/ZoomableSvg-BZlk3PFJ.js.map +0 -1
- package/dist/context-D7X470dy.js.map +0 -1
- package/dist/findLiteralMatches-BGBw8Vbl.js.map +0 -1
- package/dist/icons-Cek151jC.js.map +0 -1
- package/dist/styles-BAFscjSV.js.map +0 -1
- package/dist/svgTransforms-CJAYPk7o.js +0 -81
- package/dist/svgTransforms-CJAYPk7o.js.map +0 -1
- package/dist/themeScopeContext-D7fSyb06.js.map +0 -1
- package/dist/themeTokens-qP1-55O7.js +0 -119
- package/dist/themeTokens-qP1-55O7.js.map +0 -1
- package/dist/toast-DIC0iNRf.js.map +0 -1
- package/dist/useControllableState-M6494mCT.js.map +0 -1
- package/dist/useElement-BK3AAiIf.js +0 -24
- package/dist/useElement-BK3AAiIf.js.map +0 -1
- package/dist/utils-BW4AE8VP.js.map +0 -1
- package/dist/vegaTheme-CSvFEMBl.js.map +0 -1
|
@@ -0,0 +1,1069 @@
|
|
|
1
|
+
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
+
import { noop } from "./utils-Bd28bWgm.js";
|
|
3
|
+
import { useArgoDesign } from "./context-U293r3v-.js";
|
|
4
|
+
import { Check, ChevronDown, ChevronRight, Loader2, Minus, Plus, X } from "./icons-wcA70iQx.js";
|
|
5
|
+
import { useStableCallback } from "./internal/hooks/useStableCallback.js";
|
|
6
|
+
import { InputGroup } from "./InputGroup-B4QOPxHl.js";
|
|
7
|
+
import { Badge } from "./Badge-DIjhwPvh.js";
|
|
8
|
+
import { useElement } from "./useElement-D-RjrGa4.js";
|
|
9
|
+
import { Fragment, createContext, isValidElement, use, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { Combobox } from "@base-ui/react/combobox";
|
|
12
|
+
import { DismissableLayer } from "@radix-ui/react-dismissable-layer";
|
|
13
|
+
import { measureElement, observeElementRect, useVirtualizer } from "@tanstack/react-virtual";
|
|
14
|
+
//#region src/components/Combobox/blankValues.ts
|
|
15
|
+
/**
|
|
16
|
+
* The two blank strings a Storage filter predicates on, in list order.
|
|
17
|
+
*
|
|
18
|
+
* - Hand it to `items` where the blanks are the whole list — a value field whose other entries the
|
|
19
|
+
* user types. {@link withBlankValues} is for offering them ahead of a list that already exists.
|
|
20
|
+
*/
|
|
21
|
+
const BLANK_VALUES = ["", " "];
|
|
22
|
+
const BLANK_LABELS = {
|
|
23
|
+
"": "[empty string]",
|
|
24
|
+
" ": "[space character]"
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* A string as a row or a chip shows it — named when its text is blank, itself otherwise.
|
|
28
|
+
*
|
|
29
|
+
* - Exported so an `itemToLabel` / `itemToChipLabel` / `itemToSelectedLabel` / `renderChips`
|
|
30
|
+
* override can keep the default naming instead of retyping the labels.
|
|
31
|
+
* - The two blank values get their own labels; any other whitespace-only string (a tab, a run of
|
|
32
|
+
* spaces) falls back to a generic one, so two different ones read alike.
|
|
33
|
+
* - Identity is unaffected — `toLabel` keys items off the raw string.
|
|
34
|
+
*/
|
|
35
|
+
const namedLabel = (text) => text.trim() === "" ? BLANK_LABELS[text] ?? "[whitespace]" : text;
|
|
36
|
+
/**
|
|
37
|
+
* `values` with both blank values offered ahead of them, and duplicates collapsed.
|
|
38
|
+
*
|
|
39
|
+
* - The dedupe matters where the list is the distinct values of a Storage column: it can already
|
|
40
|
+
* hold a blank, and two `Object.is`-equal rows both report `aria-selected` and toggle each other.
|
|
41
|
+
* - First occurrence wins, so the order of the values is otherwise preserved.
|
|
42
|
+
* - String items only — the seven Storage filters this serves are all string-valued.
|
|
43
|
+
*/
|
|
44
|
+
const withBlankValues = (values) => [.../* @__PURE__ */ new Set([...BLANK_VALUES, ...values])];
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/components/Combobox/ComboboxChip.tsx
|
|
47
|
+
/**
|
|
48
|
+
* Keeps a chip's keyboard handling off its content's.
|
|
49
|
+
*
|
|
50
|
+
* - Base UI's chip `preventDefault`s Enter/Space, cancelling a nested link or button.
|
|
51
|
+
* - Capture phase, so the chip's own bubble handler never runs.
|
|
52
|
+
* - Target-guarded, so the chip's own keys (Backspace, Delete, arrows) still reach it.
|
|
53
|
+
*/
|
|
54
|
+
const stopNestedKeyDown = (event) => {
|
|
55
|
+
if (event.target !== event.currentTarget) event.stopPropagation();
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* One removable chip in a `MultiCombobox`'s `renderChips` slot or `Combobox.Chips`.
|
|
59
|
+
*
|
|
60
|
+
* - Position is identity: Base UI removes by index, so render one per `value` entry, in order.
|
|
61
|
+
* - A non-removable chip is a plain `Badge`: a chip would shift the removal index.
|
|
62
|
+
*/
|
|
63
|
+
const ComboboxChip = ({ children, color, variant }) => {
|
|
64
|
+
const renderArgo = useArgoDesign();
|
|
65
|
+
return /* @__PURE__ */ jsxs(Combobox.Chip, {
|
|
66
|
+
render: /* @__PURE__ */ jsx(Badge.Root, {
|
|
67
|
+
color,
|
|
68
|
+
variant: variant ?? (renderArgo ? "pill" : "default"),
|
|
69
|
+
className: "tw:max-w-40"
|
|
70
|
+
}),
|
|
71
|
+
onKeyDownCapture: stopNestedKeyDown,
|
|
72
|
+
children: [/* @__PURE__ */ jsx(Badge.Label, { children }), /* @__PURE__ */ jsx(Badge.Addon, {
|
|
73
|
+
variant: "inline",
|
|
74
|
+
align: "inline-end",
|
|
75
|
+
children: /* @__PURE__ */ jsx(Combobox.ChipRemove, { render: /* @__PURE__ */ jsx(Badge.Button, {
|
|
76
|
+
"aria-label": "Remove value",
|
|
77
|
+
children: /* @__PURE__ */ jsx(X, { className: "tw:size-3" })
|
|
78
|
+
}) })
|
|
79
|
+
})]
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/components/Combobox/utils.ts
|
|
84
|
+
const isPlainObject = (item) => item !== null && typeof item === "object";
|
|
85
|
+
const isNumber = (item) => typeof item === "number";
|
|
86
|
+
const isString = (item) => typeof item === "string";
|
|
87
|
+
const isLabeledItem = (item) => isPlainObject(item) && Reflect.has(item, "label") && Reflect.has(item, "value");
|
|
88
|
+
const isInternalItem = (item) => isLabeledItem(item) && "__marker" in item;
|
|
89
|
+
const isSelectAllItem = (item) => isInternalItem(item) && item.__marker === "selectAll";
|
|
90
|
+
const isCreatableItem = (item) => {
|
|
91
|
+
return isInternalItem(item) && item.__marker === "creatable";
|
|
92
|
+
};
|
|
93
|
+
const isGroupHeaderItem = (item) => isInternalItem(item) && item.__marker === "groupHeader";
|
|
94
|
+
const isGroupItem = (itemOrGroup) => itemOrGroup !== null && typeof itemOrGroup === "object" && Reflect.has(itemOrGroup, "items");
|
|
95
|
+
const isGroupItems = (items) => {
|
|
96
|
+
if (!Array.isArray(items)) return false;
|
|
97
|
+
if (items.length === 0) return false;
|
|
98
|
+
return isGroupItem(items[0]);
|
|
99
|
+
};
|
|
100
|
+
/** The options of a list, its groups flattened. */
|
|
101
|
+
const flatItems = (list) => {
|
|
102
|
+
const items = [];
|
|
103
|
+
for (const entry of list) if (!isGroupItem(entry)) items.push(entry);
|
|
104
|
+
else for (const item of entry.items) items.push(item);
|
|
105
|
+
return items;
|
|
106
|
+
};
|
|
107
|
+
/** The create row and Select All: each is drawn outside any group, even in a grouped list. */
|
|
108
|
+
const isLooseItem = (item) => isCreatableItem(item) || isSelectAllItem(item);
|
|
109
|
+
/**
|
|
110
|
+
* `items` as entries of `list`: one group without a label in a grouped list, else themselves.
|
|
111
|
+
*
|
|
112
|
+
* - Base UI reads the first entry to tell a grouped list, so every entry has to match it.
|
|
113
|
+
* - The group never reaches `groupToLabel`: {@link isEntriesGroup} tells it apart.
|
|
114
|
+
*/
|
|
115
|
+
const toEntries = (list, items) => isGroupItems(list) ? [{
|
|
116
|
+
__marker: "entries",
|
|
117
|
+
items
|
|
118
|
+
}] : items;
|
|
119
|
+
/** A group {@link toEntries} made; Base UI's filter keeps the marker, as it spreads each group. */
|
|
120
|
+
const isEntriesGroup = (entry) => isGroupItem(entry) && Reflect.get(entry, "__marker") === "entries";
|
|
121
|
+
/**
|
|
122
|
+
* Node a list row and a chip show for an item.
|
|
123
|
+
*
|
|
124
|
+
* - Names a blank string, so a row or chip never renders as nothing; {@link toLabel} does not.
|
|
125
|
+
* - A non-string `label` (a JSX node) passes through.
|
|
126
|
+
*/
|
|
127
|
+
const defaultItemToLabel = (item) => {
|
|
128
|
+
if (isNumber(item)) return item;
|
|
129
|
+
if (isString(item)) return namedLabel(item);
|
|
130
|
+
if (!isLabeledItem(item)) throw new Error("Combobox: Item does not have a `label` field. Pass `itemToLabel` for custom item shapes.");
|
|
131
|
+
return isString(item.label) ? namedLabel(item.label) : item.label;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* The node a row or a chip shows for an item when the caller passes no `itemToLabel`.
|
|
135
|
+
*
|
|
136
|
+
* - Names a blank `itemToStringLabel` result, which would otherwise render as nothing.
|
|
137
|
+
* - Falls back to the item's own string: Base UI reports the outgoing selection for one render
|
|
138
|
+
* after `items` and `itemToStringLabel` change together.
|
|
139
|
+
*/
|
|
140
|
+
const defaultRowLabel = (itemToStringLabel) => itemToStringLabel ? (item) => namedLabel(itemToStringLabel(item) ?? toLabel(item)) : defaultItemToLabel;
|
|
141
|
+
/**
|
|
142
|
+
* Display string for an item — mirrors Base UI's default.
|
|
143
|
+
*
|
|
144
|
+
* - Also the default search text and the closed `Combobox`'s input value.
|
|
145
|
+
* - Does not name blank strings: `''` may mean "nothing selected", and must keep the placeholder.
|
|
146
|
+
* - A labelled item with neither a label nor a value reads as `''`, like the string item `''`.
|
|
147
|
+
* - Naming lives in {@link defaultItemToLabel}, read only by rows and chips.
|
|
148
|
+
*/
|
|
149
|
+
const toLabel = (item) => {
|
|
150
|
+
if (isString(item)) return item;
|
|
151
|
+
if (isLabeledItem(item)) return item.label || item.value || "";
|
|
152
|
+
return String(item);
|
|
153
|
+
};
|
|
154
|
+
/** Equality key for an item — prefers `.value`. */
|
|
155
|
+
const toValueKey = (item) => {
|
|
156
|
+
if (isString(item)) return item;
|
|
157
|
+
if (isLabeledItem(item)) return item.value || item.label || "";
|
|
158
|
+
return String(item);
|
|
159
|
+
};
|
|
160
|
+
const defaultItemToIcon = (item) => isLabeledItem(item) ? item.icon : void 0;
|
|
161
|
+
const defaultItemToDisabled = (item) => isLabeledItem(item) ? item.disabled ?? false : false;
|
|
162
|
+
/** A group's `label`, as `Select` renders it; one that is not a node reads as none. */
|
|
163
|
+
const defaultGroupToLabel = (group) => {
|
|
164
|
+
const label = Reflect.get(group, "label");
|
|
165
|
+
return isString(label) || isNumber(label) || isValidElement(label) ? label : void 0;
|
|
166
|
+
};
|
|
167
|
+
const selectAllItem = {
|
|
168
|
+
__marker: "selectAll",
|
|
169
|
+
value: "__select_all__",
|
|
170
|
+
label: "Select All"
|
|
171
|
+
};
|
|
172
|
+
/** Row for the group at `index` — keyed by position, like its collapse state. */
|
|
173
|
+
const createGroupHeaderItem = (index) => ({
|
|
174
|
+
__marker: "groupHeader",
|
|
175
|
+
value: `__group_${index}__`,
|
|
176
|
+
label: ""
|
|
177
|
+
});
|
|
178
|
+
const createCreatableItem = (query) => ({
|
|
179
|
+
__marker: "creatable",
|
|
180
|
+
value: query,
|
|
181
|
+
label: query
|
|
182
|
+
});
|
|
183
|
+
/**
|
|
184
|
+
* Item-equality predicate for a Base UI combobox root.
|
|
185
|
+
*
|
|
186
|
+
* - A sentinel equals a sentinel by marker and value key (the create row is rebuilt per keystroke).
|
|
187
|
+
* - A sentinel never equals a real item.
|
|
188
|
+
* - Real items use the caller's predicate, else `Object.is`.
|
|
189
|
+
*/
|
|
190
|
+
const toItemEquality = (isItemEqualToValue) => (a, b) => {
|
|
191
|
+
if (isInternalItem(a) || isInternalItem(b)) return isInternalItem(a) && isInternalItem(b) && a.__marker === b.__marker && toValueKey(a) === toValueKey(b);
|
|
192
|
+
return isItemEqualToValue?.(a, b) ?? Object.is(a, b);
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* {@link toItemEquality} with a stable identity.
|
|
196
|
+
*
|
|
197
|
+
* - Base UI lists the comparer in an effect's deps; a new one per render re-renders every row.
|
|
198
|
+
*/
|
|
199
|
+
const useItemEquality = (isItemEqualToValue) => useMemo(() => toItemEquality(isItemEqualToValue), [isItemEqualToValue]);
|
|
200
|
+
/** `itemToStringValue` that also reads the create row, whose value is its query. */
|
|
201
|
+
const withCreatableStringValue = (itemToStringValue, allowCreate) => !allowCreate || !itemToStringValue ? itemToStringValue : (item) => isCreatableItem(item) ? item.value : itemToStringValue(item);
|
|
202
|
+
/** {@link withCreatableStringValue} with a stable identity. */
|
|
203
|
+
const useCreatableStringValue = (itemToStringValue, allowCreate) => useMemo(() => withCreatableStringValue(itemToStringValue, allowCreate), [itemToStringValue, allowCreate]);
|
|
204
|
+
const defaultToCreateValue = (query, value, queryToCreateValue) => {
|
|
205
|
+
if (queryToCreateValue) return queryToCreateValue(query);
|
|
206
|
+
if (value === void 0) return query;
|
|
207
|
+
if (isString(value)) return query;
|
|
208
|
+
if (isLabeledItem(value)) return {
|
|
209
|
+
value: query,
|
|
210
|
+
label: query
|
|
211
|
+
};
|
|
212
|
+
throw new Error("Combobox: Cannot infer item shape for `allowCreate`. Pass `queryToCreateValue` for custom item shapes.");
|
|
213
|
+
};
|
|
214
|
+
const defaultQueryToCreateLabel = (query) => `Create "${query}"`;
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/components/Combobox/ComboboxChips.tsx
|
|
217
|
+
const ComboboxChips = ({ maxVisible = 3, itemToChipLabel = defaultItemToLabel, itemToChipColor, pinnedChipLabels, variant = "pill", children }) => /* @__PURE__ */ jsx(Combobox.Value, { children: (rawValues) => {
|
|
218
|
+
const values = rawValues.filter((value) => !isInternalItem(value));
|
|
219
|
+
if (children) return children(values);
|
|
220
|
+
const visible = values.slice(0, maxVisible);
|
|
221
|
+
const overflow = values.slice(maxVisible);
|
|
222
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
223
|
+
pinnedChipLabels?.map((label, index) => /* @__PURE__ */ jsx(Badge, {
|
|
224
|
+
className: "tw:max-w-40",
|
|
225
|
+
variant,
|
|
226
|
+
children: label
|
|
227
|
+
}, index)),
|
|
228
|
+
visible.map((value, index) => /* @__PURE__ */ jsx(ComboboxChip, {
|
|
229
|
+
color: itemToChipColor?.(value),
|
|
230
|
+
variant,
|
|
231
|
+
children: itemToChipLabel(value)
|
|
232
|
+
}, index)),
|
|
233
|
+
overflow.length > 0 && /* @__PURE__ */ jsx(Badge.Root, {
|
|
234
|
+
variant: "pill",
|
|
235
|
+
children: /* @__PURE__ */ jsxs(Badge.Label, { children: ["+", overflow.length] })
|
|
236
|
+
})
|
|
237
|
+
] });
|
|
238
|
+
} });
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/components/Combobox/ComboboxClearButton.tsx
|
|
241
|
+
/** The button that clears the selection. */
|
|
242
|
+
const ComboboxClearButton = ({ disabled }) => /* @__PURE__ */ jsx(InputGroup.Button, {
|
|
243
|
+
asChild: true,
|
|
244
|
+
"aria-label": "Clear",
|
|
245
|
+
disabled,
|
|
246
|
+
children: /* @__PURE__ */ jsx(Combobox.Clear, { children: /* @__PURE__ */ jsx(X, { className: "tw:size-4" }) })
|
|
247
|
+
});
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/components/Combobox/ComboboxContent.tsx
|
|
250
|
+
const ComboboxContent = ({ ref, align = "start", side = "bottom", sideOffset = 4, alignOffset, anchor, container, className, children, ...popupProps }) => {
|
|
251
|
+
const effectiveVariant = useArgoDesign() ? "argo" : "default";
|
|
252
|
+
return /* @__PURE__ */ jsx(Combobox.Portal, {
|
|
253
|
+
container,
|
|
254
|
+
children: /* @__PURE__ */ jsx(DismissableLayer, {
|
|
255
|
+
asChild: true,
|
|
256
|
+
children: /* @__PURE__ */ jsx(Combobox.Positioner, {
|
|
257
|
+
align,
|
|
258
|
+
side,
|
|
259
|
+
sideOffset,
|
|
260
|
+
alignOffset,
|
|
261
|
+
anchor,
|
|
262
|
+
className: "tw:isolate tw:z-[1055] tailwindcss-preflight",
|
|
263
|
+
children: /* @__PURE__ */ jsx(Combobox.Popup, {
|
|
264
|
+
ref,
|
|
265
|
+
"data-chips": !!anchor,
|
|
266
|
+
"data-variant": effectiveVariant,
|
|
267
|
+
className: cn("tw:!pointer-events-auto", "tw:group/combobox-content", "tw:relative", "tw:flex tw:flex-col tw:overflow-hidden", "tw:max-h-[var(--available-height)]", "tw:w-[var(--anchor-width)]", "tw:max-w-[var(--available-width)]", "tw:origin-[var(--transform-origin)]", "tw:data-[chips=true]:min-w-[var(--anchor-width)]", "tw:rounded-lg", "tw:data-[variant=default]:rounded", "tw:bg-popover", "tw:text-popover-foreground", "tw:shadow-md", "tw:ring-1", "tw:ring-foreground/10", "tw:duration-100", "data-open:animate-in", "data-open:fade-in-0", "data-open:zoom-in-95", "data-closed:animate-out", "data-closed:fade-out-0", "data-closed:zoom-out-95", "tw:data-[side=bottom]:slide-in-from-top-2", "tw:data-[side=top]:slide-in-from-bottom-2", "tw:data-[side=left]:slide-in-from-right-2", "tw:data-[side=right]:slide-in-from-left-2", "tw:data-[side=inline-start]:slide-in-from-right-2", "tw:data-[side=inline-end]:slide-in-from-left-2", className),
|
|
268
|
+
...popupProps,
|
|
269
|
+
children
|
|
270
|
+
})
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
});
|
|
274
|
+
};
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region src/components/Combobox/ComboboxEmpty.tsx
|
|
277
|
+
const ComboboxEmpty = ({ ref, className, ...props }) => /* @__PURE__ */ jsx(Combobox.Empty, {
|
|
278
|
+
ref,
|
|
279
|
+
className: cn("tw:hidden", "tw:group-data-[empty]/combobox-content:flex", "tw:justify-center", "tw:items-center", "tw:text-center", "tw:px-2", "tw:text-muted-foreground", "tw:py-6", className),
|
|
280
|
+
...props
|
|
281
|
+
});
|
|
282
|
+
//#endregion
|
|
283
|
+
//#region src/components/Combobox/ComboboxInput.tsx
|
|
284
|
+
const ComboboxInput = ({ ref, ...props }) => /* @__PURE__ */ jsx(Combobox.Input, {
|
|
285
|
+
...props,
|
|
286
|
+
ref,
|
|
287
|
+
render: /* @__PURE__ */ jsx(InputGroup.Input, {})
|
|
288
|
+
});
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/components/Combobox/ComboboxInputGroup.tsx
|
|
291
|
+
const ComboboxInputGroup = ({ ref, state, variant, sizing, focusVariant, className, ...props }) => /* @__PURE__ */ jsx(Combobox.InputGroup, {
|
|
292
|
+
...props,
|
|
293
|
+
ref,
|
|
294
|
+
render: /* @__PURE__ */ jsx(InputGroup, {
|
|
295
|
+
state,
|
|
296
|
+
variant,
|
|
297
|
+
focusVariant,
|
|
298
|
+
sizing,
|
|
299
|
+
className
|
|
300
|
+
})
|
|
301
|
+
});
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region src/components/Combobox/ComboboxItemIndicator.tsx
|
|
304
|
+
const ComboboxItemIndicator = ({ ref, className, variant = "check", ...props }) => {
|
|
305
|
+
if (variant === "checkbox") return /* @__PURE__ */ jsx(Combobox.ItemIndicator, {
|
|
306
|
+
ref,
|
|
307
|
+
keepMounted: true,
|
|
308
|
+
className: cn("tw:group/combobox-item-indicator", "tw:inline-flex", "tw:items-center", "tw:justify-center", "tw:size-4", "tw:shrink-0", "tw:rounded", "tw:border", "tw:border-input", "tw:bg-background", "tw:data-[selected]:bg-primary", "tw:data-[selected]:border-primary", className),
|
|
309
|
+
...props,
|
|
310
|
+
children: /* @__PURE__ */ jsx(Check, { className: cn("tw:hidden", "tw:size-3", "tw:stroke-[4px]", "tw:!text-primary-foreground", "tw:group-data-[selected]/combobox-item-indicator:block") })
|
|
311
|
+
});
|
|
312
|
+
return /* @__PURE__ */ jsx(Combobox.ItemIndicator, {
|
|
313
|
+
...props,
|
|
314
|
+
ref,
|
|
315
|
+
className: cn("tw:pointer-events-none", "tw:absolute", "tw:right-2", "tw:group-data-[variant=default]/combobox-content:right-4", "tw:size-4", "tw:group-data-[highlighted]/combobox-item:text-accent-foreground", "tw:group-data-[variant=default]/combobox-content:group-data-[highlighted]/combobox-item:text-secondary-foreground", className),
|
|
316
|
+
render: /* @__PURE__ */ jsx(Check, {})
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/components/Combobox/virtualList.ts
|
|
321
|
+
/** Above this many options, `virtualized="auto"` windows the list. */
|
|
322
|
+
const VIRTUALIZE_THRESHOLD = 30;
|
|
323
|
+
/**
|
|
324
|
+
* The position a windowed list gives each option it renders.
|
|
325
|
+
*
|
|
326
|
+
* - `index` is the option's place in Base UI's flat filtered list, which keyboard navigation counts.
|
|
327
|
+
* - `aria-setsize` / `aria-posinset` keep the set's length known while most options are out of the DOM.
|
|
328
|
+
* - `undefined` outside a windowed list, so a fully rendered list keeps its markup.
|
|
329
|
+
*/
|
|
330
|
+
const VirtualRowContext = createContext(void 0);
|
|
331
|
+
/**
|
|
332
|
+
* Whether a combobox windows its list, and what ties Base UI's highlight to the window.
|
|
333
|
+
*
|
|
334
|
+
* - `'auto'` counts options, not groups, so a list of a few large groups windows too.
|
|
335
|
+
* - `onItemHighlighted` scrolls a row the keyboard reached into view; a pointer is over its row.
|
|
336
|
+
* - `ref` goes to `ComboboxVirtualList`.
|
|
337
|
+
*/
|
|
338
|
+
const useVirtualList = (items, virtualized) => {
|
|
339
|
+
const ref = useRef(null);
|
|
340
|
+
const count = isGroupItems(items) ? items.reduce((sum, group) => sum + group.items.length, 0) : items.length;
|
|
341
|
+
return {
|
|
342
|
+
enabled: virtualized === "auto" ? count > VIRTUALIZE_THRESHOLD : virtualized,
|
|
343
|
+
ref,
|
|
344
|
+
onItemHighlighted: ({ reason, index }) => {
|
|
345
|
+
if (reason !== "pointer") ref.current?.scrollToItem(index);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
};
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/components/Combobox/ComboboxItem.tsx
|
|
351
|
+
const ComboboxItem = ({ ref, className, children, icon, indicator: variant = "check", ...props }) => /* @__PURE__ */ jsxs(Combobox.Item, {
|
|
352
|
+
...props,
|
|
353
|
+
...use(VirtualRowContext),
|
|
354
|
+
ref,
|
|
355
|
+
"data-slot": "combobox-item",
|
|
356
|
+
className: cn("tw:group/combobox-item", "tw:relative", "tw:flex", "tw:flex-1", "tw:items-center", "tw:gap-2", "tw:py-2", "tw:px-2", "tw:group-data-[variant=default]/combobox-content:px-4", "tw:rounded-lg", "tw:group-data-[variant=default]/combobox-content:rounded-none", "tw:text-sm", "tw:select-none", "tw:cursor-default", "tw:outline-hidden", "tw:data-[highlighted]:bg-accent", "tw:group-data-[variant=default]/combobox-content:data-[highlighted]:bg-secondary", "tw:data-[highlighted]:text-accent-foreground", "tw:group-data-[variant=default]/combobox-content:data-[highlighted]:text-secondary-foreground", "tw:data-disabled:pointer-events-none", "tw:data-disabled:opacity-50", "tw:[&_svg]:pointer-events-none", "tw:[&_svg]:shrink-0", "tw:[&_svg]:text-muted-foreground", "tw:[&_svg:not([class*='size-'])]:size-4", className),
|
|
357
|
+
children: [
|
|
358
|
+
variant !== "none" && /* @__PURE__ */ jsx(ComboboxItemIndicator, { variant }),
|
|
359
|
+
icon,
|
|
360
|
+
/* @__PURE__ */ jsx("span", {
|
|
361
|
+
className: "tw:truncate",
|
|
362
|
+
children
|
|
363
|
+
})
|
|
364
|
+
]
|
|
365
|
+
});
|
|
366
|
+
//#endregion
|
|
367
|
+
//#region src/components/Combobox/ComboboxList.tsx
|
|
368
|
+
const ComboboxList = ({ ref, className, ...props }) => /* @__PURE__ */ jsx(Combobox.List, {
|
|
369
|
+
ref,
|
|
370
|
+
className: cn("tw:no-scrollbar", "tw:scroll-py-1", "tw:overflow-y-auto", "tw:overscroll-contain", "tw:min-h-0", "tw:flex-1", "tw:p-2", "tw:data-[empty]:p-0", "tw:group-data-[variant=default]/combobox-content:p-0", className),
|
|
371
|
+
...props
|
|
372
|
+
});
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/components/Combobox/ComboboxOpenButton.tsx
|
|
375
|
+
/**
|
|
376
|
+
* The button that opens the popup: a chevron, or a spinner while the options are loading.
|
|
377
|
+
*
|
|
378
|
+
* - The spinner swaps in for the icon inside the one button, which costs the control no width, so
|
|
379
|
+
* the input keeps its room whether or not a request is in flight.
|
|
380
|
+
* - The button keeps opening the popup while loading, so a list that already has items stays
|
|
381
|
+
* reachable.
|
|
382
|
+
*/
|
|
383
|
+
const ComboboxOpenButton = ({ disabled, isLoading }) => /* @__PURE__ */ jsx(InputGroup.Button, {
|
|
384
|
+
disabled,
|
|
385
|
+
asChild: true,
|
|
386
|
+
"aria-label": "Open combobox",
|
|
387
|
+
children: /* @__PURE__ */ jsx(Combobox.Trigger, { children: isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "tw:size-4 tw:animate-spin" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "tw:size-4" }) })
|
|
388
|
+
});
|
|
389
|
+
//#endregion
|
|
390
|
+
//#region src/components/Combobox/Group/ComboboxGroupHeader.tsx
|
|
391
|
+
/** Indent of a header's children (chevron + gap); the legacy variant pads its rows wider. */
|
|
392
|
+
const GROUP_CHILD_INDENT = "tw:pl-8 tw:group-data-[variant=default]/combobox-content:pl-10";
|
|
393
|
+
/**
|
|
394
|
+
* A group's own row, standing for the whole group.
|
|
395
|
+
*
|
|
396
|
+
* - Keyboard-navigable like any other row.
|
|
397
|
+
* - The chevron toggles by pointer; `ArrowRight` / `ArrowLeft` are handled by the owning control.
|
|
398
|
+
*/
|
|
399
|
+
const ComboboxGroupHeader = ({ value, children, expanded, onToggle, checked, indicator = "check", disabled }) => {
|
|
400
|
+
const toggleFromChevron = (event) => {
|
|
401
|
+
event.stopPropagation();
|
|
402
|
+
onToggle();
|
|
403
|
+
};
|
|
404
|
+
return /* @__PURE__ */ jsx(ComboboxItem, {
|
|
405
|
+
value,
|
|
406
|
+
disabled,
|
|
407
|
+
"aria-description": expanded === void 0 ? void 0 : expanded ? "Expanded" : "Collapsed",
|
|
408
|
+
...checked !== void 0 && { "aria-selected": checked === true },
|
|
409
|
+
indicator: "none",
|
|
410
|
+
className: "tw:font-medium",
|
|
411
|
+
onClick: checked !== void 0 ? void 0 : (event) => {
|
|
412
|
+
event.preventBaseUIHandler();
|
|
413
|
+
onToggle();
|
|
414
|
+
},
|
|
415
|
+
icon: /* @__PURE__ */ jsxs(Fragment$1, { children: [expanded !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
416
|
+
"aria-hidden": true,
|
|
417
|
+
"data-slot": "combobox-group-toggle",
|
|
418
|
+
className: "tw:inline-flex tw:shrink-0",
|
|
419
|
+
onClick: toggleFromChevron,
|
|
420
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: cn("tw:transition-transform", expanded && "tw:rotate-90") })
|
|
421
|
+
}), checked !== void 0 && /* @__PURE__ */ jsx(GroupIndicator, {
|
|
422
|
+
checked,
|
|
423
|
+
variant: indicator
|
|
424
|
+
})] }),
|
|
425
|
+
children
|
|
426
|
+
});
|
|
427
|
+
};
|
|
428
|
+
/**
|
|
429
|
+
* A group row's selection mark: all, some, or none.
|
|
430
|
+
*
|
|
431
|
+
* - Base UI's indicator is binary, so the row draws its own.
|
|
432
|
+
* - `checkbox` matches the children's leading box; `check` their trailing mark.
|
|
433
|
+
*/
|
|
434
|
+
const GroupIndicator = ({ checked, variant }) => {
|
|
435
|
+
const Mark = checked === "mixed" ? Minus : Check;
|
|
436
|
+
if (variant === "checkbox") return /* @__PURE__ */ jsx("span", {
|
|
437
|
+
"aria-hidden": true,
|
|
438
|
+
"data-checked": checked,
|
|
439
|
+
className: cn("tw:inline-flex tw:size-4 tw:shrink-0 tw:items-center tw:justify-center", "tw:rounded tw:border tw:border-input tw:bg-background", checked !== false && "tw:border-primary tw:bg-primary"),
|
|
440
|
+
children: checked !== false && /* @__PURE__ */ jsx(Mark, { className: "tw:size-3 tw:stroke-[4px] tw:!text-primary-foreground" })
|
|
441
|
+
});
|
|
442
|
+
if (checked === false) return null;
|
|
443
|
+
return /* @__PURE__ */ jsx(Mark, {
|
|
444
|
+
"aria-hidden": true,
|
|
445
|
+
className: cn("tw:pointer-events-none tw:absolute tw:right-2 tw:size-4", "tw:group-data-[variant=default]/combobox-content:right-4", "tw:group-data-[highlighted]/combobox-item:text-accent-foreground", "tw:group-data-[variant=default]/combobox-content:group-data-[highlighted]/combobox-item:text-secondary-foreground")
|
|
446
|
+
});
|
|
447
|
+
};
|
|
448
|
+
//#endregion
|
|
449
|
+
//#region src/components/Combobox/Group/ComboboxGroup.tsx
|
|
450
|
+
const ComboboxGroup = ({ ref, className, children, ...props }) => /* @__PURE__ */ jsx(Combobox.Group, {
|
|
451
|
+
ref,
|
|
452
|
+
className: cn("tw:flex tw:flex-col tw:gap-0.5", className),
|
|
453
|
+
...props,
|
|
454
|
+
children
|
|
455
|
+
});
|
|
456
|
+
//#endregion
|
|
457
|
+
//#region src/components/Combobox/Group/ComboboxGroupLabel.tsx
|
|
458
|
+
const ComboboxGroupLabel = ({ ref, className, ...props }) => /* @__PURE__ */ jsx(Combobox.GroupLabel, {
|
|
459
|
+
...props,
|
|
460
|
+
ref,
|
|
461
|
+
className: cn("tw:px-2", "tw:py-1.5", "tw:text-xs", "tw:font-medium", "tw:leading-none", "tw:text-muted-foreground", "tw:group-data-[variant=default]/combobox-content:uppercase", "tw:group-data-[variant=default]/combobox-content:font-semibold", "tw:group-data-[variant=default]/combobox-content:tracking-wider", "tw:group-data-[variant=default]/combobox-content:text-[11px]", "tw:group-data-[variant=default]/combobox-content:text-black", "tw:group-data-[variant=default]/combobox-content:pt-2", "tw:group-data-[variant=default]/combobox-content:px-4", className)
|
|
462
|
+
});
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/components/Combobox/Group/ComboboxCollection.tsx
|
|
465
|
+
const ComboboxCollection = ({ ...props }) => /* @__PURE__ */ jsx(Combobox.Collection, {
|
|
466
|
+
"data-slot": "combobox-collection",
|
|
467
|
+
...props
|
|
468
|
+
});
|
|
469
|
+
//#endregion
|
|
470
|
+
//#region src/components/Combobox/ComboboxFullList.tsx
|
|
471
|
+
/** A Base UI collection child whose rows are keyed by position, as React matches unkeyed ones. */
|
|
472
|
+
const keyed = (render) => (entry, index) => /* @__PURE__ */ jsx(Fragment, { children: render(entry) }, index);
|
|
473
|
+
/** A combobox list that renders every row; `ComboboxVirtualList` renders only those in view. */
|
|
474
|
+
const ComboboxFullList = ({ renderItem, renderGroupItem, groupToLabel }) => {
|
|
475
|
+
const renderEntry = (entry) => {
|
|
476
|
+
if (!isGroupItem(entry)) return renderItem(entry);
|
|
477
|
+
const [lead] = entry.items;
|
|
478
|
+
if (isLooseItem(lead)) return renderItem(lead);
|
|
479
|
+
const label = groupToLabel?.(entry);
|
|
480
|
+
return /* @__PURE__ */ jsxs(ComboboxGroup, {
|
|
481
|
+
items: entry.items,
|
|
482
|
+
children: [label && /* @__PURE__ */ jsx(ComboboxGroupLabel, { children: label }), /* @__PURE__ */ jsx(ComboboxCollection, { children: keyed(renderGroupItem) })]
|
|
483
|
+
});
|
|
484
|
+
};
|
|
485
|
+
return /* @__PURE__ */ jsx(ComboboxList, { children: keyed(renderEntry) });
|
|
486
|
+
};
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region src/components/Combobox/ComboboxLoadingEmpty.tsx
|
|
489
|
+
/**
|
|
490
|
+
* What the empty slot says while the options are loading, in place of the `empty` node.
|
|
491
|
+
*
|
|
492
|
+
* - `Combobox.Empty` is a polite live region, so the switch to this text and back to `empty` once
|
|
493
|
+
* the request settles is announced.
|
|
494
|
+
* - Base UI renders the slot only while the list has nothing to show, so a list that already has
|
|
495
|
+
* items keeps showing them.
|
|
496
|
+
*/
|
|
497
|
+
const ComboboxLoadingEmpty = () => /* @__PURE__ */ jsxs("span", {
|
|
498
|
+
className: "tw:inline-flex tw:items-center tw:gap-2",
|
|
499
|
+
children: [/* @__PURE__ */ jsx(Loader2, { className: "tw:size-4 tw:animate-spin" }), "Loading…"]
|
|
500
|
+
});
|
|
501
|
+
//#endregion
|
|
502
|
+
//#region src/components/Combobox/ComboboxVirtualList.tsx
|
|
503
|
+
/** Rows rendered past each edge of the viewport, so a fast scroll does not paint blank. */
|
|
504
|
+
const OVERSCAN = 12;
|
|
505
|
+
const kindOf = (row) => row.type === "label" ? "label" : row.padded ? "padded" : "plain";
|
|
506
|
+
/**
|
|
507
|
+
* Base UI's filtered entries as one row per option or group label, in list order.
|
|
508
|
+
*
|
|
509
|
+
* - A group whose lone item is the create row or Select All stays outside any group, as the fully
|
|
510
|
+
* rendered list draws it.
|
|
511
|
+
* - `aria-setsize` counts the options sharing a parent, as a browser does for a rendered list.
|
|
512
|
+
*/
|
|
513
|
+
const toRows = (entries, groupToLabel) => {
|
|
514
|
+
const rows = [];
|
|
515
|
+
const rowOfItem = [];
|
|
516
|
+
const labels = /* @__PURE__ */ new Map();
|
|
517
|
+
const push = (item, row) => {
|
|
518
|
+
rows.push({
|
|
519
|
+
type: "item",
|
|
520
|
+
item,
|
|
521
|
+
index: rowOfItem.length,
|
|
522
|
+
...row
|
|
523
|
+
});
|
|
524
|
+
rowOfItem.push(rows.length - 1);
|
|
525
|
+
};
|
|
526
|
+
if (!isGroupItems(entries)) {
|
|
527
|
+
const items = entries.filter((entry) => !isGroupItem(entry));
|
|
528
|
+
items.forEach((item, i) => push(item, {
|
|
529
|
+
padded: false,
|
|
530
|
+
setSize: items.length,
|
|
531
|
+
posInSet: i + 1
|
|
532
|
+
}));
|
|
533
|
+
return {
|
|
534
|
+
rows,
|
|
535
|
+
rowOfItem,
|
|
536
|
+
labels
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
const isLoose = (group) => isLooseItem(group.items[0]);
|
|
540
|
+
const looseCount = entries.filter(isLoose).length;
|
|
541
|
+
let loosePosition = 0;
|
|
542
|
+
entries.forEach((entry, groupIndex) => {
|
|
543
|
+
if (isLoose(entry)) {
|
|
544
|
+
for (const item of entry.items) push(item, {
|
|
545
|
+
padded: false,
|
|
546
|
+
setSize: looseCount,
|
|
547
|
+
posInSet: ++loosePosition
|
|
548
|
+
});
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const group = `group-${groupIndex}`;
|
|
552
|
+
const label = groupToLabel?.(entry);
|
|
553
|
+
if (label) {
|
|
554
|
+
labels.set(group, label);
|
|
555
|
+
rows.push({
|
|
556
|
+
type: "label",
|
|
557
|
+
group,
|
|
558
|
+
padded: false
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
entry.items.forEach((item, i) => push(item, {
|
|
562
|
+
group,
|
|
563
|
+
padded: Boolean(label) || i > 0,
|
|
564
|
+
setSize: entry.items.length,
|
|
565
|
+
posInSet: i + 1
|
|
566
|
+
}));
|
|
567
|
+
});
|
|
568
|
+
return {
|
|
569
|
+
rows,
|
|
570
|
+
rowOfItem,
|
|
571
|
+
labels
|
|
572
|
+
};
|
|
573
|
+
};
|
|
574
|
+
/**
|
|
575
|
+
* A combobox list that puts only the rows in view into the DOM.
|
|
576
|
+
*
|
|
577
|
+
* - Lists what Base UI filtered, so search and keyboard navigation cover every option.
|
|
578
|
+
* - A group keeps its `role="group"` wrapper, and its name while its label row is out of view.
|
|
579
|
+
* - Rows keep their own height; a row not yet rendered is estimated from those that were.
|
|
580
|
+
*/
|
|
581
|
+
const ComboboxVirtualList = ({ renderItem, renderGroupItem, groupToLabel, ref }) => {
|
|
582
|
+
const [listElement, attachList] = useElement();
|
|
583
|
+
const scrollMargin = useMemo(() => listElement ? Number.parseFloat(getComputedStyle(listElement).paddingTop) || 0 : 0, [listElement]);
|
|
584
|
+
const filteredItems = Combobox.useFilteredItems();
|
|
585
|
+
const { rows, rowOfItem, labels } = useMemo(() => toRows(filteredItems, groupToLabel), [filteredItems, groupToLabel]);
|
|
586
|
+
const sizesRef = useRef({});
|
|
587
|
+
const [rem] = useState(() => Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 0);
|
|
588
|
+
const virtualizer = useVirtualizer({
|
|
589
|
+
count: rows.length,
|
|
590
|
+
getScrollElement: () => listElement,
|
|
591
|
+
estimateSize: (index) => {
|
|
592
|
+
const row = rows[index];
|
|
593
|
+
const measured = sizesRef.current;
|
|
594
|
+
return (row && measured[kindOf(row)]) ?? measured.plain ?? measured.padded ?? rem;
|
|
595
|
+
},
|
|
596
|
+
measureElement: (element, entry, instance) => {
|
|
597
|
+
const size = measureElement(element, entry, instance);
|
|
598
|
+
const row = rows[instance.indexFromElement(element)];
|
|
599
|
+
if (row) {
|
|
600
|
+
const kind = kindOf(row);
|
|
601
|
+
sizesRef.current[kind] = Math.min(sizesRef.current[kind] ?? size, size);
|
|
602
|
+
}
|
|
603
|
+
return size;
|
|
604
|
+
},
|
|
605
|
+
observeElementRect: (instance, callback) => observeElementRect(instance, (rect) => callback({
|
|
606
|
+
...rect,
|
|
607
|
+
height: Math.min(rect.height, instance.targetWindow?.innerHeight ?? rect.height)
|
|
608
|
+
})),
|
|
609
|
+
overscan: OVERSCAN,
|
|
610
|
+
scrollMargin
|
|
611
|
+
});
|
|
612
|
+
useImperativeHandle(ref, () => ({ scrollToItem: (index) => {
|
|
613
|
+
const row = rowOfItem[index];
|
|
614
|
+
if (row !== void 0) virtualizer.scrollToIndex(row, { align: "auto" });
|
|
615
|
+
} }));
|
|
616
|
+
const segments = [];
|
|
617
|
+
for (const virtualItem of virtualizer.getVirtualItems()) {
|
|
618
|
+
const group = rows[virtualItem.index]?.group;
|
|
619
|
+
const last = segments.at(-1);
|
|
620
|
+
if (group !== void 0 && last?.group === group) last.items.push(virtualItem);
|
|
621
|
+
else segments.push({
|
|
622
|
+
group,
|
|
623
|
+
start: virtualItem.start,
|
|
624
|
+
items: [virtualItem]
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
const placeAt = (start) => ({
|
|
628
|
+
position: "absolute",
|
|
629
|
+
top: 0,
|
|
630
|
+
left: 0,
|
|
631
|
+
width: "100%",
|
|
632
|
+
transform: `translateY(${start - scrollMargin}px)`
|
|
633
|
+
});
|
|
634
|
+
const renderRow = ({ key, index, start }) => {
|
|
635
|
+
const row = rows[index];
|
|
636
|
+
if (!row) return null;
|
|
637
|
+
return /* @__PURE__ */ jsx("div", {
|
|
638
|
+
"data-index": index,
|
|
639
|
+
ref: virtualizer.measureElement,
|
|
640
|
+
className: row.padded ? "tw:pt-0.5" : void 0,
|
|
641
|
+
style: row.group === void 0 ? placeAt(start) : void 0,
|
|
642
|
+
children: row.type === "label" ? /* @__PURE__ */ jsx(ComboboxGroupLabel, { children: labels.get(row.group ?? "") }) : /* @__PURE__ */ jsx(VirtualRowContext, {
|
|
643
|
+
value: {
|
|
644
|
+
index: row.index,
|
|
645
|
+
"aria-setsize": row.setSize,
|
|
646
|
+
"aria-posinset": row.posInSet
|
|
647
|
+
},
|
|
648
|
+
children: row.group === void 0 ? renderItem(row.item) : renderGroupItem(row.item)
|
|
649
|
+
})
|
|
650
|
+
}, key);
|
|
651
|
+
};
|
|
652
|
+
return /* @__PURE__ */ jsx(ComboboxList, {
|
|
653
|
+
ref: attachList,
|
|
654
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
655
|
+
style: {
|
|
656
|
+
position: "relative",
|
|
657
|
+
width: "100%",
|
|
658
|
+
height: `${virtualizer.getTotalSize()}px`
|
|
659
|
+
},
|
|
660
|
+
children: segments.flatMap(({ group, start, items }) => {
|
|
661
|
+
if (group === void 0) return items.map(renderRow);
|
|
662
|
+
const label = labels.get(group);
|
|
663
|
+
const labelInView = items.some((item) => rows[item.index]?.type === "label");
|
|
664
|
+
return /* @__PURE__ */ jsxs(ComboboxGroup, {
|
|
665
|
+
className: "tw:gap-0",
|
|
666
|
+
style: placeAt(start),
|
|
667
|
+
children: [label && !labelInView && /* @__PURE__ */ jsx(ComboboxGroupLabel, {
|
|
668
|
+
className: "tw:sr-only",
|
|
669
|
+
children: label
|
|
670
|
+
}), items.map(renderRow)]
|
|
671
|
+
}, group);
|
|
672
|
+
})
|
|
673
|
+
})
|
|
674
|
+
});
|
|
675
|
+
};
|
|
676
|
+
//#endregion
|
|
677
|
+
//#region src/components/Combobox/ComboboxOptions.tsx
|
|
678
|
+
/**
|
|
679
|
+
* What a combobox popup lists: every row, the empty slot, and the loading text in it.
|
|
680
|
+
*
|
|
681
|
+
* - The list is windowed while `virtualized`, fully rendered otherwise.
|
|
682
|
+
*/
|
|
683
|
+
const ComboboxOptions = ({ isLoading, empty, virtualized, listRef, groupHeaders, groupToLabel, indicator, itemToLabel, itemToIcon, itemToDisabled, createLabel, groupRowState }) => {
|
|
684
|
+
const renderItem = (item, className) => {
|
|
685
|
+
if (isSelectAllItem(item)) return /* @__PURE__ */ jsx(ComboboxItem, {
|
|
686
|
+
value: item,
|
|
687
|
+
indicator: "checkbox",
|
|
688
|
+
children: item.label
|
|
689
|
+
});
|
|
690
|
+
if (isCreatableItem(item)) return /* @__PURE__ */ jsx(ComboboxItem, {
|
|
691
|
+
value: item,
|
|
692
|
+
icon: /* @__PURE__ */ jsx(Plus, {}),
|
|
693
|
+
children: createLabel(item.value)
|
|
694
|
+
});
|
|
695
|
+
return /* @__PURE__ */ jsx(ComboboxItem, {
|
|
696
|
+
value: item,
|
|
697
|
+
indicator,
|
|
698
|
+
icon: itemToIcon(item),
|
|
699
|
+
disabled: itemToDisabled(item),
|
|
700
|
+
className,
|
|
701
|
+
children: itemToLabel(item)
|
|
702
|
+
});
|
|
703
|
+
};
|
|
704
|
+
const renderGroupItem = (item) => {
|
|
705
|
+
const header = groupHeaders.headerOf(item);
|
|
706
|
+
if (!header) return renderItem(item, groupHeaders.collapsible ? GROUP_CHILD_INDENT : void 0);
|
|
707
|
+
const state = groupRowState?.(item);
|
|
708
|
+
return /* @__PURE__ */ jsx(ComboboxGroupHeader, {
|
|
709
|
+
value: item,
|
|
710
|
+
expanded: groupHeaders.collapsible ? !header.collapsed : void 0,
|
|
711
|
+
onToggle: () => groupHeaders.toggle(header.index),
|
|
712
|
+
checked: state?.checked,
|
|
713
|
+
indicator,
|
|
714
|
+
disabled: state?.disabled ?? false,
|
|
715
|
+
children: groupToLabel(header.group)
|
|
716
|
+
});
|
|
717
|
+
};
|
|
718
|
+
const labelOfGroup = useCallback((group) => isEntriesGroup(group) ? void 0 : groupToLabel(group), [groupToLabel]);
|
|
719
|
+
const listProps = {
|
|
720
|
+
renderItem,
|
|
721
|
+
renderGroupItem,
|
|
722
|
+
groupToLabel: groupHeaders.enabled ? void 0 : labelOfGroup
|
|
723
|
+
};
|
|
724
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ComboboxEmpty, { children: isLoading ? /* @__PURE__ */ jsx(ComboboxLoadingEmpty, {}) : empty }), virtualized ? /* @__PURE__ */ jsx(ComboboxVirtualList, {
|
|
725
|
+
ref: listRef,
|
|
726
|
+
...listProps
|
|
727
|
+
}) : /* @__PURE__ */ jsx(ComboboxFullList, { ...listProps })] });
|
|
728
|
+
};
|
|
729
|
+
//#endregion
|
|
730
|
+
//#region src/components/Combobox/ComboboxRoot.tsx
|
|
731
|
+
const ComboboxRoot = (props) => /* @__PURE__ */ jsx(Combobox.Root, { ...props });
|
|
732
|
+
//#endregion
|
|
733
|
+
//#region src/components/Combobox/ComboboxSeparator.tsx
|
|
734
|
+
const ComboboxSeparator = ({ ref, className, ...props }) => /* @__PURE__ */ jsx(Combobox.Separator, {
|
|
735
|
+
ref,
|
|
736
|
+
className: cn("tw:mx-2 tw:my-1 tw:h-px tw:bg-border", className),
|
|
737
|
+
...props
|
|
738
|
+
});
|
|
739
|
+
//#endregion
|
|
740
|
+
//#region src/components/Combobox/createdItems.ts
|
|
741
|
+
/**
|
|
742
|
+
* `list` followed by the values `allowCreate` minted, as entries of it; stable while both are.
|
|
743
|
+
*
|
|
744
|
+
* - Listed so a created value stays pickable: Base UI drops a value missing from `items`.
|
|
745
|
+
*/
|
|
746
|
+
const useWithCreated = (list, created) => useMemo(() => created.length === 0 ? list : [...list, ...toEntries(list, created)], [list, created]);
|
|
747
|
+
//#endregion
|
|
748
|
+
//#region src/components/Combobox/groupHeaders.ts
|
|
749
|
+
/**
|
|
750
|
+
* Gives each group a row (rendered with `ComboboxGroupHeader`) and collapses groups on request.
|
|
751
|
+
*
|
|
752
|
+
* - The row is the group's first item, so Base UI navigates, filters and presses it.
|
|
753
|
+
* - A collapsed group hands Base UI only its row: Base UI never filters an empty query.
|
|
754
|
+
* - A query shows every match regardless of collapse; a row shows only while its group matches.
|
|
755
|
+
* - Collapse state is keyed by a group's position in `items`.
|
|
756
|
+
*/
|
|
757
|
+
const useGroupHeaders = ({ items, collapsible, selectable, query, matches, groupToValue, isItemEqualToValue }) => {
|
|
758
|
+
const [collapsedIndexes, setCollapsedIndexes] = useState(() => /* @__PURE__ */ new Set());
|
|
759
|
+
const highlightedRef = useRef(void 0);
|
|
760
|
+
const enabled = (collapsible || selectable) && isGroupItems(items);
|
|
761
|
+
const headers = /* @__PURE__ */ new Map();
|
|
762
|
+
const listItems = !enabled ? items : items.map((group, index) => {
|
|
763
|
+
const collapsed = collapsible && query === "" && collapsedIndexes.has(index);
|
|
764
|
+
const matching = query === "" ? group.items : group.items.filter(matches);
|
|
765
|
+
const row = groupToValue ? groupToValue(group) : createGroupHeaderItem(index);
|
|
766
|
+
headers.set(row, {
|
|
767
|
+
group,
|
|
768
|
+
index,
|
|
769
|
+
collapsed,
|
|
770
|
+
matching
|
|
771
|
+
});
|
|
772
|
+
return {
|
|
773
|
+
...group,
|
|
774
|
+
items: collapsed ? [row] : [row, ...group.items]
|
|
775
|
+
};
|
|
776
|
+
});
|
|
777
|
+
const toggle = (index) => setCollapsedIndexes((prev) => {
|
|
778
|
+
const next = new Set(prev);
|
|
779
|
+
if (!next.delete(index)) next.add(index);
|
|
780
|
+
return next;
|
|
781
|
+
});
|
|
782
|
+
const headerOf = (item) => headers.get(item);
|
|
783
|
+
const highlightedHeader = () => {
|
|
784
|
+
const item = highlightedRef.current;
|
|
785
|
+
if (item === void 0) return void 0;
|
|
786
|
+
const header = headers.get(item);
|
|
787
|
+
if (header) return header;
|
|
788
|
+
for (const [row, entry] of headers) if (isItemEqualToValue(row, item)) return entry;
|
|
789
|
+
};
|
|
790
|
+
return {
|
|
791
|
+
enabled,
|
|
792
|
+
/** `items` with group rows added and collapsed groups' items removed. */
|
|
793
|
+
items: listItems,
|
|
794
|
+
collapsible,
|
|
795
|
+
headerOf,
|
|
796
|
+
toggle,
|
|
797
|
+
/** `filter` verdict for a group row (matches while its group does); `undefined` otherwise. */
|
|
798
|
+
filterHeader: (item) => {
|
|
799
|
+
const header = headerOf(item);
|
|
800
|
+
return header ? header.matching.length > 0 : void 0;
|
|
801
|
+
},
|
|
802
|
+
/** For the root's `onItemHighlighted`: which row the keyboard would toggle. */
|
|
803
|
+
onItemHighlighted: (item) => {
|
|
804
|
+
highlightedRef.current = item;
|
|
805
|
+
},
|
|
806
|
+
/** For the root's `onOpenChange`: a closed popup has no highlighted row to toggle. */
|
|
807
|
+
onOpenChange: (open) => {
|
|
808
|
+
if (!open) highlightedRef.current = void 0;
|
|
809
|
+
},
|
|
810
|
+
/**
|
|
811
|
+
* For the input's `onKeyDown`: `ArrowRight` / `ArrowLeft` expand / collapse the highlighted row.
|
|
812
|
+
* Only without a query; also stops Base UI moving to the chips.
|
|
813
|
+
*/
|
|
814
|
+
onInputKeyDown: (event) => {
|
|
815
|
+
if (!collapsible || query !== "") return;
|
|
816
|
+
if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") return;
|
|
817
|
+
const header = highlightedHeader();
|
|
818
|
+
if (!header) return;
|
|
819
|
+
event.preventDefault();
|
|
820
|
+
event.preventBaseUIHandler();
|
|
821
|
+
if (header.collapsed === (event.key === "ArrowRight")) toggle(header.index);
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
};
|
|
825
|
+
//#endregion
|
|
826
|
+
//#region src/components/Combobox/query.ts
|
|
827
|
+
/**
|
|
828
|
+
* The text a combobox's input takes, with `inputValueSanitizer` applied to what the user typed.
|
|
829
|
+
*
|
|
830
|
+
* - `input-change` is the only reason carrying typed text. Every other one carries text the
|
|
831
|
+
* control itself put there — an item's label, or the empty string a clear leaves — which a
|
|
832
|
+
* sanitizer aimed at typed characters would mangle.
|
|
833
|
+
* - A sanitizer sees the whole text on every keystroke, so it has to rewrite rather than drop:
|
|
834
|
+
* one calling `trim()` swallows the space before the next word.
|
|
835
|
+
*/
|
|
836
|
+
const sanitizeTypedInput = (next, reason, sanitizer) => reason === "input-change" ? sanitizer?.(next) ?? next : next;
|
|
837
|
+
/**
|
|
838
|
+
* Reports the query the list filters by to the control's owner.
|
|
839
|
+
*
|
|
840
|
+
* - Fires from an effect rather than the input handler because `query` is derived: in `Combobox`
|
|
841
|
+
* a selection showing its own label empties it without a keystroke, so the handler never sees
|
|
842
|
+
* every value it takes.
|
|
843
|
+
* - The mount render reports too, so an owner fetching on the query needs no first fetch of its
|
|
844
|
+
* own.
|
|
845
|
+
*/
|
|
846
|
+
const useQueryReporter = (query, onQueryChange) => {
|
|
847
|
+
const report = useStableCallback(onQueryChange ?? noop);
|
|
848
|
+
useEffect(() => {
|
|
849
|
+
report(query);
|
|
850
|
+
}, [query, report]);
|
|
851
|
+
};
|
|
852
|
+
//#endregion
|
|
853
|
+
//#region src/components/Combobox/Combobox.tsx
|
|
854
|
+
const acceptAll = () => true;
|
|
855
|
+
const NO_ITEMS = [];
|
|
856
|
+
const Combobox$1 = ({ items: _itemsProp, value, defaultValue, onValueChange, itemToStringLabel: itemToStringLabelProp, itemToStringValue, disabled, filter, inputRef, onOpenChangeComplete, isItemEqualToValue: isItemEqualToValueProp, variant, sizing, focusVariant, state, placeholder, allowClear = true, id, name, onBlur, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, "aria-required": ariaRequired, className, empty = "No items", isLoading = false, indicator, prefix, virtualized = false, inputValueSanitizer, onQueryChange, allowCreate, queryToCreateValue, queryToCreateLabel = defaultQueryToCreateLabel, canCreate, itemToDisabled = defaultItemToDisabled, itemToLabel: itemToLabelProp, itemToIcon = defaultItemToIcon, itemToSelectedLabel, groupToLabel = defaultGroupToLabel, collapsibleGroups = false, groupToValue }) => {
|
|
857
|
+
/** An item's string identity: input text, default search subject, accessible value. */
|
|
858
|
+
const labelOf = useCallback((item) => itemToStringLabelProp?.(item) ?? toLabel(item), [itemToStringLabelProp]);
|
|
859
|
+
const itemToLabel = itemToLabelProp ?? defaultRowLabel(itemToStringLabelProp);
|
|
860
|
+
const [typedText, setTypedText] = useState(null);
|
|
861
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? null);
|
|
862
|
+
const selectedItem = value !== void 0 ? value : uncontrolledValue;
|
|
863
|
+
const selectedLabel = selectedItem == null ? null : labelOf(selectedItem);
|
|
864
|
+
const isShowingSelection = selectedLabel !== null && (typedText === null || typedText === selectedLabel);
|
|
865
|
+
const inputValue = typedText ?? selectedLabel ?? "";
|
|
866
|
+
const selectedNode = itemToSelectedLabel && selectedItem != null && isShowingSelection ? itemToSelectedLabel(selectedItem) : null;
|
|
867
|
+
const query = (isShowingSelection ? "" : typedText ?? "").trim();
|
|
868
|
+
const queryLower = query.toLowerCase();
|
|
869
|
+
useQueryReporter(query, onQueryChange);
|
|
870
|
+
const busy = isLoading || void 0;
|
|
871
|
+
const itemsProp = _itemsProp ?? NO_ITEMS;
|
|
872
|
+
const sampleItem = flatItems(itemsProp)[0];
|
|
873
|
+
const isItemEqualToValue = useItemEquality(isItemEqualToValueProp);
|
|
874
|
+
const [createdItems, setCreatedItems] = useState([]);
|
|
875
|
+
const [createdItem] = createdItems;
|
|
876
|
+
const itemsHoldCreated = useMemo(() => createdItem !== void 0 && flatItems(itemsProp).some((listed) => isItemEqualToValue(listed, createdItem)), [
|
|
877
|
+
createdItem,
|
|
878
|
+
itemsProp,
|
|
879
|
+
isItemEqualToValue
|
|
880
|
+
]);
|
|
881
|
+
const created = createdItem !== void 0 && !itemsHoldCreated && selectedItem != null && isItemEqualToValue(createdItem, selectedItem) ? createdItems : NO_ITEMS;
|
|
882
|
+
const itemToStringLabel = useCallback((value) => {
|
|
883
|
+
if (isCreatableItem(value)) return value.value;
|
|
884
|
+
if (isGroupHeaderItem(value)) return value.label;
|
|
885
|
+
return labelOf(value);
|
|
886
|
+
}, [labelOf]);
|
|
887
|
+
const { contains } = Combobox.useFilter();
|
|
888
|
+
const itemFilter = filter ?? contains;
|
|
889
|
+
const groupHeaders = useGroupHeaders({
|
|
890
|
+
items: itemsProp,
|
|
891
|
+
collapsible: collapsibleGroups,
|
|
892
|
+
selectable: groupToValue !== void 0,
|
|
893
|
+
query,
|
|
894
|
+
matches: (item) => itemFilter(item, query, itemToStringLabel),
|
|
895
|
+
groupToValue,
|
|
896
|
+
isItemEqualToValue
|
|
897
|
+
});
|
|
898
|
+
const allItems = useWithCreated(itemsProp, created);
|
|
899
|
+
const listItems = useWithCreated(groupHeaders.items, created);
|
|
900
|
+
const showCreateRow = (() => {
|
|
901
|
+
if (!allowCreate || disabled || !query) return false;
|
|
902
|
+
return !flatItems(allItems).some((item) => labelOf(item).toLowerCase() === queryLower) && (!canCreate || canCreate(query));
|
|
903
|
+
})();
|
|
904
|
+
const items = useMemo(() => showCreateRow ? [...listItems, ...toEntries(listItems, [createCreatableItem(query)])] : listItems, [
|
|
905
|
+
showCreateRow,
|
|
906
|
+
listItems,
|
|
907
|
+
query
|
|
908
|
+
]);
|
|
909
|
+
const filterHeader = groupHeaders.enabled ? groupHeaders.filterHeader : void 0;
|
|
910
|
+
const queryFilter = useMemo(() => {
|
|
911
|
+
if (filterHeader) return (item, query, itemToString) => filterHeader(item) ?? (isCreatableItem(item) || itemFilter(item, query, itemToString));
|
|
912
|
+
if (!allowCreate || !filter) return filter;
|
|
913
|
+
return (item, query, itemToString) => isCreatableItem(item) || filter(item, query, itemToString);
|
|
914
|
+
}, [
|
|
915
|
+
filterHeader,
|
|
916
|
+
allowCreate,
|
|
917
|
+
filter,
|
|
918
|
+
itemFilter
|
|
919
|
+
]);
|
|
920
|
+
const wrappedFilter = isShowingSelection ? acceptAll : queryFilter;
|
|
921
|
+
const wrappedItemToStringValue = useCreatableStringValue(itemToStringValue, allowCreate);
|
|
922
|
+
const handleInputValueChange = (next, { reason }) => {
|
|
923
|
+
if (reason !== "input-change") {
|
|
924
|
+
setTypedText(null);
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const typed = inputValueSanitizer?.(next) ?? next;
|
|
928
|
+
setTypedText(typed === "" || typed.trim() !== "" ? typed : null);
|
|
929
|
+
};
|
|
930
|
+
const handleOpenChange = (open) => {
|
|
931
|
+
if (!open) setTypedText(null);
|
|
932
|
+
groupHeaders.onOpenChange(open);
|
|
933
|
+
};
|
|
934
|
+
const handleOnValueChange = (next, event) => {
|
|
935
|
+
if (isCreatableItem(next)) {
|
|
936
|
+
const newValue = defaultToCreateValue(next.value, sampleItem, queryToCreateValue);
|
|
937
|
+
setCreatedItems([newValue]);
|
|
938
|
+
setUncontrolledValue(newValue);
|
|
939
|
+
onValueChange?.(newValue, event);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
setUncontrolledValue(next);
|
|
943
|
+
onValueChange?.(next, event);
|
|
944
|
+
};
|
|
945
|
+
const virtualList = useVirtualList(allItems, virtualized);
|
|
946
|
+
const comboboxInput = /* @__PURE__ */ jsx(ComboboxInput, {
|
|
947
|
+
id,
|
|
948
|
+
name,
|
|
949
|
+
onBlur,
|
|
950
|
+
"aria-label": ariaLabel,
|
|
951
|
+
"aria-labelledby": ariaLabelledBy,
|
|
952
|
+
"aria-describedby": ariaDescribedBy,
|
|
953
|
+
"aria-invalid": ariaInvalid,
|
|
954
|
+
"aria-required": ariaRequired,
|
|
955
|
+
"aria-busy": busy,
|
|
956
|
+
placeholder,
|
|
957
|
+
disabled,
|
|
958
|
+
onKeyDown: groupHeaders.onInputKeyDown,
|
|
959
|
+
className: cn(selectedNode != null && "tw:text-transparent tw:caret-foreground tw:selection:bg-transparent")
|
|
960
|
+
});
|
|
961
|
+
return /* @__PURE__ */ jsxs(Combobox.Root, {
|
|
962
|
+
items,
|
|
963
|
+
autoHighlight: true,
|
|
964
|
+
value,
|
|
965
|
+
defaultValue,
|
|
966
|
+
filter: wrappedFilter,
|
|
967
|
+
onValueChange: handleOnValueChange,
|
|
968
|
+
itemToStringLabel,
|
|
969
|
+
isItemEqualToValue,
|
|
970
|
+
itemToStringValue: wrappedItemToStringValue,
|
|
971
|
+
onOpenChange: handleOpenChange,
|
|
972
|
+
onOpenChangeComplete,
|
|
973
|
+
disabled,
|
|
974
|
+
inputRef,
|
|
975
|
+
inputValue,
|
|
976
|
+
onInputValueChange: handleInputValueChange,
|
|
977
|
+
virtualized: virtualList.enabled,
|
|
978
|
+
onItemHighlighted: (item, details) => {
|
|
979
|
+
groupHeaders.onItemHighlighted(item);
|
|
980
|
+
virtualList.onItemHighlighted(details);
|
|
981
|
+
},
|
|
982
|
+
children: [/* @__PURE__ */ jsxs(ComboboxInputGroup, {
|
|
983
|
+
variant,
|
|
984
|
+
sizing,
|
|
985
|
+
state,
|
|
986
|
+
focusVariant,
|
|
987
|
+
className,
|
|
988
|
+
children: [itemToSelectedLabel != null ? /* @__PURE__ */ jsxs("div", {
|
|
989
|
+
className: "tw:relative tw:flex tw:min-w-0 tw:flex-1",
|
|
990
|
+
children: [(prefix != null || selectedNode != null) && /* @__PURE__ */ jsxs(InputGroup.Addon, {
|
|
991
|
+
align: "inline-start",
|
|
992
|
+
className: cn(selectedNode != null && "tw:pointer-events-none tw:absolute tw:inset-y-0 tw:left-0 tw:max-w-full tw:overflow-hidden"),
|
|
993
|
+
children: [prefix, selectedNode]
|
|
994
|
+
}), comboboxInput]
|
|
995
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [prefix != null && /* @__PURE__ */ jsx(InputGroup.Addon, {
|
|
996
|
+
align: "inline-start",
|
|
997
|
+
children: prefix
|
|
998
|
+
}), comboboxInput] }), /* @__PURE__ */ jsxs(InputGroup.Addon, {
|
|
999
|
+
align: "inline-end",
|
|
1000
|
+
children: [allowClear && /* @__PURE__ */ jsx(ComboboxClearButton, { disabled }), /* @__PURE__ */ jsx(ComboboxOpenButton, {
|
|
1001
|
+
disabled,
|
|
1002
|
+
isLoading
|
|
1003
|
+
})]
|
|
1004
|
+
})]
|
|
1005
|
+
}), /* @__PURE__ */ jsx(ComboboxContent, { children: /* @__PURE__ */ jsx(ComboboxOptions, {
|
|
1006
|
+
isLoading,
|
|
1007
|
+
empty,
|
|
1008
|
+
virtualized: virtualList.enabled,
|
|
1009
|
+
listRef: virtualList.ref,
|
|
1010
|
+
groupHeaders,
|
|
1011
|
+
groupToLabel,
|
|
1012
|
+
indicator,
|
|
1013
|
+
itemToLabel: (item) => itemToLabel(item, query),
|
|
1014
|
+
itemToIcon,
|
|
1015
|
+
itemToDisabled,
|
|
1016
|
+
createLabel: queryToCreateLabel,
|
|
1017
|
+
groupRowState: groupToValue ? (row) => ({
|
|
1018
|
+
checked: selectedItem != null && isItemEqualToValue(row, selectedItem),
|
|
1019
|
+
disabled: itemToDisabled(row)
|
|
1020
|
+
}) : void 0
|
|
1021
|
+
}) })]
|
|
1022
|
+
});
|
|
1023
|
+
};
|
|
1024
|
+
Combobox$1.Root = ComboboxRoot;
|
|
1025
|
+
Combobox$1.InputGroup = ComboboxInputGroup;
|
|
1026
|
+
Combobox$1.Input = ComboboxInput;
|
|
1027
|
+
Combobox$1.Content = ComboboxContent;
|
|
1028
|
+
Combobox$1.List = ComboboxList;
|
|
1029
|
+
Combobox$1.Item = ComboboxItem;
|
|
1030
|
+
Combobox$1.Empty = ComboboxEmpty;
|
|
1031
|
+
Combobox$1.Value = Combobox.Value;
|
|
1032
|
+
Combobox$1.Separator = ComboboxSeparator;
|
|
1033
|
+
Combobox$1.Group = ComboboxGroup;
|
|
1034
|
+
Combobox$1.GroupLabel = ComboboxGroupLabel;
|
|
1035
|
+
Combobox$1.GroupList = ComboboxCollection;
|
|
1036
|
+
Combobox$1.Chips = ComboboxChips;
|
|
1037
|
+
Combobox$1.Chip = ComboboxChip;
|
|
1038
|
+
//#endregion
|
|
1039
|
+
//#region src/components/Combobox/matchByWords.ts
|
|
1040
|
+
const toWords = (query) => query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
1041
|
+
const isFilled = (text) => text !== null && text !== void 0 && text !== "";
|
|
1042
|
+
const isTextList = (texts) => Array.isArray(texts);
|
|
1043
|
+
/**
|
|
1044
|
+
* Whether every word of `query` occurs in some of `texts`, ignoring case.
|
|
1045
|
+
*
|
|
1046
|
+
* - Words match by containment, across texts, in any order; an empty query matches everything.
|
|
1047
|
+
* - Plain lowercased `includes`, not `Intl.Collator`: `Muller` does not find `Müller`.
|
|
1048
|
+
* - Not interchangeable with kbc-ui's own `matchByWords` (single-space split, keeps empty texts).
|
|
1049
|
+
* - A `filter` for when the searchable text is not the label; else use {@link filterByWords}.
|
|
1050
|
+
*/
|
|
1051
|
+
const matchByWords = (texts, query) => {
|
|
1052
|
+
const words = toWords(query);
|
|
1053
|
+
if (words.length === 0) return true;
|
|
1054
|
+
const haystacks = (isTextList(texts) ? texts : [texts]).filter(isFilled).map((text) => String(text).toLowerCase());
|
|
1055
|
+
return words.every((word) => haystacks.some((haystack) => haystack.includes(word)));
|
|
1056
|
+
};
|
|
1057
|
+
/**
|
|
1058
|
+
* `filter` matching the item's displayed label word by word: `filter={filterByWords}`.
|
|
1059
|
+
*
|
|
1060
|
+
* - Generic, so it keeps the combobox's item type inference.
|
|
1061
|
+
* - Label: `itemToStringLabel` if passed, else the item's `label`, `value`, or string form.
|
|
1062
|
+
* - Only the label is searched, by design: never match what the user cannot see.
|
|
1063
|
+
* - Close over {@link matchByWords} to search other fields.
|
|
1064
|
+
*/
|
|
1065
|
+
const filterByWords = (item, query, itemToString) => matchByWords(itemToString?.(item) ?? toLabel(item), query);
|
|
1066
|
+
//#endregion
|
|
1067
|
+
export { BLANK_VALUES, Combobox$1 as Combobox, ComboboxClearButton, ComboboxOpenButton, ComboboxOptions, createCreatableItem, defaultGroupToLabel, defaultItemToDisabled, defaultItemToIcon, defaultQueryToCreateLabel, defaultRowLabel, defaultToCreateValue, filterByWords, flatItems, isCreatableItem, isGroupHeaderItem, isSelectAllItem, matchByWords, namedLabel, sanitizeTypedInput, selectAllItem, toEntries, toLabel, useCreatableStringValue, useGroupHeaders, useItemEquality, useQueryReporter, useVirtualList, useWithCreated, withBlankValues };
|
|
1068
|
+
|
|
1069
|
+
//# sourceMappingURL=Combobox-CxRAYOBt.js.map
|