@keboola/design 11.3.0 → 11.5.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 +208 -1
- package/CHANGELOG.md +528 -0
- package/COMPONENT-API.md +68 -46
- package/dist/{AIKit-DaFT7p92.js → AIKit-CNX6aiKm.js} +338 -113
- package/dist/AIKit-CNX6aiKm.js.map +1 -0
- package/dist/{Alert-CseY3yAj.js → Alert-Ba5b2YPq.js} +3 -3
- package/dist/{Alert-CseY3yAj.js.map → Alert-Ba5b2YPq.js.map} +1 -1
- package/dist/{AlertModal-DQAGpsEy.js → AlertModal-BGJdaRRj.js} +3 -3
- package/dist/{AlertModal-DQAGpsEy.js.map → AlertModal-BGJdaRRj.js.map} +1 -1
- package/dist/{AppShell-BUoxM3fv.js → AppShell-DRgJxpXW.js} +2 -2
- package/dist/{AppShell-BUoxM3fv.js.map → AppShell-DRgJxpXW.js.map} +1 -1
- package/dist/{Badge-Ch26CXoP.js → Badge-D0pXdekt.js} +2 -2
- package/dist/Badge-D0pXdekt.js.map +1 -0
- package/dist/{BrandEditor-BnTLMRMp.js → BrandEditor-CSANsxUz.js} +8 -8
- package/dist/{BrandEditor-BnTLMRMp.js.map → BrandEditor-CSANsxUz.js.map} +1 -1
- package/dist/{BrandLogo-V2pRUAeO.js → BrandLogo-CoKBk4MI.js} +5 -5
- package/dist/BrandLogo-CoKBk4MI.js.map +1 -0
- package/dist/{Breadcrumb-CQTPn_KB.js → Breadcrumb-g_xn_-Nf.js} +3 -3
- package/dist/{Breadcrumb-CQTPn_KB.js.map → Breadcrumb-g_xn_-Nf.js.map} +1 -1
- package/dist/{Button-CPsEQuTN.js → Button-DsRrU5F1.js} +6 -5
- package/dist/Button-DsRrU5F1.js.map +1 -0
- package/dist/{Card-Cd5HSBmv.js → Card-Dyo7055Q.js} +2 -2
- package/dist/{Card-Cd5HSBmv.js.map → Card-Dyo7055Q.js.map} +1 -1
- package/dist/{Checkbox-5VNCcV7E.js → Checkbox-CUIn2jap.js} +3 -3
- package/dist/{Checkbox-5VNCcV7E.js.map → Checkbox-CUIn2jap.js.map} +1 -1
- package/dist/{Clipboard-B7rckqV_.js → Clipboard-BTW6C-b_.js} +2 -2
- package/dist/{Clipboard-B7rckqV_.js.map → Clipboard-BTW6C-b_.js.map} +1 -1
- package/dist/{ClipboardButton-CQ6Aewpg.js → ClipboardButton-CwZJdRaz.js} +3 -3
- package/dist/{ClipboardButton-CQ6Aewpg.js.map → ClipboardButton-CwZJdRaz.js.map} +1 -1
- package/dist/{CodeEditor-CUse8znx.js → CodeEditor-C9zy7PxK.js} +16 -27
- package/dist/CodeEditor-C9zy7PxK.js.map +1 -0
- package/dist/{ColorInput-Q1D9Vcc_.js → ColorInput-BZV-u_94.js} +3 -3
- package/dist/{ColorInput-Q1D9Vcc_.js.map → ColorInput-BZV-u_94.js.map} +1 -1
- package/dist/{ColorModeSwitch-B5PXCVqB.js → ColorModeSwitch-CsWLiTBX.js} +3 -3
- package/dist/{ColorModeSwitch-B5PXCVqB.js.map → ColorModeSwitch-CsWLiTBX.js.map} +1 -1
- package/dist/{Combobox-CyoRA7oY.js → Combobox-BfIfaVMA.js} +285 -109
- package/dist/Combobox-BfIfaVMA.js.map +1 -0
- package/dist/{Command-Ds68v2rX.js → Command-Bfa1kpbt.js} +6 -6
- package/dist/{Command-Ds68v2rX.js.map → Command-Bfa1kpbt.js.map} +1 -1
- package/dist/{CopyField-DI66uY_g.js → CopyField-DpT0Ngz1.js} +2 -2
- package/dist/{CopyField-DI66uY_g.js.map → CopyField-DpT0Ngz1.js.map} +1 -1
- package/dist/{DateInput-BPj2pzsn.js → DateInput-DiEd5uCL.js} +4 -4
- package/dist/{DateInput-BPj2pzsn.js.map → DateInput-DiEd5uCL.js.map} +1 -1
- package/dist/{DatePicker-DyEGuW9m.js → DatePicker-nA8YdE84.js} +2 -2
- package/dist/{DatePicker-DyEGuW9m.js.map → DatePicker-nA8YdE84.js.map} +1 -1
- package/dist/{DateRangeInput-u9DxNbHW.js → DateRangeInput-DPfVYchl.js} +4 -4
- package/dist/{DateRangeInput-u9DxNbHW.js.map → DateRangeInput-DPfVYchl.js.map} +1 -1
- package/dist/{DateRangePicker-CYYhX6S7.js → DateRangePicker-DjSUFjh4.js} +5 -5
- package/dist/{DateRangePicker-CYYhX6S7.js.map → DateRangePicker-DjSUFjh4.js.map} +1 -1
- package/dist/{DropdownMenu-DpMEcyCq.js → DropdownMenu-CASr-jgl.js} +2 -2
- package/dist/{DropdownMenu-DpMEcyCq.js.map → DropdownMenu-CASr-jgl.js.map} +1 -1
- package/dist/{FieldItem-qQKGU9lF.js → FieldItem-B7XMmZSz.js} +3 -3
- package/dist/{FieldItem-qQKGU9lF.js.map → FieldItem-B7XMmZSz.js.map} +1 -1
- package/dist/{FileUpload-C336MVnU.js → FileUpload-ABThVZyg.js} +2 -2
- package/dist/{FileUpload-C336MVnU.js.map → FileUpload-ABThVZyg.js.map} +1 -1
- package/dist/{Form-CTygENDc.js → Form-CsttTHn4.js} +8 -8
- package/dist/Form-CsttTHn4.js.map +1 -0
- package/dist/{FormGroup-BnwP0jNu.js → FormGroup-DHvTFdno.js} +3 -3
- package/dist/{FormGroup-BnwP0jNu.js.map → FormGroup-DHvTFdno.js.map} +1 -1
- package/dist/{FullScreenModal-j-M4aPFd.js → FullScreenModal-BvPuYibe.js} +3 -3
- package/dist/{FullScreenModal-j-M4aPFd.js.map → FullScreenModal-BvPuYibe.js.map} +1 -1
- package/dist/{HoverCard-yQq-O49c.js → HoverCard-B9ZMJxjn.js} +2 -2
- package/dist/{HoverCard-yQq-O49c.js.map → HoverCard-B9ZMJxjn.js.map} +1 -1
- package/dist/{InputGroup-D7zlmqPB.js → InputGroup-DcZRlVnN.js} +24 -16
- package/dist/InputGroup-DcZRlVnN.js.map +1 -0
- package/dist/{Kbd-D6LpR7G2.js → Kbd-Cvvt91Q8.js} +14 -4
- package/dist/Kbd-Cvvt91Q8.js.map +1 -0
- package/dist/MarkedText-DNGEUVWc.js +67 -0
- package/dist/MarkedText-DNGEUVWc.js.map +1 -0
- package/dist/{MermaidDiagram-JlvuGcY-.js → MermaidDiagram-CXG5tC6J.js} +19 -18
- package/dist/MermaidDiagram-CXG5tC6J.js.map +1 -0
- package/dist/{Modal-o4ATIexE.js → Modal-Coj-H02o.js} +16 -4
- package/dist/Modal-Coj-H02o.js.map +1 -0
- package/dist/{MultiActionButtonGroup-GTeFk-L8.js → MultiActionButtonGroup-DokHbPgM.js} +3 -3
- package/dist/{MultiActionButtonGroup-GTeFk-L8.js.map → MultiActionButtonGroup-DokHbPgM.js.map} +1 -1
- package/dist/{Navbar-CAQs4BZz.js → Navbar-Liy1TPI7.js} +7 -7
- package/dist/{Navbar-CAQs4BZz.js.map → Navbar-Liy1TPI7.js.map} +1 -1
- package/dist/PageHeader-Q3IpCnQd.js.map +1 -1
- package/dist/{PageToolbar-bG2YtSa3.js → PageToolbar-DExqEYGl.js} +4 -4
- package/dist/{PageToolbar-bG2YtSa3.js.map → PageToolbar-DExqEYGl.js.map} +1 -1
- package/dist/{Pagination-BB3X7ooY.js → Pagination-C_b7Xhey.js} +2 -2
- package/dist/{Pagination-BB3X7ooY.js.map → Pagination-C_b7Xhey.js.map} +1 -1
- package/dist/{Popconfirm-C2Ky5hJO.js → Popconfirm-5pBzT_HQ.js} +12 -13
- package/dist/{Popconfirm-C2Ky5hJO.js.map → Popconfirm-5pBzT_HQ.js.map} +1 -1
- package/dist/{Popover-DsbI2HKu.js → Popover-BEbQrC_P.js} +22 -19
- package/dist/Popover-BEbQrC_P.js.map +1 -0
- package/dist/{RadioGroup-BMxuZEbT.js → RadioGroup-DXPbSj8P.js} +3 -3
- package/dist/{RadioGroup-BMxuZEbT.js.map → RadioGroup-DXPbSj8P.js.map} +1 -1
- package/dist/{Search-DFeECt5D.js → Search-5uQAiNIP.js} +2 -2
- package/dist/{Search-DFeECt5D.js.map → Search-5uQAiNIP.js.map} +1 -1
- package/dist/{SearchInput-CCpdUego.js → SearchInput-D4UgAXJK.js} +3 -3
- package/dist/{SearchInput-CCpdUego.js.map → SearchInput-D4UgAXJK.js.map} +1 -1
- package/dist/{SectionNav-Bw_MVL0_.js → SectionNav-OkKCjSA-.js} +5 -5
- package/dist/{SectionNav-Bw_MVL0_.js.map → SectionNav-OkKCjSA-.js.map} +1 -1
- package/dist/{Select-D6IZVvwL.js → Select-DV3Hak_l.js} +31 -21
- package/dist/Select-DV3Hak_l.js.map +1 -0
- package/dist/{Sheet-BIzs2K2H.js → Sheet-Chf0kX1E.js} +3 -3
- package/dist/{Sheet-BIzs2K2H.js.map → Sheet-Chf0kX1E.js.map} +1 -1
- package/dist/{Sidebar-r1TW4g_b.js → Sidebar-D3cY1kha.js} +48 -22
- package/dist/Sidebar-D3cY1kha.js.map +1 -0
- package/dist/{Slider-CjxyfEty.js → Slider-CRf-bB4y.js} +3 -3
- package/dist/{Slider-CjxyfEty.js.map → Slider-CRf-bB4y.js.map} +1 -1
- package/dist/{Switch-BueTV03C.js → Switch-B0WdGSjz.js} +8 -8
- package/dist/{Switch-BueTV03C.js.map → Switch-B0WdGSjz.js.map} +1 -1
- package/dist/{Tabs-l72-WuhK.js → Tabs-eB974xJf.js} +2 -2
- package/dist/{Tabs-l72-WuhK.js.map → Tabs-eB974xJf.js.map} +1 -1
- package/dist/{TextInput-DhdRk8qm.js → TextInput-DH5SkbsE.js} +3 -3
- package/dist/{TextInput-DhdRk8qm.js.map → TextInput-DH5SkbsE.js.map} +1 -1
- package/dist/{ThemeProvider-DZfGdf1v.js → ThemeProvider-2RMdVGxO.js} +95 -15
- package/dist/ThemeProvider-2RMdVGxO.js.map +1 -0
- package/dist/{TimePicker-B6d2rAbX.js → TimePicker-BGeqc-Ed.js} +2 -2
- package/dist/{TimePicker-B6d2rAbX.js.map → TimePicker-BGeqc-Ed.js.map} +1 -1
- package/dist/{Timeline-6btyJl4D.js → Timeline-BG5Xogxh.js} +11 -11
- package/dist/{Timeline-6btyJl4D.js.map → Timeline-BG5Xogxh.js.map} +1 -1
- package/dist/{Toast-CxXUulYN.js → Toast-Dr6Uw7ao.js} +2 -2
- package/dist/{Toast-CxXUulYN.js.map → Toast-Dr6Uw7ao.js.map} +1 -1
- package/dist/{Workbench-BzE-Vvd9.js → Workbench-UR2FBC7I.js} +3 -1
- package/dist/Workbench-UR2FBC7I.js.map +1 -0
- package/dist/{ZoomableSvg-CNIzRHKH.js → ZoomableSvg-pooPb1Cu.js} +4 -4
- package/dist/{ZoomableSvg-CNIzRHKH.js.map → ZoomableSvg-pooPb1Cu.js.map} +1 -1
- package/dist/{context-BrNtMc1H.js → context-D7X470dy.js} +4 -3
- package/dist/context-D7X470dy.js.map +1 -0
- package/dist/{defaults-CTfvj2KB.js → defaults-i_xG2F_1.js} +2 -4
- package/dist/defaults-i_xG2F_1.js.map +1 -0
- package/dist/editors.js +5 -5
- package/dist/findLiteralMatches-BGBw8Vbl.js +62 -0
- package/dist/findLiteralMatches-BGBw8Vbl.js.map +1 -0
- package/dist/flint.js +134 -8
- package/dist/flint.js.map +1 -1
- package/dist/index.d.ts +1118 -566
- package/dist/index.js +64 -62
- package/dist/internal/blocks/AIKit.js +2 -2
- package/dist/internal/blocks/AppShell.js +1 -1
- package/dist/internal/blocks/AuthLayout.js +118 -0
- package/dist/internal/blocks/AuthLayout.js.map +1 -0
- package/dist/internal/blocks/BrandEditor.js +1 -1
- package/dist/internal/blocks/ChartPanel.js +1 -1
- package/dist/internal/blocks/ClipboardButton.js +1 -1
- package/dist/internal/blocks/ColorInput.js +1 -1
- package/dist/internal/blocks/ColorModeSwitch.js +1 -1
- package/dist/internal/blocks/Command.js +1 -1
- package/dist/internal/blocks/CopyField.js +1 -1
- package/dist/internal/blocks/DateInput.js +1 -1
- package/dist/internal/blocks/DateRangeInput.js +1 -1
- package/dist/internal/blocks/EmptyConfigurationActionCard.js +1 -1
- package/dist/internal/blocks/ErrorState.js +1 -1
- package/dist/internal/blocks/ExportMenu.js +5 -5
- package/dist/internal/blocks/ExportMenu.js.map +1 -1
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
- package/dist/internal/blocks/Form.js +1 -1
- package/dist/internal/blocks/FormGroup.js +1 -1
- package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
- package/dist/internal/blocks/MultiCombobox.js +116 -54
- package/dist/internal/blocks/MultiCombobox.js.map +1 -1
- package/dist/internal/blocks/NumberInput.js +1 -1
- package/dist/internal/blocks/PageToolbar.js +1 -1
- package/dist/internal/blocks/PasswordInput.js +2 -2
- package/dist/internal/blocks/SearchInput.js +1 -1
- package/dist/internal/blocks/SearchInputWithNavigation.js +3 -3
- package/dist/internal/blocks/SectionNav.js +1 -1
- package/dist/internal/blocks/SplitButton.js +2 -2
- package/dist/internal/blocks/StatCard.js +1 -1
- package/dist/internal/blocks/TextInput.js +1 -1
- package/dist/internal/blocks/Textarea.js +1 -1
- package/dist/internal/blocks/TimeInput.js +3 -3
- package/dist/internal/components/Alert.js +1 -1
- package/dist/internal/components/AlertModal.js +1 -1
- package/dist/internal/components/Avatar.js +1 -1
- package/dist/internal/components/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/Card.js +1 -1
- package/dist/internal/components/Checkbox.js +1 -1
- package/dist/internal/components/Clipboard.js +1 -1
- package/dist/internal/components/CollapsiblePanel.js +1 -1
- package/dist/internal/components/Combobox.js +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/Modal.js +1 -1
- package/dist/internal/components/Navbar.js +1 -1
- package/dist/internal/components/Pagination.js +1 -1
- package/dist/internal/components/Popconfirm.js +1 -1
- package/dist/internal/components/Popover.js +1 -1
- package/dist/internal/components/RadioGroup.js +1 -1
- package/dist/internal/components/Search.js +1 -1
- package/dist/internal/components/Select.js +1 -1
- package/dist/internal/components/Sheet.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/Switch.js +1 -1
- package/dist/internal/components/Tabs.js +1 -1
- package/dist/internal/components/ThemeProvider.js +4 -4
- 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/Toggle.js +3 -3
- package/dist/internal/components/Toggle.js.map +1 -1
- package/dist/internal/components/Tooltip.js +1 -1
- package/dist/internal/components/Truncated.js +1 -1
- package/dist/internal/components/Workbench.js +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/utils.js +3 -3
- package/dist/markdown-editor.js +32 -26
- package/dist/markdown-editor.js.map +1 -1
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.js +24 -25
- package/dist/rjsf.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/testing.js +4 -4
- package/dist/testing.js.map +1 -1
- package/dist/{useColorSchemeState-BJEk6esG.js → themeScopeContext-D7fSyb06.js} +17 -4
- package/dist/themeScopeContext-D7fSyb06.js.map +1 -0
- package/dist/{themeTokens-7T1AFLhq.js → themeTokens-qP1-55O7.js} +38 -11
- package/dist/themeTokens-qP1-55O7.js.map +1 -0
- package/dist/{toast-BweSoKn3.js → toast-DIC0iNRf.js} +2 -2
- package/dist/{toast-BweSoKn3.js.map → toast-DIC0iNRf.js.map} +1 -1
- package/dist/{utils-B-g7d_Jb.js → utils-DSvrhU8E.js} +7 -3
- package/dist/{utils-B-g7d_Jb.js.map → utils-DSvrhU8E.js.map} +1 -1
- package/dist/vega.d.ts +1 -1
- package/dist/vega.js +3 -3
- package/dist/vega.js.map +1 -1
- package/dist/{vegaTheme-FBXgAdHK.js → vegaTheme-CSvFEMBl.js} +6 -6
- package/dist/vegaTheme-CSvFEMBl.js.map +1 -0
- package/package.json +12 -10
- package/src/styles.css +3 -0
- package/dist/AIKit-DaFT7p92.js.map +0 -1
- package/dist/Badge-Ch26CXoP.js.map +0 -1
- package/dist/BrandLogo-V2pRUAeO.js.map +0 -1
- package/dist/Button-CPsEQuTN.js.map +0 -1
- package/dist/CodeEditor-CUse8znx.js.map +0 -1
- package/dist/Combobox-CyoRA7oY.js.map +0 -1
- package/dist/Form-CTygENDc.js.map +0 -1
- package/dist/InputGroup-D7zlmqPB.js.map +0 -1
- package/dist/Kbd-D6LpR7G2.js.map +0 -1
- package/dist/MarkedText-Ckbft5mw.js +0 -44
- package/dist/MarkedText-Ckbft5mw.js.map +0 -1
- package/dist/MermaidDiagram-JlvuGcY-.js.map +0 -1
- package/dist/Modal-o4ATIexE.js.map +0 -1
- package/dist/Popover-DsbI2HKu.js.map +0 -1
- package/dist/Select-D6IZVvwL.js.map +0 -1
- package/dist/Sidebar-r1TW4g_b.js.map +0 -1
- package/dist/ThemeProvider-DZfGdf1v.js.map +0 -1
- package/dist/Workbench-BzE-Vvd9.js.map +0 -1
- package/dist/context-BrNtMc1H.js.map +0 -1
- package/dist/defaults-CTfvj2KB.js.map +0 -1
- package/dist/escapeStringRegexp-8MxP2knR.js +0 -6
- package/dist/escapeStringRegexp-8MxP2knR.js.map +0 -1
- package/dist/themeTokens-7T1AFLhq.js.map +0 -1
- package/dist/useColorSchemeState-BJEk6esG.js.map +0 -1
- package/dist/vegaTheme-FBXgAdHK.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeEditor-C9zy7PxK.js","names":["cmPlaceholder","placeholder"],"sources":["../src/components/CodeEditor/ButtonToolbar.tsx","../src/components/CodeEditor/modes/dbt.ts","../src/components/CodeEditor/modes/jsonnet.ts","../src/components/CodeEditor/diffWash.ts","../src/components/CodeEditor/syntaxPalette.ts","../src/components/CodeEditor/helpers.ts","../src/components/CodeEditor/editorChrome.ts","../src/components/CodeEditor/search.ts","../src/components/CodeEditor/ToggleComponentHelp.tsx","../src/components/CodeEditor/tokenTheme.ts","../src/components/CodeEditor/tooltips.ts","../src/components/CodeEditor/variableCompletion.ts","../src/components/CodeEditor/CodeEditor.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { ClipboardButton } from '../../blocks/ClipboardButton';\n\n// Floats over the top-right corner of the editor it is rendered into — private to\n// `CodeEditor`, which is the `relative` ancestor it positions against. `right-3`\n// leaves room for the scrollbar track, whose width the browser owns and no token\n// here describes.\nexport const ButtonToolbar = ({ value, children }: { value?: string; children?: ReactNode }) => {\n if (!value && !children) return null;\n\n return (\n <div className=\"tw:absolute tw:right-3 tw:top-1 tw:z-10 tw:flex tw:gap-0.5 tw:overflow-visible tw:rounded tw:border tw:border-solid tw:border-border tw:!bg-background tw:p-px tw:shadow-sm\">\n {!!value && <ClipboardButton size=\"icon-xs\" variant=\"invisible\" text={value} />}\n {children}\n </div>\n );\n};\n","import type { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';\nimport { simpleMode } from '@codemirror/legacy-modes/mode/simple-mode';\n\n// A dbt step is `dbt <command> [<subcommand>] [arguments, flags and selectors]`,\n// and the vocabulary below is grouped by the slot it belongs to — both to colour\n// it and to decide what is worth offering where.\nconst COMMANDS = [\n 'run-operation',\n 'run',\n 'test',\n 'seed',\n 'snapshot',\n 'list',\n 'ls',\n 'compile',\n 'build',\n 'deps',\n 'docs',\n 'source',\n];\nconst SUBCOMMANDS: Record<string, string[]> = { docs: ['generate'], source: ['freshness'] };\nconst ARGUMENTS = ['--select', '--exclude', '--selector', '--defer', '--resource-type', '-s'];\n// The arguments whose value is a graph selector, and so the only ones a selector\n// method has anything to attach to.\nconst SELECTORS = ['--select', '--exclude', '-s'];\nconst METHODS = [\n 'path:',\n 'source:',\n 'tag:',\n 'package:',\n 'config:',\n 'test_type:',\n 'test_name:',\n 'state:',\n 'exposure:',\n 'metric:',\n 'result:',\n 'source_status:',\n 'column_name:',\n];\nconst FLAGS = [\n '--fail-fast',\n '--warn-error',\n '--favor-state',\n '--vars',\n '--models',\n '--threads',\n '--profiles-dir',\n '--profile',\n '--full-refresh',\n];\n\n// A subcommand only ever highlights together with its command, so `dbt docs` stays\n// unpainted until `generate` follows it.\nconst COMMAND_PHRASES = COMMANDS.flatMap((command) => {\n const subcommands = SUBCOMMANDS[command];\n\n return subcommands ? subcommands.map((subcommand) => `${command} ${subcommand}`) : [command];\n});\n\n// Alternation is first-match, so a word that prefixes another has to come first\n// (`run-operation` before `run`, `--profiles-dir` before `--profile`). Sorting by\n// length keeps that true however the lists above are written.\nconst alternation = (list: string[]) => [...list].sort((a, b) => b.length - a.length).join('|');\n\n// Every keyword follows whitespace, so the leading run is part of the match.\n// Commands and arguments end on a word boundary; methods and flags carry their\n// own terminator (`:`) or need none.\nconst word = (list: string[]) => new RegExp(`^\\\\s+(?:${alternation(list)})\\\\b`, 'i');\nconst prefix = (list: string[]) => new RegExp(`^\\\\s+(?:${alternation(list)})`, 'i');\n\n// The word being completed: letters, digits, `_`, `-` and the `:` a selector\n// method ends with. Whitespace stays out of it, so a two-word label like `docs\n// generate` cannot stretch the match back across the words before the cursor.\nconst WORD = /[\\w:-]*$/;\n\nconst asOptions = (list: string[], type: string): Completion[] =>\n list.map((label) => ({ label, type }));\n\n// `type` drives the popup icon, so each group carries the one that matches the\n// colour the mode paints it in.\nconst DBT: Completion[] = [{ label: 'dbt', type: 'keyword' }];\nconst COMMAND_OPTIONS = asOptions(COMMANDS, 'keyword');\nconst SUBCOMMAND_OPTIONS: Record<string, Completion[]> = Object.fromEntries(\n Object.entries(SUBCOMMANDS).map(([command, subcommands]) => [\n command,\n asOptions(subcommands, 'keyword'),\n ]),\n);\nconst ARGUMENT_OPTIONS = asOptions(ARGUMENTS, 'variable');\nconst FLAG_OPTIONS = asOptions(FLAGS, 'constant');\nconst METHOD_OPTIONS = asOptions(METHODS, 'property');\n\n// Which slice of the vocabulary the cursor's slot can hold, given the words\n// already finished ahead of it. Offering the whole vocabulary everywhere proposes\n// `dbt` mid-command and a selector method with no selector to attach to.\nconst optionsAfter = (words: string[]): Completion[] => {\n const [step, command, ...rest] = words;\n\n if (step === undefined) return DBT;\n if (step.toLowerCase() !== 'dbt') return [];\n if (command === undefined) return COMMAND_OPTIONS;\n\n const subcommands = SUBCOMMAND_OPTIONS[command.toLowerCase()];\n if (subcommands && rest.length === 0) return subcommands;\n\n // A selector argument takes any number of space-separated values, so what\n // decides the slot is the last argument, not whether a selector appeared at all:\n // `--select tag:a tag:b` keeps offering methods, `--select a --profile p` stops.\n const lastArgument = rest.filter((it) => it.startsWith('-')).at(-1);\n const selecting = lastArgument !== undefined && SELECTORS.includes(lastArgument.toLowerCase());\n\n return selecting\n ? [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS, ...METHOD_OPTIONS]\n : [...ARGUMENT_OPTIONS, ...FLAG_OPTIONS];\n};\n\nconst complete = (context: CompletionContext): CompletionResult | null => {\n const typed = context.matchBefore(WORD);\n\n // `WORD` also matches the empty string, so without this the popup would open on\n // every space. Asking for completions explicitly still opens it there.\n if (!typed?.text && !context.explicit) return null;\n\n const from = typed?.from ?? context.pos;\n const line = context.state.doc.lineAt(from);\n const options = optionsAfter(\n line.text\n .slice(0, from - line.from)\n .split(/\\s+/)\n .filter(Boolean),\n );\n\n return options.length > 0 ? { from, options, validFor: WORD } : null;\n};\n\nexport const dbt = simpleMode({\n languageData: {\n // `toggleComment` is a no-op without these, so Mod-/ silently does nothing.\n commentTokens: { line: '--', block: { open: '/*', close: '*/' } },\n autocomplete: complete,\n },\n start: [\n { regex: /\"(?:[^\\\\]|\\\\.)*?(?:\"|$)/, token: 'string' },\n // Word-bounded, so `dbtX` is not a dbt step whose first word happens to\n // colour — the same thing the completion source asks of it.\n { regex: /dbt\\b/, token: 'keyword', sol: true },\n { regex: word(COMMAND_PHRASES), token: 'keyword' },\n { regex: word(ARGUMENTS), token: 'variableName' },\n { regex: prefix(METHODS), token: 'propertyName' },\n { regex: prefix(FLAGS), token: 'attributeName' },\n { regex: /(?:@|\\*|,|\\+\\d+|\\d+\\+|\\+)/, token: 'operator' },\n { regex: /'.*'/, token: 'string' },\n { regex: /true|false/, token: 'atom' },\n ],\n});\n","import type { StreamParser } from '@codemirror/language';\n\n/**\n * Ported from google/codemirror-mode-jsonnet (Apache-2.0), the mode written by\n * the language's own authors, which was never taken past CodeMirror 5.\n * CodeMirror 5 style names are replaced by their CodeMirror 6 highlight tags:\n * `string-2` is `escape`, `error` is `invalid`.\n *\n * Every pattern is anchored and hoisted. `StringStream.match` slices the rest of\n * the line and, without `^`, scans all of it for a match it then discards unless\n * it started at the cursor — so an unanchored probe costs the whole remaining\n * line, and this tokenizer makes up to twenty of them per token.\n */\n\nconst COMMENT_END = /^\\*\\//;\nconst COMMENT_START = /^\\/\\/|^#/;\nconst C_COMMENT_START = /^\\/\\*/;\nconst TEXT_BLOCK = /^\\|\\|\\|/;\nconst TEXT_BLOCK_END = /^\\s*\\|\\|\\|/;\nconst RAW_DOUBLE = /^\"\"/;\nconst RAW_SINGLE = /^''/;\nconst CLOSE_DOUBLE = /^\"/;\nconst CLOSE_SINGLE = /^'/;\nconst ESCAPE = /^\\\\[\\\\\"'/bfnrt0]/;\nconst UNICODE_ESCAPE = /^\\\\u[0-9a-fA-F]{4}/;\nconst BACKSLASH = /^\\\\/;\nconst IMPORT = /^import(?:str)?\\s*(@?)([\"'])/;\nconst QUOTE = /^(@?)([\"'])/;\nconst ROOT = /^\\$/;\nconst NUMBER = /^(?:\\.\\d+|\\d+\\.?\\d*)(?:e[-+]?\\d+)?/i;\nconst OPERATOR = /^[-+/*=<>!&~^|$%]+/;\nconst IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*/;\n\nconst KEYWORDS: Record<string, 'keyword' | 'atom'> = {\n local: 'keyword',\n self: 'keyword',\n super: 'keyword',\n assert: 'keyword',\n function: 'keyword',\n if: 'keyword',\n then: 'keyword',\n else: 'keyword',\n for: 'keyword',\n in: 'keyword',\n tailstrict: 'keyword',\n error: 'keyword',\n true: 'atom',\n false: 'atom',\n null: 'atom',\n};\n\ntype State = {\n cComment: boolean;\n textBlock: boolean;\n textBlockIndent: number | null;\n string: boolean;\n importString: boolean;\n stringSingle: boolean;\n stringRaw: boolean;\n};\n\nexport const jsonnet: StreamParser<State> = {\n name: 'jsonnet',\n\n // `toggleComment` is a no-op without these, so Mod-/ silently does nothing.\n languageData: { commentTokens: { line: '//', block: { open: '/*', close: '*/' } } },\n\n startState: () => ({\n cComment: false,\n textBlock: false,\n textBlockIndent: null,\n string: false,\n importString: false,\n stringSingle: false,\n stringRaw: false,\n }),\n\n token: (stream, state) => {\n if (state.cComment) {\n if (stream.match(COMMENT_END)) {\n state.cComment = false;\n return 'comment';\n }\n stream.next();\n return 'comment';\n }\n\n // A `|||` block runs from its own first content line to the first line\n // indented less than that — so the closing `|||` has to be recognised\n // before the indent is measured, or a block closed at column 0 never ends.\n if (state.textBlock) {\n if (state.textBlockIndent == null) {\n if (stream.match(TEXT_BLOCK_END)) {\n state.textBlock = false;\n return 'string';\n }\n state.textBlockIndent = stream.indentation();\n }\n if (stream.indentation() >= state.textBlockIndent) {\n stream.skipToEnd();\n return 'string';\n }\n if (stream.match(TEXT_BLOCK_END)) {\n state.textBlock = false;\n return 'string';\n }\n stream.next();\n return 'invalid';\n }\n\n // Quoted and `@`-raw strings, single or double, plain or after an import.\n if (state.string || state.importString) {\n const style = state.string ? 'string' : 'meta';\n\n if (state.stringRaw) {\n if (stream.match(state.stringSingle ? RAW_SINGLE : RAW_DOUBLE)) return 'escape';\n } else {\n if (stream.match(ESCAPE)) return 'escape';\n if (stream.match(UNICODE_ESCAPE)) return 'escape';\n if (stream.match(BACKSLASH)) return 'invalid';\n }\n\n if (stream.match(state.stringSingle ? CLOSE_SINGLE : CLOSE_DOUBLE)) {\n state.string = false;\n state.importString = false;\n return style;\n }\n\n stream.next();\n return style;\n }\n\n if (stream.match(COMMENT_START)) {\n stream.skipToEnd();\n return 'comment';\n }\n if (stream.match(C_COMMENT_START)) {\n state.cComment = true;\n return 'comment';\n }\n\n // An import opens a string that is styled as meta rather than as content.\n const imported = stream.match(IMPORT);\n if (Array.isArray(imported)) {\n state.importString = true;\n state.stringRaw = imported[1] === '@';\n state.stringSingle = imported[2] === \"'\";\n return 'meta';\n }\n\n const quoted = stream.match(QUOTE);\n if (Array.isArray(quoted)) {\n state.string = true;\n state.stringRaw = quoted[1] === '@';\n state.stringSingle = quoted[2] === \"'\";\n return 'string';\n }\n\n if (stream.match(TEXT_BLOCK)) {\n state.textBlock = true;\n state.textBlockIndent = null;\n return 'string';\n }\n\n if (stream.match(ROOT)) return 'keyword';\n if (stream.match(NUMBER)) return 'number';\n if (stream.match(OPERATOR)) return 'operator';\n\n // Consumed whole so that a keyword's prefix (`locally`) is not styled.\n const identifier = stream.match(IDENTIFIER);\n if (Array.isArray(identifier)) return KEYWORDS[identifier[0]] ?? null;\n\n stream.next();\n return null;\n },\n};\n","import type { ResolvedColorScheme } from '../ThemeProvider/types';\n\n/**\n * Alpha suffixes for the dark-scheme diff and state tints.\n *\n * - The line fill stays subtle enough for the `foreground` text to read; the gutter sits a step\n * stronger so the scan-lane is still obvious next to it.\n * - `DARK_LINE_ALPHA` also carries the run-state and search washes in `highlighting.ts` and\n * `search.ts`, which are static base themes and so append the suffix themselves.\n */\nexport const DARK_LINE_ALPHA = '29'; /* 16% */\nconst DARK_GUTTER_ALPHA = '47'; /* 28% */\n\n/**\n * The two diff fills, per scheme: light keeps the opaque pastel, dark tints the same `500` hue at\n * low alpha over whatever token surface is behind it.\n *\n * - Its own module, importing nothing, so `MergeEditor` can share it without reaching into\n * `CodeEditor/helpers.ts` and pulling the language modes and the CodeMirror runtime with it.\n * - Shared by the unified merge wash in `helpers.ts` and `buildDiffHighlightTheme` in\n * `MergeEditor/decorations.ts`, so the two views cannot drift apart on the alphas.\n * - Callers pass the hue and the pastel; which one is used is this function's business.\n */\nexport const buildDiffWash = (scheme: ResolvedColorScheme) => {\n const dark = scheme === 'dark';\n\n return {\n line: (hue: string, pastel: string) => (dark ? `${hue}${DARK_LINE_ALPHA}` : pastel),\n gutter: (hue: string, pastel: string) => (dark ? `${hue}${DARK_GUTTER_ALPHA}` : pastel),\n };\n};\n","import { tags } from '@lezer/highlight';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nimport type { ResolvedColorScheme } from '../ThemeProvider/types';\n\n/**\n * The tag colours layered over the stock github palette, per colour scheme.\n *\n * - Its own module, importing nothing but the tag vocabulary and the ramps, so\n * `scripts/contrast-audit.ts` can measure the palette without pulling the language modes and the\n * CodeMirror runtime into a build script.\n * - Later entries win over the stock rule for the same tag — both `githubLightInit` and\n * `githubDarkInit` concatenate these after their own.\n * - `foreground` is the caller's, because it is a live `--*` token rather than a ramp step: the\n * theme passes `resolveToken('foreground')`, the audit passes the scheme's channel value.\n * - Every ramp step here is a light/dark pair, and each pair is chosen against **two** surfaces —\n * the theme's `background` setting is the page, but `variant=\"field\"` paints on `muted`, which\n * the theme never sees. Ratios in the comments are quoted `background` / `muted`.\n */\nexport const buildSyntaxPalette = (scheme: ResolvedColorScheme, foreground: string) => {\n const dark = scheme === 'dark';\n\n return [\n // Plain identifiers, quoted identifiers (`\"a column\"`) and brackets carry no colour of their\n // own, matching github.com's own rendering — stock github lumps brackets in with comments.\n { tag: [tags.name, tags.special(tags.string), tags.bracket], color: foreground },\n // Functions — light `600` 6.13 / 5.84, dark `300` 9.62 / 7.80.\n { tag: tags.standard(tags.name), color: dark ? colors.purple[300] : colors.purple[600] },\n // Special vars — light `800` 7.26 / 6.92, dark `300` 13.49 / 10.94.\n { tag: tags.special(tags.name), color: dark ? colors.cyan[300] : colors.cyan[800] },\n // Strings — light `800` 7.23 / 6.89, dark `300` 13.53 / 10.97.\n { tag: tags.string, color: dark ? colors.warning[300] : colors.warning[800] },\n // The four below re-target stock light colours that sit below AA, each to the nearest step of\n // our own ramp in the same hue. Dark needs none of them — `githubDarkStyle` clears AA on every\n // surface — so under dark they fall through to it.\n //\n // Ratios are `background` / `muted`; `CONTRAST-AUDIT.md` carries all four surfaces and the\n // stock values these replace.\n ...(dark\n ? []\n : [\n // Keywords — 5.96 / 5.69, from 4.38 / 4.18.\n { tag: [tags.keyword, tags.typeName, tags.typeOperator], color: colors.error[550] },\n // Comments — 6.44 / 6.15, from 4.61 / 4.40.\n { tag: tags.comment, color: colors.neutral[500] },\n // Markdown quotes — 7.15 / 6.82, from 4.43 / 4.22.\n { tag: tags.quote, color: colors.green[900] },\n // Lex errors — 7.81 / 7.45. The stock red clears both of these and fails the read-only\n // wash at 4.44, the darkest of the four surfaces an editor paints on.\n { tag: tags.invalid, color: colors.error[700] },\n ]),\n // Dark only, because `githubDarkStyle` carries no `escape` rule where the light array does.\n // The jsonnet mode emits it for `\\n` and `\\uXXXX`; unpainted, those fall back to `foreground`\n // and stop being distinguishable from the amber string body they sit in. `blue[300]` is\n // 10.97 / 8.90 and reads as \"special, inside a string\" against that amber.\n ...(dark ? [{ tag: [tags.escape, tags.url, tags.link], color: colors.blue[300] }] : []),\n ];\n};\n","import { javascript } from '@codemirror/lang-javascript';\nimport { json, jsonParseLinter } from '@codemirror/lang-json';\nimport { python } from '@codemirror/lang-python';\nimport { MSSQL, MySQL, PLSQL, PostgreSQL, StandardSQL } from '@codemirror/lang-sql';\nimport { StreamLanguage } from '@codemirror/language';\nimport { r } from '@codemirror/legacy-modes/mode/r';\nimport { shell } from '@codemirror/legacy-modes/mode/shell';\nimport { toml } from '@codemirror/legacy-modes/mode/toml';\nimport type { LintSource } from '@codemirror/lint';\nimport { linter } from '@codemirror/lint';\nimport { githubDarkInit, githubLightInit } from '@uiw/codemirror-theme-github';\nimport type { BasicSetupOptions } from '@uiw/react-codemirror';\n\nimport { getSqlLanguageSupport } from '@keboola/codemirror-lang-sql';\nimport colors from '@keboola/tailwind-config/colors';\n\nimport { resolveToken } from '../../utils/themeTokens';\nimport type { ResolvedColorScheme } from '../ThemeProvider/types';\n\nimport { dbt } from './modes/dbt';\nimport { jsonnet } from './modes/jsonnet';\nimport { buildDiffWash } from './diffWash';\nimport { buildSyntaxPalette } from './syntaxPalette';\n\n// The MIME vocabulary callers pass. Kept as a const so the runtime whitelist and\n// the type stay one list — an annotated `LANGUAGE_MODE[]` copy elsewhere silently\n// drifts, since the type checker accepts a short one.\nexport const LANGUAGE_MODES = [\n 'application/json',\n 'text/plain',\n 'text/x-python',\n 'text/x-sql',\n 'text/x-mysql',\n 'text/x-pgsql',\n 'text/x-mssql',\n // Snowflake, under a historical name — these strings are a published prop contract.\n 'text/x-sfsql',\n 'text/x-bqsql',\n 'text/x-plsql',\n 'text/x-rsrc',\n 'text/x-sh',\n 'text/x-toml',\n 'text/jsonnet',\n 'text/x-dbt',\n 'text/javascript',\n 'text/typescript',\n] as const;\n\nexport type LANGUAGE_MODE = (typeof LANGUAGE_MODES)[number];\n\nexport const isLanguageMode = (mode: string): mode is LANGUAGE_MODE =>\n (LANGUAGE_MODES as readonly string[]).includes(mode);\n\n// `readOnly` reaches CodeMirror as `contenteditable`, so the two states are only\n// addressable through it. Exported because `fieldChrome` overrides the read-only\n// wash below by re-declaring the same key — which only works while the strings\n// match exactly.\nexport const READ_ONLY_EDITOR = '&.cm-editor:has(.cm-content[contenteditable=\"false\"])';\nexport const EDITABLE_EDITOR = '&.cm-editor:has(.cm-content[contenteditable=\"true\"])';\n\n/**\n * Editor chrome and the unified merge (diff) wash.\n *\n * - Chrome surfaces (selection, read-only wash) resolve from live `--*` tokens, so they re-skin\n * with brand and colour scheme. Fallback channels mirror the light-mode token values for SSR /\n * no-provider parity.\n * - Diff colours stay categorical — fixed across brands, because added/removed is meaning, not\n * chrome — but each is a light/dark pair from `buildDiffWash`, shared with\n * `buildDiffHighlightTheme` in `MergeEditor/decorations.ts`.\n * - This wash reaches only `CodeEditor`'s *unified* merge view — the one a `previousValue` turns on.\n * `MergePane` builds its own theme from scratch.\n */\nexport const buildBaseThemeStyles = (scheme: ResolvedColorScheme) => {\n const { line, gutter } = buildDiffWash(scheme);\n const dark = scheme === 'dark';\n\n return {\n '*': { lineHeight: '20px' },\n '*::selection': {\n backgroundColor: resolveToken('primary', '31 143 255'),\n color: `${resolveToken('primary-foreground', '255 255 255')} !important`,\n },\n // The recessed wash. `secondary` sits a step darker than `muted` in light but a step *lighter*\n // in dark, where it would take the palette's tightest colour (`comment`) to 4.27:1 — so dark\n // asks for `muted` (4.89:1). The inversion is a token-system quirk, not an editor one.\n // Re-pointable: set `--code-editor-surface` on any ancestor and the body and gutters follow it.\n [READ_ONLY_EDITOR]: {\n backgroundColor: `var(--code-editor-surface, ${\n dark ? resolveToken('muted', '38 38 45') : resolveToken('secondary', '226 232 240')\n })`,\n },\n [`${READ_ONLY_EDITOR} .cm-gutters`]: {\n backgroundColor: `var(--code-editor-surface, ${resolveToken('border', '229 231 235')})`,\n },\n '&.cm-editor .cm-scroller': { overflowAnchor: 'none' },\n '&.cm-editor, &.cm-editor .cm-scroller': {\n minHeight: '100%',\n flexGrow: 1,\n alignItems: 'stretch !important',\n outline: 'none',\n },\n '.cm-gutter.cm-foldGutter': { display: 'none !important' },\n '.cm-gutter.cm-lineNumbers': { paddingLeft: '20px', paddingRight: '6px' },\n '.cm-gutters': { height: 'auto' },\n\n // merge (diff) view\n '&[class*=\"cm-merge-\"] .cm-deletedLine': {\n backgroundColor: line(colors.error[500], colors.error[100]),\n },\n '&[class*=\"cm-merge-\"] .cm-changedLine': {\n backgroundColor: line(colors.green[500], colors.green[100]),\n },\n '&[class*=\"cm-merge-\"] .cm-deletedLineGutter': {\n backgroundColor: gutter(colors.error[500], colors.error[200]),\n },\n '&[class*=\"cm-merge-\"] .cm-changedLineGutter': {\n backgroundColor: gutter(colors.green[500], colors.green[200]),\n },\n '&[class*=\"cm-merge-\"] .cm-deletedText': {\n background: gutter(colors.error[500], colors.error[200]),\n },\n '&[class*=\"cm-merge-\"] .cm-changedText': {\n background: gutter(colors.green[500], colors.green[200]),\n },\n // The container and its gutter follow the page, not the diff — a fixed white here would be the\n // whole editor as a light slab under dark.\n '&[class*=\"cm-merge-\"]': {\n backgroundColor: `${resolveToken('background', '249 250 251')} !important`,\n },\n '&[class*=\"cm-merge-\"] .cm-gutters': {\n backgroundColor: `${resolveToken('muted', '241 245 249')} !important`,\n },\n '.cm-changeGutter': { position: 'absolute', zIndex: -1, width: '100%', paddingLeft: 0 },\n '&[class*=\"cm-merge-\"] .cm-changedLine,&[class*=\"cm-merge-\"] .cm-line, &[class*=\"cm-merge-\"] .cm-deletedChunk':\n { paddingLeft: 0 },\n };\n};\n\n// Dead whatever the editor does with them: `buildBaseThemeStyles` hides the fold\n// gutter outright, and `buildCustomTheme` paints the active line transparent.\n//\n// `autocompletion` is off because both editors install their own and a second instance\n// is not a no-op: `CodeEditor` gates its copy on `readOnly` and on `withCompletions`,\n// and `SqlEditor` passes options through `installExtensions`, which basicSetup's\n// option-less copy would compete with.\nconst ALWAYS_OFF = {\n autocompletion: false,\n drawSelection: false,\n foldGutter: false,\n foldKeymap: false,\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n} as const;\n\n// `basicSetup` enables everything it is not told to skip, so a viewer would\n// otherwise install bracket closing and keybindings for commands a read-only\n// document rejects. Search stays — Mod-f is useful on a viewer. Same reasoning\n// as `shouldLintJson` below.\n//\n// `history` stays too, though a viewer can never add an entry: a caller that\n// flips `readOnly` mid-session reconfigures the view, and a reconfigure discards\n// state fields the new configuration doesn't have. Leaving it out saves nothing\n// and costs the editable session its undo stack.\nexport const buildBasicSetup = (readOnly: boolean): BasicSetupOptions => ({\n ...ALWAYS_OFF,\n ...(readOnly\n ? {\n closeBrackets: false,\n closeBracketsKeymap: false,\n lintKeymap: false,\n indentOnInput: false,\n rectangularSelection: false,\n dropCursor: false,\n highlightSelectionMatches: false,\n }\n : null),\n});\n\n/**\n * The syntax theme, per colour scheme.\n *\n * - The stock github palette is picked by scheme: `githubDarkInit` under dark, `githubLightInit`\n * otherwise. One palette cannot serve both — the light set scores 1.14:1 to 4.31:1 on the two\n * dark surfaces, so 10 of its 11 colours failed AA there (UT-5194).\n * - `githubDarkInit` also passes `dark: true` to `EditorView.theme`, which sets the\n * `EditorView.darkTheme` facet. That is what makes the `&dark` rules apply — CodeMirror's own\n * base theme (cursor, selection layer, panels, buttons) and ours (`search.ts`,\n * `highlighting.ts`) both key off it, so they follow the scheme without a second signal.\n * - Chrome (surface, gutter, selection, caret) resolves from live `--*` tokens, so it re-skins with\n * the brand too. Fallback channels mirror the light-mode token values, for SSR and jsdom.\n * - `caret` and `selectionMatch` are pinned because the two initialisers disagree on them, and the\n * branch would otherwise change values nothing here chose. The caret follows `foreground`; before\n * the facet was set, CodeMirror's own default painted it black on the dark page, so it was\n * invisible. `selectionMatch` is a 10% `primary` tint, which beats each initialiser's own value\n * on the token it hurts most: 3.82:1 against the light default's 3.29, 5.40:1 against the dark\n * default's 3.57. Any occurrence wash costs contrast — this is the cheapest one, and it is the\n * same in both schemes.\n * - `styles` comes from `buildSyntaxPalette`, which lives apart so the audit script can measure it.\n *\n * Those overrides exist because the github theme paints every `name`-family tag one colour, and in\n * SQL nearly every token is a name — identifiers, function calls and `$variables` all drowned\n * together, and a keyword that doubles as a function (`create or REPLACE`) read as a value\n * (UT-5024). Instead: identifiers and brackets carry no colour, functions and special vars get\n * their own hues, and amber is unique to string literals — in JSON that shifts string values from\n * navy to amber, the one visible non-SQL change.\n */\nexport const buildCustomTheme = (scheme: ResolvedColorScheme) => {\n const foreground = resolveToken('foreground', '30 41 59');\n const init = scheme === 'dark' ? githubDarkInit : githubLightInit;\n\n return init({\n settings: {\n fontFamily: `'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New'`,\n background: resolveToken('background', '249 250 251'),\n foreground,\n caret: foreground,\n gutterBackground: resolveToken('muted', '241 245 249'),\n gutterForeground: resolveToken('muted-foreground', '100 116 139'),\n gutterBorder: 'transparent',\n lineHighlight: 'transparent',\n selection: resolveToken('primary', '31 143 255'),\n selectionMatch: resolveToken('primary', '31 143 255', 0.1),\n },\n styles: buildSyntaxPalette(scheme, foreground),\n });\n};\n\nexport const getLanguageMode = (mode?: LANGUAGE_MODE) => {\n switch (mode) {\n case undefined:\n case 'application/json':\n return json();\n case 'text/x-python':\n return python();\n case 'text/x-sql':\n return getSqlLanguageSupport(StandardSQL);\n case 'text/x-mysql':\n return getSqlLanguageSupport(MySQL);\n case 'text/x-pgsql':\n return getSqlLanguageSupport(PostgreSQL);\n case 'text/x-mssql':\n return getSqlLanguageSupport(MSSQL);\n case 'text/x-sfsql':\n return getSqlLanguageSupport('snowflake');\n case 'text/x-bqsql':\n return getSqlLanguageSupport('bigquery');\n case 'text/x-plsql':\n return getSqlLanguageSupport(PLSQL);\n case 'text/x-rsrc':\n return StreamLanguage.define(r);\n case 'text/x-sh':\n return StreamLanguage.define(shell);\n case 'text/x-toml':\n return StreamLanguage.define(toml);\n case 'text/jsonnet':\n return StreamLanguage.define(jsonnet);\n case 'text/x-dbt':\n return StreamLanguage.define(dbt);\n case 'text/javascript':\n return javascript({ jsx: true });\n case 'text/typescript':\n return javascript({ jsx: true, typescript: true });\n // No language — `text/plain` lands here, and so does any mode added to\n // LANGUAGE_MODES without an arm above. Unstyled text is the safe degradation;\n // a `json()` default would colour unrelated content as if it were JSON.\n default:\n return [];\n }\n};\n\n// The JSON parse linter is only useful on an editable editor — a read-only one\n// can't act on the errors, so running it is wasted work and its underlines are\n// noise (e.g. non-strict JSON shown read-only in Kai chat).\nexport const shouldLintJson = (mode: LANGUAGE_MODE | undefined, readOnly: boolean): boolean =>\n mode === 'application/json' && !readOnly;\n\n/**\n * Wraps a lint source so a blank document produces no diagnostics.\n *\n * `jsonParseLinter` reports \"Unexpected end of input\" for empty content, which is right for a file and\n * wrong for an *optional* form field: it starts empty, and clearing it is how its value is removed.\n * Left unwrapped, every such field opens with a red gutter marker contradicting its own validation —\n * `CodeEditorField` puts six of them on one screen.\n *\n * Exported for its test: the wrapper is the behaviour worth pinning, and it needs no editor to exercise.\n */\nexport const skipBlankDocument =\n (source: LintSource): LintSource =>\n (view) =>\n view.state.doc.toString().trim() === '' ? [] : source(view);\n\n/**\n * The JSON linter, optionally blind to a blank document.\n *\n * - `allowBlankDocument` is opt-in, and only `CodeEditorField` opts in (from `!required`). Suppressing\n * the marker by default would break callers that treat empty as invalid *and* say so nowhere else:\n * `ex-generic/JsonConfiguration.tsx`, `flows/TaskParamsModalContent.tsx` and\n * `stream/PayloadTest.tsx` all gate their button on `isValidJsonConfig`, which is `false` for `''`,\n * with no `disabledReason` — so the gutter marker is the only thing explaining a dead button.\n * - Not derivable from `variant`: `ex-generic/FunctionControl.tsx` is `variant=\"field\"` and empty is\n * an error there too. Whether blank is valid is the *field's* contract, not the control's shape.\n */\nexport const buildJsonLinter = (allowBlankDocument: boolean) => {\n const source = jsonParseLinter();\n\n return linter(allowBlankDocument ? skipBlankDocument(source) : source);\n};\n","import colors from '@keboola/tailwind-config/colors';\n\nimport { resolveToken } from '../../utils/themeTokens';\nimport type { ResolvedColorScheme } from '../ThemeProvider/types';\n\nimport { EDITABLE_EDITOR, READ_ONLY_EDITOR } from './helpers';\n\n/**\n * The parts of an editor's outer chrome that differ between presets; how they\n * reach CodeMirror's selectors lives once in `buildChromeStyles`.\n */\nexport type EditorChrome = {\n surface: string;\n borderColor: string;\n readOnlySurface: string;\n readOnlyBorderColor: string;\n /** `null` for a preset with no hover affordance — form inputs have none. */\n hoverBorderColor: string | null;\n focusBorderColor: string;\n focusRing: string;\n radius: string;\n paddingY: string;\n /** `null` leaves CodeMirror's own 6px/2px line inset alone. */\n paddingX: { left: string; right: string } | null;\n};\n\n/**\n * Mirrors `InputGroup` at the sizing each design language gives a `TextInput`,\n * so an editor dropped into a form reads as one of its fields.\n *\n * The legacy preset reads the neutral ramp because the legacy `secondary`\n * variant does. No semantic token holds that grey, and the nearest one\n * (`--muted`) is a few points off — which is the \"almost, but not quite, the\n * input next to it\" mismatch this preset exists to remove.\n *\n * That ramp is fixed, so the legacy preset needs its own scheme pair — a legacy brand and the dark\n * scheme are independent choices, and `neutral[100]` under dark is a light slab: `foreground` on it\n * is 1.09:1 and the darkest syntax colour 2.69:1. Dark mirrors the same two steps from the other\n * end of the ramp (`800` / `900`, 5.00:1 and 6.14:1 for that colour).\n */\nexport const buildInputChrome = (isArgo: boolean, scheme: ResolvedColorScheme): EditorChrome => {\n const dark = scheme === 'dark';\n const legacySurface = dark ? colors.neutral[800] : colors.neutral[100];\n const legacyReadOnly = dark ? colors.neutral[900] : colors.neutral[150];\n\n return {\n surface: isArgo ? resolveToken('muted', '241 245 249') : legacySurface,\n borderColor: isArgo ? resolveToken('input', '203 213 225') : legacySurface,\n readOnlySurface: isArgo ? resolveToken('muted', '241 245 249') : legacyReadOnly,\n readOnlyBorderColor: isArgo ? resolveToken('input', '203 213 225') : legacyReadOnly,\n hoverBorderColor: null,\n focusBorderColor: isArgo\n ? resolveToken('primary', '37 99 235')\n : resolveToken('ring', '31 143 255'),\n focusRing: `0 0 0 4px ${resolveToken('ring', '31 143 255', isArgo ? 0.5 : 0.3)}`,\n radius: isArgo ? 'var(--radius-lg, 0.25rem)' : '0.25rem',\n // 2px border + 2×this + `.cm-content`'s own 4px + a 20px line, against the\n // height a one-line `TextInput` has: argo forces `sizing: 'medium'` (36px),\n // legacy leaves it at `default` (40px).\n paddingY: isArgo ? '3px' : '5px',\n // Tops `.cm-line`'s 6px/2px up to the 16px an input's text is inset by.\n paddingX: { left: '10px', right: '14px' },\n };\n};\n\n/** The SQL workspace's notebook cell: a white canvas, not a form control. */\nexport const buildCanvasChrome = (): EditorChrome => ({\n surface: resolveToken('card', '255 255 255'),\n borderColor: 'transparent',\n readOnlySurface: resolveToken('muted', '241 245 249'),\n readOnlyBorderColor: 'transparent',\n hoverBorderColor: resolveToken('ring', '31 143 255'),\n focusBorderColor: resolveToken('ring', '31 143 255'),\n focusRing: `0 0 0 4px ${resolveToken('ring', '31 143 255', 0.3)}`,\n radius: '8px',\n paddingY: '8px',\n paddingX: null,\n});\n\n/**\n * Spread over `buildBaseThemeStyles()` — never used alone. The read-only keys\n * are the base's own, so they replace its wash instead of landing beside it.\n */\nexport const buildChromeStyles = (chrome: EditorChrome) => ({\n '&.cm-editor': {\n border: `solid 1px ${chrome.borderColor}`,\n borderRadius: chrome.radius,\n backgroundColor: chrome.surface,\n paddingTop: chrome.paddingY,\n paddingBottom: chrome.paddingY,\n },\n '&.cm-editor :is(.cm-gutters,.cm-scroller)': { backgroundColor: chrome.surface },\n\n ...(chrome.paddingX\n ? {\n // Only without a gutter: there the editor reads as a one-line input and\n // its text should start where a neighbouring `TextInput`'s does. With a\n // gutter, the gutter owns the left edge.\n '&.cm-editor:not(:has(.cm-gutters)) .cm-content': {\n paddingLeft: chrome.paddingX.left,\n paddingRight: chrome.paddingX.right,\n },\n }\n : null),\n\n ...(chrome.hoverBorderColor\n ? { [`${EDITABLE_EDITOR}:hover`]: { borderColor: chrome.hoverBorderColor } }\n : null),\n [`${EDITABLE_EDITOR}:focus-within`]: {\n borderColor: chrome.focusBorderColor,\n boxShadow: chrome.focusRing,\n },\n\n [READ_ONLY_EDITOR]: {\n backgroundColor: chrome.readOnlySurface,\n borderColor: chrome.readOnlyBorderColor,\n },\n [`${READ_ONLY_EDITOR} .cm-gutters`]: { backgroundColor: chrome.readOnlySurface },\n [`${READ_ONLY_EDITOR} .cm-scroller`]: { backgroundColor: chrome.readOnlySurface },\n});\n","import { StateEffect, StateField, type Text } from '@codemirror/state';\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n ViewPlugin,\n type ViewUpdate,\n} from '@codemirror/view';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nimport { findLiteralMatches } from '../../utils/findLiteralMatches';\n\nimport { DARK_LINE_ALPHA } from './diffWash';\n\n// Represents a single search match in the editor\ntype SearchMatch = {\n /** Start position in document */\n from: number;\n /** End position in document */\n to: number;\n /** Local match index within this editor (0-based) */\n localIndex: number;\n};\n\n// Effect to update search state\nconst setSearchEffect = StateEffect.define<{\n query: string;\n selectedMatchIndex?: number;\n}>();\n\n// State to track current search matches\ntype SearchState = {\n query: string;\n selectedMatchIndex?: number;\n matches: SearchMatch[];\n decorations: DecorationSet;\n};\n\n// Find all matches in the document\nfunction findMatches(doc: Text, query: string): SearchMatch[] {\n // Ahead of `doc.toString()`, which joins the whole rope. A query longer than the document is\n // what pasting a document into the search box looks like.\n if (!query || query.length > doc.length) return [];\n\n return findLiteralMatches(doc.toString(), query).map((from, index) => ({\n from,\n to: from + query.length,\n localIndex: index,\n }));\n}\n\n// Create decorations for search matches\nfunction createDecorations(matches: SearchMatch[], selectedLocalIndex?: number): DecorationSet {\n const decorations = matches.map((match) => {\n const isSelected = match.localIndex === selectedLocalIndex;\n\n const decoration = Decoration.mark({\n class: isSelected ? 'cm-searchMatch-selected' : 'cm-searchMatch',\n });\n\n return decoration.range(match.from, match.to);\n });\n\n return Decoration.set(decorations, true);\n}\n\n// StateField to manage search state\nconst searchField = StateField.define<SearchState>({\n create() {\n return {\n query: '',\n selectedMatchIndex: undefined,\n matches: [],\n decorations: Decoration.none,\n };\n },\n\n update(state, tr) {\n let newState = state;\n\n // Handle search effect\n for (const effect of tr.effects) {\n if (!effect.is(setSearchEffect)) {\n continue;\n }\n\n const { query, selectedMatchIndex } = effect.value;\n\n // Find matches\n const matches = findMatches(tr.state.doc, query);\n\n // Create decorations\n const decorations = createDecorations(matches, selectedMatchIndex);\n\n newState = {\n query,\n selectedMatchIndex,\n matches,\n decorations,\n };\n }\n\n // Map decorations through document changes\n if (tr.docChanged && newState.query) {\n const matches = findMatches(tr.state.doc, newState.query);\n const decorations = createDecorations(matches, newState.selectedMatchIndex);\n\n newState = {\n ...newState,\n matches,\n decorations,\n };\n }\n\n return newState;\n },\n\n provide: (field) => EditorView.decorations.from(field, (state) => state.decorations),\n});\n\n// View plugin to handle scrolling to selected match\nconst searchViewPlugin = ViewPlugin.fromClass(\n class {\n private lastSelectedIndex?: number;\n\n update(update: ViewUpdate) {\n const state = update.state.field(searchField);\n\n // Scroll to selected match when it changes\n if (\n state.selectedMatchIndex !== undefined &&\n state.selectedMatchIndex !== this.lastSelectedIndex\n ) {\n const match = state.matches[state.selectedMatchIndex];\n\n if (match) {\n requestAnimationFrame(() => {\n update.view.dispatch({\n effects: EditorView.scrollIntoView(match.from, { y: 'center' }),\n });\n });\n }\n\n this.lastSelectedIndex = state.selectedMatchIndex;\n }\n\n // Reset if no selection\n if (state.selectedMatchIndex === undefined) {\n this.lastSelectedIndex = undefined;\n }\n }\n },\n);\n\n/**\n * Match and current-match fills, per colour scheme.\n *\n * - `&dark` is how a *static* base theme follows the scheme, without becoming a\n * `useThemedExtension` builder and a second entry in its never-evicting cache. It applies\n * whenever the `EditorView.darkTheme` facet is set — see `buildBaseThemeStyles`' callers, which\n * set it explicitly.\n * - Light text is `blue[700]`: 5.42:1 on the fill, and 6.29:1 for white on the current match.\n * - Dark tints `blue[500]` for the plain match, with `blue[200]` text: 11.10:1 on the page surface,\n * 8.86:1 on the `variant=\"field\"` one. The current match keeps a solid `blue[500]` and takes\n * `neutral[900]` as its text (5.78:1) — white on it is 2.55:1, since the token that reads as\n * \"strong\" in light is a light colour.\n */\nconst searchTheme = EditorView.baseTheme({\n '.cm-searchMatch': {\n backgroundColor: colors.blue[100],\n },\n '.cm-searchMatch > span': {\n color: `${colors.blue[700]} !important`,\n },\n '.cm-searchMatch-selected': {\n backgroundColor: colors.blue[700],\n },\n '.cm-searchMatch-selected > span': {\n color: `${colors.white} !important`,\n },\n\n '&dark .cm-searchMatch': {\n backgroundColor: `${colors.blue[500]}${DARK_LINE_ALPHA}`,\n },\n '&dark .cm-searchMatch > span': {\n color: `${colors.blue[200]} !important`,\n },\n '&dark .cm-searchMatch-selected': {\n backgroundColor: colors.blue[500],\n },\n '&dark .cm-searchMatch-selected > span': {\n color: `${colors.neutral[900]} !important`,\n },\n});\n\nexport function searchExtension() {\n return [searchField, searchViewPlugin, searchTheme];\n}\n\nexport function updateSearch(view: EditorView, query: string, selectedMatchIndex?: number) {\n view.dispatch({ effects: setSearchEffect.of({ query, selectedMatchIndex }) });\n}\n","import { isMac } from '../../utils';\nimport { Kbd } from '../Kbd';\n\nexport const ToggleComponentHelp = () => (\n <div>\n Use <Kbd>{isMac ? 'Command+/' : 'Ctrl+/'}</Kbd> to toggle comments.\n </div>\n);\n","import { type Extension } from '@codemirror/state';\n\nimport type { ResolvedColorScheme } from '../ThemeProvider/types';\nimport { useThemeAttributes } from '../ThemeProvider/useThemeAttributes';\n\n// Cached across component instances, not just across renders. A CodeMirror theme\n// extension carries its own StyleModule, and mounting an EditorView appends its\n// rules to a document-level stylesheet — which invalidates style for the whole\n// document. Sharing one module per theme keeps the stylesheet a constant size no\n// matter how many editors mount.\nconst themeCache = new Map<string, Extension>();\n\n/**\n * Memoize a CodeMirror theme/extension built from `resolveToken`, shared across\n * every instance that passes the same `cacheKey` and rebuilt whenever the active\n * brand / light-dark mode changes. `build` reads live `--*` values off `<html>`,\n * so the active theme is an invisible dependency a deps array can't see.\n *\n * `build` receives the scheme those values were read under, for the theme values\n * that are a light/dark *pair* rather than a token lookup (a categorical diff\n * wash has no semantic token, but an opaque light pastel still has to become a\n * low-alpha tint under dark). It comes from the same read that produced the key,\n * so a builder cannot resolve one scheme's colours under the other one's key.\n *\n * `cacheKey` is the extension's full identity: anything the builder closes over\n * must be part of it (e.g. `` `merge-pane:${deleted}` ``), or instances built\n * from different inputs would share one theme.\n */\nexport const useThemedExtension = (\n cacheKey: string,\n build: (scheme: ResolvedColorScheme) => Extension,\n): Extension => {\n const { scheme, cacheKey: themeKey } = useThemeAttributes();\n const key = `${themeKey} ${cacheKey}`;\n\n // The module-level cache is the memo; reading and filling it during render is\n // idempotent and keyed only on values already stable for the render.\n let cached = themeCache.get(key);\n if (!cached) {\n cached = build(scheme);\n themeCache.set(key, cached);\n }\n\n return cached;\n};\n","import { useMemo } from 'react';\nimport { Compartment, type Extension } from '@codemirror/state';\nimport { tooltips, ViewPlugin } from '@codemirror/view';\n\n// A `position: fixed` box is laid out against the viewport — and so escapes\n// every scroll container above it — only while no ancestor claims the job of\n// being its containing block. This encodes the CSS rule for who claims it\n// rather than the subset this repo happens to use today; `contain` and\n// `will-change` take value lists, so those two are matched loosely.\n//\n// `content-visibility` is absent on purpose: it implies containment without\n// saying so through `contain`, and it is handled below as a clipper — which is\n// the stronger of the two properties for our purposes.\nconst establishesFixedContainingBlock = (style: CSSStyleDeclaration) =>\n style.transform !== 'none' ||\n style.translate !== 'none' ||\n style.rotate !== 'none' ||\n style.scale !== 'none' ||\n style.perspective !== 'none' ||\n style.filter !== 'none' ||\n style.backdropFilter !== 'none' ||\n /\\b(paint|layout|strict|content)\\b/.test(style.contain) ||\n /\\b(transform|perspective|filter|contain)\\b/.test(style.willChange);\n\n// Crops its content, so hosting the tooltip inside it would not help. Paint\n// containment — which `content-visibility: auto` turns on without ever showing\n// up in computed `contain` — crops even a fixed-position descendant, and so\n// does a mask.\nconst crops = (style: CSSStyleDeclaration) =>\n style.overflowX !== 'visible' ||\n style.overflowY !== 'visible' ||\n style.maskImage !== 'none' ||\n style.contentVisibility !== 'visible' ||\n /\\b(paint|strict|content)\\b/.test(style.contain);\n\n/**\n * Where a tooltip can hang without being cropped, or `null` for \"wherever\n * CodeMirror would put it anyway\".\n *\n * Two ancestors matter, and they are not the same ancestor. The **outermost\n * cropper** is the one to get above — landing anywhere below it leaves the\n * tooltip inside the box doing the cropping. The **containing block** is where\n * the search can stop, because from there upwards `position: fixed` is measured\n * against that element and nothing higher can crop it.\n *\n * `document.body` and `<html>` are not treated as croppers: a fixed box whose\n * containing block is the viewport is not clipped by their overflow, and\n * hosting outside `<body>` would drop the tooltip out of the app's stacking and\n * pointer-events scope for no gain.\n */\nconst findTooltipHost = (from: HTMLElement) => {\n let outermostCropper: HTMLElement | null = null;\n\n for (let node = from.parentElement; node && node !== document.body; node = node.parentElement) {\n const style = getComputedStyle(node);\n\n if (crops(style)) {\n outermostCropper = node;\n } else if (establishesFixedContainingBlock(style)) {\n return outermostCropper?.parentElement ?? node;\n }\n }\n\n return outermostCropper?.parentElement ?? null;\n};\n\n/**\n * `tooltips()`, re-hosted so the completion popup is never cropped.\n *\n * CodeMirror hangs tooltips inside the editor and lets `position: fixed` carry\n * them past its edges. That holds only while the viewport is their containing\n * block — a modal centred with a translate, a sheet sliding in, or a box under\n * paint containment takes that job, and then every scroller, mask and contained\n * box in between crops the popup instead. A tall editor hides the damage; a\n * one-line one shows a sliver of an unreadable list.\n *\n * The two shapes this has to survive in production are a `Modal`, whose body\n * scrolls and carries the argo fade mask, and kbc-ui's SQL editor, which wraps\n * every code block in `content-visibility: auto` to keep long scripts cheap.\n *\n * Hosting the layer above the outermost cropper clears all of that while keeping\n * the popup inside the modal's stacking, focus and pointer-events scope — which\n * `document.body` would not: the popup would sit behind the modal, and Radix\n * leaves the body `pointer-events: none` while a dialog is open.\n *\n * Both editors install this, and it is the only place either of them configures\n * a tooltip host. Keep it that way: CodeMirror's tooltip config takes the first\n * contributor that names a parent, so a second mechanism would not compose with\n * this one — it would silently win or lose on extension order.\n */\nconst tooltipsExtension = (): Extension => {\n // The resolved host lives in a compartment, not in an appended config: React\n // hands CodeMirror a new extension array whenever the editor's props move,\n // which dispatches a full reconfigure. That replaces appended config, while\n // compartment contents are carried over.\n const layer = new Compartment();\n\n return [\n layer.of(tooltips()),\n ViewPlugin.define((view) => {\n // Deferred on two counts: a plugin cannot dispatch while the view it\n // belongs to is still being built, and reading computed styles here would\n // force a style and layout flush in the middle of the commit that inserted\n // the editor. The lookup is one-shot — an ancestor that gains a transform\n // afterwards is not picked up.\n const scheduled = setTimeout(() => {\n if (!view.dom.isConnected) return;\n\n const parent = findTooltipHost(view.dom);\n if (parent) view.dispatch({ effects: layer.reconfigure(tooltips({ parent })) });\n });\n\n return { destroy: () => clearTimeout(scheduled) };\n }),\n ];\n};\n\n/**\n * The extension above, built once per editor. Rebuilding it would hand\n * CodeMirror a fresh compartment and plugin on every reconfigure, dropping the\n * host it had already resolved — so it is only ever reached through this hook.\n */\nexport const useTooltipsExtension = () => useMemo(tooltipsExtension, []);\n","import type { Completion, CompletionContext, CompletionSource } from '@codemirror/autocomplete';\n\nimport { useStableCallback } from '../../hooks/useStableCallback';\n\nexport type EditorVariable = { name: string; value?: string };\n\n// Keywords come by the hundred from the language, so a variable would otherwise rank\n// below every one of them that shares a prefix.\nconst BOOST = 2000;\n\n// One brace or two, because `closeBrackets` turns a typed `{` into `{}` and a caret\n// that has only opened the placeholder is still asking for a variable. One charset\n// for the name throughout: a second, narrower one would start the range mid-name on\n// anything it disagreed about, and a range that starts mid-name never matches.\nconst NAME = String.raw`[\\w-]*`;\nconst AT_CARET = new RegExp(String.raw`(?:\\{{1,2} ?)?${NAME}$`);\nconst NAME_AT_END = new RegExp(`${NAME}$`);\nconst OPENING = /\\{{1,2} ?$/;\nconst CLOSING = /^ ?\\}{1,2}/;\n\n/**\n * Completes a mustache-style `{{name}}` placeholder.\n */\nexport const completeVariables = (variables: EditorVariable[] = []): CompletionSource => {\n if (variables.length === 0) return () => null;\n\n const options: Completion[] = variables.map(({ name, value }) => ({\n // The bare name: `SqlEditor` filters prefix-only while `CodeEditor` filters\n // fuzzily, and this is the only spelling both accept whether or not the caret\n // has typed the braces. The braces are `displayLabel`, which is what renders.\n label: name,\n displayLabel: `{{${name}}}`,\n detail: value,\n type: 'variable',\n boost: BOOST,\n apply: (view, completion, from, to) => {\n const { doc } = view.state;\n const line = doc.lineAt(from);\n const insert = `{{${completion.label}}}`;\n\n // The range covers the name alone, so the braces around it are found rather\n // than assumed — `closeBrackets` may have added a closing one nobody typed.\n const opening = OPENING.exec(doc.sliceString(line.from, from));\n const closing = CLOSING.exec(doc.sliceString(to, line.to));\n const start = opening ? from - opening[0].length : from;\n const end = closing ? to + closing[0].length : to;\n\n view.dispatch({\n changes: { from: start, to: end, insert },\n selection: { anchor: start + insert.length },\n });\n },\n }));\n\n return (context: CompletionContext) => {\n const match = context.matchBefore(AT_CARET);\n\n if (!match?.text) return null;\n\n const [name = ''] = NAME_AT_END.exec(match.text) ?? [];\n\n return { from: match.to - name.length, options };\n };\n};\n\n/**\n * The completion source both editors install, with an identity that never moves.\n *\n * Both hold it inside the memo that keys their whole extension tree, and callers\n * build the list inline — a config row mapped to `{ name, value }` in a store\n * selector, so a fresh array arrives on every store push. Because CodeMirror asks\n * the source for options rather than reading them up front, holding it steady costs\n * nothing: a completion request always reaches the latest render's variables.\n */\nexport const useVariableCompletion = (variables: EditorVariable[] = []): CompletionSource =>\n useStableCallback(completeVariables(variables));\n","import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';\nimport type { KeyboardEvent, ReactNode } from 'react';\nimport type { CompletionSource } from '@codemirror/autocomplete';\nimport { autocompletion, completeAnyWord } from '@codemirror/autocomplete';\nimport { unifiedMergeView } from '@codemirror/merge';\nimport { EditorView, keymap, placeholder as cmPlaceholder } from '@codemirror/view';\nimport CodeMirror, {\n EditorState,\n type Extension,\n type ReactCodeMirrorRef,\n} from '@uiw/react-codemirror';\n\nimport { keyCodes } from '../../constants/keyCodes';\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport { cn } from '../../utils';\nimport { HelpBlock } from '../HelpBlock';\nimport { useArgoDesign } from '../ThemeProvider/context';\n\nimport { ButtonToolbar } from './ButtonToolbar';\nimport { buildChromeStyles, buildInputChrome } from './editorChrome';\nimport type { LANGUAGE_MODE } from './helpers';\nimport {\n buildBaseThemeStyles,\n buildBasicSetup,\n buildCustomTheme,\n buildJsonLinter,\n getLanguageMode,\n shouldLintJson,\n} from './helpers';\nimport { searchExtension, updateSearch } from './search';\nimport { ToggleComponentHelp } from './ToggleComponentHelp';\nimport { useThemedExtension } from './tokenTheme';\nimport { useTooltipsExtension } from './tooltips';\nimport { type EditorVariable, useVariableCompletion } from './variableCompletion';\n\ntype Props = {\n value: string;\n previousValue?: string;\n /**\n * `'field'` draws the chrome an `InputGroup` draws — surface, border, radius,\n * focus ring, read-only wash — for an editor that is one control among others\n * in a form. It sizes to its content, so don't pin its height.\n *\n * `'plain'` (the default) is the full-bleed surface of an editor that *is* the\n * panel: a modal body, a chat block, a fixed-height viewer already framed by\n * whatever contains it.\n */\n variant?: 'plain' | 'field';\n mode?: LANGUAGE_MODE;\n placeholder?: string;\n /** Names the editable region for screen readers — the editor has no visible label of its own. */\n ariaLabel?: string;\n /**\n * Names the editable region from an existing element, for when the label is already on screen.\n * Prefer this over `ariaLabel` inside a form — `CodeEditorField` passes the field's own label id.\n */\n ariaLabelledBy?: string;\n /** Links the editable region to help / error text. Space-delimited idref list. */\n ariaDescribedBy?: string;\n /** Marks the editable region invalid. Visual error styling is the caller's (`variant=\"field\"`). */\n ariaInvalid?: boolean;\n ariaRequired?: boolean;\n /**\n * Treats a blank document as valid instead of a parse error (JSON modes only).\n *\n * - Off by default: for a standalone editor \"Unexpected end of input\" is correct, and at several\n * call sites the gutter marker is the only thing explaining a Save button that\n * `isValidJsonConfig('') === false` has already disabled.\n * - `CodeEditorField` turns it on for a field that is not `required`, where an empty document is\n * how the value is removed.\n */\n allowBlankDocument?: boolean;\n /**\n * Fires when focus leaves the editable region — what a form connector needs to mark its field\n * blurred, which is the gate errors are revealed on.\n *\n * - Bound as a CodeMirror DOM handler on the content node, not on the wrapper: the wrapper is not\n * what gets focused.\n * - Installed only when passed, so an editor without it keeps the extension set it had.\n */\n onBlur?: () => void;\n /**\n * Highlights every occurrence and scrolls the selected one into view. The find\n * UI is the caller's — pass the query it holds, and omit both props entirely to\n * leave the search extension uninstalled.\n */\n searchQuery?: string;\n searchMatchIndex?: number;\n readOnly?: boolean;\n /**\n * Refuses edits while leaving the editor looking and behaving as it did — for a\n * transient lock such as an in-flight save, where a keystroke landing mid-request\n * would be overwritten by the response. `readOnly` is the wrong prop for that:\n * it turns the editor into a viewer, greying the surface and taking the lint\n * marks and completions with it.\n */\n inputLocked?: boolean;\n /**\n * A flat list of completions, offered everywhere in the document. One word per\n * label: CodeMirror derives the pattern for the word being completed from the\n * labels' characters, so a space in one widens it across whitespace and the\n * editor offers nothing past the first word of a line. A phrase belongs in\n * `completionSource`.\n *\n * Compared by identity, like `completionSource` — hand the editor a stable array.\n */\n autocompletions?: string[];\n /**\n * Completions that depend on where the cursor is — a column list offered only\n * after its table, say. Wins over both `autocompletions` and `completeAny`,\n * which stay the right props for a list that is the same everywhere in the\n * document and for having no list at all. Like them, it opens on typing.\n *\n * Compared by identity: build it in a `useMemo` or the editor rebuilds its whole\n * extension tree on every render.\n */\n completionSource?: CompletionSource;\n /**\n * Configuration variables, completed into `{{name}}`. Independent of\n * `completionSource`: both are offered, so a caller keeps its own completions and\n * gets variables spelled the way the rest of the platform writes them.\n */\n variables?: EditorVariable[];\n /**\n * Whether the completion popup runs at all.\n *\n * - `false` silences every source, the *language's* own vocabulary included.\n * - For a field highlighted as a language nobody authors there: pasted `.env` and a\n * cURL command sit in shell mode for its colours, and shell's `ls`, `sudo`, `vim`\n * are noise over content we cannot predict.\n */\n withCompletions?: boolean;\n extraKeys?: Record<string, () => void>;\n withToggleCommentHint?: boolean;\n withAutofocus?: boolean;\n withLineNumbers?: boolean;\n withLineWrapping?: boolean;\n withCollapseUnchanged?: boolean;\n withCopyButton?: boolean;\n completeAny?: boolean;\n help?: ReactNode;\n helpPostfix?: ReactNode;\n /**\n * Extra actions for the toolbar that floats over the editor's top-right corner,\n * beside the copy button. The toolbar is a 28px chip, so pass `size=\"icon-xs\"`\n * buttons — a default-sized one grows the chip and de-aligns the copy button.\n */\n renderAdditionalButtons?: (value?: string) => ReactNode;\n className?: string;\n} & (\n | { readOnly: true; onChange?: never }\n // `boolean` rather than `false`: a field the user's permissions may lock still\n // needs its handler for the case where they can edit.\n | { readOnly?: boolean; onChange: (value: string) => void }\n);\n\nconst emptyObject = {};\n\nexport const CodeEditor = ({\n value,\n previousValue,\n onChange,\n variant = 'plain',\n mode = 'application/json',\n placeholder = '',\n ariaLabel,\n ariaLabelledBy,\n ariaDescribedBy,\n ariaInvalid,\n ariaRequired,\n allowBlankDocument = false,\n onBlur,\n searchQuery,\n searchMatchIndex,\n readOnly = false,\n inputLocked = false,\n autocompletions,\n completionSource,\n variables,\n withCompletions = true,\n extraKeys = emptyObject,\n withToggleCommentHint = false,\n withAutofocus = false,\n withLineNumbers = true,\n withLineWrapping = true,\n withCollapseUnchanged = false,\n withCopyButton = false,\n completeAny = false,\n help = null,\n helpPostfix = null,\n renderAdditionalButtons,\n className,\n}: Props) => {\n // CodeMirror rebuilds and re-resolves the whole extension tree whenever the\n // change handler's identity moves, and callers pass inline arrows.\n const handleChange = useStableCallback((next: string) => onChange?.(next));\n const handleBlur = useStableCallback(() => onBlur?.());\n\n // Themes re-resolve their `--*` tokens on brand / light-dark change. The\n // syntax palette is keyed without a component prefix so `SqlEditor` — which\n // builds it from the same `buildCustomTheme` — shares this one module.\n // Presence, not truthiness: a caller that searches always passes the prop, so\n // the extension set stays stable while the query changes.\n const withSearch = searchQuery !== undefined;\n // Same presence-not-truthiness reasoning as `withSearch`: gate the handler extension on the prop\n // being passed at all, so every existing caller keeps the extension set it had.\n const withBlur = onBlur !== undefined;\n const editorRef = useRef<ReactCodeMirrorRef>(null);\n\n // One object so the extension list has a single dependency instead of five, and `null` when nothing\n // is set so the extension is left out entirely rather than added empty.\n const contentAria = useMemo(() => {\n const attributes: Record<string, string> = {};\n if (ariaLabel !== undefined) attributes['aria-label'] = ariaLabel;\n if (ariaLabelledBy !== undefined) attributes['aria-labelledby'] = ariaLabelledBy;\n if (ariaDescribedBy !== undefined) attributes['aria-describedby'] = ariaDescribedBy;\n // Stringified because `contentAttributes` writes DOM attributes, where `aria-invalid=\"false\"` and\n // an absent attribute mean the same thing but `false` would be dropped by a truthiness check.\n if (ariaInvalid !== undefined) attributes['aria-invalid'] = String(ariaInvalid);\n if (ariaRequired !== undefined) attributes['aria-required'] = String(ariaRequired);\n return Object.keys(attributes).length > 0 ? attributes : null;\n }, [ariaLabel, ariaLabelledBy, ariaDescribedBy, ariaInvalid, ariaRequired]);\n\n useEffect(() => {\n const view = editorRef.current?.view;\n if (view && withSearch) updateSearch(view, searchQuery, searchMatchIndex);\n }, [withSearch, searchQuery, searchMatchIndex]);\n\n // A view created while a query is already set — a remount, a tab switch —\n // starts with no highlights unless the search is applied as it is built.\n const handleCreateEditor = useStableCallback((view: EditorView) => {\n if (searchQuery) updateSearch(view, searchQuery, searchMatchIndex);\n });\n\n // Same reasoning as `onChange` above, one level out: callers build this object\n // inline, so keying the extensions on it would reconfigure the editor on every\n // parent render. Only the set of bound keys can change what the keymap *is* —\n // the handlers behind them are read when the key is actually pressed.\n const extraKeysRef = useRef(extraKeys);\n useLayoutEffect(() => {\n extraKeysRef.current = extraKeys;\n });\n\n const boundKeysSignature = Object.keys(extraKeys).join('\\n');\n const boundKeys = useMemo(\n () => boundKeysSignature.split('\\n').filter(Boolean),\n [boundKeysSignature],\n );\n\n const tooltipLayer = useTooltipsExtension();\n\n // `languageData.of` takes a function CodeMirror calls per completion request, so\n // the source is built here rather than inside it — otherwise every keystroke that\n // opens the popup rebuilds an option per variable.\n const variableCompletion = useVariableCompletion(variables);\n\n const customTheme = useThemedExtension('editor:syntax', buildCustomTheme);\n\n // The brand decides which `InputGroup` the field chrome has to match, so it is\n // part of the theme's identity — `useThemedExtension` caches per key across\n // every instance, and the theme signal it keys on carries only `<html>`.\n const isArgo = useArgoDesign();\n const isField = variant === 'field';\n const baseTheme = useThemedExtension(\n isField ? `code-editor:field:${isArgo ? 'argo' : 'legacy'}` : 'code-editor:chrome',\n (scheme) =>\n // `dark` sets `EditorView.darkTheme`, which is what activates every `&dark` rule — ours in\n // `search.ts` / `highlighting.ts`, and CodeMirror's own for the cursor, selection layer and\n // panels. Declared here rather than inherited from whichever github palette\n // `buildCustomTheme` picked, so swapping that palette cannot silently turn them all off.\n EditorView.theme(\n {\n ...buildBaseThemeStyles(scheme),\n ...(isField ? buildChromeStyles(buildInputChrome(isArgo, scheme)) : null),\n },\n { dark: scheme === 'dark' },\n ),\n );\n\n const commonExtensions: Extension[] = useMemo(() => {\n const callerCompletions =\n completionSource ??\n (completeAny ? completeAnyWord : autocompletions?.length ? autocompletions : null);\n\n // An empty list is left out: CodeMirror wraps a list in `completeFromList`, which\n // answers an empty result rather than none, so the editor would run a source that\n // can never match on every keystroke.\n const completionEntries = [\n ...(callerCompletions ? [{ autocomplete: callerCompletions }] : []),\n { autocomplete: variableCompletion },\n ];\n\n return [\n getLanguageMode(mode),\n shouldLintJson(mode, readOnly) ? buildJsonLinter(allowBlankDocument) : [],\n withLineWrapping ? EditorView.lineWrapping : [],\n EditorState.languageData.of(() => completionEntries),\n keymap.of(\n boundKeys.map((key) => ({\n key,\n run: () => {\n extraKeysRef.current[key]?.();\n return true;\n },\n })),\n ),\n readOnly || !withCompletions\n ? []\n : [\n // The only `autocompletion()` an editor gets — `buildBasicSetup` turns\n // basicSetup's own off. Not gated on the completion props: that hid what the\n // *language* supplies — dbt's vocabulary, Snowflake's keywords — behind a\n // shortcut, and macOS leaves no usable one. With nothing to offer no popup\n // opens anyway, so only `withCompletions={false}` asks for silence.\n autocompletion(),\n ],\n // Every a11y attribute goes onto the *content* node, not the wrapper: CodeMirror's\n // `div[role=\"textbox\"]` is what gets focused, so it is the only element AT will read them from.\n contentAria ? EditorView.contentAttributes.of(contentAria) : [],\n withBlur ? EditorView.domEventHandlers({ blur: handleBlur }) : [],\n withSearch ? searchExtension() : [],\n tooltipLayer,\n baseTheme,\n ];\n }, [\n autocompletions,\n completionSource,\n variableCompletion,\n completeAny,\n withCompletions,\n boundKeys,\n mode,\n readOnly,\n allowBlankDocument,\n withLineWrapping,\n baseTheme,\n contentAria,\n withBlur,\n handleBlur,\n withSearch,\n tooltipLayer,\n ]);\n\n const extensions = useMemo(() => {\n return [\n ...commonExtensions,\n cmPlaceholder(placeholder),\n EditorView.editable.of(!readOnly),\n // The lock is this facet and nothing else. `contenteditable` is what the\n // read-only wash keys off, and `basicSetup` is what holds the undo history,\n // so leaving both alone is what makes the lock invisible.\n EditorState.readOnly.of(readOnly || inputLocked),\n previousValue\n ? unifiedMergeView({\n original: previousValue,\n mergeControls: false,\n highlightChanges: false,\n collapseUnchanged: withCollapseUnchanged ? {} : undefined,\n })\n : [],\n ];\n }, [commonExtensions, placeholder, readOnly, inputLocked, previousValue, withCollapseUnchanged]);\n\n const config = useMemo(() => {\n return {\n ...buildBasicSetup(readOnly),\n lineNumbers: withLineNumbers,\n // Mod-f opens CodeMirror's own panel, which would run a second query and a\n // second match count over the same document beside the caller's input.\n ...(withSearch ? { searchKeymap: false } : null),\n };\n }, [withLineNumbers, readOnly, withSearch]);\n\n return (\n // oxlint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n data-variant={variant}\n className={cn(\n // Scoped to the box CodeMirror renders into rather than to every child, so\n // the toolbar below does not have to undo all three in `!important`.\n 'tw:relative tw:flex tw:min-h-0 tw:flex-col tw:[&_.cm-mergeViewEditor]:overflow-visible tw:[&_.cm-mergeViewEditors]:h-full tw:[&_.cm-mergeView]:h-full tw:[&_>.cm-theme]:h-full',\n // A field's `.cm-editor` is rounded, so the square box behind it would show\n // at the corners, and `overflow-auto` would crop the focus ring — a shadow\n // painted outside the editor's own box.\n isField\n ? 'tw:[&_>.cm-theme]:overflow-visible tw:[&_>.cm-theme]:bg-transparent'\n : 'tw:[&_>.cm-theme]:overflow-auto tw:[&_>.cm-theme]:bg-background',\n className,\n )}\n onKeyDown={(event: KeyboardEvent) => {\n if (event.key === keyCodes.ESCAPE) {\n event.stopPropagation();\n }\n }}\n >\n <ButtonToolbar value={withCopyButton ? value : undefined}>\n {renderAdditionalButtons?.(value)}\n </ButtonToolbar>\n <CodeMirror\n ref={editorRef}\n onCreateEditor={handleCreateEditor}\n theme={customTheme}\n value={value}\n onChange={handleChange}\n extensions={extensions}\n autoFocus={withAutofocus}\n basicSetup={config}\n />\n {!readOnly && (withToggleCommentHint || help || helpPostfix) && (\n <HelpBlock className=\"tw:mt-2 tw:flex tw:flex-wrap tw:gap-1\">\n {help}\n {withToggleCommentHint ? <ToggleComponentHelp /> : null}\n {helpPostfix}\n </HelpBlock>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { createChangeInputEvent } from "./utils-
|
|
2
|
+
import { createChangeInputEvent } from "./utils-DSvrhU8E.js";
|
|
3
3
|
import { mergeRefs } from "./internal/utils/mergeRefs.js";
|
|
4
4
|
import { Pipette, X } from "./icons-Cek151jC.js";
|
|
5
|
-
import { InputGroup } from "./InputGroup-
|
|
5
|
+
import { InputGroup } from "./InputGroup-DcZRlVnN.js";
|
|
6
6
|
import { useControllableState } from "./useControllableState-M6494mCT.js";
|
|
7
7
|
import { useRef } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -177,4 +177,4 @@ const ColorInput = ({ ref, state, variant, focusVariant, sizing, className, valu
|
|
|
177
177
|
//#endregion
|
|
178
178
|
export { ColorInput };
|
|
179
179
|
|
|
180
|
-
//# sourceMappingURL=ColorInput-
|
|
180
|
+
//# sourceMappingURL=ColorInput-BZV-u_94.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorInput-Q1D9Vcc_.js","names":[],"sources":["../src/blocks/ColorInput/utils.ts","../src/blocks/ColorInput/ColorPicker.tsx","../src/blocks/ColorInput/ColorInput.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\n\nconst HEX_CHARSET = /^[0-9a-fA-F]+$/;\n// `#` + 3, 4, 6, or 8 hex digits — every length CSS accepts as a hex color.\nconst COMPLETE_HEX_PATTERN = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\n// Longest hex body CSS accepts (`#rrggbbaa` without the hash).\nconst MAX_HEX_BODY_LENGTH = 8;\n// Native <input type=\"color\"> default when fed anything unparseable.\nconst PICKER_FALLBACK = '#000000';\n\nconst extractHexBody = (value: unknown): string | null => {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n if (trimmed === '') return null;\n return trimmed.startsWith('#') ? trimmed.slice(1) : trimmed;\n};\n\nexport const isCompleteHexColor = (value: string): boolean => COMPLETE_HEX_PATTERN.test(value);\n\n// @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/showPicker\nexport const showPicker = (input: HTMLInputElement) => {\n const isShowPickerSupported = 'showPicker' in HTMLInputElement.prototype;\n isShowPickerSupported ? input.showPicker() : input.click();\n};\n\n/**\n * Coerces free-form text into a partial hex color for the visible text\n * input. Allows up to 8 hex digits to support `#rrggbbaa` (RGBA / alpha).\n *\n * Behaviour:\n * - empty / null / undefined / non-string → `''`\n * - trims surrounding whitespace\n * - prepends `#` when the user types raw hex without it\n * - keeps only the leading run of valid hex digits, dropping the rest\n * - caps total length at `# + 8` hex digits\n * - returns `''` when no valid hex digits remain (e.g. bare `#`, `zz`) so\n * the input doesn't sit on a lonely `#`\n *\n * Note: the result may be a *prefix* (e.g. `#a`, `#ab`) that is not yet a\n * valid CSS color — gate any rendering on `isCompleteHexColor`.\n */\nexport const coerceHexInputValue = (value?: string | null): string => {\n const body = extractHexBody(value);\n if (body === null) return '';\n const [validBody] = body.match(/^[0-9a-fA-F]+/) ?? [];\n if (!validBody) return '';\n return `#${validBody.slice(0, MAX_HEX_BODY_LENGTH)}`;\n};\n\n/**\n * Coerces any value into the strict lowercase `#rrggbb` form required by the\n * native `<input type=\"color\">`. Anything the picker can't render is\n * collapsed to `#000000`.\n *\n * - 3-digit shorthand (`#abc`) → expanded to 6 digits (`#aabbcc`)\n * - 4/8-digit RGBA → alpha channel is dropped\n * - invalid characters, wrong length, or non-string types → `#000000`\n *\n * The native picker silently lowercases its value; we lowercase here too so\n * controlled consumers see the same string round-trip.\n */\nexport const coerceColorPickerValue = (value: ComponentProps<'input'>['value'] | null) => {\n const body = extractHexBody(value);\n if (body === null || !HEX_CHARSET.test(body)) return PICKER_FALLBACK;\n\n if (body.length === 3 || body.length === 4) {\n const [r, g, b] = body;\n return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();\n }\n if (body.length === 6 || body.length === 8) {\n return `#${body.slice(0, 6).toLowerCase()}`;\n }\n return PICKER_FALLBACK;\n};\n","import { type ComponentProps, type ComponentRef, useRef } from 'react';\n\nimport { InputGroup } from '../../components/InputGroup';\nimport { Pipette } from '../../icons';\n\nimport { coerceColorPickerValue, showPicker } from './utils';\n\ntype Props = Omit<ComponentProps<'input'>, 'type'>;\n\nexport const ColorPicker = ({ value, disabled, readOnly, ...props }: Props) => {\n const pickerRef = useRef<ComponentRef<'input'>>(null);\n\n const handleOpenPicker = () => {\n if (!pickerRef.current) return;\n showPicker(pickerRef.current);\n };\n\n return (\n <div className=\"tw:relative\">\n <input\n {...props}\n ref={pickerRef}\n type=\"color\"\n value={coerceColorPickerValue(value)}\n tabIndex={-1}\n aria-hidden\n className=\"tw:pointer-events-none tw:absolute tw:left-0 tw:top-full tw:size-0 tw:opacity-0\"\n disabled={disabled}\n readOnly={readOnly}\n />\n <InputGroup.Button\n onMouseDown={(event) => event.preventDefault()}\n disabled={disabled || readOnly}\n onClick={handleOpenPicker}\n aria-label=\"Pick color\"\n >\n <Pipette className=\"tw:size-4\" />\n </InputGroup.Button>\n </div>\n );\n};\n","import { useRef } from 'react';\nimport type {\n ChangeEventHandler,\n ComponentProps,\n ComponentRef,\n FocusEventHandler,\n MouseEventHandler,\n} from 'react';\n\nimport { InputGroup } from '../../components/InputGroup';\nimport { useControllableState } from '../../hooks/useControllableState';\nimport { X } from '../../icons';\nimport { cn, createChangeInputEvent, mergeRefs } from '../../utils';\n\nimport { ColorPicker } from './ColorPicker';\nimport { coerceHexInputValue, isCompleteHexColor } from './utils';\n\ntype InputGroupProps = Pick<\n ComponentProps<typeof InputGroup>,\n 'variant' | 'focusVariant' | 'state' | 'sizing'\n>;\n\ntype InputGroupInputProps = Omit<ComponentProps<typeof InputGroup.Input>, 'value' | 'defaultValue'>;\n\ntype Props = InputGroupProps &\n InputGroupInputProps & {\n value?: string | null;\n defaultValue?: string | null;\n onValueChange?: (value: string) => void;\n onValueBlur?: (value: string) => void;\n allowClear?: boolean;\n };\n\nexport const ColorInput = ({\n ref,\n\n // group props\n state,\n variant,\n focusVariant,\n sizing,\n className,\n\n // own props\n value: valueProp,\n onValueChange,\n onValueBlur,\n onChange,\n onBlur,\n defaultValue,\n allowClear = false,\n\n // input props\n disabled,\n readOnly,\n ...restInputProps\n}: Props) => {\n const inputRef = useRef<ComponentRef<'input'>>(null);\n\n const [value, setValue] = useControllableState<string>({\n // A `null` controlled value stays controlled (coerced to ''); `undefined` is uncontrolled.\n prop: valueProp === null ? '' : valueProp,\n defaultProp: defaultValue ?? '',\n onChange: onValueChange,\n });\n\n const isControlled = valueProp !== undefined;\n\n const canClear = allowClear && !!value && !disabled && !readOnly;\n const swatchColor = coerceHexInputValue(value);\n const isValidSwatch = isCompleteHexColor(swatchColor);\n\n // Preserve raw text while the user is typing — sanitise on blur.\n const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n setValue(event.target.value);\n onChange?.(event);\n };\n\n const handleBlur: FocusEventHandler<HTMLInputElement> = (event) => {\n const newValue = event.target.value;\n const sanitizedNewValue = coerceHexInputValue(newValue);\n\n if (sanitizedNewValue !== newValue) {\n // In controlled mode, let the parent decide whether to apply the\n // sanitised value via `onValueChange` — don't fight its `value` prop.\n if (!isControlled) event.target.value = sanitizedNewValue;\n setValue(sanitizedNewValue);\n }\n\n onValueBlur?.(sanitizedNewValue);\n onBlur?.(event);\n };\n\n const handlePickerChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n setValue(coerceHexInputValue(event.target.value));\n onChange?.(event);\n };\n\n const handleClear: MouseEventHandler<HTMLButtonElement> = () => {\n if (!inputRef.current) return;\n inputRef.current.value = '';\n setValue('');\n onChange?.(createChangeInputEvent(inputRef.current));\n };\n\n return (\n <InputGroup\n state={state}\n variant={variant}\n sizing={sizing}\n focusVariant={focusVariant}\n className={className}\n >\n <InputGroup.Addon\n align=\"inline-start\"\n className={cn(\n { 'tw:-ml-7 tw:opacity-0': !value },\n 'tw:transition-[opacity,margin]',\n 'tw:ease-linear',\n 'tw:duration-200',\n )}\n >\n <div\n style={isValidSwatch ? { background: swatchColor } : undefined}\n className={cn(\n 'tw:size-5',\n 'tw:shrink-0',\n 'tw:rounded-sm',\n 'tw:border',\n 'tw:border-solid',\n 'tw:border-neutral-300',\n {\n 'tw:bg-[linear-gradient(to_top_right,transparent_calc(50%_-_1px),theme(colors.red.300)_calc(50%_-_1px),theme(colors.red.300)_calc(50%_+_1px),transparent_calc(50%_+_1px))]':\n !isValidSwatch,\n },\n )}\n />\n </InputGroup.Addon>\n\n <InputGroup.Input\n {...restInputProps}\n type=\"text\"\n ref={mergeRefs(ref ?? null, inputRef)}\n value={value}\n onChange={handleChange}\n onBlur={handleBlur}\n disabled={disabled}\n readOnly={readOnly}\n />\n\n <InputGroup.Addon align=\"inline-end\">\n {canClear && (\n <InputGroup.Button\n // prevents input focus stealing\n onMouseDown={(event) => event.preventDefault()}\n onClick={handleClear}\n aria-label=\"Clear color\"\n >\n <X className=\"tw:size-4\" />\n </InputGroup.Button>\n )}\n <ColorPicker\n disabled={disabled}\n readOnly={readOnly}\n value={value}\n onChange={handlePickerChange}\n />\n </InputGroup.Addon>\n </InputGroup>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ColorInput-BZV-u_94.js","names":[],"sources":["../src/blocks/ColorInput/utils.ts","../src/blocks/ColorInput/ColorPicker.tsx","../src/blocks/ColorInput/ColorInput.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\n\nconst HEX_CHARSET = /^[0-9a-fA-F]+$/;\n// `#` + 3, 4, 6, or 8 hex digits — every length CSS accepts as a hex color.\nconst COMPLETE_HEX_PATTERN = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\n// Longest hex body CSS accepts (`#rrggbbaa` without the hash).\nconst MAX_HEX_BODY_LENGTH = 8;\n// Native <input type=\"color\"> default when fed anything unparseable.\nconst PICKER_FALLBACK = '#000000';\n\nconst extractHexBody = (value: unknown): string | null => {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n if (trimmed === '') return null;\n return trimmed.startsWith('#') ? trimmed.slice(1) : trimmed;\n};\n\nexport const isCompleteHexColor = (value: string): boolean => COMPLETE_HEX_PATTERN.test(value);\n\n// @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/showPicker\nexport const showPicker = (input: HTMLInputElement) => {\n const isShowPickerSupported = 'showPicker' in HTMLInputElement.prototype;\n isShowPickerSupported ? input.showPicker() : input.click();\n};\n\n/**\n * Coerces free-form text into a partial hex color for the visible text\n * input. Allows up to 8 hex digits to support `#rrggbbaa` (RGBA / alpha).\n *\n * Behaviour:\n * - empty / null / undefined / non-string → `''`\n * - trims surrounding whitespace\n * - prepends `#` when the user types raw hex without it\n * - keeps only the leading run of valid hex digits, dropping the rest\n * - caps total length at `# + 8` hex digits\n * - returns `''` when no valid hex digits remain (e.g. bare `#`, `zz`) so\n * the input doesn't sit on a lonely `#`\n *\n * Note: the result may be a *prefix* (e.g. `#a`, `#ab`) that is not yet a\n * valid CSS color — gate any rendering on `isCompleteHexColor`.\n */\nexport const coerceHexInputValue = (value?: string | null): string => {\n const body = extractHexBody(value);\n if (body === null) return '';\n const [validBody] = body.match(/^[0-9a-fA-F]+/) ?? [];\n if (!validBody) return '';\n return `#${validBody.slice(0, MAX_HEX_BODY_LENGTH)}`;\n};\n\n/**\n * Coerces any value into the strict lowercase `#rrggbb` form required by the\n * native `<input type=\"color\">`. Anything the picker can't render is\n * collapsed to `#000000`.\n *\n * - 3-digit shorthand (`#abc`) → expanded to 6 digits (`#aabbcc`)\n * - 4/8-digit RGBA → alpha channel is dropped\n * - invalid characters, wrong length, or non-string types → `#000000`\n *\n * The native picker silently lowercases its value; we lowercase here too so\n * controlled consumers see the same string round-trip.\n */\nexport const coerceColorPickerValue = (value: ComponentProps<'input'>['value'] | null) => {\n const body = extractHexBody(value);\n if (body === null || !HEX_CHARSET.test(body)) return PICKER_FALLBACK;\n\n if (body.length === 3 || body.length === 4) {\n const [r, g, b] = body;\n return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();\n }\n if (body.length === 6 || body.length === 8) {\n return `#${body.slice(0, 6).toLowerCase()}`;\n }\n return PICKER_FALLBACK;\n};\n","import { type ComponentProps, type ComponentRef, useRef } from 'react';\n\nimport { InputGroup } from '../../components/InputGroup';\nimport { Pipette } from '../../icons';\n\nimport { coerceColorPickerValue, showPicker } from './utils';\n\ntype Props = Omit<ComponentProps<'input'>, 'type'>;\n\nexport const ColorPicker = ({ value, disabled, readOnly, ...props }: Props) => {\n const pickerRef = useRef<ComponentRef<'input'>>(null);\n\n const handleOpenPicker = () => {\n if (!pickerRef.current) return;\n showPicker(pickerRef.current);\n };\n\n return (\n <div className=\"tw:relative\">\n <input\n {...props}\n ref={pickerRef}\n type=\"color\"\n value={coerceColorPickerValue(value)}\n tabIndex={-1}\n aria-hidden\n className=\"tw:pointer-events-none tw:absolute tw:left-0 tw:top-full tw:size-0 tw:opacity-0\"\n disabled={disabled}\n readOnly={readOnly}\n />\n <InputGroup.Button\n onMouseDown={(event) => event.preventDefault()}\n disabled={disabled || readOnly}\n onClick={handleOpenPicker}\n aria-label=\"Pick color\"\n >\n <Pipette className=\"tw:size-4\" />\n </InputGroup.Button>\n </div>\n );\n};\n","import { useRef } from 'react';\nimport type {\n ChangeEventHandler,\n ComponentProps,\n ComponentRef,\n FocusEventHandler,\n MouseEventHandler,\n} from 'react';\n\nimport { InputGroup } from '../../components/InputGroup';\nimport { useControllableState } from '../../hooks/useControllableState';\nimport { X } from '../../icons';\nimport { cn, createChangeInputEvent, mergeRefs } from '../../utils';\n\nimport { ColorPicker } from './ColorPicker';\nimport { coerceHexInputValue, isCompleteHexColor } from './utils';\n\ntype InputGroupProps = Pick<\n ComponentProps<typeof InputGroup>,\n 'variant' | 'focusVariant' | 'state' | 'sizing'\n>;\n\ntype InputGroupInputProps = Omit<ComponentProps<typeof InputGroup.Input>, 'value' | 'defaultValue'>;\n\ntype Props = InputGroupProps &\n InputGroupInputProps & {\n value?: string | null;\n defaultValue?: string | null;\n onValueChange?: (value: string) => void;\n onValueBlur?: (value: string) => void;\n allowClear?: boolean;\n };\n\nexport const ColorInput = ({\n ref,\n\n // group props\n state,\n variant,\n focusVariant,\n sizing,\n className,\n\n // own props\n value: valueProp,\n onValueChange,\n onValueBlur,\n onChange,\n onBlur,\n defaultValue,\n allowClear = false,\n\n // input props\n disabled,\n readOnly,\n ...restInputProps\n}: Props) => {\n const inputRef = useRef<ComponentRef<'input'>>(null);\n\n const [value, setValue] = useControllableState<string>({\n // A `null` controlled value stays controlled (coerced to ''); `undefined` is uncontrolled.\n prop: valueProp === null ? '' : valueProp,\n defaultProp: defaultValue ?? '',\n onChange: onValueChange,\n });\n\n const isControlled = valueProp !== undefined;\n\n const canClear = allowClear && !!value && !disabled && !readOnly;\n const swatchColor = coerceHexInputValue(value);\n const isValidSwatch = isCompleteHexColor(swatchColor);\n\n // Preserve raw text while the user is typing — sanitise on blur.\n const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n setValue(event.target.value);\n onChange?.(event);\n };\n\n const handleBlur: FocusEventHandler<HTMLInputElement> = (event) => {\n const newValue = event.target.value;\n const sanitizedNewValue = coerceHexInputValue(newValue);\n\n if (sanitizedNewValue !== newValue) {\n // In controlled mode, let the parent decide whether to apply the\n // sanitised value via `onValueChange` — don't fight its `value` prop.\n if (!isControlled) event.target.value = sanitizedNewValue;\n setValue(sanitizedNewValue);\n }\n\n onValueBlur?.(sanitizedNewValue);\n onBlur?.(event);\n };\n\n const handlePickerChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n setValue(coerceHexInputValue(event.target.value));\n onChange?.(event);\n };\n\n const handleClear: MouseEventHandler<HTMLButtonElement> = () => {\n if (!inputRef.current) return;\n inputRef.current.value = '';\n setValue('');\n onChange?.(createChangeInputEvent(inputRef.current));\n };\n\n return (\n <InputGroup\n state={state}\n variant={variant}\n sizing={sizing}\n focusVariant={focusVariant}\n className={className}\n >\n <InputGroup.Addon\n align=\"inline-start\"\n className={cn(\n { 'tw:-ml-7 tw:opacity-0': !value },\n 'tw:transition-[opacity,margin]',\n 'tw:ease-linear',\n 'tw:duration-200',\n )}\n >\n <div\n style={isValidSwatch ? { background: swatchColor } : undefined}\n className={cn(\n 'tw:size-5',\n 'tw:shrink-0',\n 'tw:rounded-sm',\n 'tw:border',\n 'tw:border-solid',\n 'tw:border-neutral-300',\n {\n 'tw:bg-[linear-gradient(to_top_right,transparent_calc(50%_-_1px),theme(colors.red.300)_calc(50%_-_1px),theme(colors.red.300)_calc(50%_+_1px),transparent_calc(50%_+_1px))]':\n !isValidSwatch,\n },\n )}\n />\n </InputGroup.Addon>\n\n <InputGroup.Input\n {...restInputProps}\n type=\"text\"\n ref={mergeRefs(ref ?? null, inputRef)}\n value={value}\n onChange={handleChange}\n onBlur={handleBlur}\n disabled={disabled}\n readOnly={readOnly}\n />\n\n <InputGroup.Addon align=\"inline-end\">\n {canClear && (\n <InputGroup.Button\n // prevents input focus stealing\n onMouseDown={(event) => event.preventDefault()}\n onClick={handleClear}\n aria-label=\"Clear color\"\n >\n <X className=\"tw:size-4\" />\n </InputGroup.Button>\n )}\n <ColorPicker\n disabled={disabled}\n readOnly={readOnly}\n value={value}\n onChange={handlePickerChange}\n />\n </InputGroup.Addon>\n </InputGroup>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Monitor, Moon, Sun } from "./icons-Cek151jC.js";
|
|
2
|
-
import { Button } from "./Button-
|
|
3
|
-
import { DropdownMenu } from "./DropdownMenu-
|
|
2
|
+
import { Button } from "./Button-DsRrU5F1.js";
|
|
3
|
+
import { DropdownMenu } from "./DropdownMenu-CASr-jgl.js";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/blocks/ColorModeSwitch/ColorModeSwitch.tsx
|
|
6
6
|
const OPTIONS = [
|
|
@@ -74,4 +74,4 @@ const ColorModeSwitch = ({ value, onValueChange, size = "small", className }) =>
|
|
|
74
74
|
//#endregion
|
|
75
75
|
export { ColorModeSwitch };
|
|
76
76
|
|
|
77
|
-
//# sourceMappingURL=ColorModeSwitch-
|
|
77
|
+
//# sourceMappingURL=ColorModeSwitch-CsWLiTBX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorModeSwitch-
|
|
1
|
+
{"version":3,"file":"ColorModeSwitch-CsWLiTBX.js","names":[],"sources":["../src/blocks/ColorModeSwitch/ColorModeSwitch.tsx"],"sourcesContent":["import { Button } from '../../components/Button';\nimport { DropdownMenu } from '../../components/DropdownMenu';\nimport type { ColorScheme } from '../../components/ThemeProvider';\nimport type { LucideIcon } from '../../icons';\nimport { Monitor, Moon, Sun } from '../../icons';\n\ntype Props = {\n /** The active color scheme. Controlled — pair with `onValueChange`. */\n value: ColorScheme;\n /** Called with the chosen scheme when the user picks a menu item. */\n onValueChange: (value: ColorScheme) => void;\n /** Trigger button size. Defaults to `small`. */\n size?: 'small' | 'medium';\n className?: string;\n};\n\nconst OPTIONS: { value: ColorScheme; label: string; icon: LucideIcon }[] = [\n { value: 'light', label: 'Light', icon: Sun },\n { value: 'dark', label: 'Dark', icon: Moon },\n { value: 'system', label: 'System', icon: Monitor },\n];\n\nconst triggerSizeMap = { small: 'icon-sm', medium: 'icon' } as const;\n\n/**\n * Light / dark / system control — a single icon-only `Button` (showing the active\n * scheme) that opens a `DropdownMenu` of the three options. Composed, not a new\n * primitive. **Controlled:** it renders `value` and reports changes; it does not\n * own the state. `ThemeProvider.colorScheme` is a controlled prop, so wire this to\n * wherever that state lives:\n *\n * ```tsx\n * const [scheme, setScheme] = useState<ColorScheme>('system');\n * <ThemeProvider colorScheme={scheme}>…</ThemeProvider>\n * <ColorModeSwitch value={scheme} onValueChange={setScheme} />\n * ```\n *\n * The menu uses `DropdownMenu.RadioGroup` for single-select semantics; the active\n * item is marked as checked. The trigger's `aria-label` names the current scheme.\n */\nexport const ColorModeSwitch = ({ value, onValueChange, size = 'small', className }: Props) => {\n const active = OPTIONS.find((option) => option.value === value);\n const ActiveIcon = active?.icon ?? Monitor;\n const activeLabel = active?.label ?? 'System';\n\n return (\n <DropdownMenu>\n <DropdownMenu.Trigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size={triggerSizeMap[size]}\n aria-label={`Color mode: ${activeLabel}`}\n title={`Color mode: ${activeLabel}`}\n className={className}\n >\n <ActiveIcon className=\"tw:size-4\" />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.RadioGroup value={value} onValueChange={onValueChange}>\n {OPTIONS.map(({ value: option, label, icon: Icon }) => (\n <DropdownMenu.RadioItem\n key={option}\n value={option}\n icon={<Icon />}\n indicator=\"check\"\n indicatorAlign=\"end\"\n closeOnSelect\n >\n {label}\n </DropdownMenu.RadioItem>\n ))}\n </DropdownMenu.RadioGroup>\n </DropdownMenu.Content>\n </DropdownMenu>\n );\n};\n"],"mappings":";;;;;AAgBA,MAAM,UAAqE;CACzE;EAAE,OAAO;EAAS,OAAO;EAAS,MAAM;CAAI;CAC5C;EAAE,OAAO;EAAQ,OAAO;EAAQ,MAAM;CAAK;CAC3C;EAAE,OAAO;EAAU,OAAO;EAAU,MAAM;CAAQ;AACpD;AAEA,MAAM,iBAAiB;CAAE,OAAO;CAAW,QAAQ;AAAO;;;;;;;;;;;;;;;;;AAkB1D,MAAa,mBAAmB,EAAE,OAAO,eAAe,OAAO,SAAS,gBAAuB;CAC7F,MAAM,SAAS,QAAQ,MAAM,WAAW,OAAO,UAAU,KAAK;CAC9D,MAAM,aAAa,QAAQ,QAAQ;CACnC,MAAM,cAAc,QAAQ,SAAS;CAErC,OACE,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,aAAa,SAAd;EAAsB,SAAA;EACpB,UAAA,oBAAC,QAAD;GACE,MAAK;GACL,SAAQ;GACR,MAAM,eAAe;GACrB,cAAY,eAAe;GAC3B,OAAO,eAAe;GACX;GAEX,UAAA,oBAAC,YAAD,EAAY,WAAU,YAAa,CAAA;EAC7B,CAAA;CACY,CAAA,GACtB,oBAAC,aAAa,SAAd;EAAsB,OAAM;EAC1B,UAAA,oBAAC,aAAa,YAAd;GAAgC;GAAsB;GACnD,UAAA,QAAQ,KAAK,EAAE,OAAO,QAAQ,OAAO,MAAM,WAC1C,oBAAC,aAAa,WAAd;IAEE,OAAO;IACP,MAAM,oBAAC,MAAD,CAAO,CAAA;IACb,WAAU;IACV,gBAAe;IACf,eAAA;IAEC,UAAA;GACqB,GARjB,MAQiB,CACzB;EACsB,CAAA;CACL,CAAA,CACV,EAAA,CAAA;AAElB"}
|