@keboola/design 11.6.1 → 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 +50 -9
- package/CHANGELOG.md +241 -0
- package/COMPONENT-API.md +337 -288
- package/README.md +12 -2
- package/dist/{AIKit-CQxVwyAk.js → AIKit-BD4r7ff-.js} +807 -199
- package/dist/AIKit-BD4r7ff-.js.map +1 -0
- package/dist/{Alert-C4Y9IwMI.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-CS9P4r2p.js → BrandEditor-BU23Vl8V.js} +7 -7
- package/dist/{BrandEditor-CS9P4r2p.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-D1id7YXd.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-Bqr6zXcW.js → Checkbox-8yIIgY7g.js} +4 -4
- package/dist/Checkbox-8yIIgY7g.js.map +1 -0
- package/dist/{Clipboard-C2YBRfD8.js → Clipboard-_xf6hMDD.js} +2 -2
- package/dist/{Clipboard-C2YBRfD8.js.map → Clipboard-_xf6hMDD.js.map} +1 -1
- package/dist/{ClipboardButton-CrljClL1.js → ClipboardButton-DHa1trtI.js} +4 -4
- package/dist/{ClipboardButton-CrljClL1.js.map → ClipboardButton-DHa1trtI.js.map} +1 -1
- package/dist/{CodeEditor-C9AS8Ch0.js → CodeEditor-BSo-oLFG.js} +55 -165
- package/dist/CodeEditor-BSo-oLFG.js.map +1 -0
- package/dist/{ColorInput-Dg87lKcR.js → ColorInput-DSMqrs2-.js} +12 -27
- package/dist/ColorInput-DSMqrs2-.js.map +1 -0
- package/dist/{ColorModeSwitch-CsWLiTBX.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-CqxoI_De.js → Command-BU_cVurn.js} +4 -4
- package/dist/{Command-CqxoI_De.js.map → Command-BU_cVurn.js.map} +1 -1
- package/dist/{CopyField-Rx9HPTbJ.js → CopyField-6_c-NdLO.js} +17 -53
- package/dist/{CopyField-Rx9HPTbJ.js.map → CopyField-6_c-NdLO.js.map} +1 -1
- package/dist/{DateInput-DpifECUQ.js → DateInput-DyEErfJf.js} +6 -6
- package/dist/{DateInput-DpifECUQ.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-9MIw7P6L.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-CASr-jgl.js → DropdownMenu-gRM-A8qU.js} +11 -6
- package/dist/DropdownMenu-gRM-A8qU.js.map +1 -0
- package/dist/{FieldItem-DtPTzNef.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-DAaatlBk.js → Form-95rVLfX8.js} +15 -23
- package/dist/{Form-DAaatlBk.js.map → Form-95rVLfX8.js.map} +1 -1
- package/dist/{FormGroup-Bl8JmnzJ.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-DcZRlVnN.js → InputGroup-B4QOPxHl.js} +12 -13
- package/dist/InputGroup-B4QOPxHl.js.map +1 -0
- package/dist/{Kbd-D1Azcc4g.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-CujFxVzk.js → MermaidDiagram-BQvz6bhv.js} +16 -34
- package/dist/MermaidDiagram-BQvz6bhv.js.map +1 -0
- package/dist/{Modal-Coj-H02o.js → Modal-Driyqs_N.js} +17 -34
- package/dist/Modal-Driyqs_N.js.map +1 -0
- package/dist/{ModalTitle-C76ke2eo.js → ModalTitle-BxopkIoQ.js} +3 -3
- package/dist/ModalTitle-BxopkIoQ.js.map +1 -0
- package/dist/{MultiActionButtonGroup-CNNoBQbv.js → MultiActionButtonGroup-BPnmzBtw.js} +3 -3
- package/dist/{MultiActionButtonGroup-CNNoBQbv.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-CUBsuP7r.js → RadioGroup-CBPRLRN0.js} +4 -4
- package/dist/{RadioGroup-CUBsuP7r.js.map → RadioGroup-CBPRLRN0.js.map} +1 -1
- package/dist/{Search-DVpJuzr9.js → Search-DmkQo716.js} +3 -3
- package/dist/{Search-DVpJuzr9.js.map → Search-DmkQo716.js.map} +1 -1
- package/dist/{SearchInput-Q85p8Ews.js → SearchInput-CEfQDNl3.js} +8 -13
- package/dist/SearchInput-CEfQDNl3.js.map +1 -0
- package/dist/{SectionNav-mpmSM3OC.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-Chf0kX1E.js → Sheet-C-yXk5Da.js} +5 -9
- package/dist/Sheet-C-yXk5Da.js.map +1 -0
- package/dist/{Sidebar-CTWsHZhF.js → Sidebar-Ds0E6PbR.js} +181 -33
- package/dist/Sidebar-Ds0E6PbR.js.map +1 -0
- package/dist/{Slider-Bv0B6lI0.js → Slider-DWdu9NuM.js} +3 -3
- package/dist/{Slider-Bv0B6lI0.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-DiEMxVF6.js → TextInput-CDG2XpBl.js} +12 -15
- package/dist/TextInput-CDG2XpBl.js.map +1 -0
- package/dist/{ThemeProvider-BI6JWBdJ.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-BG5Xogxh.js → Timeline-B-I6sb0M.js} +2 -2
- package/dist/{Timeline-BG5Xogxh.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-U_VH3QRO.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 +1461 -1809
- package/dist/index.js +70 -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 +129 -0
- package/dist/internal/blocks/ChipEditor.js.map +1 -0
- 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 +162 -165
- 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 +60 -0
- package/dist/internal/components/StatusDot.js.map +1 -0
- 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 +2 -2
- 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/mergeRefs.js +27 -9
- package/dist/internal/utils/mergeRefs.js.map +1 -1
- package/dist/internal/utils.js +3 -3
- 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-DnkrFYqY.js → utils-Bd28bWgm.js} +53 -20
- 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 +11 -9
- package/src/styles.css +120 -14
- package/src/theme.css +126 -6
- package/dist/AIKit-CQxVwyAk.js.map +0 -1
- package/dist/Alert-C4Y9IwMI.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-D1id7YXd.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-Bqr6zXcW.js.map +0 -1
- package/dist/CodeEditor-C9AS8Ch0.js.map +0 -1
- package/dist/ColorInput-Dg87lKcR.js.map +0 -1
- package/dist/ColorModeSwitch-CsWLiTBX.js.map +0 -1
- package/dist/Combobox-BfanUAqY.js +0 -619
- package/dist/Combobox-BfanUAqY.js.map +0 -1
- package/dist/DateRangeInput-9MIw7P6L.js.map +0 -1
- package/dist/DateRangePicker-DjSUFjh4.js.map +0 -1
- package/dist/DropdownMenu-CASr-jgl.js.map +0 -1
- package/dist/FieldItem-DtPTzNef.js.map +0 -1
- package/dist/FormGroup-Bl8JmnzJ.js.map +0 -1
- package/dist/FullScreenModal-CN9nAs72.js.map +0 -1
- package/dist/InputGroup-DcZRlVnN.js.map +0 -1
- package/dist/Kbd-D1Azcc4g.js.map +0 -1
- package/dist/MermaidDiagram-CujFxVzk.js.map +0 -1
- package/dist/Modal-Coj-H02o.js.map +0 -1
- package/dist/ModalTitle-C76ke2eo.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-Q85p8Ews.js.map +0 -1
- package/dist/SectionNav-mpmSM3OC.js.map +0 -1
- package/dist/Sheet-Chf0kX1E.js.map +0 -1
- package/dist/Sidebar-CTWsHZhF.js.map +0 -1
- package/dist/TextInput-DiEMxVF6.js.map +0 -1
- package/dist/ThemeProvider-BI6JWBdJ.js.map +0 -1
- package/dist/ZoomableSvg-U_VH3QRO.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-DkF6esWL.js +0 -15
- package/dist/useElement-DkF6esWL.js.map +0 -1
- package/dist/utils-DnkrFYqY.js.map +0 -1
- package/dist/vegaTheme-CSvFEMBl.js.map +0 -1
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { Tooltip, TooltipProvider } from "./utils-
|
|
3
|
-
import { AlertCircle, ChevronDown, ChevronLeft, ChevronRight, CircleCheck, CirclePause, CircleX, Loader2, Maximize2, Minimize2, Play, Send, Sparkles, ThumbsDown, ThumbsUp, TriangleAlert, X, XCircle } from "./icons-
|
|
4
|
-
import { Button } from "./Button-
|
|
2
|
+
import { Tooltip, TooltipProvider } from "./utils-Bd28bWgm.js";
|
|
3
|
+
import { AlertCircle, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Ban, BarChart3, Bell, Bug, Calendar, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Circle, CircleAlert, CircleCheck, CircleHelp, CirclePause, CirclePlay, CirclePlus, CircleStop, CircleX, Clock, Cog, Copy, Database, Download, Ellipsis, ExternalLink, Eye, File, FilePen, FileText, Flag, Folder, Gauge, GitBranch, GitMerge, GitPullRequest, Globe, Hand, History, Hourglass, Info, Key, Layers, LineChart, Link, List, ListChecks, Loader2, Lock, Mail, Maximize2, Minimize2, Minus, Pencil, Play, Plus, RefreshCw, Rocket, RotateCcw, RotateCw, Save, Search, Send, Settings, Sparkles, Star, Table, ThumbsDown, ThumbsUp, Trash2, TriangleAlert, Upload, User, Users, WandSparkles, Warehouse, Workflow, X, XCircle, Zap } from "./icons-wcA70iQx.js";
|
|
4
|
+
import { Button } from "./Button-Ca4Q3VJU.js";
|
|
5
5
|
import { ButtonGroup } from "./internal/components/ButtonGroup.js";
|
|
6
|
-
import { ClipboardButton } from "./ClipboardButton-
|
|
7
|
-
import { FullScreenModal, FullScreenModalBody, FullScreenModalHeader } from "./FullScreenModal-
|
|
6
|
+
import { ClipboardButton } from "./ClipboardButton-DHa1trtI.js";
|
|
7
|
+
import { FullScreenModal, FullScreenModalBody, FullScreenModalHeader } from "./FullScreenModal-CD7mYeTz.js";
|
|
8
8
|
import { Truncated } from "./internal/components/Truncated.js";
|
|
9
|
-
import { HoverCard } from "./HoverCard-
|
|
10
|
-
import { Command } from "./Command-
|
|
11
|
-
import { TextInput } from "./TextInput-
|
|
12
|
-
import { Checkbox } from "./Checkbox-
|
|
13
|
-
import { Badge } from "./Badge-
|
|
9
|
+
import { HoverCard } from "./HoverCard-B8OKu9XZ.js";
|
|
10
|
+
import { Command } from "./Command-BU_cVurn.js";
|
|
11
|
+
import { TextInput } from "./TextInput-CDG2XpBl.js";
|
|
12
|
+
import { Checkbox } from "./Checkbox-8yIIgY7g.js";
|
|
13
|
+
import { Badge } from "./Badge-DIjhwPvh.js";
|
|
14
14
|
import { Textarea } from "./internal/blocks/Textarea.js";
|
|
15
|
-
import { Table } from "./Table-
|
|
15
|
+
import { Table as Table$1 } from "./Table-BaVT5Tkn.js";
|
|
16
16
|
import { DiagramSkeleton } from "./internal/blocks/DiagramShared/DiagramSkeleton.js";
|
|
17
17
|
import { DiagramSource } from "./DiagramSource-C5_d8Gdj.js";
|
|
18
18
|
import { Progress } from "./internal/components/Progress.js";
|
|
19
19
|
import { Slot } from "@radix-ui/react-slot";
|
|
20
|
-
import { isValidElement, useCallback, useEffect, useId, useRef, useState } from "react";
|
|
20
|
+
import { createContext, isValidElement, use, useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
21
21
|
import { cva } from "class-variance-authority";
|
|
22
22
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
23
23
|
import TextareaAutosize from "react-textarea-autosize";
|
|
@@ -26,50 +26,85 @@ import remarkGfm from "remark-gfm";
|
|
|
26
26
|
//#region src/blocks/AIKit/AnswerActions.tsx
|
|
27
27
|
const VOTE_BUTTONS = [{
|
|
28
28
|
vote: "up",
|
|
29
|
-
label: "Good answer",
|
|
30
29
|
icon: /* @__PURE__ */ jsx(ThumbsUp, { className: "tw:size-4" })
|
|
31
30
|
}, {
|
|
32
31
|
vote: "down",
|
|
33
|
-
label: "Bad answer",
|
|
34
32
|
icon: /* @__PURE__ */ jsx(ThumbsDown, { className: "tw:size-4" })
|
|
35
33
|
}];
|
|
34
|
+
const DEFAULT_LABELS = {
|
|
35
|
+
up: "Good answer",
|
|
36
|
+
down: "Bad answer"
|
|
37
|
+
};
|
|
38
|
+
/** Roomier for a panel; compact for a dense transcript. */
|
|
39
|
+
const SIZES = {
|
|
40
|
+
small: {
|
|
41
|
+
button: "icon-xs",
|
|
42
|
+
gap: "extra-small"
|
|
43
|
+
},
|
|
44
|
+
medium: {
|
|
45
|
+
button: "icon-sm",
|
|
46
|
+
gap: "little-small"
|
|
47
|
+
}
|
|
48
|
+
};
|
|
36
49
|
/**
|
|
37
|
-
*
|
|
50
|
+
* Copy and thumbs up/down for a finished answer.
|
|
38
51
|
*
|
|
39
|
-
* -
|
|
40
|
-
*
|
|
41
|
-
* -
|
|
42
|
-
* - **A vote can be changed but not withdrawn.** `aria-pressed` says which one is recorded, and
|
|
43
|
-
* both buttons stay focusable so a reader can switch. Pressing the pressed one re-sends the
|
|
44
|
-
* same vote.
|
|
45
|
-
* - The recorded vote and the write are the caller's: the two chats vote against different
|
|
46
|
-
* endpoints, and only the caller knows whether a turn is finished enough to rate.
|
|
52
|
+
* - Always rendered, never hover-only, so it is reachable without a pointer.
|
|
53
|
+
* - A vote can be changed but not withdrawn; pressing the pressed one re-sends it.
|
|
54
|
+
* - The caller owns the recorded vote and the write.
|
|
47
55
|
*/
|
|
48
|
-
const AnswerActions = ({ copyText, vote, onVote }) => {
|
|
56
|
+
const AnswerActions = ({ copyText, vote, onVote, onCopy, actions, labels = DEFAULT_LABELS, confirmation, size = "small", layout = "inline" }) => {
|
|
57
|
+
const { button, gap } = SIZES[size];
|
|
58
|
+
const votes = VOTE_BUTTONS.map(({ vote: candidate, icon }) => {
|
|
59
|
+
const isRecorded = vote === candidate;
|
|
60
|
+
const label = labels[candidate];
|
|
61
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
62
|
+
tooltip: label,
|
|
63
|
+
placement: "top",
|
|
64
|
+
triggerAsChild: true,
|
|
65
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
66
|
+
size: button,
|
|
67
|
+
variant: "invisible",
|
|
68
|
+
className: cn(isRecorded && candidate === "up" && "tw:bg-success/10 tw:text-success tw:hover:not-disabled:bg-success/20 tw:hover:not-disabled:text-success", isRecorded && candidate === "down" && "tw:bg-destructive/10 tw:text-destructive tw:hover:not-disabled:bg-destructive/20 tw:hover:not-disabled:text-destructive"),
|
|
69
|
+
"aria-label": label,
|
|
70
|
+
"aria-pressed": isRecorded,
|
|
71
|
+
onClick: () => onVote(candidate),
|
|
72
|
+
children: icon
|
|
73
|
+
})
|
|
74
|
+
}, candidate);
|
|
75
|
+
});
|
|
76
|
+
const copy = copyText ? /* @__PURE__ */ jsx(ClipboardButton, {
|
|
77
|
+
text: copyText,
|
|
78
|
+
tooltip: "Copy answer",
|
|
79
|
+
size: button,
|
|
80
|
+
variant: "invisible",
|
|
81
|
+
onClick: onCopy
|
|
82
|
+
}) : null;
|
|
83
|
+
const said = confirmation ? /* @__PURE__ */ jsx("span", {
|
|
84
|
+
"aria-live": "polite",
|
|
85
|
+
className: "tw:ml-1 tw:text-xs tw:font-medium tw:text-foreground tw:empty:hidden tw:animate-in tw:fade-in tw:slide-in-from-left-1 tw:duration-300",
|
|
86
|
+
children: vote ? confirmation[vote] : ""
|
|
87
|
+
}) : null;
|
|
88
|
+
if (layout === "split") return /* @__PURE__ */ jsxs("div", {
|
|
89
|
+
className: "tw:flex tw:w-full tw:items-center tw:justify-between tw:gap-2",
|
|
90
|
+
children: [/* @__PURE__ */ jsxs(ButtonGroup, {
|
|
91
|
+
space: gap,
|
|
92
|
+
"aria-label": "Answer actions",
|
|
93
|
+
children: [votes, said]
|
|
94
|
+
}), /* @__PURE__ */ jsxs(ButtonGroup, {
|
|
95
|
+
space: gap,
|
|
96
|
+
children: [actions, copy]
|
|
97
|
+
})]
|
|
98
|
+
});
|
|
49
99
|
return /* @__PURE__ */ jsxs(ButtonGroup, {
|
|
50
|
-
space:
|
|
100
|
+
space: gap,
|
|
51
101
|
"aria-label": "Answer actions",
|
|
52
|
-
children: [
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const isRecorded = vote === candidate;
|
|
59
|
-
return /* @__PURE__ */ jsx(Tooltip, {
|
|
60
|
-
tooltip: label,
|
|
61
|
-
placement: "top",
|
|
62
|
-
triggerAsChild: true,
|
|
63
|
-
children: /* @__PURE__ */ jsx(Button, {
|
|
64
|
-
size: "icon-xs",
|
|
65
|
-
variant: isRecorded ? "secondary" : "invisible",
|
|
66
|
-
"aria-label": label,
|
|
67
|
-
"aria-pressed": isRecorded,
|
|
68
|
-
onClick: () => onVote(candidate),
|
|
69
|
-
children: icon
|
|
70
|
-
})
|
|
71
|
-
}, candidate);
|
|
72
|
-
})]
|
|
102
|
+
children: [
|
|
103
|
+
copy,
|
|
104
|
+
votes,
|
|
105
|
+
actions,
|
|
106
|
+
said
|
|
107
|
+
]
|
|
73
108
|
});
|
|
74
109
|
};
|
|
75
110
|
//#endregion
|
|
@@ -98,6 +133,12 @@ const variantClasses = {
|
|
|
98
133
|
dismissed: "tw:text-muted-foreground tw:focus-visible:outline-ring tw:not-disabled:hover:text-foreground"
|
|
99
134
|
};
|
|
100
135
|
const iconClasses = "tw:size-3.5 tw:shrink-0 tw:basis-3.5 tw:opacity-70";
|
|
136
|
+
const variantStatus = {
|
|
137
|
+
success: "finished",
|
|
138
|
+
error: "failed",
|
|
139
|
+
processing: "running",
|
|
140
|
+
dismissed: "not run"
|
|
141
|
+
};
|
|
101
142
|
const renderVariantIcon$1 = (variant) => {
|
|
102
143
|
if (variant === "processing") return /* @__PURE__ */ jsx(Loader2, { className: cn(iconClasses, "tw:animate-spin") });
|
|
103
144
|
if (variant === "error" || variant === "dismissed") return /* @__PURE__ */ jsx(XCircle, { className: iconClasses });
|
|
@@ -108,13 +149,21 @@ const CollapsibleStepHeader = ({ isExpanded, onToggle, label, variant = "success
|
|
|
108
149
|
type: "button",
|
|
109
150
|
"aria-expanded": isExpanded,
|
|
110
151
|
onClick: onToggle,
|
|
152
|
+
"data-variant": variant,
|
|
111
153
|
className: cn("tw:flex tw:w-fit tw:items-center tw:gap-1.5 tw:text-left tw:text-xs tw:font-medium tw:transition-colors tw:focus-visible:outline tw:focus-visible:outline-2 tw:focus-visible:outline-offset-2 tw:disabled:opacity-40", variantClasses[variant]),
|
|
112
154
|
children: [renderVariantIcon$1(variant), /* @__PURE__ */ jsxs("span", {
|
|
113
155
|
className: "tw:min-w-0",
|
|
114
|
-
children: [
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
156
|
+
children: [
|
|
157
|
+
label,
|
|
158
|
+
/* @__PURE__ */ jsx("span", {
|
|
159
|
+
className: "tw:sr-only",
|
|
160
|
+
children: ` (${variantStatus[variant]})`
|
|
161
|
+
}),
|
|
162
|
+
/* @__PURE__ */ jsxs("span", {
|
|
163
|
+
className: "tw:whitespace-nowrap",
|
|
164
|
+
children: ["", /* @__PURE__ */ jsx(ChevronDown, { className: cn("tw:ml-1.5 tw:inline-block tw:size-3.5 tw:align-middle tw:transition-transform", isExpanded && "tw:rotate-180") })]
|
|
165
|
+
})
|
|
166
|
+
]
|
|
118
167
|
})]
|
|
119
168
|
});
|
|
120
169
|
};
|
|
@@ -189,20 +238,236 @@ const AnswerSummary = ({ items, variant = "success", noAnswerLabel = "No answer"
|
|
|
189
238
|
});
|
|
190
239
|
};
|
|
191
240
|
//#endregion
|
|
241
|
+
//#region src/blocks/AIKit/ChatInlineIcon.tsx
|
|
242
|
+
/**
|
|
243
|
+
* The Lucide component each `icon:<name>` token draws.
|
|
244
|
+
*
|
|
245
|
+
* - Names are FontAwesome-solid ones, published as `CHAT_INLINE_ICON_NAMES`.
|
|
246
|
+
* - The `satisfies` is the drift guard: a name the prompt teaches and this map lacks fails to compile.
|
|
247
|
+
* - Read through `Object.hasOwn`: `icon:constructor` would otherwise hit `Object.prototype`.
|
|
248
|
+
*/
|
|
249
|
+
const ICON_REGISTRY = {
|
|
250
|
+
"alert-circle": AlertCircle,
|
|
251
|
+
"arrow-down": ArrowDown,
|
|
252
|
+
"arrow-left": ArrowLeft,
|
|
253
|
+
"arrow-right": ArrowRight,
|
|
254
|
+
"arrow-rotate-back": RotateCcw,
|
|
255
|
+
"arrow-rotate-left": RotateCcw,
|
|
256
|
+
"arrow-rotate-right": RotateCw,
|
|
257
|
+
"arrow-up": ArrowUp,
|
|
258
|
+
"arrow-up-right-from-square": ExternalLink,
|
|
259
|
+
"arrows-rotate": RefreshCw,
|
|
260
|
+
analytics: BarChart3,
|
|
261
|
+
ban: Ban,
|
|
262
|
+
bell: Bell,
|
|
263
|
+
bug: Bug,
|
|
264
|
+
calendar: Calendar,
|
|
265
|
+
changes: FilePen,
|
|
266
|
+
"chart-line": LineChart,
|
|
267
|
+
check: Check,
|
|
268
|
+
"check-circle": CircleCheck,
|
|
269
|
+
"chevron-down": ChevronDown,
|
|
270
|
+
"chevron-left": ChevronLeft,
|
|
271
|
+
"chevron-right": ChevronRight,
|
|
272
|
+
"chevron-up": ChevronUp,
|
|
273
|
+
circle: Circle,
|
|
274
|
+
"circle-check": CircleCheck,
|
|
275
|
+
"circle-exclamation": CircleAlert,
|
|
276
|
+
"circle-info": Info,
|
|
277
|
+
"circle-pause": CirclePause,
|
|
278
|
+
"circle-play": CirclePlay,
|
|
279
|
+
"circle-plus": CirclePlus,
|
|
280
|
+
"circle-question": CircleHelp,
|
|
281
|
+
"circle-stop": CircleStop,
|
|
282
|
+
"circle-xmark": CircleX,
|
|
283
|
+
clock: Clock,
|
|
284
|
+
"clock-rotate-left": History,
|
|
285
|
+
"code-branch": GitBranch,
|
|
286
|
+
"code-merge": GitMerge,
|
|
287
|
+
"code-pull-request": GitPullRequest,
|
|
288
|
+
cog: Cog,
|
|
289
|
+
configuration: Settings,
|
|
290
|
+
copy: Copy,
|
|
291
|
+
database: Database,
|
|
292
|
+
"diagram-project": Workflow,
|
|
293
|
+
download: Download,
|
|
294
|
+
ellipsis: Ellipsis,
|
|
295
|
+
envelope: Mail,
|
|
296
|
+
"exclamation-circle": CircleAlert,
|
|
297
|
+
"exclamation-triangle": TriangleAlert,
|
|
298
|
+
eye: Eye,
|
|
299
|
+
file: File,
|
|
300
|
+
"file-lines": FileText,
|
|
301
|
+
flag: Flag,
|
|
302
|
+
folder: Folder,
|
|
303
|
+
gauge: Gauge,
|
|
304
|
+
gear: Settings,
|
|
305
|
+
globe: Globe,
|
|
306
|
+
hand: Hand,
|
|
307
|
+
"hourglass-half": Hourglass,
|
|
308
|
+
"info-circle": Info,
|
|
309
|
+
key: Key,
|
|
310
|
+
"layer-group": Layers,
|
|
311
|
+
link: Link,
|
|
312
|
+
"list-check": ListChecks,
|
|
313
|
+
"list-ul": List,
|
|
314
|
+
lock: Lock,
|
|
315
|
+
"magnifying-glass": Search,
|
|
316
|
+
minus: Minus,
|
|
317
|
+
"paper-plane-top": Send,
|
|
318
|
+
pen: Pencil,
|
|
319
|
+
play: Play,
|
|
320
|
+
plus: Plus,
|
|
321
|
+
refresh: RefreshCw,
|
|
322
|
+
rocket: Rocket,
|
|
323
|
+
save: Save,
|
|
324
|
+
"save-changes": Save,
|
|
325
|
+
search: Search,
|
|
326
|
+
spinner: Loader2,
|
|
327
|
+
sparkles: Sparkles,
|
|
328
|
+
star: Star,
|
|
329
|
+
stop: CircleStop,
|
|
330
|
+
table: Table,
|
|
331
|
+
"thumbs-down": ThumbsDown,
|
|
332
|
+
"thumbs-up": ThumbsUp,
|
|
333
|
+
transformation: WandSparkles,
|
|
334
|
+
trash: Trash2,
|
|
335
|
+
"triangle-exclamation": TriangleAlert,
|
|
336
|
+
upload: Upload,
|
|
337
|
+
user: User,
|
|
338
|
+
"user-group": Users,
|
|
339
|
+
warning: TriangleAlert,
|
|
340
|
+
warehouse: Warehouse,
|
|
341
|
+
xmark: X,
|
|
342
|
+
zap: Zap
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* Extra classes a single name needs.
|
|
346
|
+
*
|
|
347
|
+
* - `spinner` spins (per `MAINTAINING.md`): a still `Loader2` reads as a broken ring.
|
|
348
|
+
* - Read through `Object.hasOwn`, like the registry.
|
|
349
|
+
*/
|
|
350
|
+
const ICON_CLASSES = { spinner: "tw:animate-spin" };
|
|
351
|
+
/**
|
|
352
|
+
* A whole `icon:<name>` token and nothing else.
|
|
353
|
+
*
|
|
354
|
+
* - Must match the name shape `remarkIconSyntax` (`@keboola/kai-chat`) accepts.
|
|
355
|
+
* - Anchored, so inline code like `` `icon: database` `` or `` `icon:` `` stays code.
|
|
356
|
+
*/
|
|
357
|
+
const TOKEN = /^icon:([a-z][a-z0-9-]*)$/;
|
|
358
|
+
/** Built once: an answer is re-parsed per streamed chunk, so `isArriving` runs per code node. */
|
|
359
|
+
const ICON_NAMES = Object.keys(ICON_REGISTRY);
|
|
360
|
+
/** Whether a name is a strict prefix of a registry name: `tabl` → `true`, `table-name` → `false`. */
|
|
361
|
+
const isArriving = (name) => ICON_NAMES.some((key) => key.length > name.length && key.startsWith(name));
|
|
362
|
+
/**
|
|
363
|
+
* The icon name in a code node's text, if the text is a token — drawn, or still arriving.
|
|
364
|
+
*
|
|
365
|
+
* - An unknown name → `undefined`, so the call site's `<code>` fall-through keeps the text.
|
|
366
|
+
* - A prefix of a known name is a token still streaming; `<ChatInlineIcon />` draws it blank.
|
|
367
|
+
* - A name that is both (`save`, of `save-changes`) is drawn now.
|
|
368
|
+
*/
|
|
369
|
+
const getChatInlineIconName = (text) => {
|
|
370
|
+
const name = TOKEN.exec(text)?.[1];
|
|
371
|
+
if (name === void 0) return void 0;
|
|
372
|
+
return Object.hasOwn(ICON_REGISTRY, name) || isArriving(name) ? name : void 0;
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
* One inline `icon:<name>` token, drawn at the size of the text it leads.
|
|
376
|
+
*
|
|
377
|
+
* - An unknown name (a token still arriving) renders nothing.
|
|
378
|
+
* - `mr` widens the single source space, which reads as cramped beside a glyph.
|
|
379
|
+
* - The heavier stroke holds its own beside a bold heading.
|
|
380
|
+
* - `aria-hidden`: the token's text is removed, so the glyph has no label to announce.
|
|
381
|
+
*/
|
|
382
|
+
const ChatInlineIcon = ({ name }) => {
|
|
383
|
+
const Icon = Object.hasOwn(ICON_REGISTRY, name) ? ICON_REGISTRY[name] : void 0;
|
|
384
|
+
if (Icon === void 0) return null;
|
|
385
|
+
return /* @__PURE__ */ jsx(Icon, {
|
|
386
|
+
"aria-hidden": true,
|
|
387
|
+
className: cn("tw:mr-[0.15em] tw:inline-block tw:size-[1em] tw:shrink-0 tw:align-[-0.125em] tw:text-muted-foreground", Object.hasOwn(ICON_CLASSES, name) ? ICON_CLASSES[name] : void 0),
|
|
388
|
+
strokeWidth: 2.25
|
|
389
|
+
});
|
|
390
|
+
};
|
|
391
|
+
//#endregion
|
|
392
|
+
//#region src/blocks/AIKit/FileDownloadChip.tsx
|
|
393
|
+
/**
|
|
394
|
+
* A file the agent wrote, offered inside its own answer.
|
|
395
|
+
*
|
|
396
|
+
* - The whole chip is the control: a small icon beside a truncating filename is hard to hit.
|
|
397
|
+
* - Presentation only — the host fetches and saves, through its own auth.
|
|
398
|
+
*/
|
|
399
|
+
const FileDownloadChip = ({ fileName, filePath, size, isPending = false, onDownload, className }) => /* @__PURE__ */ jsxs(Button, {
|
|
400
|
+
variant: "secondary",
|
|
401
|
+
size: "small",
|
|
402
|
+
isLoading: isPending,
|
|
403
|
+
"aria-disabled": isPending,
|
|
404
|
+
"aria-label": `Download ${filePath ?? fileName}`,
|
|
405
|
+
title: filePath,
|
|
406
|
+
onClick: () => {
|
|
407
|
+
if (!isPending) onDownload();
|
|
408
|
+
},
|
|
409
|
+
className: cn("tw:max-w-full tw:justify-start tw:gap-2 tw:font-normal", className),
|
|
410
|
+
children: [
|
|
411
|
+
!isPending && /* @__PURE__ */ jsx(FileText, { className: "tw:size-4 tw:shrink-0 tw:text-muted-foreground" }),
|
|
412
|
+
/* @__PURE__ */ jsx("span", {
|
|
413
|
+
className: "tw:truncate",
|
|
414
|
+
children: fileName
|
|
415
|
+
}),
|
|
416
|
+
size !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
417
|
+
className: "tw:shrink-0 tw:text-xs tw:text-muted-foreground",
|
|
418
|
+
children: size
|
|
419
|
+
}),
|
|
420
|
+
!isPending && /* @__PURE__ */ jsx(Download, { className: "tw:size-4 tw:shrink-0" })
|
|
421
|
+
]
|
|
422
|
+
});
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/blocks/AIKit/InlineStepGroup.tsx
|
|
425
|
+
/** The surface colour, as the custom property the step icons mask against. */
|
|
426
|
+
const surfaceStyle = (surface) => ({ "--inline-step-surface": surface });
|
|
427
|
+
/**
|
|
428
|
+
* A collapsible run of agent steps behind one summary line; rows arrive as children.
|
|
429
|
+
*
|
|
430
|
+
* - Connector sits at the icon centre line (`pl-5` + half a `size-5` box), drawn once so it
|
|
431
|
+
* survives icon-less rows.
|
|
432
|
+
* - Animates `grid-template-rows`; children stay mounted while closed.
|
|
433
|
+
* - `role="group"`, not a `region` landmark: dozens per transcript would drown real landmarks.
|
|
434
|
+
*/
|
|
435
|
+
const InlineStepGroup = ({ label, variant = "success", isExpanded, onToggle, surface = "rgb(var(--background))", "aria-label": ariaLabel, "data-testid": testId, className, children }) => /* @__PURE__ */ jsxs("section", {
|
|
436
|
+
role: "group",
|
|
437
|
+
className: cn("tw:flex tw:flex-col", className),
|
|
438
|
+
"aria-label": ariaLabel,
|
|
439
|
+
"data-testid": testId,
|
|
440
|
+
children: [/* @__PURE__ */ jsx(CollapsibleStepHeader, {
|
|
441
|
+
isExpanded,
|
|
442
|
+
onToggle,
|
|
443
|
+
label,
|
|
444
|
+
variant
|
|
445
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
446
|
+
className: cn("tw:grid tw:transition-[grid-template-rows] tw:duration-200 tw:ease-out tw:motion-reduce:transition-none", isExpanded ? "tw:grid-rows-[1fr]" : "tw:grid-rows-[0fr]"),
|
|
447
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
448
|
+
className: "tw:min-h-0 tw:overflow-hidden",
|
|
449
|
+
inert: !isExpanded,
|
|
450
|
+
"aria-hidden": isExpanded ? void 0 : true,
|
|
451
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
452
|
+
style: surfaceStyle(surface),
|
|
453
|
+
className: "tw:relative tw:flex tw:flex-col tw:gap-4 tw:pt-4 tw:pl-5",
|
|
454
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
455
|
+
"aria-hidden": "true",
|
|
456
|
+
className: "tw:pointer-events-none tw:absolute tw:top-4 tw:bottom-0 tw:left-[30px] tw:w-px tw:bg-border"
|
|
457
|
+
}), children]
|
|
458
|
+
})
|
|
459
|
+
})
|
|
460
|
+
})]
|
|
461
|
+
});
|
|
462
|
+
//#endregion
|
|
192
463
|
//#region src/blocks/AIKit/DiagramBlock.tsx
|
|
193
464
|
/**
|
|
194
465
|
* One diagram block: a skeleton while its chunk loads, the fence source plus a retry if it fails.
|
|
195
466
|
*
|
|
196
|
-
* -
|
|
197
|
-
*
|
|
198
|
-
* -
|
|
199
|
-
*
|
|
200
|
-
* a background loop would retry that one forever.
|
|
201
|
-
* - The failure is already logged by the loader, which knows the chunk's name.
|
|
202
|
-
* - A new `load` resets the block: every fence renders this same component type, so a block that
|
|
203
|
-
* switches dialect would otherwise keep drawing through the dialect it had before.
|
|
204
|
-
* - Both the renderer and the loader are functions held in state, so they go in through the
|
|
205
|
-
* setter form — React runs a bare function as a lazy initializer or an updater instead.
|
|
467
|
+
* - Each attempt is a fresh fetch; the loader drops its rejected promise and logs the failure.
|
|
468
|
+
* - Retry is manual: a chunk gone after a deploy never returns, so a timer would loop forever.
|
|
469
|
+
* - A new `load` resets the block, or a dialect switch keeps the previous renderer.
|
|
470
|
+
* - Functions in state go through the setter form, or React calls them.
|
|
206
471
|
*/
|
|
207
472
|
const DiagramBlock = ({ load, code }) => {
|
|
208
473
|
const [Diagram, setDiagram] = useState(null);
|
|
@@ -241,16 +506,12 @@ const DiagramBlock = ({ load, code }) => {
|
|
|
241
506
|
//#endregion
|
|
242
507
|
//#region src/blocks/AIKit/diagramChunk.ts
|
|
243
508
|
/**
|
|
244
|
-
* An on-demand diagram chunk
|
|
509
|
+
* An on-demand diagram chunk, shared between mounts and retryable.
|
|
245
510
|
*
|
|
246
|
-
* - `lazy()
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* -
|
|
250
|
-
* - A failed one is cleared, so the next mount imports again. Same contract as
|
|
251
|
-
* `getFlintRuntime()` one level down, inside `FlintChart`.
|
|
252
|
-
* - The failure is logged here, where the chunk's name is known, so the swap to plain source is
|
|
253
|
-
* never silent and a retry that fails again says so.
|
|
511
|
+
* - Not `lazy()`: it memoizes a failed import, stranding every diagram until a reload.
|
|
512
|
+
* - A resolved import is kept; a failed one is cleared so the next mount retries.
|
|
513
|
+
* - Same contract as `getFlintRuntime()` in `FlintChart`.
|
|
514
|
+
* - Failures are logged here, where the chunk's name is known.
|
|
254
515
|
*/
|
|
255
516
|
const diagramChunk = (name, load) => {
|
|
256
517
|
let pending = null;
|
|
@@ -267,7 +528,10 @@ const diagramChunk = (name, load) => {
|
|
|
267
528
|
//#region src/blocks/AIKit/Markdown.tsx
|
|
268
529
|
const loadMermaid = diagramChunk("MermaidDiagram", () => import("@keboola/design/mermaid").then((module) => module.MermaidDiagram));
|
|
269
530
|
const loadFlint = diagramChunk("FlintChart", () => import("@keboola/design/flint").then((module) => module.FlintChart));
|
|
270
|
-
const
|
|
531
|
+
const PROSE_CLASS = {
|
|
532
|
+
answer: "tw:prose tw:prose-answer tw:prose-code-chip tw:break-words",
|
|
533
|
+
chrome: "tw:prose tw:prose-sm tw:prose-code-chip tw:break-words"
|
|
534
|
+
};
|
|
271
535
|
const getText = (node) => {
|
|
272
536
|
if (typeof node === "string") return node;
|
|
273
537
|
if (typeof node === "number") return String(node);
|
|
@@ -282,25 +546,14 @@ const getLanguage = (element) => {
|
|
|
282
546
|
if (typeof props.className !== "string") return void 0;
|
|
283
547
|
return props.className.match(/language-(\S+)/)?.[1];
|
|
284
548
|
};
|
|
285
|
-
/**
|
|
286
|
-
* The plugins this renderer always runs.
|
|
287
|
-
*
|
|
288
|
-
* - GFM is part of its contract: tables route through the design `Table`, and autolinks and
|
|
289
|
-
* task lists are what an assistant answer is written in.
|
|
290
|
-
* - A caller's own plugins are appended to these, never substituted for them.
|
|
291
|
-
*/
|
|
549
|
+
/** Always run; a caller's plugins are appended, never substituted. */
|
|
292
550
|
const baseRemarkPlugins = [remarkGfm];
|
|
293
551
|
/**
|
|
294
552
|
* Fence language → the on-demand chunk that draws it.
|
|
295
553
|
*
|
|
296
|
-
* -
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
* - `flint-chart` is an alias — it is the fence tag flint's own docs use, so a model emits it
|
|
300
|
-
* unprompted often enough to matter. `markdownComponents.tsx` in kbc-ui carries the same pair.
|
|
301
|
-
* - Read through `Object.hasOwn`, never by plain index: a fence tagged ```constructor or
|
|
302
|
-
* ```valueOf otherwise answers with an `Object.prototype` member, which is truthy, and calling
|
|
303
|
-
* it as a loader throws — taking the whole message subtree down with it.
|
|
554
|
+
* - Dialects come from kai-agent's prompt; keep in sync with kbc-ui `markdownComponents.tsx`.
|
|
555
|
+
* - `flint-chart`: alias models emit unprompted.
|
|
556
|
+
* - Read via `Object.hasOwn`: ```constructor would otherwise hit `Object.prototype` and throw.
|
|
304
557
|
*/
|
|
305
558
|
const DIAGRAM_CHUNKS = {
|
|
306
559
|
mermaid: loadMermaid,
|
|
@@ -310,14 +563,32 @@ const DIAGRAM_CHUNKS = {
|
|
|
310
563
|
/**
|
|
311
564
|
* The fence languages this renderer draws instead of printing.
|
|
312
565
|
*
|
|
313
|
-
* -
|
|
314
|
-
*
|
|
315
|
-
* keystroke fetches the chunk. Sharing the list is what keeps that hold-back from missing a
|
|
316
|
-
* dialect this map has and the caller does not.
|
|
317
|
-
* - Frozen, because it is that shared contract: a consumer that pushed onto it would change how
|
|
318
|
-
* every other app in the same bundle holds a fence back.
|
|
566
|
+
* - Streaming callers hold an open fence back as plain code, or every keystroke fetches the chunk.
|
|
567
|
+
* - Frozen: it is shared across every app in the bundle.
|
|
319
568
|
*/
|
|
320
569
|
const DIAGRAM_LANGUAGES = Object.freeze(Object.keys(DIAGRAM_CHUNKS));
|
|
570
|
+
/**
|
|
571
|
+
* Whether the `code` being rendered sits inside a fenced block.
|
|
572
|
+
*
|
|
573
|
+
* - Set by `pre`: a fence without info string has no `language-…` class, like inline code.
|
|
574
|
+
*/
|
|
575
|
+
const CodeBlockContext = createContext(false);
|
|
576
|
+
/**
|
|
577
|
+
* The `code` renderer: an inline `icon:<name>` token becomes the icon it names.
|
|
578
|
+
*
|
|
579
|
+
* - Fenced blocks never swap.
|
|
580
|
+
* - Unknown names stay code; a name still streaming renders nothing.
|
|
581
|
+
*/
|
|
582
|
+
const MarkdownCode = ({ children, className, ...props }) => {
|
|
583
|
+
const { node: _node, ...rest } = props;
|
|
584
|
+
const name = use(CodeBlockContext) ? void 0 : getChatInlineIconName(getText(children));
|
|
585
|
+
if (name !== void 0) return /* @__PURE__ */ jsx(ChatInlineIcon, { name });
|
|
586
|
+
return /* @__PURE__ */ jsx("code", {
|
|
587
|
+
className,
|
|
588
|
+
...rest,
|
|
589
|
+
children
|
|
590
|
+
});
|
|
591
|
+
};
|
|
321
592
|
const baseComponents = {
|
|
322
593
|
pre({ children, ...props }) {
|
|
323
594
|
const child = Array.isArray(children) ? children[0] : children;
|
|
@@ -344,10 +615,14 @@ const baseComponents = {
|
|
|
344
615
|
})
|
|
345
616
|
}), /* @__PURE__ */ jsx("pre", {
|
|
346
617
|
...rest,
|
|
347
|
-
children
|
|
618
|
+
children: /* @__PURE__ */ jsx(CodeBlockContext, {
|
|
619
|
+
value: true,
|
|
620
|
+
children
|
|
621
|
+
})
|
|
348
622
|
})]
|
|
349
623
|
});
|
|
350
624
|
},
|
|
625
|
+
code: MarkdownCode,
|
|
351
626
|
a({ children, href, ...props }) {
|
|
352
627
|
const { node: _node, ...rest } = props;
|
|
353
628
|
const isExternal = !!href && /^https?:\/\//.test(href);
|
|
@@ -365,7 +640,7 @@ const baseComponents = {
|
|
|
365
640
|
const { node: _node, ...rest } = props;
|
|
366
641
|
return /* @__PURE__ */ jsx("div", {
|
|
367
642
|
className: "tw:not-prose tw:my-4",
|
|
368
|
-
children: /* @__PURE__ */ jsx(Table, {
|
|
643
|
+
children: /* @__PURE__ */ jsx(Table$1, {
|
|
369
644
|
bordered: true,
|
|
370
645
|
className: cn("tw:!mb-0", className),
|
|
371
646
|
...rest
|
|
@@ -374,74 +649,80 @@ const baseComponents = {
|
|
|
374
649
|
},
|
|
375
650
|
thead(props) {
|
|
376
651
|
const { node: _node, ...rest } = props;
|
|
377
|
-
return /* @__PURE__ */ jsx(Table.Header, { ...rest });
|
|
652
|
+
return /* @__PURE__ */ jsx(Table$1.Header, { ...rest });
|
|
378
653
|
},
|
|
379
654
|
tbody(props) {
|
|
380
655
|
const { node: _node, ...rest } = props;
|
|
381
|
-
return /* @__PURE__ */ jsx(Table.Body, { ...rest });
|
|
656
|
+
return /* @__PURE__ */ jsx(Table$1.Body, { ...rest });
|
|
382
657
|
},
|
|
383
658
|
tr(props) {
|
|
384
659
|
const { node: _node, ...rest } = props;
|
|
385
|
-
return /* @__PURE__ */ jsx(Table.Row, { ...rest });
|
|
660
|
+
return /* @__PURE__ */ jsx(Table$1.Row, { ...rest });
|
|
386
661
|
},
|
|
387
662
|
th(props) {
|
|
388
663
|
const { node: _node, ...rest } = props;
|
|
389
|
-
return /* @__PURE__ */ jsx(Table.Head, { ...rest });
|
|
664
|
+
return /* @__PURE__ */ jsx(Table$1.Head, { ...rest });
|
|
390
665
|
},
|
|
391
666
|
td(props) {
|
|
392
667
|
const { node: _node, ...rest } = props;
|
|
393
|
-
return /* @__PURE__ */ jsx(Table.Cell, { ...rest });
|
|
668
|
+
return /* @__PURE__ */ jsx(Table$1.Cell, { ...rest });
|
|
394
669
|
}
|
|
395
670
|
};
|
|
396
671
|
/**
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
672
|
+
* The prose surface an answer is drawn on.
|
|
673
|
+
*
|
|
674
|
+
* - Wrap all `Block`s of one answer in one `Root`, so `:first-child`/`:last-child` span the reply.
|
|
675
|
+
* - `data-prose` is `MessageBubble`'s colour hook; Tailwind can't target `tw:prose` directly.
|
|
676
|
+
* - Spacing overrides need `!`: `tw:prose-answer` rules are `(0,2,1)`, above `[&_p]:mb-1`.
|
|
400
677
|
*/
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
};
|
|
678
|
+
const MarkdownRoot = ({ children, className, rhythm = "answer" }) => /* @__PURE__ */ jsx("div", {
|
|
679
|
+
"data-prose": true,
|
|
680
|
+
className: cn(PROSE_CLASS[rhythm], className),
|
|
681
|
+
children
|
|
682
|
+
});
|
|
683
|
+
/** One parsed piece of an answer, with no surface of its own; memoise at the call site. */
|
|
684
|
+
const MarkdownBlock = ({ children, remarkPlugins, components: componentOverrides }) => /* @__PURE__ */ jsx(ReactMarkdown, {
|
|
685
|
+
remarkPlugins: remarkPlugins === void 0 ? baseRemarkPlugins : [...baseRemarkPlugins, ...remarkPlugins],
|
|
686
|
+
components: componentOverrides === void 0 ? baseComponents : {
|
|
687
|
+
...baseComponents,
|
|
688
|
+
...componentOverrides
|
|
689
|
+
},
|
|
690
|
+
children
|
|
691
|
+
});
|
|
692
|
+
/**
|
|
693
|
+
* Read-only GFM Markdown renderer with design-token typography.
|
|
694
|
+
*
|
|
695
|
+
* - Needs a `TooltipProvider` at the app root (code copy button).
|
|
696
|
+
* - Pass `rhythm="chrome"` for content a model did not write.
|
|
697
|
+
*/
|
|
698
|
+
const Markdown = ({ className, rhythm, ...blockProps }) => /* @__PURE__ */ jsx(MarkdownRoot, {
|
|
699
|
+
className,
|
|
700
|
+
rhythm,
|
|
701
|
+
children: /* @__PURE__ */ jsx(MarkdownBlock, { ...blockProps })
|
|
702
|
+
});
|
|
703
|
+
Markdown.Root = MarkdownRoot;
|
|
704
|
+
Markdown.Block = MarkdownBlock;
|
|
415
705
|
//#endregion
|
|
416
706
|
//#region src/blocks/AIKit/MarkdownTable.tsx
|
|
417
707
|
/** How much wider than its column a table has to be before the column is the wrong surface. */
|
|
418
708
|
const EXPAND_RATIO = 1.5;
|
|
419
709
|
/**
|
|
420
|
-
* The
|
|
710
|
+
* The fade's end colour — must match the host's surface, or it draws a strip over the data.
|
|
421
711
|
*
|
|
422
|
-
* -
|
|
423
|
-
* token and it draws a contrasting strip over the data instead of hiding it.
|
|
424
|
-
* - Full class strings, not a composed `tw:from-${token}`: Tailwind reads literals.
|
|
712
|
+
* - Full class strings: Tailwind reads literals.
|
|
425
713
|
*/
|
|
426
714
|
const FADE_SURFACE = {
|
|
427
715
|
card: "tw:from-card",
|
|
428
716
|
background: "tw:from-background"
|
|
429
717
|
};
|
|
430
718
|
/**
|
|
431
|
-
* A table in an answer
|
|
719
|
+
* A table in an answer that shows when it is cut off on the right.
|
|
432
720
|
*
|
|
433
|
-
* -
|
|
434
|
-
* - The
|
|
435
|
-
*
|
|
436
|
-
*
|
|
437
|
-
* -
|
|
438
|
-
* - A painted gradient rather than the `tw:scroll-fade-x` mask, which needs scroll-driven
|
|
439
|
-
* animations: the build floor is `baseline-widely-available` (Safari 16, Firefox 104), and there
|
|
440
|
-
* the utility either fades both edges of a table that fits or, behind the `supports-` guard
|
|
441
|
-
* `PageLayout` uses, says nothing at all — which is the state this component exists to end. The
|
|
442
|
-
* mask also has to sit on the scrolling element, and that is `Table`'s own container, not ours.
|
|
443
|
-
* - Past `EXPAND_RATIO` the fade is joined by `onExpand`'s action, drawn without waiting for a
|
|
444
|
-
* hover: it reports that content is cut off, which the reader needs before going looking.
|
|
721
|
+
* - Controls sit in a fixed-height rail above the grid, so they never cover rows or shift them.
|
|
722
|
+
* - The fade shows only while content remains to the right.
|
|
723
|
+
* - A painted gradient, not `tw:scroll-fade-x`: that needs scroll-driven animations, which the
|
|
724
|
+
* `baseline-widely-available` build floor lacks, and must sit on `Table`'s own container.
|
|
725
|
+
* - Past `EXPAND_RATIO` the expand action shows without hover.
|
|
445
726
|
*/
|
|
446
727
|
const MarkdownTable = ({ children, actions, onExpand, surface = "card", className }) => {
|
|
447
728
|
const frameRef = useRef(null);
|
|
@@ -551,7 +832,7 @@ const contentClasses = cva([
|
|
|
551
832
|
"tw:py-2",
|
|
552
833
|
"tw:rounded-xl",
|
|
553
834
|
"tw:overflow-hidden",
|
|
554
|
-
"tw:
|
|
835
|
+
"tw:wrap-anywhere"
|
|
555
836
|
]
|
|
556
837
|
} },
|
|
557
838
|
defaultVariants: { variant: "assistant" }
|
|
@@ -896,6 +1177,58 @@ const PlanRewritingIndicator = ({ label = "Rewriting the plan..." }) => /* @__PU
|
|
|
896
1177
|
})]
|
|
897
1178
|
});
|
|
898
1179
|
//#endregion
|
|
1180
|
+
//#region src/blocks/AIKit/constants.ts
|
|
1181
|
+
/**
|
|
1182
|
+
* Names the container query `PromptInput`'s `inline` row reads to fold into the stacked layout.
|
|
1183
|
+
*
|
|
1184
|
+
* It has to sit on an **ancestor**: a container query matches descendants only, so the field that
|
|
1185
|
+
* would read it cannot name it, and its own wrapper is the width the fold changes. A host that
|
|
1186
|
+
* never names it keeps the one-line row at every width.
|
|
1187
|
+
*/
|
|
1188
|
+
const PROMPT_INPUT_CONTAINER = "tw:@container/composer";
|
|
1189
|
+
//#endregion
|
|
1190
|
+
//#region src/blocks/AIKit/AnimatedHeight.tsx
|
|
1191
|
+
/**
|
|
1192
|
+
* A box whose height eases to whatever its content measures.
|
|
1193
|
+
*
|
|
1194
|
+
* - Content is measured with a `ResizeObserver`; without one (jsdom) the box is plain `auto`.
|
|
1195
|
+
* - The first measurement lands without a transition, so mounting with content does not grow in.
|
|
1196
|
+
* - Overflow is clipped only while the height moves, so focus rings are not cut off at rest.
|
|
1197
|
+
* - `prefers-reduced-motion` drops the transition.
|
|
1198
|
+
*/
|
|
1199
|
+
const AnimatedHeight = ({ children, className }) => {
|
|
1200
|
+
const contentRef = useRef(null);
|
|
1201
|
+
const heightRef = useRef(void 0);
|
|
1202
|
+
const [height, setHeight] = useState();
|
|
1203
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
1204
|
+
useLayoutEffect(() => {
|
|
1205
|
+
const node = contentRef.current;
|
|
1206
|
+
if (!node || typeof ResizeObserver === "undefined") return;
|
|
1207
|
+
const observer = new ResizeObserver(() => {
|
|
1208
|
+
const next = node.offsetHeight;
|
|
1209
|
+
const prev = heightRef.current;
|
|
1210
|
+
if (prev !== void 0 && prev !== next && hasMotion()) setIsAnimating(true);
|
|
1211
|
+
heightRef.current = next;
|
|
1212
|
+
setHeight(next);
|
|
1213
|
+
});
|
|
1214
|
+
observer.observe(node);
|
|
1215
|
+
return () => observer.disconnect();
|
|
1216
|
+
}, []);
|
|
1217
|
+
const handleTransitionEnd = (event) => {
|
|
1218
|
+
if (event.target !== event.currentTarget || event.propertyName !== "height") return;
|
|
1219
|
+
setIsAnimating(false);
|
|
1220
|
+
};
|
|
1221
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1222
|
+
style: { height },
|
|
1223
|
+
onTransitionEnd: handleTransitionEnd,
|
|
1224
|
+
className: cn("tw:transition-[height] tw:duration-200 tw:ease-out tw:motion-reduce:transition-none", isAnimating && "tw:overflow-hidden", className),
|
|
1225
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1226
|
+
ref: contentRef,
|
|
1227
|
+
children
|
|
1228
|
+
})
|
|
1229
|
+
});
|
|
1230
|
+
};
|
|
1231
|
+
//#endregion
|
|
899
1232
|
//#region src/blocks/AIKit/PromptInputAction.tsx
|
|
900
1233
|
const PromptInputAction = ({ ref, onMouseDown, ...rest }) => {
|
|
901
1234
|
const handleOnMouseDown = (event) => {
|
|
@@ -910,39 +1243,152 @@ const PromptInputAction = ({ ref, onMouseDown, ...rest }) => {
|
|
|
910
1243
|
};
|
|
911
1244
|
//#endregion
|
|
912
1245
|
//#region src/blocks/AIKit/PromptInputCommands.tsx
|
|
913
|
-
|
|
914
|
-
|
|
1246
|
+
/** What the menu needs above or below the composer before it will open on that side. */
|
|
1247
|
+
const MENU_HEIGHT = 440;
|
|
1248
|
+
/** As tall as the list ever gets, however much room there is. */
|
|
1249
|
+
const MENU_MAX_HEIGHT = 416;
|
|
1250
|
+
/** Space kept from the measured edge; `POPUP_CHROME` is the popup's own border and padding. */
|
|
1251
|
+
const MENU_GUTTER = 16;
|
|
1252
|
+
const POPUP_CHROME = 10;
|
|
1253
|
+
/**
|
|
1254
|
+
* The rows a typed filter leaves.
|
|
1255
|
+
*
|
|
1256
|
+
* - An empty filter keeps everything.
|
|
1257
|
+
* - A row matches on its label or its value.
|
|
1258
|
+
* - Matching nothing falls back to the action rows.
|
|
1259
|
+
*/
|
|
1260
|
+
const matchesFilter = (items, filterValue) => {
|
|
1261
|
+
if (!filterValue) return items;
|
|
1262
|
+
const query = filterValue.toLowerCase();
|
|
1263
|
+
const matched = items.filter((item) => item.label.toLowerCase().includes(query) || item.value.toLowerCase().includes(query));
|
|
1264
|
+
return matched.length > 0 ? matched : items.filter((item) => item.onSelect !== void 0);
|
|
1265
|
+
};
|
|
1266
|
+
/**
|
|
1267
|
+
* The band the menu has to stay inside: the window, narrowed by every ancestor that clips.
|
|
1268
|
+
*
|
|
1269
|
+
* - The chat sidebar's panel clips well below the window's top edge.
|
|
1270
|
+
*/
|
|
1271
|
+
const CLIPS = /* @__PURE__ */ new Set([
|
|
1272
|
+
"hidden",
|
|
1273
|
+
"auto",
|
|
1274
|
+
"scroll",
|
|
1275
|
+
"clip",
|
|
1276
|
+
"overlay"
|
|
1277
|
+
]);
|
|
1278
|
+
const clipBand = (node) => {
|
|
1279
|
+
let top = 0;
|
|
1280
|
+
let bottom = window.innerHeight;
|
|
1281
|
+
let parent = node.parentElement;
|
|
1282
|
+
while (parent) {
|
|
1283
|
+
const { overflowY, overflowX } = window.getComputedStyle(parent);
|
|
1284
|
+
if (CLIPS.has(overflowY) || CLIPS.has(overflowX)) {
|
|
1285
|
+
const box = parent.getBoundingClientRect();
|
|
1286
|
+
top = Math.max(top, box.top);
|
|
1287
|
+
bottom = Math.min(bottom, box.bottom);
|
|
1288
|
+
}
|
|
1289
|
+
parent = parent.parentElement;
|
|
1290
|
+
}
|
|
1291
|
+
return {
|
|
1292
|
+
top,
|
|
1293
|
+
bottom
|
|
1294
|
+
};
|
|
1295
|
+
};
|
|
1296
|
+
const PromptInputCommands = ({ items, open, onSelect, filterValue, emptyText = "No commands found", panel, groupAction, groupHeading, children }) => {
|
|
1297
|
+
const filtered = matchesFilter(items, filterValue);
|
|
1298
|
+
const [highlighted, setHighlighted] = useState();
|
|
1299
|
+
const [wasOpen, setWasOpen] = useState(open);
|
|
1300
|
+
if (open !== wasOpen) {
|
|
1301
|
+
setWasOpen(open);
|
|
1302
|
+
if (open) setHighlighted(void 0);
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Which side the menu opens on.
|
|
1306
|
+
*
|
|
1307
|
+
* - Above by default; below when there is not room above and more room below.
|
|
1308
|
+
* - Re-measured while open: the composer and the transcript above it move.
|
|
1309
|
+
*/
|
|
1310
|
+
const rootRef = useRef(null);
|
|
1311
|
+
const [below, setBelow] = useState(false);
|
|
1312
|
+
const [maxHeight, setMaxHeight] = useState(MENU_MAX_HEIGHT);
|
|
1313
|
+
const measure = useCallback(() => {
|
|
1314
|
+
const node = rootRef.current;
|
|
1315
|
+
const box = node?.getBoundingClientRect();
|
|
1316
|
+
if (!node || !box) return;
|
|
1317
|
+
const band = clipBand(node);
|
|
1318
|
+
const above = box.top - band.top;
|
|
1319
|
+
const under = band.bottom - box.bottom;
|
|
1320
|
+
const openBelow = above < MENU_HEIGHT && under > above;
|
|
1321
|
+
setBelow(openBelow);
|
|
1322
|
+
setMaxHeight(Math.max(0, Math.min(MENU_MAX_HEIGHT, (openBelow ? under : above) - MENU_GUTTER - POPUP_CHROME)));
|
|
1323
|
+
}, []);
|
|
1324
|
+
const attachRoot = useCallback((node) => {
|
|
1325
|
+
rootRef.current = node;
|
|
1326
|
+
if (node) measure();
|
|
1327
|
+
}, [measure]);
|
|
1328
|
+
useEffect(() => {
|
|
1329
|
+
if (!open) return;
|
|
1330
|
+
const node = rootRef.current;
|
|
1331
|
+
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(measure) : null;
|
|
1332
|
+
if (node) observer?.observe(node);
|
|
1333
|
+
window.addEventListener("resize", measure);
|
|
1334
|
+
window.addEventListener("scroll", measure, true);
|
|
1335
|
+
return () => {
|
|
1336
|
+
observer?.disconnect();
|
|
1337
|
+
window.removeEventListener("resize", measure);
|
|
1338
|
+
window.removeEventListener("scroll", measure, true);
|
|
1339
|
+
};
|
|
1340
|
+
}, [open, measure]);
|
|
1341
|
+
const highlightedValue = filtered.some((item) => item.value === highlighted) ? highlighted : filtered[0]?.value;
|
|
915
1342
|
const groups = filtered.reduce((acc, item) => {
|
|
916
1343
|
const group = acc[item.group] ?? [];
|
|
917
1344
|
group.push(item);
|
|
918
1345
|
acc[item.group] = group;
|
|
919
1346
|
return acc;
|
|
920
1347
|
}, {});
|
|
1348
|
+
const menuStyle = { "--prompt-menu-max-h": `${maxHeight}px` };
|
|
921
1349
|
return /* @__PURE__ */ jsxs(Command, {
|
|
1350
|
+
ref: attachRoot,
|
|
922
1351
|
loop: true,
|
|
923
1352
|
className: "tw:relative",
|
|
924
1353
|
shouldFilter: false,
|
|
1354
|
+
value: highlightedValue ?? "",
|
|
1355
|
+
onValueChange: setHighlighted,
|
|
925
1356
|
children: [open && /* @__PURE__ */ jsx("div", {
|
|
926
|
-
className: cn("tw:absolute tw:
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1357
|
+
className: cn("tw:absolute tw:left-0 tw:z-50 tw:w-full tw:max-w-lg", below ? "tw:top-full tw:mt-1" : "tw:bottom-full tw:mb-1", "tw:rounded-[14px] tw:border tw:border-border tw:bg-popover tw:text-popover-foreground tw:shadow-lg", "tw:p-1"),
|
|
1358
|
+
style: menuStyle,
|
|
1359
|
+
children: panel ? /* @__PURE__ */ jsx("div", {
|
|
1360
|
+
className: "tw:p-3",
|
|
1361
|
+
children: panel
|
|
1362
|
+
}) : filtered.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
1363
|
+
className: "tw:py-3 tw:pl-4 tw:text-center tw:text-sm tw:text-muted-foreground",
|
|
1364
|
+
children: emptyText
|
|
930
1365
|
}) : /* @__PURE__ */ jsx(Command.List, {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1366
|
+
className: "tw:group-data-[variant=argo]/command:px-1 tw:group-data-[variant=argo]/command:pb-1",
|
|
1367
|
+
viewPortClassName: "tw:max-h-[var(--prompt-menu-max-h)] tw:[&>div]:!block",
|
|
1368
|
+
children: Object.entries(groups).map(([groupName, groupItems], index) => /* @__PURE__ */ jsx(Command.Group, {
|
|
1369
|
+
heading: groupName ? /* @__PURE__ */ jsxs("span", {
|
|
1370
|
+
className: "tw:flex tw:items-center tw:justify-between tw:gap-2",
|
|
1371
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1372
|
+
className: "tw:min-w-0 tw:truncate",
|
|
1373
|
+
children: groupHeading?.(groupName) ?? groupName
|
|
1374
|
+
}), groupAction?.(groupName)]
|
|
1375
|
+
}) : void 0,
|
|
1376
|
+
className: cn("tw:[&_[cmdk-group-heading]]:normal-case", "tw:[&_[cmdk-group-heading]]:tracking-normal", "tw:[&_[cmdk-group-heading]]:border-b-0", "tw:[&_[cmdk-group-heading]]:!py-0", "tw:[&_[cmdk-group-heading]]:mt-2", "tw:[&_[cmdk-group-heading]]:mb-1", "tw:[&_[cmdk-group-heading]]:pl-2", "tw:[&_[cmdk-group-heading]]:text-xs", index > 0 && "tw:mt-3"),
|
|
1377
|
+
children: groupItems.map((item) => /* @__PURE__ */ jsxs(Command.Item, {
|
|
935
1378
|
value: item.value,
|
|
936
|
-
|
|
937
|
-
onSelect: () => onSelect(item
|
|
938
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
1379
|
+
className: "tw:w-full tw:min-w-0 tw:rounded-md",
|
|
1380
|
+
onSelect: () => onSelect(item),
|
|
1381
|
+
children: [item.icon, /* @__PURE__ */ jsxs("div", {
|
|
939
1382
|
className: "tw:flex tw:min-w-0 tw:flex-1 tw:flex-col",
|
|
940
|
-
children: [
|
|
1383
|
+
children: [item.content ?? /* @__PURE__ */ jsx("span", {
|
|
1384
|
+
className: "tw:truncate",
|
|
1385
|
+
children: item.label
|
|
1386
|
+
}), item.description && /* @__PURE__ */ jsx(Truncated, {
|
|
941
1387
|
text: item.description,
|
|
942
1388
|
twoLines: true,
|
|
943
1389
|
className: "tw:text-xs tw:text-muted-foreground"
|
|
944
1390
|
})]
|
|
945
|
-
})
|
|
1391
|
+
})]
|
|
946
1392
|
}, item.value))
|
|
947
1393
|
}, groupName))
|
|
948
1394
|
})
|
|
@@ -950,6 +1396,27 @@ const PromptInputCommands = ({ items, open, onSelect, filterValue, children }) =
|
|
|
950
1396
|
});
|
|
951
1397
|
};
|
|
952
1398
|
//#endregion
|
|
1399
|
+
//#region src/blocks/AIKit/PromptInputMenuTrigger.tsx
|
|
1400
|
+
/**
|
|
1401
|
+
* The composer's "add to message" button.
|
|
1402
|
+
*
|
|
1403
|
+
* - One glyph for both states: a plus rotated 45° reads as a close cross, so nothing swaps.
|
|
1404
|
+
* - `aria-expanded` mirrors `open`; the accessible name changes with it.
|
|
1405
|
+
* - Wrapped in `PromptInputAction` so a click does not hand focus to the textarea.
|
|
1406
|
+
*/
|
|
1407
|
+
const PromptInputMenuTrigger = ({ open = false, large = false, className, ref, ...props }) => /* @__PURE__ */ jsx(PromptInputAction, { children: /* @__PURE__ */ jsx(Button, {
|
|
1408
|
+
ref,
|
|
1409
|
+
type: "button",
|
|
1410
|
+
size: large ? "icon" : "icon-sm",
|
|
1411
|
+
variant: "invisible",
|
|
1412
|
+
"aria-expanded": open,
|
|
1413
|
+
"aria-label": open ? "Close menu" : "Add to message",
|
|
1414
|
+
"data-testid": "prompt-input-menu-trigger",
|
|
1415
|
+
className: cn("tw:rounded-full", "tw:hover:not-disabled:bg-muted tw:hover:not-disabled:text-foreground tw:hover:not-disabled:border-transparent", "tw:aria-expanded:bg-muted", className),
|
|
1416
|
+
...props,
|
|
1417
|
+
children: /* @__PURE__ */ jsx(Plus, { className: cn(large ? "tw:size-5" : "tw:size-4", "tw:transition-transform tw:duration-300 tw:ease-out tw:motion-reduce:transition-none", open && "tw:rotate-135") })
|
|
1418
|
+
}) });
|
|
1419
|
+
//#endregion
|
|
953
1420
|
//#region src/blocks/AIKit/PromptInputSubmit.tsx
|
|
954
1421
|
const ARIA_LABEL_BY_STATUS = {
|
|
955
1422
|
ready: "Send message",
|
|
@@ -996,6 +1463,42 @@ const CMDK_HIJACKED_KEYS = /* @__PURE__ */ new Set([
|
|
|
996
1463
|
"Enter"
|
|
997
1464
|
]);
|
|
998
1465
|
const isCmdkNavigation = (event) => event.key !== "Enter" || !(event.metaKey || event.ctrlKey || event.altKey);
|
|
1466
|
+
/**
|
|
1467
|
+
* The `@token` the caret sits at the end of, if any.
|
|
1468
|
+
*
|
|
1469
|
+
* - `@` has to open a word: it must start the value or follow whitespace.
|
|
1470
|
+
* - The token holds no whitespace or second `@` and runs past the caret, so a mid-word pick takes the word.
|
|
1471
|
+
* - `start` indexes the `@` itself, so replacing `[start, end)` removes the token.
|
|
1472
|
+
*/
|
|
1473
|
+
const findMentionToken = (value, caret) => {
|
|
1474
|
+
const before = value.slice(0, caret);
|
|
1475
|
+
const match = /(?:^|\s)@([^\s@]*)$/.exec(before);
|
|
1476
|
+
if (!match) return null;
|
|
1477
|
+
const typed = match[1] ?? "";
|
|
1478
|
+
const tail = /^[^\s@]*/.exec(value.slice(caret))?.[0] ?? "";
|
|
1479
|
+
return {
|
|
1480
|
+
start: caret - typed.length - 1,
|
|
1481
|
+
end: caret + tail.length,
|
|
1482
|
+
query: typed + tail
|
|
1483
|
+
};
|
|
1484
|
+
};
|
|
1485
|
+
/**
|
|
1486
|
+
* The `/token` a message leads with, while the caret is still on it.
|
|
1487
|
+
*
|
|
1488
|
+
* - Only the first token: the Agent SDK expands a skill only at the start of a message.
|
|
1489
|
+
* - Text may follow it.
|
|
1490
|
+
* - The caret past the token closes the menu.
|
|
1491
|
+
*/
|
|
1492
|
+
const findSlashToken = (value, caret) => {
|
|
1493
|
+
const match = /^\/(\S*)/.exec(value);
|
|
1494
|
+
if (!match) return null;
|
|
1495
|
+
const end = match[0].length;
|
|
1496
|
+
if (caret > end) return null;
|
|
1497
|
+
return {
|
|
1498
|
+
end,
|
|
1499
|
+
query: match[1] ?? ""
|
|
1500
|
+
};
|
|
1501
|
+
};
|
|
999
1502
|
const promptInputVariants = cva([
|
|
1000
1503
|
"tailwindcss-preflight",
|
|
1001
1504
|
"tw:relative",
|
|
@@ -1024,11 +1527,7 @@ const promptInputVariants = cva([
|
|
|
1024
1527
|
"tw:pt-3",
|
|
1025
1528
|
"tw:pb-2"
|
|
1026
1529
|
],
|
|
1027
|
-
inline: [
|
|
1028
|
-
"tw:flex-row",
|
|
1029
|
-
"tw:py-3",
|
|
1030
|
-
"tw:items-center"
|
|
1031
|
-
]
|
|
1530
|
+
inline: ["tw:flex-col", "tw:py-3"]
|
|
1032
1531
|
} }
|
|
1033
1532
|
});
|
|
1034
1533
|
const wrapperVariants = cva(null, {
|
|
@@ -1038,7 +1537,7 @@ const wrapperVariants = cva(null, {
|
|
|
1038
1537
|
inline: ""
|
|
1039
1538
|
} }
|
|
1040
1539
|
});
|
|
1041
|
-
const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, disabled, disableSubmit, value = "", onValueChange, status = "ready", maxRows = 6, minRows, commands, autoFocus, textareaRef: publishedRef, ...textareaProps }) => {
|
|
1540
|
+
const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, attachments, className, disabled, disableSubmit, value = "", onValueChange, status = "ready", maxRows = 6, minRows, commands, commandsGroupAction, panel, mentions, onMentionSelect, mentionsEmptyText = "Nothing to attach", mentionsGroupHeading, mentionsMultiple = false, autoFocus, textareaRef: publishedRef, ...textareaProps }) => {
|
|
1042
1541
|
const defaultMinRows = variant === "inline" ? 1 : 2;
|
|
1043
1542
|
const isDisabled = (disabled || disableSubmit || !value.trim()) && status !== "streaming" && status !== "interrupted";
|
|
1044
1543
|
const textareaId = useId();
|
|
@@ -1048,15 +1547,29 @@ const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, dis
|
|
|
1048
1547
|
if (publishedRef) publishedRef.current = node;
|
|
1049
1548
|
}, [publishedRef]);
|
|
1050
1549
|
const [dismissedValue, setDismissedValue] = useState(null);
|
|
1550
|
+
const [caret, setCaret] = useState(0);
|
|
1551
|
+
const [caretValue, setCaretValue] = useState(value);
|
|
1552
|
+
const moveCaret = (next, forValue) => {
|
|
1553
|
+
setCaret(next);
|
|
1554
|
+
setCaretValue(forValue);
|
|
1555
|
+
};
|
|
1556
|
+
if (value !== caretValue) moveCaret(value.length, value);
|
|
1051
1557
|
const autoFocusRef = useRef(autoFocus);
|
|
1052
1558
|
useEffect(() => {
|
|
1053
1559
|
if (autoFocusRef.current) textareaRef.current?.focus({ preventScroll: true });
|
|
1054
1560
|
}, []);
|
|
1055
1561
|
if (dismissedValue !== null && value !== dismissedValue) setDismissedValue(null);
|
|
1056
1562
|
const hasCommands = !!commands && commands.length > 0;
|
|
1057
|
-
const
|
|
1058
|
-
const
|
|
1059
|
-
const
|
|
1563
|
+
const panelOpen = panel !== void 0;
|
|
1564
|
+
const hasMentions = mentions !== void 0;
|
|
1565
|
+
const hasMenus = hasCommands || hasMentions;
|
|
1566
|
+
const slashToken = hasCommands && !panelOpen && value !== dismissedValue ? findSlashToken(value, Math.min(caret, value.length)) : null;
|
|
1567
|
+
const commandsOpen = slashToken !== null;
|
|
1568
|
+
const mentionToken = hasMentions && !commandsOpen && !panelOpen && value !== dismissedValue ? findMentionToken(value, Math.min(caret, value.length)) : null;
|
|
1569
|
+
const mentionsOpen = mentionToken !== null;
|
|
1570
|
+
const menuOpen = commandsOpen || mentionsOpen || panelOpen;
|
|
1571
|
+
const menuItems = commandsOpen ? commands ?? [] : mentions ?? [];
|
|
1572
|
+
const menuFilter = commandsOpen ? slashToken.query : mentionToken?.query ?? "";
|
|
1060
1573
|
const handleSubmit = () => {
|
|
1061
1574
|
if (isDisabled) return;
|
|
1062
1575
|
if (status === "streaming") onAbort?.();
|
|
@@ -1068,21 +1581,71 @@ const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, dis
|
|
|
1068
1581
|
handleSubmit();
|
|
1069
1582
|
};
|
|
1070
1583
|
const handleOnChange = (event) => {
|
|
1584
|
+
moveCaret(event.target.selectionStart ?? event.target.value.length, event.target.value);
|
|
1071
1585
|
onValueChange?.(event.target.value);
|
|
1072
1586
|
};
|
|
1073
|
-
const
|
|
1074
|
-
|
|
1587
|
+
const handleOnSelect = (event) => {
|
|
1588
|
+
moveCaret(event.currentTarget.selectionStart ?? 0, event.currentTarget.value);
|
|
1589
|
+
};
|
|
1590
|
+
const handleMenuSelect = (item) => {
|
|
1591
|
+
if (item.onSelect) {
|
|
1592
|
+
const start = mentionToken?.start ?? 0;
|
|
1593
|
+
const end = mentionToken?.end ?? slashToken?.end;
|
|
1594
|
+
if (end !== void 0) {
|
|
1595
|
+
const next = value.slice(0, start) + value.slice(end);
|
|
1596
|
+
onValueChange?.(next);
|
|
1597
|
+
moveCaret(start, next);
|
|
1598
|
+
}
|
|
1599
|
+
item.onSelect();
|
|
1600
|
+
textareaRef.current?.focus();
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
if (mentionToken) {
|
|
1604
|
+
const keep = mentionsMultiple ? "@" : "";
|
|
1605
|
+
const next = value.slice(0, mentionToken.start) + keep + value.slice(mentionToken.end);
|
|
1606
|
+
const nextCaret = mentionToken.start + keep.length;
|
|
1607
|
+
onValueChange?.(next);
|
|
1608
|
+
moveCaret(nextCaret, next);
|
|
1609
|
+
requestAnimationFrame(() => {
|
|
1610
|
+
textareaRef.current?.setSelectionRange(nextCaret, nextCaret);
|
|
1611
|
+
});
|
|
1612
|
+
onMentionSelect?.(item);
|
|
1613
|
+
} else {
|
|
1614
|
+
const rest = slashToken ? value.slice(slashToken.end).replace(/^\s+/, "") : "";
|
|
1615
|
+
const head = `${item.value} `;
|
|
1616
|
+
onValueChange?.(head + rest);
|
|
1617
|
+
moveCaret(head.length, head + rest);
|
|
1618
|
+
requestAnimationFrame(() => {
|
|
1619
|
+
textareaRef.current?.setSelectionRange(head.length, head.length);
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1075
1622
|
textareaRef.current?.focus();
|
|
1076
1623
|
};
|
|
1624
|
+
const dismissMenu = () => {
|
|
1625
|
+
if (value.trim() === "/" || value.trim() === "@") {
|
|
1626
|
+
onValueChange?.("");
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
if (mentionToken && mentionToken.query === "") {
|
|
1630
|
+
const next = (value.slice(0, mentionToken.start) + value.slice(mentionToken.end)).replace(/\s+$/, "");
|
|
1631
|
+
onValueChange?.(next);
|
|
1632
|
+
moveCaret(next.length, next);
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
setDismissedValue(value);
|
|
1636
|
+
};
|
|
1077
1637
|
const handleOnKeyDown = (event) => {
|
|
1078
|
-
if (
|
|
1638
|
+
if (menuOpen) {
|
|
1079
1639
|
if (event.key === "Escape") {
|
|
1080
1640
|
event.preventDefault();
|
|
1081
|
-
|
|
1641
|
+
if (panel) panel.onClose();
|
|
1642
|
+
else dismissMenu();
|
|
1082
1643
|
return;
|
|
1083
1644
|
}
|
|
1084
|
-
if (
|
|
1085
|
-
|
|
1645
|
+
if (panelOpen) return;
|
|
1646
|
+
if (event.key === "ArrowUp" || event.key === "ArrowDown") return;
|
|
1647
|
+
if (event.key === "Enter" && matchesFilter(menuItems, menuFilter).length > 0) return;
|
|
1648
|
+
} else if (hasMenus && CMDK_HIJACKED_KEYS.has(event.key) && isCmdkNavigation(event)) event.stopPropagation();
|
|
1086
1649
|
if (event.key === "Enter" && !event.shiftKey && !event.ctrlKey && !event.metaKey) {
|
|
1087
1650
|
event.preventDefault();
|
|
1088
1651
|
if (status !== "streaming") handleSubmit();
|
|
@@ -1100,48 +1663,69 @@ const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, dis
|
|
|
1100
1663
|
"data-status": status,
|
|
1101
1664
|
onMouseDown: handleOnMouseDown,
|
|
1102
1665
|
onSubmit: handleOnSubmit,
|
|
1103
|
-
className: cn(promptInputVariants({ variant }), disabled && "tw:bg-none tw:border-border tw:shadow-[inset_0_100vw_rgb(var(--muted))] tw:cursor-default"),
|
|
1666
|
+
className: cn(promptInputVariants({ variant }), disabled && "tw:bg-none tw:border-border tw:shadow-[inset_0_100vw_rgb(var(--muted))] tw:cursor-default", className),
|
|
1104
1667
|
children: [
|
|
1105
|
-
|
|
1106
|
-
className: "tw
|
|
1107
|
-
children:
|
|
1668
|
+
/* @__PURE__ */ jsx(AnimatedHeight, {
|
|
1669
|
+
className: "tw:-mb-2",
|
|
1670
|
+
children: attachments && /* @__PURE__ */ jsx("div", {
|
|
1671
|
+
className: "tw:flex tw:flex-col tw:gap-2 tw:pb-4",
|
|
1672
|
+
children: attachments
|
|
1673
|
+
})
|
|
1108
1674
|
}),
|
|
1109
1675
|
/* @__PURE__ */ jsx("label", {
|
|
1110
1676
|
htmlFor: textareaId,
|
|
1111
1677
|
className: "tw:sr-only",
|
|
1112
1678
|
children: "Prompt Input"
|
|
1113
1679
|
}),
|
|
1114
|
-
/* @__PURE__ */ jsx(TextareaAutosize, {
|
|
1115
|
-
...textareaProps,
|
|
1116
|
-
disabled,
|
|
1117
|
-
minRows: minRows ?? defaultMinRows,
|
|
1118
|
-
maxRows,
|
|
1119
|
-
id: textareaId,
|
|
1120
|
-
ref: setTextareaNode,
|
|
1121
|
-
value,
|
|
1122
|
-
onChange: handleOnChange,
|
|
1123
|
-
onKeyDown: handleOnKeyDown,
|
|
1124
|
-
className: cn("tw:resize-none", "tw:outline-hidden", "tw:w-full", "tw:px-2", "tw:bg-transparent", disabled ? "tw:text-muted-foreground" : "tw:text-foreground", "tw:text-sm", "tw:font-sans", "tw:transition-[width]", "tw:delay-75", "tw:ease-linear", "tw:overflow-auto")
|
|
1125
|
-
}),
|
|
1126
1680
|
/* @__PURE__ */ jsxs("div", {
|
|
1127
|
-
className: cn("tw:flex tw:
|
|
1128
|
-
children: [
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1681
|
+
className: cn("tw:flex tw:min-w-0 tw:gap-2", variant === "inline" ? "tw:flex-row tw:items-center tw:@max-[480px]/composer:flex-wrap" : "tw:flex-col"),
|
|
1682
|
+
children: [
|
|
1683
|
+
prefix && /* @__PURE__ */ jsx("div", {
|
|
1684
|
+
className: "tw:flex tw:shrink-0 tw:items-center",
|
|
1685
|
+
children: prefix
|
|
1686
|
+
}),
|
|
1687
|
+
/* @__PURE__ */ jsx("div", {
|
|
1688
|
+
className: cn("tw:flex tw:min-w-0 tw:items-center", variant === "inline" ? "tw:grow tw:@max-[480px]/composer:order-first tw:@max-[480px]/composer:basis-full" : "tw:flex-1"),
|
|
1689
|
+
children: /* @__PURE__ */ jsx(TextareaAutosize, {
|
|
1690
|
+
...textareaProps,
|
|
1691
|
+
disabled,
|
|
1692
|
+
minRows: minRows ?? defaultMinRows,
|
|
1693
|
+
maxRows,
|
|
1694
|
+
id: textareaId,
|
|
1695
|
+
ref: setTextareaNode,
|
|
1696
|
+
value,
|
|
1697
|
+
onChange: handleOnChange,
|
|
1698
|
+
onSelect: handleOnSelect,
|
|
1699
|
+
onKeyDown: handleOnKeyDown,
|
|
1700
|
+
className: cn("tw:resize-none", "tw:outline-hidden", "tw:min-w-32 tw:flex-1", variant === "inline" ? "tw:@max-[480px]/composer:pl-2" : "tw:pl-2 tw:pr-0", "tw:bg-transparent", disabled ? "tw:text-muted-foreground" : "tw:text-foreground", "tw:text-sm", "tw:font-sans", "tw:transition-[width]", "tw:delay-75", "tw:ease-linear", "tw:overflow-auto")
|
|
1701
|
+
})
|
|
1702
|
+
}),
|
|
1703
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1704
|
+
className: cn("tw:flex tw:items-center tw:gap-1", "tw:[&>*:last-child]:ml-1", "tw:shrink-0", variant === "inline" && "tw:pr-2.5 tw:@max-[480px]/composer:grow tw:@max-[480px]/composer:pr-0"),
|
|
1705
|
+
children: [suffix, /* @__PURE__ */ jsx(PromptInputSubmit, {
|
|
1706
|
+
disabled: isDisabled,
|
|
1707
|
+
status
|
|
1708
|
+
})]
|
|
1709
|
+
})
|
|
1710
|
+
]
|
|
1132
1711
|
})
|
|
1133
1712
|
]
|
|
1134
1713
|
})
|
|
1135
1714
|
});
|
|
1136
|
-
return /* @__PURE__ */ jsx(TooltipProvider, { children:
|
|
1137
|
-
items:
|
|
1138
|
-
open:
|
|
1139
|
-
onSelect:
|
|
1140
|
-
filterValue:
|
|
1715
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: hasMenus ? /* @__PURE__ */ jsx(PromptInputCommands, {
|
|
1716
|
+
items: menuItems,
|
|
1717
|
+
open: menuOpen,
|
|
1718
|
+
onSelect: handleMenuSelect,
|
|
1719
|
+
filterValue: menuFilter,
|
|
1720
|
+
emptyText: mentionsOpen ? mentionsEmptyText : "No commands found",
|
|
1721
|
+
panel: panel?.content,
|
|
1722
|
+
groupAction: commandsOpen ? commandsGroupAction : void 0,
|
|
1723
|
+
groupHeading: mentionsOpen ? mentionsGroupHeading : void 0,
|
|
1141
1724
|
children: formEl
|
|
1142
1725
|
}) : formEl });
|
|
1143
1726
|
};
|
|
1144
1727
|
PromptInput.Action = PromptInputAction;
|
|
1728
|
+
PromptInput.MenuTrigger = PromptInputMenuTrigger;
|
|
1145
1729
|
//#endregion
|
|
1146
1730
|
//#region src/blocks/AIKit/Question.tsx
|
|
1147
1731
|
const handleKeyDown = (callback) => (e) => {
|
|
@@ -1154,6 +1738,10 @@ const Question = ({ question, header, options, multiSelect = true, selectedOptio
|
|
|
1154
1738
|
const [isCustomExpanded, setIsCustomExpanded] = useState(false);
|
|
1155
1739
|
const isCustomSelected = isCustomExpanded || customAnswer.length > 0;
|
|
1156
1740
|
const hasSteps = currentStep != null && totalSteps != null;
|
|
1741
|
+
const showStepControls = hasSteps && totalSteps > 1;
|
|
1742
|
+
const showSkipButton = showSkip && onSkip != null;
|
|
1743
|
+
const showSubmitButton = multiSelect || isCustomSelected;
|
|
1744
|
+
const showFooter = showStepControls || showSkipButton || showSubmitButton;
|
|
1157
1745
|
const progressValue = hasSteps ? currentStep / totalSteps * 100 : 0;
|
|
1158
1746
|
const isFirstStep = currentStep === 1;
|
|
1159
1747
|
const isLastStep = hasSteps && currentStep === totalSteps;
|
|
@@ -1280,14 +1868,14 @@ const Question = ({ question, header, options, multiSelect = true, selectedOptio
|
|
|
1280
1868
|
}),
|
|
1281
1869
|
/* @__PURE__ */ jsxs("div", {
|
|
1282
1870
|
className: "tw:flex tw:flex-col",
|
|
1283
|
-
children: [
|
|
1871
|
+
children: [showStepControls && /* @__PURE__ */ jsx(Progress, {
|
|
1284
1872
|
size: "sm",
|
|
1285
1873
|
value: progressValue,
|
|
1286
1874
|
className: "tw:rounded-none"
|
|
1287
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
1288
|
-
className: cn("tw:flex tw:items-center tw:justify-end tw:gap-4 tw:px-4 tw:py-3", !
|
|
1875
|
+
}), showFooter && /* @__PURE__ */ jsxs("div", {
|
|
1876
|
+
className: cn("tw:flex tw:items-center tw:justify-end tw:gap-4 tw:px-4 tw:py-3", !showStepControls && "tw:border-0 tw:border-t tw:border-solid tw:border-border"),
|
|
1289
1877
|
children: [
|
|
1290
|
-
|
|
1878
|
+
showStepControls && /* @__PURE__ */ jsxs("div", {
|
|
1291
1879
|
className: "tw:flex tw:items-center tw:gap-2",
|
|
1292
1880
|
children: [
|
|
1293
1881
|
/* @__PURE__ */ jsx("button", {
|
|
@@ -1316,14 +1904,14 @@ const Question = ({ question, header, options, multiSelect = true, selectedOptio
|
|
|
1316
1904
|
})
|
|
1317
1905
|
]
|
|
1318
1906
|
}),
|
|
1319
|
-
|
|
1907
|
+
showSkipButton && /* @__PURE__ */ jsx(Button, {
|
|
1320
1908
|
variant: "outline",
|
|
1321
1909
|
size: "small",
|
|
1322
1910
|
onClick: onSkip,
|
|
1323
1911
|
"data-testid": "question-skip-button",
|
|
1324
1912
|
children: "Skip"
|
|
1325
1913
|
}),
|
|
1326
|
-
|
|
1914
|
+
showSubmitButton && (submitTooltip ? /* @__PURE__ */ jsx(Tooltip, {
|
|
1327
1915
|
tooltip: submitTooltip,
|
|
1328
1916
|
placement: "top",
|
|
1329
1917
|
triggerAsChild: true,
|
|
@@ -1656,6 +2244,25 @@ const formatPercentage = (value) => {
|
|
|
1656
2244
|
return `${value < 100 ? Math.min(rounded, 99) : rounded}%`;
|
|
1657
2245
|
};
|
|
1658
2246
|
//#endregion
|
|
2247
|
+
//#region src/blocks/AIKit/UsageBar.tsx
|
|
2248
|
+
/**
|
|
2249
|
+
* One budget, as a labelled row over a bar.
|
|
2250
|
+
*
|
|
2251
|
+
* - `value` is clamped by `clampPercentage` — `Progress`'s indicator is unclamped.
|
|
2252
|
+
*/
|
|
2253
|
+
const UsageBar = ({ value, label, variant, className, ...props }) => /* @__PURE__ */ jsxs("span", {
|
|
2254
|
+
...props,
|
|
2255
|
+
className: cn("tw:flex tw:flex-col tw:gap-1.5 tw:text-xs tw:text-muted-foreground", className),
|
|
2256
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
2257
|
+
className: "tw:flex tw:items-baseline tw:justify-between tw:gap-2",
|
|
2258
|
+
children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", { children: `${formatPercentage(Math.max(0, 100 - value))} left` })]
|
|
2259
|
+
}), /* @__PURE__ */ jsx(Progress, {
|
|
2260
|
+
size: "sm",
|
|
2261
|
+
variant,
|
|
2262
|
+
value: clampPercentage(value)
|
|
2263
|
+
})]
|
|
2264
|
+
});
|
|
2265
|
+
//#endregion
|
|
1659
2266
|
//#region src/blocks/AIKit/UsageStatsRing.tsx
|
|
1660
2267
|
const UsageStatsRing = ({ value, size = 16, strokeWidth = 2.5, className }) => {
|
|
1661
2268
|
const radius = Math.max(0, (size - strokeWidth) / 2 - 1);
|
|
@@ -1698,9 +2305,10 @@ const UsageStats = ({ value, alert = false, children, className, ariaLabel, alig
|
|
|
1698
2305
|
onOpenChange,
|
|
1699
2306
|
children: [/* @__PURE__ */ jsx(HoverCard.Trigger, {
|
|
1700
2307
|
asChild: true,
|
|
1701
|
-
children: /* @__PURE__ */ jsxs("
|
|
2308
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
2309
|
+
type: "button",
|
|
1702
2310
|
"aria-label": ariaLabel ?? defaultLabel,
|
|
1703
|
-
className: cn("tw:relative tw:inline-flex tw:size-8 tw:items-center tw:justify-center", className),
|
|
2311
|
+
className: cn("tw:relative tw:inline-flex tw:size-8 tw:shrink-0 tw:items-center tw:justify-center", "tw:cursor-pointer tw:rounded-full tw:border-0 tw:bg-transparent tw:p-0", "tw:transition-colors tw:hover:bg-muted", "tw:focus-visible:outline-hidden tw:focus-visible:ring-2 tw:focus-visible:ring-ring/50", className),
|
|
1704
2312
|
children: [/* @__PURE__ */ jsx(UsageStatsRing, { value }), hasAlert && /* @__PURE__ */ jsx(AlertCircle, {
|
|
1705
2313
|
"data-testid": "usage-stats-alert",
|
|
1706
2314
|
className: cn("tw:absolute tw:-right-0.5 tw:-top-0.5 tw:size-3", isWarning ? "tw:text-warning-500" : "tw:text-error-500")
|
|
@@ -1715,6 +2323,6 @@ const UsageStats = ({ value, alert = false, children, className, ariaLabel, alig
|
|
|
1715
2323
|
});
|
|
1716
2324
|
};
|
|
1717
2325
|
//#endregion
|
|
1718
|
-
export { AnswerActions, AnswerSummary, CollapsibleStepHeader, DIAGRAM_LANGUAGES, InlineStepDetail, InlineStepLabel, Markdown, MarkdownTable, MessageBubble, PlanApproval, PlanRewritingIndicator, PromptInput, Question, QuestionBlock, SuggestedPrompt, ThinkingIndicator, ToolCallApproval, ToolCallChip, ToolCallStatusHeader, UsageStats, UsageStatsRing, clampPercentage, formatPercentage };
|
|
2326
|
+
export { AnswerActions, AnswerSummary, ChatInlineIcon, CollapsibleStepHeader, DIAGRAM_LANGUAGES, FileDownloadChip, InlineStepDetail, InlineStepGroup, InlineStepLabel, Markdown, MarkdownTable, MessageBubble, PROMPT_INPUT_CONTAINER, PlanApproval, PlanRewritingIndicator, PromptInput, Question, QuestionBlock, SuggestedPrompt, ThinkingIndicator, ToolCallApproval, ToolCallChip, ToolCallStatusHeader, UsageBar, UsageStats, UsageStatsRing, clampPercentage, findMentionToken, findSlashToken, formatPercentage, getChatInlineIconName };
|
|
1719
2327
|
|
|
1720
|
-
//# sourceMappingURL=AIKit-
|
|
2328
|
+
//# sourceMappingURL=AIKit-BD4r7ff-.js.map
|