@kanzo-tech/ui 0.0.1-alpha
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/README.md +60 -0
- package/dist/analytics.d.ts +36 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +155 -0
- package/dist/analytics.js.map +1 -0
- package/dist/charts/arrow.d.ts +37 -0
- package/dist/charts/arrow.d.ts.map +1 -0
- package/dist/charts/arrow.js +29 -0
- package/dist/charts/arrow.js.map +1 -0
- package/dist/charts/chart-axes.d.ts +59 -0
- package/dist/charts/chart-axes.d.ts.map +1 -0
- package/dist/charts/chart-axes.js +39 -0
- package/dist/charts/chart-axes.js.map +1 -0
- package/dist/charts/chart-config.d.ts +52 -0
- package/dist/charts/chart-config.d.ts.map +1 -0
- package/dist/charts/chart-config.js +43 -0
- package/dist/charts/chart-config.js.map +1 -0
- package/dist/charts/chart-inputs.d.ts +174 -0
- package/dist/charts/chart-inputs.d.ts.map +1 -0
- package/dist/charts/chart-inputs.js +382 -0
- package/dist/charts/chart-inputs.js.map +1 -0
- package/dist/charts/chart-interactors.d.ts +75 -0
- package/dist/charts/chart-interactors.d.ts.map +1 -0
- package/dist/charts/chart-interactors.js +35 -0
- package/dist/charts/chart-interactors.js.map +1 -0
- package/dist/charts/chart-legend.d.ts +38 -0
- package/dist/charts/chart-legend.d.ts.map +1 -0
- package/dist/charts/chart-legend.js +49 -0
- package/dist/charts/chart-legend.js.map +1 -0
- package/dist/charts/chart-marks.d.ts +124 -0
- package/dist/charts/chart-marks.d.ts.map +1 -0
- package/dist/charts/chart-marks.js +109 -0
- package/dist/charts/chart-marks.js.map +1 -0
- package/dist/charts/chart-root.d.ts +90 -0
- package/dist/charts/chart-root.d.ts.map +1 -0
- package/dist/charts/chart-root.js +162 -0
- package/dist/charts/chart-root.js.map +1 -0
- package/dist/charts/chart-spec.d.ts +126 -0
- package/dist/charts/chart-spec.d.ts.map +1 -0
- package/dist/charts/chart-spec.js +133 -0
- package/dist/charts/chart-spec.js.map +1 -0
- package/dist/charts/chart-stat.d.ts +23 -0
- package/dist/charts/chart-stat.d.ts.map +1 -0
- package/dist/charts/chart-stat.js +24 -0
- package/dist/charts/chart-stat.js.map +1 -0
- package/dist/charts/id-set-client.d.ts +42 -0
- package/dist/charts/id-set-client.d.ts.map +1 -0
- package/dist/charts/id-set-client.js +43 -0
- package/dist/charts/id-set-client.js.map +1 -0
- package/dist/charts/mosaic-provider.d.ts +70 -0
- package/dist/charts/mosaic-provider.d.ts.map +1 -0
- package/dist/charts/mosaic-provider.js +53 -0
- package/dist/charts/mosaic-provider.js.map +1 -0
- package/dist/charts/query-client.d.ts +22 -0
- package/dist/charts/query-client.d.ts.map +1 -0
- package/dist/charts/query-client.js +26 -0
- package/dist/charts/query-client.js.map +1 -0
- package/dist/charts/tokenized-plot.d.ts +26 -0
- package/dist/charts/tokenized-plot.d.ts.map +1 -0
- package/dist/charts/tokenized-plot.js +41 -0
- package/dist/charts/tokenized-plot.js.map +1 -0
- package/dist/charts/use-chart-query.d.ts +30 -0
- package/dist/charts/use-chart-query.d.ts.map +1 -0
- package/dist/charts/use-chart-query.js +19 -0
- package/dist/charts/use-chart-query.js.map +1 -0
- package/dist/composites/CodeEditor.d.ts +64 -0
- package/dist/composites/CodeEditor.d.ts.map +1 -0
- package/dist/composites/CodeEditor.js +521 -0
- package/dist/composites/CodeEditor.js.map +1 -0
- package/dist/composites/MadeWith.d.ts +39 -0
- package/dist/composites/MadeWith.d.ts.map +1 -0
- package/dist/composites/MadeWith.js +30 -0
- package/dist/composites/MadeWith.js.map +1 -0
- package/dist/composites/Preferences.d.ts +155 -0
- package/dist/composites/Preferences.d.ts.map +1 -0
- package/dist/composites/Preferences.js +501 -0
- package/dist/composites/Preferences.js.map +1 -0
- package/dist/composites/Questionnaire.d.ts +215 -0
- package/dist/composites/Questionnaire.d.ts.map +1 -0
- package/dist/composites/Questionnaire.js +422 -0
- package/dist/composites/Questionnaire.js.map +1 -0
- package/dist/composites/SidebarIdentity.d.ts +63 -0
- package/dist/composites/SidebarIdentity.d.ts.map +1 -0
- package/dist/composites/SidebarIdentity.js +103 -0
- package/dist/composites/SidebarIdentity.js.map +1 -0
- package/dist/composites/code-editor-search.d.ts +40 -0
- package/dist/composites/code-editor-search.d.ts.map +1 -0
- package/dist/composites/code-editor-search.js +212 -0
- package/dist/composites/code-editor-search.js.map +1 -0
- package/dist/composites/sidebar.d.ts +129 -0
- package/dist/composites/sidebar.d.ts.map +1 -0
- package/dist/composites/sidebar.js +671 -0
- package/dist/composites/sidebar.js.map +1 -0
- package/dist/composites/theme-notice.d.ts +54 -0
- package/dist/composites/theme-notice.d.ts.map +1 -0
- package/dist/composites/theme-notice.js +19 -0
- package/dist/composites/theme-notice.js.map +1 -0
- package/dist/editor.d.ts +3 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +6 -0
- package/dist/editor.js.map +1 -0
- package/dist/guard-corpus.d.ts +63 -0
- package/dist/guard-corpus.d.ts.map +1 -0
- package/dist/index.d.ts +112 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +696 -0
- package/dist/index.js.map +1 -0
- package/dist/layouts/section.d.ts +166 -0
- package/dist/layouts/section.d.ts.map +1 -0
- package/dist/layouts/section.js +153 -0
- package/dist/layouts/section.js.map +1 -0
- package/dist/layouts/shell.d.ts +128 -0
- package/dist/layouts/shell.d.ts.map +1 -0
- package/dist/layouts/shell.js +107 -0
- package/dist/layouts/shell.js.map +1 -0
- package/dist/lib/cn.d.ts +4 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +9 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/is-active-path.d.ts +13 -0
- package/dist/lib/is-active-path.d.ts.map +1 -0
- package/dist/lib/is-active-path.js +7 -0
- package/dist/lib/is-active-path.js.map +1 -0
- package/dist/lib/theme-tick.d.ts +37 -0
- package/dist/lib/theme-tick.d.ts.map +1 -0
- package/dist/lib/theme-tick.js +30 -0
- package/dist/lib/theme-tick.js.map +1 -0
- package/dist/lib/token-color.d.ts +74 -0
- package/dist/lib/token-color.d.ts.map +1 -0
- package/dist/lib/token-color.js +35 -0
- package/dist/lib/token-color.js.map +1 -0
- package/dist/lib/use-is-mobile.d.ts +2 -0
- package/dist/lib/use-is-mobile.d.ts.map +1 -0
- package/dist/lib/use-is-mobile.js +17 -0
- package/dist/lib/use-is-mobile.js.map +1 -0
- package/dist/shark-parity.divergences.d.ts +104 -0
- package/dist/shark-parity.divergences.d.ts.map +1 -0
- package/dist/simples/FacetFilter.d.ts +57 -0
- package/dist/simples/FacetFilter.d.ts.map +1 -0
- package/dist/simples/FacetFilter.js +167 -0
- package/dist/simples/FacetFilter.js.map +1 -0
- package/dist/simples/FieldArray.d.ts +42 -0
- package/dist/simples/FieldArray.d.ts.map +1 -0
- package/dist/simples/FieldArray.js +76 -0
- package/dist/simples/FieldArray.js.map +1 -0
- package/dist/simples/Link.d.ts +38 -0
- package/dist/simples/Link.d.ts.map +1 -0
- package/dist/simples/Link.js +24 -0
- package/dist/simples/Link.js.map +1 -0
- package/dist/simples/accordion.d.ts +8 -0
- package/dist/simples/accordion.d.ts.map +1 -0
- package/dist/simples/accordion.js +78 -0
- package/dist/simples/accordion.js.map +1 -0
- package/dist/simples/action-bar.d.ts +101 -0
- package/dist/simples/action-bar.d.ts.map +1 -0
- package/dist/simples/action-bar.js +195 -0
- package/dist/simples/action-bar.js.map +1 -0
- package/dist/simples/alert-dialog.d.ts +24 -0
- package/dist/simples/alert-dialog.d.ts.map +1 -0
- package/dist/simples/alert-dialog.js +43 -0
- package/dist/simples/alert-dialog.js.map +1 -0
- package/dist/simples/alert.d.ts +36 -0
- package/dist/simples/alert.d.ts.map +1 -0
- package/dist/simples/alert.js +123 -0
- package/dist/simples/alert.js.map +1 -0
- package/dist/simples/avatar.d.ts +37 -0
- package/dist/simples/avatar.d.ts.map +1 -0
- package/dist/simples/avatar.js +133 -0
- package/dist/simples/avatar.js.map +1 -0
- package/dist/simples/badge.d.ts +66 -0
- package/dist/simples/badge.d.ts.map +1 -0
- package/dist/simples/badge.js +138 -0
- package/dist/simples/badge.js.map +1 -0
- package/dist/simples/breadcrumb.d.ts +19 -0
- package/dist/simples/breadcrumb.d.ts.map +1 -0
- package/dist/simples/breadcrumb.js +107 -0
- package/dist/simples/breadcrumb.js.map +1 -0
- package/dist/simples/button-group.d.ts +19 -0
- package/dist/simples/button-group.d.ts.map +1 -0
- package/dist/simples/button-group.js +69 -0
- package/dist/simples/button-group.js.map +1 -0
- package/dist/simples/button.d.ts +148 -0
- package/dist/simples/button.d.ts.map +1 -0
- package/dist/simples/button.js +157 -0
- package/dist/simples/button.js.map +1 -0
- package/dist/simples/calendar.d.ts +45 -0
- package/dist/simples/calendar.d.ts.map +1 -0
- package/dist/simples/calendar.js +342 -0
- package/dist/simples/calendar.js.map +1 -0
- package/dist/simples/card.d.ts +43 -0
- package/dist/simples/card.d.ts.map +1 -0
- package/dist/simples/card.js +151 -0
- package/dist/simples/card.js.map +1 -0
- package/dist/simples/checkbox.d.ts +25 -0
- package/dist/simples/checkbox.d.ts.map +1 -0
- package/dist/simples/checkbox.js +103 -0
- package/dist/simples/checkbox.js.map +1 -0
- package/dist/simples/client-only.d.ts +3 -0
- package/dist/simples/client-only.d.ts.map +1 -0
- package/dist/simples/client-only.js +7 -0
- package/dist/simples/client-only.js.map +1 -0
- package/dist/simples/clipboard.d.ts +11 -0
- package/dist/simples/clipboard.d.ts.map +1 -0
- package/dist/simples/clipboard.js +99 -0
- package/dist/simples/clipboard.js.map +1 -0
- package/dist/simples/collapsible.d.ts +8 -0
- package/dist/simples/collapsible.d.ts.map +1 -0
- package/dist/simples/collapsible.js +79 -0
- package/dist/simples/collapsible.js.map +1 -0
- package/dist/simples/color-picker.d.ts +62 -0
- package/dist/simples/color-picker.d.ts.map +1 -0
- package/dist/simples/color-picker.js +391 -0
- package/dist/simples/color-picker.js.map +1 -0
- package/dist/simples/combobox.d.ts +66 -0
- package/dist/simples/combobox.d.ts.map +1 -0
- package/dist/simples/combobox.js +230 -0
- package/dist/simples/combobox.js.map +1 -0
- package/dist/simples/command.d.ts +45 -0
- package/dist/simples/command.d.ts.map +1 -0
- package/dist/simples/command.js +180 -0
- package/dist/simples/command.js.map +1 -0
- package/dist/simples/data-list.d.ts +25 -0
- package/dist/simples/data-list.d.ts.map +1 -0
- package/dist/simples/data-list.js +62 -0
- package/dist/simples/data-list.js.map +1 -0
- package/dist/simples/date-picker.d.ts +16 -0
- package/dist/simples/date-picker.d.ts.map +1 -0
- package/dist/simples/date-picker.js +117 -0
- package/dist/simples/date-picker.js.map +1 -0
- package/dist/simples/diagnostic.d.ts +138 -0
- package/dist/simples/diagnostic.d.ts.map +1 -0
- package/dist/simples/diagnostic.js +288 -0
- package/dist/simples/diagnostic.js.map +1 -0
- package/dist/simples/dialog.d.ts +100 -0
- package/dist/simples/dialog.d.ts.map +1 -0
- package/dist/simples/dialog.js +267 -0
- package/dist/simples/dialog.js.map +1 -0
- package/dist/simples/download-trigger.d.ts +3 -0
- package/dist/simples/download-trigger.d.ts.map +1 -0
- package/dist/simples/download-trigger.js +7 -0
- package/dist/simples/download-trigger.js.map +1 -0
- package/dist/simples/editable.d.ts +23 -0
- package/dist/simples/editable.d.ts.map +1 -0
- package/dist/simples/editable.js +70 -0
- package/dist/simples/editable.js.map +1 -0
- package/dist/simples/field.d.ts +58 -0
- package/dist/simples/field.d.ts.map +1 -0
- package/dist/simples/field.js +285 -0
- package/dist/simples/field.js.map +1 -0
- package/dist/simples/file-upload.d.ts +19 -0
- package/dist/simples/file-upload.d.ts.map +1 -0
- package/dist/simples/file-upload.js +192 -0
- package/dist/simples/file-upload.js.map +1 -0
- package/dist/simples/float.d.ts +45 -0
- package/dist/simples/float.d.ts.map +1 -0
- package/dist/simples/float.js +40 -0
- package/dist/simples/float.js.map +1 -0
- package/dist/simples/floating-panel.d.ts +25 -0
- package/dist/simples/floating-panel.d.ts.map +1 -0
- package/dist/simples/floating-panel.js +95 -0
- package/dist/simples/floating-panel.js.map +1 -0
- package/dist/simples/highlight.d.ts +6 -0
- package/dist/simples/highlight.d.ts.map +1 -0
- package/dist/simples/highlight.js +24 -0
- package/dist/simples/highlight.js.map +1 -0
- package/dist/simples/hover-card.d.ts +11 -0
- package/dist/simples/hover-card.d.ts.map +1 -0
- package/dist/simples/hover-card.js +83 -0
- package/dist/simples/hover-card.js.map +1 -0
- package/dist/simples/image-cropper.d.ts +17 -0
- package/dist/simples/image-cropper.d.ts.map +1 -0
- package/dist/simples/image-cropper.js +139 -0
- package/dist/simples/image-cropper.js.map +1 -0
- package/dist/simples/input-group.d.ts +116 -0
- package/dist/simples/input-group.d.ts.map +1 -0
- package/dist/simples/input-group.js +245 -0
- package/dist/simples/input-group.js.map +1 -0
- package/dist/simples/input.d.ts +26 -0
- package/dist/simples/input.d.ts.map +1 -0
- package/dist/simples/input.js +60 -0
- package/dist/simples/input.js.map +1 -0
- package/dist/simples/item.d.ts +72 -0
- package/dist/simples/item.d.ts.map +1 -0
- package/dist/simples/item.js +180 -0
- package/dist/simples/item.js.map +1 -0
- package/dist/simples/json-tree-view.d.ts +7 -0
- package/dist/simples/json-tree-view.d.ts.map +1 -0
- package/dist/simples/json-tree-view.js +71 -0
- package/dist/simples/json-tree-view.js.map +1 -0
- package/dist/simples/kbd.d.ts +25 -0
- package/dist/simples/kbd.d.ts.map +1 -0
- package/dist/simples/kbd.js +50 -0
- package/dist/simples/kbd.js.map +1 -0
- package/dist/simples/listbox.d.ts +46 -0
- package/dist/simples/listbox.d.ts.map +1 -0
- package/dist/simples/listbox.js +218 -0
- package/dist/simples/listbox.js.map +1 -0
- package/dist/simples/menu.d.ts +60 -0
- package/dist/simples/menu.d.ts.map +1 -0
- package/dist/simples/menu.js +294 -0
- package/dist/simples/menu.js.map +1 -0
- package/dist/simples/native-select.d.ts +36 -0
- package/dist/simples/native-select.d.ts.map +1 -0
- package/dist/simples/native-select.js +77 -0
- package/dist/simples/native-select.js.map +1 -0
- package/dist/simples/number-input.d.ts +35 -0
- package/dist/simples/number-input.d.ts.map +1 -0
- package/dist/simples/number-input.js +142 -0
- package/dist/simples/number-input.js.map +1 -0
- package/dist/simples/pagination.d.ts +11 -0
- package/dist/simples/pagination.d.ts.map +1 -0
- package/dist/simples/pagination.js +78 -0
- package/dist/simples/pagination.js.map +1 -0
- package/dist/simples/password-input.d.ts +23 -0
- package/dist/simples/password-input.d.ts.map +1 -0
- package/dist/simples/password-input.js +90 -0
- package/dist/simples/password-input.js.map +1 -0
- package/dist/simples/pin-input.d.ts +30 -0
- package/dist/simples/pin-input.d.ts.map +1 -0
- package/dist/simples/pin-input.js +71 -0
- package/dist/simples/pin-input.js.map +1 -0
- package/dist/simples/popover.d.ts +42 -0
- package/dist/simples/popover.d.ts.map +1 -0
- package/dist/simples/popover.js +188 -0
- package/dist/simples/popover.js.map +1 -0
- package/dist/simples/progress.d.ts +23 -0
- package/dist/simples/progress.d.ts.map +1 -0
- package/dist/simples/progress.js +82 -0
- package/dist/simples/progress.js.map +1 -0
- package/dist/simples/prose.d.ts +17 -0
- package/dist/simples/prose.d.ts.map +1 -0
- package/dist/simples/prose.js +18 -0
- package/dist/simples/prose.js.map +1 -0
- package/dist/simples/radio-group.d.ts +23 -0
- package/dist/simples/radio-group.d.ts.map +1 -0
- package/dist/simples/radio-group.js +149 -0
- package/dist/simples/radio-group.js.map +1 -0
- package/dist/simples/rating.d.ts +10 -0
- package/dist/simples/rating.d.ts.map +1 -0
- package/dist/simples/rating.js +81 -0
- package/dist/simples/rating.js.map +1 -0
- package/dist/simples/resizable.d.ts +16 -0
- package/dist/simples/resizable.d.ts.map +1 -0
- package/dist/simples/resizable.js +57 -0
- package/dist/simples/resizable.js.map +1 -0
- package/dist/simples/scroll-area.d.ts +23 -0
- package/dist/simples/scroll-area.d.ts.map +1 -0
- package/dist/simples/scroll-area.js +88 -0
- package/dist/simples/scroll-area.js.map +1 -0
- package/dist/simples/segment-group.d.ts +27 -0
- package/dist/simples/segment-group.d.ts.map +1 -0
- package/dist/simples/segment-group.js +129 -0
- package/dist/simples/segment-group.js.map +1 -0
- package/dist/simples/select.d.ts +34 -0
- package/dist/simples/select.d.ts.map +1 -0
- package/dist/simples/select.js +258 -0
- package/dist/simples/select.js.map +1 -0
- package/dist/simples/separator.d.ts +12 -0
- package/dist/simples/separator.d.ts.map +1 -0
- package/dist/simples/separator.js +27 -0
- package/dist/simples/separator.js.map +1 -0
- package/dist/simples/sheet.d.ts +94 -0
- package/dist/simples/sheet.d.ts.map +1 -0
- package/dist/simples/sheet.js +172 -0
- package/dist/simples/sheet.js.map +1 -0
- package/dist/simples/show.d.ts +10 -0
- package/dist/simples/show.d.ts.map +1 -0
- package/dist/simples/show.js +9 -0
- package/dist/simples/show.js.map +1 -0
- package/dist/simples/skeleton.d.ts +3 -0
- package/dist/simples/skeleton.d.ts.map +1 -0
- package/dist/simples/skeleton.js +23 -0
- package/dist/simples/skeleton.js.map +1 -0
- package/dist/simples/skip-nav.d.ts +54 -0
- package/dist/simples/skip-nav.d.ts.map +1 -0
- package/dist/simples/skip-nav.js +42 -0
- package/dist/simples/skip-nav.js.map +1 -0
- package/dist/simples/slider.d.ts +29 -0
- package/dist/simples/slider.d.ts.map +1 -0
- package/dist/simples/slider.js +189 -0
- package/dist/simples/slider.js.map +1 -0
- package/dist/simples/spinner.d.ts +2 -0
- package/dist/simples/spinner.d.ts.map +1 -0
- package/dist/simples/spinner.js +20 -0
- package/dist/simples/spinner.js.map +1 -0
- package/dist/simples/stat-tile.d.ts +31 -0
- package/dist/simples/stat-tile.d.ts.map +1 -0
- package/dist/simples/stat-tile.js +64 -0
- package/dist/simples/stat-tile.js.map +1 -0
- package/dist/simples/status.d.ts +48 -0
- package/dist/simples/status.d.ts.map +1 -0
- package/dist/simples/status.js +57 -0
- package/dist/simples/status.js.map +1 -0
- package/dist/simples/steps.d.ts +20 -0
- package/dist/simples/steps.d.ts.map +1 -0
- package/dist/simples/steps.js +171 -0
- package/dist/simples/steps.js.map +1 -0
- package/dist/simples/suggestions.d.ts +43 -0
- package/dist/simples/suggestions.d.ts.map +1 -0
- package/dist/simples/suggestions.js +38 -0
- package/dist/simples/suggestions.js.map +1 -0
- package/dist/simples/swatch.d.ts +73 -0
- package/dist/simples/swatch.d.ts.map +1 -0
- package/dist/simples/swatch.js +35 -0
- package/dist/simples/swatch.js.map +1 -0
- package/dist/simples/switch.d.ts +5 -0
- package/dist/simples/switch.d.ts.map +1 -0
- package/dist/simples/switch.js +71 -0
- package/dist/simples/switch.js.map +1 -0
- package/dist/simples/table.d.ts +55 -0
- package/dist/simples/table.d.ts.map +1 -0
- package/dist/simples/table.js +166 -0
- package/dist/simples/table.js.map +1 -0
- package/dist/simples/tabs.d.ts +55 -0
- package/dist/simples/tabs.d.ts.map +1 -0
- package/dist/simples/tabs.js +133 -0
- package/dist/simples/tabs.js.map +1 -0
- package/dist/simples/tags-input.d.ts +64 -0
- package/dist/simples/tags-input.d.ts.map +1 -0
- package/dist/simples/tags-input.js +228 -0
- package/dist/simples/tags-input.js.map +1 -0
- package/dist/simples/textarea.d.ts +6 -0
- package/dist/simples/textarea.d.ts.map +1 -0
- package/dist/simples/textarea.js +34 -0
- package/dist/simples/textarea.js.map +1 -0
- package/dist/simples/toast.d.ts +20 -0
- package/dist/simples/toast.d.ts.map +1 -0
- package/dist/simples/toast.js +127 -0
- package/dist/simples/toast.js.map +1 -0
- package/dist/simples/toggle-group.d.ts +20 -0
- package/dist/simples/toggle-group.d.ts.map +1 -0
- package/dist/simples/toggle-group.js +82 -0
- package/dist/simples/toggle-group.js.map +1 -0
- package/dist/simples/toggle.d.ts +35 -0
- package/dist/simples/toggle.d.ts.map +1 -0
- package/dist/simples/toggle.js +57 -0
- package/dist/simples/toggle.js.map +1 -0
- package/dist/simples/tooltip.d.ts +8 -0
- package/dist/simples/tooltip.d.ts.map +1 -0
- package/dist/simples/tooltip.js +80 -0
- package/dist/simples/tooltip.js.map +1 -0
- package/dist/simples/tour.d.ts +81 -0
- package/dist/simples/tour.d.ts.map +1 -0
- package/dist/simples/tour.js +253 -0
- package/dist/simples/tour.js.map +1 -0
- package/dist/simples/tree-view.d.ts +64 -0
- package/dist/simples/tree-view.d.ts.map +1 -0
- package/dist/simples/tree-view.js +300 -0
- package/dist/simples/tree-view.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/table/data-table-content.d.ts +18 -0
- package/dist/table/data-table-content.d.ts.map +1 -0
- package/dist/table/data-table-content.js +53 -0
- package/dist/table/data-table-content.js.map +1 -0
- package/dist/table/data-table-pagination.d.ts +8 -0
- package/dist/table/data-table-pagination.d.ts.map +1 -0
- package/dist/table/data-table-pagination.js +65 -0
- package/dist/table/data-table-pagination.js.map +1 -0
- package/dist/table/data-table-root.d.ts +10 -0
- package/dist/table/data-table-root.d.ts.map +1 -0
- package/dist/table/data-table-root.js +21 -0
- package/dist/table/data-table-root.js.map +1 -0
- package/dist/table/data-table-toolbar.d.ts +44 -0
- package/dist/table/data-table-toolbar.d.ts.map +1 -0
- package/dist/table/data-table-toolbar.js +87 -0
- package/dist/table/data-table-toolbar.js.map +1 -0
- package/dist/table/select-column.d.ts +16 -0
- package/dist/table/select-column.d.ts.map +1 -0
- package/dist/table/select-column.js +39 -0
- package/dist/table/select-column.js.map +1 -0
- package/dist/table/sortableHeader.d.ts +25 -0
- package/dist/table/sortableHeader.d.ts.map +1 -0
- package/dist/table/sortableHeader.js +43 -0
- package/dist/table/sortableHeader.js.map +1 -0
- package/dist/table/use-data-table.d.ts +40 -0
- package/dist/table/use-data-table.d.ts.map +1 -0
- package/dist/table/use-data-table.js +65 -0
- package/dist/table/use-data-table.js.map +1 -0
- package/dist/table.d.ts +15 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +22 -0
- package/dist/table.js.map +1 -0
- package/dist/theme/KanzoTheme.d.ts +74 -0
- package/dist/theme/KanzoTheme.d.ts.map +1 -0
- package/dist/theme/KanzoTheme.js +61 -0
- package/dist/theme/KanzoTheme.js.map +1 -0
- package/dist/theme/KanzoThemeProvider.d.ts +144 -0
- package/dist/theme/KanzoThemeProvider.d.ts.map +1 -0
- package/dist/theme/KanzoThemeProvider.js +271 -0
- package/dist/theme/KanzoThemeProvider.js.map +1 -0
- package/dist/theme/theme-context.d.ts +146 -0
- package/dist/theme/theme-context.d.ts.map +1 -0
- package/dist/theme/theme-context.js +18 -0
- package/dist/theme/theme-context.js.map +1 -0
- package/dist/theme/theme-script.d.ts +17 -0
- package/dist/theme/theme-script.d.ts.map +1 -0
- package/dist/theme/theme-script.js +16 -0
- package/dist/theme/theme-script.js.map +1 -0
- package/package.json +201 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var j = Object.defineProperty;
|
|
3
|
+
var J = (e, t, n) => t in e ? j(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
|
|
4
|
+
var x = (e, t, n) => J(e, typeof t != "symbol" ? t + "" : t, n);
|
|
5
|
+
import { jsx as k } from "react/jsx-runtime";
|
|
6
|
+
import { useRef as l, useState as E, useEffect as g } from "react";
|
|
7
|
+
import { createPortal as Q } from "react-dom";
|
|
8
|
+
import { cn as M } from "../lib/cn.js";
|
|
9
|
+
import { kanzoSearch as U } from "./code-editor-search.js";
|
|
10
|
+
import { useKanzoThemeOptional as X } from "../theme/theme-context.js";
|
|
11
|
+
import { Compartment as y, EditorState as v, Annotation as Y, RangeSet as Z } from "@codemirror/state";
|
|
12
|
+
import { EditorView as d, keymap as _, drawSelection as $, dropCursor as rr, highlightSpecialChars as er, rectangularSelection as or, crosshairCursor as tr, lineNumbers as ar, placeholder as nr, ViewPlugin as cr, gutterLineClass as ir, Decoration as G, GutterMarker as lr } from "@codemirror/view";
|
|
13
|
+
import { history as dr, defaultKeymap as sr, historyKeymap as mr } from "@codemirror/commands";
|
|
14
|
+
import { foldKeymap as ur, bracketMatching as gr, indentOnInput as pr, foldGutter as fr, syntaxHighlighting as vr, HighlightStyle as br } from "@codemirror/language";
|
|
15
|
+
import { closeBracketsKeymap as hr, completionKeymap as xr, autocompletion as kr, closeBrackets as yr } from "@codemirror/autocomplete";
|
|
16
|
+
import { searchKeymap as wr, highlightSelectionMatches as Cr } from "@codemirror/search";
|
|
17
|
+
import { tags as r } from "@lezer/highlight";
|
|
18
|
+
const K = Y.define(), Sr = br.define([
|
|
19
|
+
{ tag: [r.keyword, r.operatorKeyword, r.controlKeyword, r.definitionKeyword, r.moduleKeyword, r.self], color: "var(--syntax-keyword)" },
|
|
20
|
+
{ tag: [r.atom, r.bool, r.constant(r.name), r.standard(r.name)], color: "var(--syntax-number)" },
|
|
21
|
+
{ tag: [r.string, r.special(r.string), r.docString, r.character, r.regexp], color: "var(--syntax-string)" },
|
|
22
|
+
// An escape sequence inside a string used to fall through to --foreground, so `\n` rendered
|
|
23
|
+
// as plain text mid-string. `t.escape`'s parent is `literal`, which was unmapped.
|
|
24
|
+
{ tag: [r.escape, r.special(r.brace)], color: "var(--syntax-number)" },
|
|
25
|
+
{ tag: [r.number, r.integer, r.float, r.unit], color: "var(--syntax-number)" },
|
|
26
|
+
{ tag: [r.comment, r.lineComment, r.blockComment, r.docComment], color: "var(--faint)", fontStyle: "italic" },
|
|
27
|
+
// Object keys and attribute names. These used to be grouped with `variableName`, which
|
|
28
|
+
// resolved to a token byte-identical to --foreground — so every key in a JSON document
|
|
29
|
+
// rendered as unstyled text and the whole sample looked near-monochrome.
|
|
30
|
+
{ tag: [r.propertyName, r.attributeName], color: "var(--syntax-property)" },
|
|
31
|
+
{ tag: [r.function(r.variableName), r.function(r.propertyName), r.macroName], color: "var(--syntax-function)" },
|
|
32
|
+
// Declarations are coloured; plain variable USES inherit --foreground, as in most themes.
|
|
33
|
+
{ tag: [r.definition(r.variableName), r.definition(r.propertyName)], color: "var(--syntax-identifier)" },
|
|
34
|
+
{ tag: [r.operator, r.derefOperator, r.arithmeticOperator, r.logicOperator, r.bitwiseOperator, r.compareOperator, r.updateOperator], color: "var(--foreground)" },
|
|
35
|
+
{ tag: [r.punctuation, r.separator, r.bracket, r.angleBracket, r.squareBracket, r.paren, r.brace], color: "var(--muted-foreground)" },
|
|
36
|
+
{ tag: [r.typeName, r.className, r.namespace, r.tagName, r.labelName], color: "var(--syntax-type)" },
|
|
37
|
+
{ tag: [r.meta, r.annotation, r.processingInstruction, r.documentMeta], color: "var(--faint)" },
|
|
38
|
+
{ tag: [r.url, r.link], color: "var(--syntax-function)", textDecoration: "underline" },
|
|
39
|
+
// Markdown: only `heading` was mapped, so prose rendered flat.
|
|
40
|
+
{ tag: r.heading, color: "var(--syntax-keyword)", fontWeight: "bold" },
|
|
41
|
+
{ tag: r.emphasis, fontStyle: "italic" },
|
|
42
|
+
{ tag: r.strong, fontWeight: "bold" },
|
|
43
|
+
{ tag: r.strikethrough, textDecoration: "line-through" },
|
|
44
|
+
{ tag: [r.monospace, r.list], color: "var(--syntax-string)" },
|
|
45
|
+
{ tag: r.quote, color: "var(--faint)" },
|
|
46
|
+
// Diff.
|
|
47
|
+
{ tag: r.inserted, color: "var(--success)" },
|
|
48
|
+
{ tag: r.deleted, color: "var(--destructive)" },
|
|
49
|
+
{ tag: r.changed, color: "var(--warning)" },
|
|
50
|
+
{ tag: r.invalid, color: "var(--destructive-foreground)" }
|
|
51
|
+
]), Nr = vr(Sr, { fallback: !0 }), Hr = G.line({ class: "cm-activeLine" }), Ir = new class extends lr {
|
|
52
|
+
constructor() {
|
|
53
|
+
super(...arguments);
|
|
54
|
+
x(this, "elementClass", "cm-activeLineGutter");
|
|
55
|
+
}
|
|
56
|
+
}(), R = (e) => {
|
|
57
|
+
if (e.selection.ranges.some((s) => !s.empty)) return [];
|
|
58
|
+
const t = [];
|
|
59
|
+
let n = -1;
|
|
60
|
+
for (const s of e.selection.ranges) {
|
|
61
|
+
const { from: m } = e.doc.lineAt(s.head);
|
|
62
|
+
m > n && (t.push(m), n = m);
|
|
63
|
+
}
|
|
64
|
+
return t;
|
|
65
|
+
}, Lr = cr.fromClass(
|
|
66
|
+
class {
|
|
67
|
+
constructor(e) {
|
|
68
|
+
x(this, "decorations");
|
|
69
|
+
this.decorations = z(e.state);
|
|
70
|
+
}
|
|
71
|
+
update(e) {
|
|
72
|
+
(e.docChanged || e.selectionSet) && (this.decorations = z(e.state));
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{ decorations: (e) => e.decorations }
|
|
76
|
+
), z = (e) => G.set(R(e).map((t) => Hr.range(t))), Or = ir.compute(
|
|
77
|
+
["selection", "doc"],
|
|
78
|
+
(e) => Z.of(R(e).map((t) => Ir.range(t)))
|
|
79
|
+
), Br = d.theme({
|
|
80
|
+
// `flex: 1`, not `height: 100%`: the chrome surface sizes with `min-height`/`max-height`, and
|
|
81
|
+
// a percentage height does not resolve against a `min-height`'d parent — so the editor stayed
|
|
82
|
+
// at content height and the field's extra `min-height` showed as dead space below the last
|
|
83
|
+
// line. As a flex child of the flex-column surface it fills the field; `min-height: 0` lets it
|
|
84
|
+
// shrink so `.cm-scroller` scrolls once content passes `max-height`.
|
|
85
|
+
"&": { fontSize: "var(--kanzo-font-size-base, 14px)", backgroundColor: "transparent", flex: "1 1 auto", minHeight: 0 },
|
|
86
|
+
// NO PADDING AT ALL any more, and that is the fix for a gap somebody could see: the vertical
|
|
87
|
+
// padding used to live here, and `.cm-line` sits INSIDE it — so the active-line highlight on the
|
|
88
|
+
// first line started half a rem below the top of the field and read as a bar floating in a
|
|
89
|
+
// margin. It moved to `.cm-scroller`, which contains the gutter as well as the content, so both
|
|
90
|
+
// shift together and the numbers stay on their lines.
|
|
91
|
+
//
|
|
92
|
+
// NO BACKGROUND either, and no horizontal padding. Both were here and both were wrong:
|
|
93
|
+
//
|
|
94
|
+
// · An opaque background on `.cm-content` HIDES THE SELECTION. `drawSelection` paints into
|
|
95
|
+
// `.cm-selectionLayer`, a sibling at `z-index: -2`, and CSS paints negative-z-index
|
|
96
|
+
// descendants *below* the backgrounds of in-flow block-level siblings — so the paper
|
|
97
|
+
// covered the layer completely. There is no fallback either: `drawSelection` forces the
|
|
98
|
+
// native `::selection` to transparent, so a selection rendered as nothing at all and the
|
|
99
|
+
// selected glyphs went invisible. Verified in the browser, and it is why no CodeMirror
|
|
100
|
+
// theme upstream puts a background here. The paper is on `.cm-scroller` now.
|
|
101
|
+
// · Horizontal padding here inset the ACTIVE LINE highlight by 12px at each edge, because
|
|
102
|
+
// the highlight is `.cm-line`'s own background and `.cm-line` sits inside the padding
|
|
103
|
+
// box. The row read as a floating bar rather than a highlighted line. The inset moved to
|
|
104
|
+
// `.cm-line`, so the highlight spans the field and the text keeps the same rhythm.
|
|
105
|
+
".cm-content": {
|
|
106
|
+
// Explicitly zero, and as the SHORTHAND: CodeMirror's base theme ships `padding: 4px 0` here,
|
|
107
|
+
// and a longhand `padding-block: 0` beside a shorthand loses — measured in the browser, the
|
|
108
|
+
// content kept its 4px and the gutter numbers drifted 4px off their lines. That 4px was the
|
|
109
|
+
// last of the gap above the first line's highlight.
|
|
110
|
+
padding: 0,
|
|
111
|
+
color: "var(--foreground)",
|
|
112
|
+
caretColor: "var(--foreground)"
|
|
113
|
+
},
|
|
114
|
+
// The field rhythm — 0.75rem is Textarea's `px-3`, so code sits on the same inset as an
|
|
115
|
+
// input's text (rem-based, so it tracks the density preference). On the LINE, so every
|
|
116
|
+
// full-width line decoration (active line, and any caller's `Decoration.line`) reaches the
|
|
117
|
+
// edges instead of stopping short of them.
|
|
118
|
+
//
|
|
119
|
+
// The inset is a HANGING one: a wrapped line resumes past the first row's start, so a Turtle URI
|
|
120
|
+
// that does not fit reads as a continuation rather than as a new statement. `basics` turns
|
|
121
|
+
// `EditorView.lineWrapping` on, so in a narrow pane most lines are wrapped ones — which is where
|
|
122
|
+
// the editor is used: a dock beside a canvas, an aside beside a table.
|
|
123
|
+
".cm-line": {
|
|
124
|
+
paddingBlock: 0,
|
|
125
|
+
paddingInlineStart: "2rem",
|
|
126
|
+
paddingInlineEnd: "0.75rem",
|
|
127
|
+
textIndent: "-1.25rem"
|
|
128
|
+
},
|
|
129
|
+
// The font belongs on `.cm-scroller`, not `.cm-content`: the GUTTER is a child of the
|
|
130
|
+
// scroller, and CodeMirror's base sets `.cm-scroller { font-family: monospace }`. With the
|
|
131
|
+
// family only on the content, line numbers rendered in the browser's generic monospace —
|
|
132
|
+
// Courier on many systems — beside content in the Kanzo stack. It also made the gutter's
|
|
133
|
+
// `min-width: 2.25ch` compute against the wrong font.
|
|
134
|
+
".cm-scroller": {
|
|
135
|
+
// NO VERTICAL INSET, on either surface. It was `0.5rem` here, on the argument that a code field
|
|
136
|
+
// wants the same breathing room `Textarea` has — and what it actually produced was nine pixels
|
|
137
|
+
// between the field's border and the first line, and a first line that does not start where
|
|
138
|
+
// every other box on the screen starts. A pane docked under its own header showed it worst.
|
|
139
|
+
// A caller who wants an inset has `className` and the surface it owns.
|
|
140
|
+
fontFamily: "var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace)",
|
|
141
|
+
lineHeight: "1.5",
|
|
142
|
+
overflow: "auto",
|
|
143
|
+
// Fill the editor so clicking the empty area below the last line still lands the caret,
|
|
144
|
+
// rather than leaving dead surface — see the `&` note.
|
|
145
|
+
flexGrow: 1,
|
|
146
|
+
minHeight: 0,
|
|
147
|
+
// The paper. It lives here and NOT on `.cm-content` — see the note there: an opaque
|
|
148
|
+
// background on the content box hides the selection layer beneath it. The scroller fills
|
|
149
|
+
// the whole field (flexGrow above), so the paper reaches the bottom on a short document.
|
|
150
|
+
background: "var(--background)"
|
|
151
|
+
},
|
|
152
|
+
"&.cm-focused": { outline: "none" },
|
|
153
|
+
// The gutter column carries its own tint. It used to be painted by the scroller instead, on
|
|
154
|
+
// the grounds that a fill here "only spans the content rows and stops mid-field on a short
|
|
155
|
+
// document" — measured against the current CodeMirror, that is no longer true: this element
|
|
156
|
+
// is sized to the full scroller height, so the column reaches the bottom. Reclaiming it
|
|
157
|
+
// freed the scroller to hold the paper, which is what un-hides the selection layer.
|
|
158
|
+
// No divider; the tint step from `--muted` to the scroller's `--background` is the separation.
|
|
159
|
+
".cm-gutters": {
|
|
160
|
+
// NO vertical padding: the scroller's is the only one, and the gutter is inside it, so every
|
|
161
|
+
// number already sits at its line's y. Repeating it here dropped each number one step too
|
|
162
|
+
// low — verified back when the padding was on `.cm-content`: a constant 9px below its line.
|
|
163
|
+
background: "var(--muted)",
|
|
164
|
+
border: "none",
|
|
165
|
+
color: "var(--faint)"
|
|
166
|
+
},
|
|
167
|
+
// Line numbers: tabular figures (no jitter across 9→10→100), right-aligned with breathing
|
|
168
|
+
// room from the border edge, and a comfortable minimum width.
|
|
169
|
+
".cm-lineNumbers .cm-gutterElement": {
|
|
170
|
+
fontVariantNumeric: "tabular-nums",
|
|
171
|
+
fontFeatureSettings: '"tnum"',
|
|
172
|
+
minWidth: "2.25ch",
|
|
173
|
+
padding: "0 0.5rem 0 0.75rem",
|
|
174
|
+
textAlign: "right",
|
|
175
|
+
cursor: "pointer",
|
|
176
|
+
transition: "color 120ms, background-color 120ms"
|
|
177
|
+
},
|
|
178
|
+
// A line number is a click target (it selects the line), so it has to answer the
|
|
179
|
+
// pointer — without this the whole column reads as inert decoration.
|
|
180
|
+
// Quieter than the active line on purpose: this is a hover affordance, and at equal
|
|
181
|
+
// strength the two read as the same state and the column flickers as the pointer moves.
|
|
182
|
+
".cm-lineNumbers .cm-gutterElement:hover": {
|
|
183
|
+
backgroundColor: "color-mix(in srgb, var(--editor-active-line, var(--muted)) 60%, transparent)",
|
|
184
|
+
color: "var(--foreground)"
|
|
185
|
+
},
|
|
186
|
+
".cm-foldGutter .cm-gutterElement:hover": { color: "var(--foreground)" },
|
|
187
|
+
".cm-placeholder": { color: "var(--muted-foreground)" },
|
|
188
|
+
// `highlightSpecialChars` ships its own `&light`/`&dark` rule at a raw `red` / `#f78`. Whichever
|
|
189
|
+
// half the appearance selects is a raw hue nobody chose. Tokenised here, at equal specificity and
|
|
190
|
+
// later in the sheet, so ours wins in both.
|
|
191
|
+
".cm-specialChar": { color: "var(--destructive-foreground)" },
|
|
192
|
+
// ── Floating surfaces ─────────────────────────────────────────────────────────
|
|
193
|
+
// CodeMirror ships its own light-mode chrome for tooltips, autocomplete and the
|
|
194
|
+
// search panel. Left alone they arrive as white boxes with system-blue selection —
|
|
195
|
+
// the moment an editor is more than a text box, that is where the theme visibly
|
|
196
|
+
// breaks. These read from the same tokens as `popover` / `menu`.
|
|
197
|
+
".cm-tooltip": {
|
|
198
|
+
background: "var(--popover)",
|
|
199
|
+
color: "var(--popover-foreground)",
|
|
200
|
+
border: "1px solid var(--border)",
|
|
201
|
+
borderRadius: "var(--radius-md)",
|
|
202
|
+
boxShadow: "0 4px 12px rgb(0 0 0 / 0.08)",
|
|
203
|
+
overflow: "hidden"
|
|
204
|
+
},
|
|
205
|
+
// The divider between an autocomplete tooltip's sections. CodeMirror's `&light` default is
|
|
206
|
+
// `1px solid #bbb`, and it is the half with no `&dark` counterpart — so before the facet followed
|
|
207
|
+
// the appearance it drew a pale hairline inside a dark popover, and it is *still* the rule that
|
|
208
|
+
// covers a light page. Found by `codemirror-dark-parity.test.ts`, not by looking.
|
|
209
|
+
".cm-tooltip-section:not(:first-child)": { borderTop: "1px solid var(--border)" },
|
|
210
|
+
".cm-tooltip .cm-tooltip-arrow:before": { borderTopColor: "var(--border)" },
|
|
211
|
+
".cm-tooltip .cm-tooltip-arrow:after": { borderTopColor: "var(--popover)" },
|
|
212
|
+
".cm-tooltip-autocomplete > ul": {
|
|
213
|
+
fontFamily: "var(--font-mono, ui-monospace, monospace)",
|
|
214
|
+
maxHeight: "16rem"
|
|
215
|
+
},
|
|
216
|
+
".cm-tooltip-autocomplete > ul > li": {
|
|
217
|
+
padding: "0.125rem 0.5rem",
|
|
218
|
+
lineHeight: "1.6"
|
|
219
|
+
},
|
|
220
|
+
".cm-tooltip-autocomplete > ul > li[aria-selected]": {
|
|
221
|
+
background: "var(--accent)",
|
|
222
|
+
color: "var(--accent-foreground)"
|
|
223
|
+
},
|
|
224
|
+
".cm-completionLabel": { color: "inherit" },
|
|
225
|
+
".cm-completionMatchedText": {
|
|
226
|
+
color: "var(--primary)",
|
|
227
|
+
fontWeight: "600",
|
|
228
|
+
textDecoration: "none"
|
|
229
|
+
},
|
|
230
|
+
".cm-completionDetail": {
|
|
231
|
+
color: "var(--muted-foreground)",
|
|
232
|
+
fontStyle: "normal",
|
|
233
|
+
marginInlineStart: "0.5rem"
|
|
234
|
+
},
|
|
235
|
+
".cm-completionIcon": { opacity: 0.64, paddingInlineEnd: "0.5rem" },
|
|
236
|
+
".cm-panels": {
|
|
237
|
+
background: "var(--card)",
|
|
238
|
+
color: "var(--card-foreground)",
|
|
239
|
+
borderColor: "var(--border)"
|
|
240
|
+
},
|
|
241
|
+
".cm-panels.cm-panels-top": { borderBottom: "1px solid var(--border)" },
|
|
242
|
+
".cm-panels.cm-panels-bottom": { borderTop: "1px solid var(--border)" },
|
|
243
|
+
// **`.cm-textfield` and `.cm-button` are no longer OUR controls, and that is the whole point of
|
|
244
|
+
// `code-editor-search.tsx`.** The find/replace panel is `InputGroup`, `Toggle`, `Button` and
|
|
245
|
+
// `ButtonGroup` now, rendered through a portal, so it wears the library's typography, focus ring
|
|
246
|
+
// and hover states rather than a run of rules restating them in CSS. Six selectors went with it:
|
|
247
|
+
// `.cm-panel.cm-search`, its `input, button, label { font-size: inherit }`, the two
|
|
248
|
+
// `.cm-textfield` rules and the two for `button[name=close]`.
|
|
249
|
+
//
|
|
250
|
+
// These two stay, unscoped, for the controls that are still CodeMirror's: `gotoLine`'s dialog
|
|
251
|
+
// (Mod-Alt-G), and any panel a caller's own extensions bring — `@codemirror/lint`'s is the
|
|
252
|
+
// obvious one, and it is a caller's dependency rather than ours.
|
|
253
|
+
//
|
|
254
|
+
// **They also have to stay because they are the only thing standing between a page and a box
|
|
255
|
+
// nobody themed.** `&light .cm-textfield { background: white; border: 1px solid silver }` and
|
|
256
|
+
// `&light .cm-button { background: linear-gradient(#eff1f5, #d9d9df) }` are one half of it and
|
|
257
|
+
// `&dark`'s `#333` and `linear-gradient(#393939, #111)` are the other; the `darkTheme` facet picks
|
|
258
|
+
// which, and neither is a token. `codemirror-dark-parity.test.ts` checks BOTH halves and fails the
|
|
259
|
+
// day either selector leaves this file. The previous
|
|
260
|
+
// spelling was `.cm-panel.cm-search .cm-textfield`, which covered the search field and left
|
|
261
|
+
// `gotoLine`'s identical field wearing the white default; before that it was `input[type=text]`,
|
|
262
|
+
// which matched nothing at all, because CodeMirror sets no `type` on it.
|
|
263
|
+
".cm-textfield": {
|
|
264
|
+
background: "var(--background)",
|
|
265
|
+
color: "var(--foreground)",
|
|
266
|
+
border: "1px solid var(--input)",
|
|
267
|
+
borderRadius: "var(--radius-sm)",
|
|
268
|
+
padding: "0.125rem 0.375rem",
|
|
269
|
+
outline: "none"
|
|
270
|
+
},
|
|
271
|
+
".cm-textfield:focus": {
|
|
272
|
+
borderColor: "var(--ring)",
|
|
273
|
+
boxShadow: "0 0 0 3px color-mix(in srgb, var(--ring) 32%, transparent)"
|
|
274
|
+
},
|
|
275
|
+
".cm-button": {
|
|
276
|
+
background: "var(--secondary)",
|
|
277
|
+
color: "var(--secondary-foreground)",
|
|
278
|
+
border: "1px solid transparent",
|
|
279
|
+
borderRadius: "var(--radius-sm)",
|
|
280
|
+
backgroundImage: "none",
|
|
281
|
+
padding: "0.125rem 0.5rem",
|
|
282
|
+
cursor: "pointer"
|
|
283
|
+
},
|
|
284
|
+
".cm-button:hover": { background: "var(--accent)" },
|
|
285
|
+
".cm-button:active": { backgroundImage: "none" },
|
|
286
|
+
".cm-dialog": { padding: "0.375rem 0.5rem", fontSize: "var(--kanzo-font-size-small, 12px)" },
|
|
287
|
+
".cm-dialog label": { display: "inline-flex", alignItems: "center", gap: "0.375rem" },
|
|
288
|
+
".cm-dialog-close": { color: "var(--muted-foreground)", cursor: "pointer" },
|
|
289
|
+
".cm-dialog-close:hover": { color: "var(--foreground)" },
|
|
290
|
+
// Search hits: the current one is the primary-tinted anchor, the rest are quieter so
|
|
291
|
+
// "where am I" stays readable at a glance.
|
|
292
|
+
".cm-searchMatch": {
|
|
293
|
+
backgroundColor: "var(--warning-a5)",
|
|
294
|
+
outline: "1px solid var(--border)",
|
|
295
|
+
borderRadius: "2px"
|
|
296
|
+
},
|
|
297
|
+
".cm-searchMatch.cm-searchMatch-selected": {
|
|
298
|
+
backgroundColor: "var(--warning-a8)",
|
|
299
|
+
outline: "1px solid var(--warning)"
|
|
300
|
+
},
|
|
301
|
+
// Lint diagnostics — semantic tokens, so severity survives a re-theme.
|
|
302
|
+
".cm-diagnostic": {
|
|
303
|
+
padding: "0.25rem 0.5rem",
|
|
304
|
+
borderInlineStartWidth: "3px",
|
|
305
|
+
borderInlineStartStyle: "solid",
|
|
306
|
+
fontFamily: "var(--font-sans)"
|
|
307
|
+
},
|
|
308
|
+
".cm-diagnostic-error": { borderInlineStartColor: "var(--destructive)" },
|
|
309
|
+
".cm-diagnostic-warning": { borderInlineStartColor: "var(--warning)" },
|
|
310
|
+
".cm-diagnostic-info": { borderInlineStartColor: "var(--info)" },
|
|
311
|
+
".cm-lintPoint-error:after": { borderBottomColor: "var(--destructive)" },
|
|
312
|
+
".cm-lintPoint-warning:after": { borderBottomColor: "var(--warning)" },
|
|
313
|
+
// Scrollbars: the default OS chrome is the loudest thing in a dark editor.
|
|
314
|
+
".cm-scroller::-webkit-scrollbar": { width: "10px", height: "10px" },
|
|
315
|
+
".cm-scroller::-webkit-scrollbar-track": { background: "transparent" },
|
|
316
|
+
".cm-scroller::-webkit-scrollbar-thumb": {
|
|
317
|
+
background: "color-mix(in srgb, var(--muted-foreground) 32%, transparent)",
|
|
318
|
+
borderRadius: "6px",
|
|
319
|
+
border: "2px solid transparent",
|
|
320
|
+
backgroundClip: "content-box"
|
|
321
|
+
},
|
|
322
|
+
".cm-scroller::-webkit-scrollbar-thumb:hover": {
|
|
323
|
+
background: "color-mix(in srgb, var(--muted-foreground) 56%, transparent)",
|
|
324
|
+
backgroundClip: "content-box"
|
|
325
|
+
},
|
|
326
|
+
".cm-scroller::-webkit-scrollbar-corner": { background: "transparent" },
|
|
327
|
+
// Tokenised selection (drawSelection), active line, matching bracket, search matches.
|
|
328
|
+
".cm-cursor, .cm-dropCursor": { borderLeftColor: "var(--foreground)" },
|
|
329
|
+
// The full child chain is LOAD-BEARING. CodeMirror's base theme ships
|
|
330
|
+
// `&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground`
|
|
331
|
+
// (@codemirror/view), which compiles to specificity 0,5,0. A flat
|
|
332
|
+
// `&.cm-focused .cm-selectionBackground` is 0,3,0 and LOSES — so the focused selection
|
|
333
|
+
// rendered in CodeMirror's stock lavender (#d7d4f0) instead of a Kanzo token. Worse, that
|
|
334
|
+
// base rule is `&light`, and for as long as the `darkTheme` facet was pinned false the light
|
|
335
|
+
// lavender applied in dark mode too. It is driven from the appearance now, which moves the
|
|
336
|
+
// default to `&dark`'s — a different stock colour, still not ours, still covered by this rule.
|
|
337
|
+
"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
338
|
+
backgroundColor: "var(--brand-a5)"
|
|
339
|
+
},
|
|
340
|
+
// **A selection must not repaint the text, and ours repainted all of it.** `tokens.css` sets a
|
|
341
|
+
// document-wide `::selection { bg-primary/80 text-primary-foreground }`, which is right
|
|
342
|
+
// everywhere prose is selected and wrong inside an editor: `drawSelection` suppresses the native
|
|
343
|
+
// selection's *background* and not its `color`, so the fill came from `.cm-selectionBackground`
|
|
344
|
+
// — `--brand-a5`, black at 12% — while every glyph inside it took `--primary-foreground`.
|
|
345
|
+
//
|
|
346
|
+
// Measured on `/docs/forms/code-editor`: #fafafa text on a #dcdcdc block. Keys, strings and
|
|
347
|
+
// numbers all flattened to one near-white, so selecting seven lines of JSON erased the
|
|
348
|
+
// highlighting from them. It happens under every palette, because a `-foreground` role is a
|
|
349
|
+
// contrast colour for a fill that is not being painted here.
|
|
350
|
+
//
|
|
351
|
+
// `currentColor` is the fix, and it has to be `currentColor` and not a token: a fixed colour
|
|
352
|
+
// flattens the tokens just as thoroughly, one shade later.
|
|
353
|
+
".cm-selectionBackground, .cm-content ::selection": {
|
|
354
|
+
backgroundColor: "var(--brand-a5)",
|
|
355
|
+
color: "currentColor"
|
|
356
|
+
},
|
|
357
|
+
".cm-activeLine": { backgroundColor: "var(--editor-active-line, var(--muted))" },
|
|
358
|
+
// The active line's gutter cell is emphasised beyond the row: stronger tint, full-strength
|
|
359
|
+
// ink and a weight bump so the current line number stands out from the dim column.
|
|
360
|
+
".cm-activeLineGutter": {
|
|
361
|
+
backgroundColor: "var(--editor-active-line, var(--muted))",
|
|
362
|
+
color: "var(--foreground)",
|
|
363
|
+
fontWeight: "600"
|
|
364
|
+
},
|
|
365
|
+
".cm-matchingBracket, &.cm-focused .cm-matchingBracket": { backgroundColor: "var(--brand-a5)", outline: "1px solid var(--primary)" },
|
|
366
|
+
".cm-nonmatchingBracket": { backgroundColor: "var(--destructive-a4)" },
|
|
367
|
+
// **A neutral tint, because it is not a search hit.** This wore `--warning-a5`, byte for byte
|
|
368
|
+
// what `.cm-searchMatch` wears — so the other occurrences of the word under your caret were
|
|
369
|
+
// indistinguishable from the hits of a query you actually typed, and the two co-occur constantly:
|
|
370
|
+
// open the find panel while a word is selected and every match looks like the same kind of thing.
|
|
371
|
+
//
|
|
372
|
+
// They are not. A search hit is something you asked for; this is the editor noticing a
|
|
373
|
+
// repetition. Every editor that draws both separates them the same way — the query keeps the
|
|
374
|
+
// colour, the passive one goes neutral — and `--base-a5` is the house's neutral wash. It also
|
|
375
|
+
// takes the collision off `--warning-a5`, which `Highlight` uses for a search-term mark in prose.
|
|
376
|
+
".cm-selectionMatch": { backgroundColor: "var(--base-a5)" },
|
|
377
|
+
".cm-foldGutter .cm-gutterElement": { cursor: "pointer", color: "var(--faint)" },
|
|
378
|
+
".cm-foldPlaceholder": { background: "var(--muted)", border: "1px solid var(--border)", color: "var(--muted-foreground)", borderRadius: "var(--radius-sm)", padding: "0 4px" }
|
|
379
|
+
}), F = (e) => e ? d.darkTheme.of(!0) : [];
|
|
380
|
+
function jr(e) {
|
|
381
|
+
var L;
|
|
382
|
+
const t = l(null), n = l(void 0), [s, m] = E(!1), a = l(e);
|
|
383
|
+
a.current = e;
|
|
384
|
+
const w = l(new y()), C = l(new y()), S = l(new y()), p = ((L = X()) == null ? void 0 : L.resolvedAppearance) === "dark", N = l(p);
|
|
385
|
+
N.current = p;
|
|
386
|
+
const [T, H] = E([]);
|
|
387
|
+
g(() => {
|
|
388
|
+
var O, B;
|
|
389
|
+
const o = a.current.basics ?? !0;
|
|
390
|
+
let P = 0;
|
|
391
|
+
const W = {
|
|
392
|
+
panel: (c, i) => {
|
|
393
|
+
const u = document.createElement("div"), f = ++P;
|
|
394
|
+
return {
|
|
395
|
+
dom: u,
|
|
396
|
+
top: i == null ? void 0 : i.top,
|
|
397
|
+
mount: () => H((h) => [...h, { id: f, dom: u, node: c }]),
|
|
398
|
+
destroy: () => H((h) => h.filter((q) => q.id !== f))
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}, D = d.updateListener.of((c) => {
|
|
402
|
+
var i, u;
|
|
403
|
+
c.focusChanged && m(c.view.hasFocus), c.docChanged && (c.transactions.some((f) => f.annotation(K)) || (u = (i = a.current).onChange) == null || u.call(i, c.state.doc.toString()));
|
|
404
|
+
}), V = a.current.wrap ?? !0, A = o ? [
|
|
405
|
+
dr(),
|
|
406
|
+
_.of([
|
|
407
|
+
...sr,
|
|
408
|
+
...mr,
|
|
409
|
+
...wr,
|
|
410
|
+
...hr,
|
|
411
|
+
...xr,
|
|
412
|
+
...ur
|
|
413
|
+
]),
|
|
414
|
+
...V ? [d.lineWrapping] : [],
|
|
415
|
+
$(),
|
|
416
|
+
rr(),
|
|
417
|
+
// `completionKeymap` was already bound below, but the extension itself was never
|
|
418
|
+
// installed — so Ctrl-Space did nothing and the ~25 lines of
|
|
419
|
+
// `.cm-tooltip-autocomplete` styling in this theme were dead CSS.
|
|
420
|
+
kr(),
|
|
421
|
+
// Makes NBSP, zero-width and control characters visible. Without it they are
|
|
422
|
+
// invisible in the document, which is a real footgun when editing data.
|
|
423
|
+
er(),
|
|
424
|
+
// Alt-drag column selection, and the crosshair cursor that signals it is available.
|
|
425
|
+
or(),
|
|
426
|
+
tr(),
|
|
427
|
+
Lr,
|
|
428
|
+
gr(),
|
|
429
|
+
yr(),
|
|
430
|
+
pr(),
|
|
431
|
+
Cr(),
|
|
432
|
+
// **`search()` has to be in the configuration, and it was not.** `searchKeymap` was
|
|
433
|
+
// bound below and nothing installed the extension, so `openSearchPanel` appended the
|
|
434
|
+
// defaults itself the first time Mod-F was pressed — which works, and silently discards
|
|
435
|
+
// any configuration, `createPanel` included. Same shape as the `autocompletion()` bug
|
|
436
|
+
// noted further down: a keymap for an extension nobody added.
|
|
437
|
+
U(W),
|
|
438
|
+
Nr,
|
|
439
|
+
Br
|
|
440
|
+
] : [], b = new d({
|
|
441
|
+
parent: t.current,
|
|
442
|
+
state: v.create({
|
|
443
|
+
doc: a.current.value ?? "",
|
|
444
|
+
extensions: [
|
|
445
|
+
// Multiple cursors. Off by default in CodeMirror, and table stakes in an editor.
|
|
446
|
+
v.allowMultipleSelections.of(!0),
|
|
447
|
+
...A,
|
|
448
|
+
...a.current.lineNumbers ? [ar()] : [],
|
|
449
|
+
...o && a.current.lineNumbers ? [Or, fr()] : [],
|
|
450
|
+
...a.current.placeholder ? [nr(a.current.placeholder)] : [],
|
|
451
|
+
D,
|
|
452
|
+
S.current.of(F(N.current)),
|
|
453
|
+
w.current.of(a.current.extensions ?? []),
|
|
454
|
+
C.current.of([
|
|
455
|
+
d.editable.of(!a.current.readOnly),
|
|
456
|
+
v.readOnly.of(!!a.current.readOnly)
|
|
457
|
+
])
|
|
458
|
+
]
|
|
459
|
+
})
|
|
460
|
+
});
|
|
461
|
+
return n.current = b, (B = (O = a.current).onView) == null || B.call(O, b), () => {
|
|
462
|
+
var c, i;
|
|
463
|
+
(i = (c = a.current).onView) == null || i.call(c, null), b.destroy();
|
|
464
|
+
};
|
|
465
|
+
}, []), g(() => {
|
|
466
|
+
const o = n.current;
|
|
467
|
+
!o || o.hasFocus || e.value !== o.state.doc.toString() && o.dispatch({
|
|
468
|
+
changes: { from: 0, to: o.state.doc.length, insert: e.value },
|
|
469
|
+
annotations: K.of(!0)
|
|
470
|
+
});
|
|
471
|
+
}, [e.value]), g(() => {
|
|
472
|
+
var o;
|
|
473
|
+
(o = n.current) == null || o.dispatch({ effects: w.current.reconfigure(e.extensions ?? []) });
|
|
474
|
+
}, [e.extensions]), g(() => {
|
|
475
|
+
var o;
|
|
476
|
+
(o = n.current) == null || o.dispatch({ effects: S.current.reconfigure(F(p)) });
|
|
477
|
+
}, [p]), g(() => {
|
|
478
|
+
var o;
|
|
479
|
+
(o = n.current) == null || o.dispatch({
|
|
480
|
+
effects: C.current.reconfigure([
|
|
481
|
+
d.editable.of(!e.readOnly),
|
|
482
|
+
v.readOnly.of(!!e.readOnly)
|
|
483
|
+
])
|
|
484
|
+
});
|
|
485
|
+
}, [e.readOnly]);
|
|
486
|
+
const I = T.map((o) => Q(o.node, o.dom, String(o.id)));
|
|
487
|
+
return e.chrome === !1 ? /* @__PURE__ */ k(
|
|
488
|
+
"div",
|
|
489
|
+
{
|
|
490
|
+
className: M("flex flex-col", e.className),
|
|
491
|
+
"data-slot": "code-editor",
|
|
492
|
+
ref: t,
|
|
493
|
+
style: { minHeight: e.minHeight, maxHeight: e.maxHeight },
|
|
494
|
+
children: I
|
|
495
|
+
}
|
|
496
|
+
) : /* @__PURE__ */ k("div", { "data-slot": "code-editor", style: { flex: 1, width: "100%" }, children: /* @__PURE__ */ k(
|
|
497
|
+
"div",
|
|
498
|
+
{
|
|
499
|
+
"data-slot": "code-editor-surface",
|
|
500
|
+
"data-focused": s || void 0,
|
|
501
|
+
"data-invalid": e.invalid || void 0,
|
|
502
|
+
ref: t,
|
|
503
|
+
className: M(
|
|
504
|
+
"flex w-full flex-col overflow-hidden",
|
|
505
|
+
"rounded-lg border border-input bg-transparent shadow-xs/5 bg-field",
|
|
506
|
+
"transition-[color,box-shadow]",
|
|
507
|
+
"data-focused:border-primary data-focused:ring-[3px] data-focused:ring-ring",
|
|
508
|
+
"data-invalid:border-destructive data-invalid:ring-[3px] data-invalid:ring-destructive/24",
|
|
509
|
+
"motion-reduce:transition-none!"
|
|
510
|
+
),
|
|
511
|
+
style: { minHeight: e.minHeight, maxHeight: e.maxHeight },
|
|
512
|
+
children: I
|
|
513
|
+
}
|
|
514
|
+
) });
|
|
515
|
+
}
|
|
516
|
+
export {
|
|
517
|
+
jr as CodeEditor,
|
|
518
|
+
Sr as kanzoHighlightStyle,
|
|
519
|
+
Nr as kanzoHighlighting
|
|
520
|
+
};
|
|
521
|
+
//# sourceMappingURL=CodeEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeEditor.js","sources":["../../src/composites/CodeEditor.tsx"],"sourcesContent":["\"use client\";\n\nimport { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"../lib/cn.js\";\nimport { type ReactPanelHost, kanzoSearch } from \"./code-editor-search.js\";\nimport { useKanzoThemeOptional } from \"../theme/theme-context.js\";\nimport { Annotation, Compartment, EditorState, type Extension, RangeSet } from \"@codemirror/state\";\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n GutterMarker,\n ViewPlugin,\n type ViewUpdate,\n crosshairCursor,\n drawSelection,\n dropCursor,\n gutterLineClass,\n highlightSpecialChars,\n keymap,\n lineNumbers as cmLineNumbers,\n placeholder as cmPlaceholder,\n rectangularSelection,\n} from \"@codemirror/view\";\nimport { defaultKeymap, history, historyKeymap } from \"@codemirror/commands\";\nimport {\n HighlightStyle,\n bracketMatching,\n foldGutter,\n foldKeymap,\n indentOnInput,\n syntaxHighlighting,\n} from \"@codemirror/language\";\nimport { autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap } from \"@codemirror/autocomplete\";\nimport { highlightSelectionMatches, searchKeymap } from \"@codemirror/search\";\nimport { tags as t } from \"@lezer/highlight\";\n\n/**\n * A **CodeMirror 6** editing surface — the reusable lifecycle core (view\n * create/destroy, controlled-value reconcile, live-reconfigured `extensions`\n * slot, readOnly toggle) plus optional batteries + chrome. Domain-free: it knows\n * nothing about any specific language — the consumer injects that via `extensions`.\n *\n * Two consumer shapes, both real:\n * · **Batteries-included** (default): history + default keymap + line wrapping +\n * the Kanzo-tokened theme, wrapped in a styled focus-ring chrome. For quick\n * editors (a JSON field, a code preview).\n * · **Bring-your-own** (`basics={false} chrome={false}`): a bare surface driven\n * entirely by the caller's `extensions`, for a mature editor that owns its own\n * theme/keymap/behaviour (e.g. fossil's LSP editor). `onView` hands back the\n * `EditorView` for side-wiring.\n */\n\nconst External = Annotation.define<boolean>();\n\n/**\n * Kanzo syntax theme — maps Lezer highlight tags to the design tokens, so a consumer's language\n * extension is coloured by whichever palette document is on the page. Exported so a\n * bring-your-own editor can wire the same palette. Inert until the caller injects a language\n * (there is no tree to tag).\n *\n * **Seven of these are `--syntax-*` and the rest are tokens that already existed**, which is the\n * shape the palette layer settled on: `comment` is `--faint` (the quietest legible ink — a gutter\n * number, a field's placeholder and a code comment are one decision), `punctuation` is\n * `--muted-foreground`, `operator` is `--foreground`, and `invalid` is the destructive family.\n * There were thirteen `--syntax-*` tokens; six of them were duplicating a tint the ramp\n * already publishes.\n *\n * The seven that remain are derived per tenant and graded against `--editor-active-line`, so a\n * palette finally repaints keywords: Dracula's pink, Nord's purple, Catppuccin's mauve. Every\n * document used to declare Kanzo's.\n */\nexport const kanzoHighlightStyle = HighlightStyle.define([\n { tag: [t.keyword, t.operatorKeyword, t.controlKeyword, t.definitionKeyword, t.moduleKeyword, t.self], color: \"var(--syntax-keyword)\" },\n { tag: [t.atom, t.bool, t.constant(t.name), t.standard(t.name)], color: \"var(--syntax-number)\" },\n { tag: [t.string, t.special(t.string), t.docString, t.character, t.regexp], color: \"var(--syntax-string)\" },\n // An escape sequence inside a string used to fall through to --foreground, so `\\n` rendered\n // as plain text mid-string. `t.escape`'s parent is `literal`, which was unmapped.\n { tag: [t.escape, t.special(t.brace)], color: \"var(--syntax-number)\" },\n { tag: [t.number, t.integer, t.float, t.unit], color: \"var(--syntax-number)\" },\n { tag: [t.comment, t.lineComment, t.blockComment, t.docComment], color: \"var(--faint)\", fontStyle: \"italic\" },\n // Object keys and attribute names. These used to be grouped with `variableName`, which\n // resolved to a token byte-identical to --foreground — so every key in a JSON document\n // rendered as unstyled text and the whole sample looked near-monochrome.\n { tag: [t.propertyName, t.attributeName], color: \"var(--syntax-property)\" },\n { tag: [t.function(t.variableName), t.function(t.propertyName), t.macroName], color: \"var(--syntax-function)\" },\n // Declarations are coloured; plain variable USES inherit --foreground, as in most themes.\n { tag: [t.definition(t.variableName), t.definition(t.propertyName)], color: \"var(--syntax-identifier)\" },\n { tag: [t.operator, t.derefOperator, t.arithmeticOperator, t.logicOperator, t.bitwiseOperator, t.compareOperator, t.updateOperator], color: \"var(--foreground)\" },\n { tag: [t.punctuation, t.separator, t.bracket, t.angleBracket, t.squareBracket, t.paren, t.brace], color: \"var(--muted-foreground)\" },\n { tag: [t.typeName, t.className, t.namespace, t.tagName, t.labelName], color: \"var(--syntax-type)\" },\n { tag: [t.meta, t.annotation, t.processingInstruction, t.documentMeta], color: \"var(--faint)\" },\n { tag: [t.url, t.link], color: \"var(--syntax-function)\", textDecoration: \"underline\" },\n // Markdown: only `heading` was mapped, so prose rendered flat.\n { tag: t.heading, color: \"var(--syntax-keyword)\", fontWeight: \"bold\" },\n { tag: t.emphasis, fontStyle: \"italic\" },\n { tag: t.strong, fontWeight: \"bold\" },\n { tag: t.strikethrough, textDecoration: \"line-through\" },\n { tag: [t.monospace, t.list], color: \"var(--syntax-string)\" },\n { tag: t.quote, color: \"var(--faint)\" },\n // Diff.\n { tag: t.inserted, color: \"var(--success)\" },\n { tag: t.deleted, color: \"var(--destructive)\" },\n { tag: t.changed, color: \"var(--warning)\" },\n { tag: t.invalid, color: \"var(--destructive-foreground)\" },\n]);\n\n/** The Kanzo highlight style as a ready-to-drop extension. */\nexport const kanzoHighlighting: Extension = syntaxHighlighting(kanzoHighlightStyle, { fallback: true });\n\n/**\n * The caret's line — **and only while nothing is selected.**\n *\n * `highlightActiveLine` decorates the line under every range's `head` whether the range is empty or\n * not (`@codemirror/view@6.43.4`), so one line of a selection also wore the active-line band. Ours\n * is `--muted`, which is *lighter* than the selection tint and runs the full width, so that line\n * read as hovered rather than selected: two affordances arguing over one row. VS Code drops its\n * line highlight while a selection exists, and this is that.\n *\n * Reimplemented rather than suppressed with a CSS rule. Overriding upstream would leave two\n * extensions drawing the same decoration and the reason for it nowhere near the theme.\n */\nconst caretLine = Decoration.line({ class: \"cm-activeLine\" });\n\nconst caretLineGutter = new (class extends GutterMarker {\n override elementClass = \"cm-activeLineGutter\";\n})();\n\n/** The line start of each caret, empty while any range holds a selection. Ranges arrive sorted. */\nconst caretLines = (state: EditorState): number[] => {\n if (state.selection.ranges.some((r) => !r.empty)) return [];\n const starts: number[] = [];\n let last = -1;\n for (const r of state.selection.ranges) {\n const { from } = state.doc.lineAt(r.head);\n if (from > last) {\n starts.push(from);\n last = from;\n }\n }\n return starts;\n};\n\nconst highlightCaretLine = ViewPlugin.fromClass(\n class {\n decorations: DecorationSet;\n constructor(view: EditorView) {\n this.decorations = build(view.state);\n }\n update(u: ViewUpdate) {\n if (u.docChanged || u.selectionSet) this.decorations = build(u.state);\n }\n },\n { decorations: (v) => v.decorations },\n);\n\nconst build = (state: EditorState): DecorationSet =>\n Decoration.set(caretLines(state).map((from) => caretLine.range(from)));\n\nconst highlightCaretLineGutter = gutterLineClass.compute([\"selection\", \"doc\"], (state) =>\n RangeSet.of(caretLines(state).map((from) => caretLineGutter.range(from))),\n);\n\nconst baseTheme = EditorView.theme({\n // `flex: 1`, not `height: 100%`: the chrome surface sizes with `min-height`/`max-height`, and\n // a percentage height does not resolve against a `min-height`'d parent — so the editor stayed\n // at content height and the field's extra `min-height` showed as dead space below the last\n // line. As a flex child of the flex-column surface it fills the field; `min-height: 0` lets it\n // shrink so `.cm-scroller` scrolls once content passes `max-height`.\n \"&\": { fontSize: \"var(--kanzo-font-size-base, 14px)\", backgroundColor: \"transparent\", flex: \"1 1 auto\", minHeight: 0 },\n // NO PADDING AT ALL any more, and that is the fix for a gap somebody could see: the vertical\n // padding used to live here, and `.cm-line` sits INSIDE it — so the active-line highlight on the\n // first line started half a rem below the top of the field and read as a bar floating in a\n // margin. It moved to `.cm-scroller`, which contains the gutter as well as the content, so both\n // shift together and the numbers stay on their lines.\n //\n // NO BACKGROUND either, and no horizontal padding. Both were here and both were wrong:\n //\n // · An opaque background on `.cm-content` HIDES THE SELECTION. `drawSelection` paints into\n // `.cm-selectionLayer`, a sibling at `z-index: -2`, and CSS paints negative-z-index\n // descendants *below* the backgrounds of in-flow block-level siblings — so the paper\n // covered the layer completely. There is no fallback either: `drawSelection` forces the\n // native `::selection` to transparent, so a selection rendered as nothing at all and the\n // selected glyphs went invisible. Verified in the browser, and it is why no CodeMirror\n // theme upstream puts a background here. The paper is on `.cm-scroller` now.\n // · Horizontal padding here inset the ACTIVE LINE highlight by 12px at each edge, because\n // the highlight is `.cm-line`'s own background and `.cm-line` sits inside the padding\n // box. The row read as a floating bar rather than a highlighted line. The inset moved to\n // `.cm-line`, so the highlight spans the field and the text keeps the same rhythm.\n \".cm-content\": {\n // Explicitly zero, and as the SHORTHAND: CodeMirror's base theme ships `padding: 4px 0` here,\n // and a longhand `padding-block: 0` beside a shorthand loses — measured in the browser, the\n // content kept its 4px and the gutter numbers drifted 4px off their lines. That 4px was the\n // last of the gap above the first line's highlight.\n padding: 0,\n color: \"var(--foreground)\",\n caretColor: \"var(--foreground)\",\n },\n // The field rhythm — 0.75rem is Textarea's `px-3`, so code sits on the same inset as an\n // input's text (rem-based, so it tracks the density preference). On the LINE, so every\n // full-width line decoration (active line, and any caller's `Decoration.line`) reaches the\n // edges instead of stopping short of them.\n //\n // The inset is a HANGING one: a wrapped line resumes past the first row's start, so a Turtle URI\n // that does not fit reads as a continuation rather than as a new statement. `basics` turns\n // `EditorView.lineWrapping` on, so in a narrow pane most lines are wrapped ones — which is where\n // the editor is used: a dock beside a canvas, an aside beside a table.\n \".cm-line\": {\n paddingBlock: 0,\n paddingInlineStart: \"2rem\",\n paddingInlineEnd: \"0.75rem\",\n textIndent: \"-1.25rem\",\n },\n // The font belongs on `.cm-scroller`, not `.cm-content`: the GUTTER is a child of the\n // scroller, and CodeMirror's base sets `.cm-scroller { font-family: monospace }`. With the\n // family only on the content, line numbers rendered in the browser's generic monospace —\n // Courier on many systems — beside content in the Kanzo stack. It also made the gutter's\n // `min-width: 2.25ch` compute against the wrong font.\n \".cm-scroller\": {\n // NO VERTICAL INSET, on either surface. It was `0.5rem` here, on the argument that a code field\n // wants the same breathing room `Textarea` has — and what it actually produced was nine pixels\n // between the field's border and the first line, and a first line that does not start where\n // every other box on the screen starts. A pane docked under its own header showed it worst.\n // A caller who wants an inset has `className` and the surface it owns.\n fontFamily: \"var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace)\",\n lineHeight: \"1.5\",\n overflow: \"auto\",\n // Fill the editor so clicking the empty area below the last line still lands the caret,\n // rather than leaving dead surface — see the `&` note.\n flexGrow: 1,\n minHeight: 0,\n // The paper. It lives here and NOT on `.cm-content` — see the note there: an opaque\n // background on the content box hides the selection layer beneath it. The scroller fills\n // the whole field (flexGrow above), so the paper reaches the bottom on a short document.\n background: \"var(--background)\",\n },\n \"&.cm-focused\": { outline: \"none\" },\n // The gutter column carries its own tint. It used to be painted by the scroller instead, on\n // the grounds that a fill here \"only spans the content rows and stops mid-field on a short\n // document\" — measured against the current CodeMirror, that is no longer true: this element\n // is sized to the full scroller height, so the column reaches the bottom. Reclaiming it\n // freed the scroller to hold the paper, which is what un-hides the selection layer.\n // No divider; the tint step from `--muted` to the scroller's `--background` is the separation.\n \".cm-gutters\": {\n // NO vertical padding: the scroller's is the only one, and the gutter is inside it, so every\n // number already sits at its line's y. Repeating it here dropped each number one step too\n // low — verified back when the padding was on `.cm-content`: a constant 9px below its line.\n background: \"var(--muted)\",\n border: \"none\",\n color: \"var(--faint)\",\n },\n // Line numbers: tabular figures (no jitter across 9→10→100), right-aligned with breathing\n // room from the border edge, and a comfortable minimum width.\n \".cm-lineNumbers .cm-gutterElement\": {\n fontVariantNumeric: \"tabular-nums\",\n fontFeatureSettings: '\"tnum\"',\n minWidth: \"2.25ch\",\n padding: \"0 0.5rem 0 0.75rem\",\n textAlign: \"right\",\n cursor: \"pointer\",\n transition: \"color 120ms, background-color 120ms\",\n },\n // A line number is a click target (it selects the line), so it has to answer the\n // pointer — without this the whole column reads as inert decoration.\n // Quieter than the active line on purpose: this is a hover affordance, and at equal\n // strength the two read as the same state and the column flickers as the pointer moves.\n \".cm-lineNumbers .cm-gutterElement:hover\": {\n backgroundColor: \"color-mix(in srgb, var(--editor-active-line, var(--muted)) 60%, transparent)\",\n color: \"var(--foreground)\",\n },\n \".cm-foldGutter .cm-gutterElement:hover\": { color: \"var(--foreground)\" },\n \".cm-placeholder\": { color: \"var(--muted-foreground)\" },\n // `highlightSpecialChars` ships its own `&light`/`&dark` rule at a raw `red` / `#f78`. Whichever\n // half the appearance selects is a raw hue nobody chose. Tokenised here, at equal specificity and\n // later in the sheet, so ours wins in both.\n \".cm-specialChar\": { color: \"var(--destructive-foreground)\" },\n\n // ── Floating surfaces ─────────────────────────────────────────────────────────\n // CodeMirror ships its own light-mode chrome for tooltips, autocomplete and the\n // search panel. Left alone they arrive as white boxes with system-blue selection —\n // the moment an editor is more than a text box, that is where the theme visibly\n // breaks. These read from the same tokens as `popover` / `menu`.\n \".cm-tooltip\": {\n background: \"var(--popover)\",\n color: \"var(--popover-foreground)\",\n border: \"1px solid var(--border)\",\n borderRadius: \"var(--radius-md)\",\n boxShadow: \"0 4px 12px rgb(0 0 0 / 0.08)\",\n overflow: \"hidden\",\n },\n // The divider between an autocomplete tooltip's sections. CodeMirror's `&light` default is\n // `1px solid #bbb`, and it is the half with no `&dark` counterpart — so before the facet followed\n // the appearance it drew a pale hairline inside a dark popover, and it is *still* the rule that\n // covers a light page. Found by `codemirror-dark-parity.test.ts`, not by looking.\n \".cm-tooltip-section:not(:first-child)\": { borderTop: \"1px solid var(--border)\" },\n \".cm-tooltip .cm-tooltip-arrow:before\": { borderTopColor: \"var(--border)\" },\n \".cm-tooltip .cm-tooltip-arrow:after\": { borderTopColor: \"var(--popover)\" },\n \".cm-tooltip-autocomplete > ul\": {\n fontFamily: \"var(--font-mono, ui-monospace, monospace)\",\n maxHeight: \"16rem\",\n },\n \".cm-tooltip-autocomplete > ul > li\": {\n padding: \"0.125rem 0.5rem\",\n lineHeight: \"1.6\",\n },\n \".cm-tooltip-autocomplete > ul > li[aria-selected]\": {\n background: \"var(--accent)\",\n color: \"var(--accent-foreground)\",\n },\n \".cm-completionLabel\": { color: \"inherit\" },\n \".cm-completionMatchedText\": {\n color: \"var(--primary)\",\n fontWeight: \"600\",\n textDecoration: \"none\",\n },\n \".cm-completionDetail\": {\n color: \"var(--muted-foreground)\",\n fontStyle: \"normal\",\n marginInlineStart: \"0.5rem\",\n },\n \".cm-completionIcon\": { opacity: 0.64, paddingInlineEnd: \"0.5rem\" },\n\n \".cm-panels\": {\n background: \"var(--card)\",\n color: \"var(--card-foreground)\",\n borderColor: \"var(--border)\",\n },\n \".cm-panels.cm-panels-top\": { borderBottom: \"1px solid var(--border)\" },\n \".cm-panels.cm-panels-bottom\": { borderTop: \"1px solid var(--border)\" },\n\n // **`.cm-textfield` and `.cm-button` are no longer OUR controls, and that is the whole point of\n // `code-editor-search.tsx`.** The find/replace panel is `InputGroup`, `Toggle`, `Button` and\n // `ButtonGroup` now, rendered through a portal, so it wears the library's typography, focus ring\n // and hover states rather than a run of rules restating them in CSS. Six selectors went with it:\n // `.cm-panel.cm-search`, its `input, button, label { font-size: inherit }`, the two\n // `.cm-textfield` rules and the two for `button[name=close]`.\n //\n // These two stay, unscoped, for the controls that are still CodeMirror's: `gotoLine`'s dialog\n // (Mod-Alt-G), and any panel a caller's own extensions bring — `@codemirror/lint`'s is the\n // obvious one, and it is a caller's dependency rather than ours.\n //\n // **They also have to stay because they are the only thing standing between a page and a box\n // nobody themed.** `&light .cm-textfield { background: white; border: 1px solid silver }` and\n // `&light .cm-button { background: linear-gradient(#eff1f5, #d9d9df) }` are one half of it and\n // `&dark`'s `#333` and `linear-gradient(#393939, #111)` are the other; the `darkTheme` facet picks\n // which, and neither is a token. `codemirror-dark-parity.test.ts` checks BOTH halves and fails the\n // day either selector leaves this file. The previous\n // spelling was `.cm-panel.cm-search .cm-textfield`, which covered the search field and left\n // `gotoLine`'s identical field wearing the white default; before that it was `input[type=text]`,\n // which matched nothing at all, because CodeMirror sets no `type` on it.\n \".cm-textfield\": {\n background: \"var(--background)\",\n color: \"var(--foreground)\",\n border: \"1px solid var(--input)\",\n borderRadius: \"var(--radius-sm)\",\n padding: \"0.125rem 0.375rem\",\n outline: \"none\",\n },\n \".cm-textfield:focus\": {\n borderColor: \"var(--ring)\",\n boxShadow: \"0 0 0 3px color-mix(in srgb, var(--ring) 32%, transparent)\",\n },\n \".cm-button\": {\n background: \"var(--secondary)\",\n color: \"var(--secondary-foreground)\",\n border: \"1px solid transparent\",\n borderRadius: \"var(--radius-sm)\",\n backgroundImage: \"none\",\n padding: \"0.125rem 0.5rem\",\n cursor: \"pointer\",\n },\n \".cm-button:hover\": { background: \"var(--accent)\" },\n \".cm-button:active\": { backgroundImage: \"none\" },\n \".cm-dialog\": { padding: \"0.375rem 0.5rem\", fontSize: \"var(--kanzo-font-size-small, 12px)\" },\n \".cm-dialog label\": { display: \"inline-flex\", alignItems: \"center\", gap: \"0.375rem\" },\n \".cm-dialog-close\": { color: \"var(--muted-foreground)\", cursor: \"pointer\" },\n \".cm-dialog-close:hover\": { color: \"var(--foreground)\" },\n\n // Search hits: the current one is the primary-tinted anchor, the rest are quieter so\n // \"where am I\" stays readable at a glance.\n \".cm-searchMatch\": {\n backgroundColor: \"var(--warning-a5)\",\n outline: \"1px solid var(--border)\",\n borderRadius: \"2px\",\n },\n \".cm-searchMatch.cm-searchMatch-selected\": {\n backgroundColor: \"var(--warning-a8)\",\n outline: \"1px solid var(--warning)\",\n },\n\n // Lint diagnostics — semantic tokens, so severity survives a re-theme.\n \".cm-diagnostic\": {\n padding: \"0.25rem 0.5rem\",\n borderInlineStartWidth: \"3px\",\n borderInlineStartStyle: \"solid\",\n fontFamily: \"var(--font-sans)\",\n },\n \".cm-diagnostic-error\": { borderInlineStartColor: \"var(--destructive)\" },\n \".cm-diagnostic-warning\": { borderInlineStartColor: \"var(--warning)\" },\n \".cm-diagnostic-info\": { borderInlineStartColor: \"var(--info)\" },\n \".cm-lintPoint-error:after\": { borderBottomColor: \"var(--destructive)\" },\n \".cm-lintPoint-warning:after\": { borderBottomColor: \"var(--warning)\" },\n\n // Scrollbars: the default OS chrome is the loudest thing in a dark editor.\n \".cm-scroller::-webkit-scrollbar\": { width: \"10px\", height: \"10px\" },\n \".cm-scroller::-webkit-scrollbar-track\": { background: \"transparent\" },\n \".cm-scroller::-webkit-scrollbar-thumb\": {\n background: \"color-mix(in srgb, var(--muted-foreground) 32%, transparent)\",\n borderRadius: \"6px\",\n border: \"2px solid transparent\",\n backgroundClip: \"content-box\",\n },\n \".cm-scroller::-webkit-scrollbar-thumb:hover\": {\n background: \"color-mix(in srgb, var(--muted-foreground) 56%, transparent)\",\n backgroundClip: \"content-box\",\n },\n \".cm-scroller::-webkit-scrollbar-corner\": { background: \"transparent\" },\n // Tokenised selection (drawSelection), active line, matching bracket, search matches.\n \".cm-cursor, .cm-dropCursor\": { borderLeftColor: \"var(--foreground)\" },\n // The full child chain is LOAD-BEARING. CodeMirror's base theme ships\n // `&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground`\n // (@codemirror/view), which compiles to specificity 0,5,0. A flat\n // `&.cm-focused .cm-selectionBackground` is 0,3,0 and LOSES — so the focused selection\n // rendered in CodeMirror's stock lavender (#d7d4f0) instead of a Kanzo token. Worse, that\n // base rule is `&light`, and for as long as the `darkTheme` facet was pinned false the light\n // lavender applied in dark mode too. It is driven from the appearance now, which moves the\n // default to `&dark`'s — a different stock colour, still not ours, still covered by this rule.\n \"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground\": {\n backgroundColor: \"var(--brand-a5)\",\n },\n // **A selection must not repaint the text, and ours repainted all of it.** `tokens.css` sets a\n // document-wide `::selection { bg-primary/80 text-primary-foreground }`, which is right\n // everywhere prose is selected and wrong inside an editor: `drawSelection` suppresses the native\n // selection's *background* and not its `color`, so the fill came from `.cm-selectionBackground`\n // — `--brand-a5`, black at 12% — while every glyph inside it took `--primary-foreground`.\n //\n // Measured on `/docs/forms/code-editor`: #fafafa text on a #dcdcdc block. Keys, strings and\n // numbers all flattened to one near-white, so selecting seven lines of JSON erased the\n // highlighting from them. It happens under every palette, because a `-foreground` role is a\n // contrast colour for a fill that is not being painted here.\n //\n // `currentColor` is the fix, and it has to be `currentColor` and not a token: a fixed colour\n // flattens the tokens just as thoroughly, one shade later.\n \".cm-selectionBackground, .cm-content ::selection\": {\n backgroundColor: \"var(--brand-a5)\",\n color: \"currentColor\",\n },\n \".cm-activeLine\": { backgroundColor: \"var(--editor-active-line, var(--muted))\" },\n // The active line's gutter cell is emphasised beyond the row: stronger tint, full-strength\n // ink and a weight bump so the current line number stands out from the dim column.\n \".cm-activeLineGutter\": {\n backgroundColor: \"var(--editor-active-line, var(--muted))\",\n color: \"var(--foreground)\",\n fontWeight: \"600\",\n },\n \".cm-matchingBracket, &.cm-focused .cm-matchingBracket\": { backgroundColor: \"var(--brand-a5)\", outline: \"1px solid var(--primary)\" },\n \".cm-nonmatchingBracket\": { backgroundColor: \"var(--destructive-a4)\" },\n // **A neutral tint, because it is not a search hit.** This wore `--warning-a5`, byte for byte\n // what `.cm-searchMatch` wears — so the other occurrences of the word under your caret were\n // indistinguishable from the hits of a query you actually typed, and the two co-occur constantly:\n // open the find panel while a word is selected and every match looks like the same kind of thing.\n //\n // They are not. A search hit is something you asked for; this is the editor noticing a\n // repetition. Every editor that draws both separates them the same way — the query keeps the\n // colour, the passive one goes neutral — and `--base-a5` is the house's neutral wash. It also\n // takes the collision off `--warning-a5`, which `Highlight` uses for a search-term mark in prose.\n \".cm-selectionMatch\": { backgroundColor: \"var(--base-a5)\" },\n \".cm-foldGutter .cm-gutterElement\": { cursor: \"pointer\", color: \"var(--faint)\" },\n \".cm-foldPlaceholder\": { background: \"var(--muted)\", border: \"1px solid var(--border)\", color: \"var(--muted-foreground)\", borderRadius: \"var(--radius-sm)\", padding: \"0 4px\" },\n});\n\n/**\n * **The base theme's other half, switched on by the side the page is wearing.**\n *\n * `EditorView.theme(spec, { dark })` bakes the answer into the theme, and ours cannot: it is ONE\n * theme for both appearances, because the tokens flip underneath it. So the facet is set beside the\n * theme instead of by it, from `resolvedAppearance`, and `codemirror-dark-parity.test.ts` widened to\n * both halves the day this landed — until now only `&light` could ever apply, and now either can.\n *\n * `false` is spelled as *nothing*, not as `of(false)`: the facet combines with\n * `values.indexOf(true) > -1`, so a `false` from us would not switch off a `true` a caller's own\n * theme contributed, and pretending otherwise would be the more confusing lie.\n */\nconst darkFacet = (dark: boolean): Extension => (dark ? EditorView.darkTheme.of(true) : []);\n\nexport interface CodeEditorProps {\n value: string;\n onChange?: (value: string) => void;\n /** The language brain — CodeMirror extensions injected by the consumer (LSP,\n * StreamParser, autocomplete, linting…). Reconfigured live when it changes. */\n extensions?: Extension;\n readOnly?: boolean;\n lineNumbers?: boolean;\n invalid?: boolean;\n placeholder?: string;\n minHeight?: string;\n maxHeight?: string;\n /** Include the built-in batteries (history + default keymap + line wrapping +\n * the Kanzo token theme). Default true. Set false when the caller's `extensions`\n * own all behaviour and theming. */\n basics?: boolean;\n /**\n * Wrap long lines, or scroll sideways. Default true, which is what `basics` always did.\n *\n * Wrapping is right where the editor is a reading surface in a narrow pane; it is wrong where\n * the document has structure a reader tracks by column — a Turtle predicate list read against\n * its indentation stops being a list once every third line reflows. There is no third option:\n * `EditorView.lineWrapping` is on or it is not.\n *\n * Read once, when the view is built — like `basics`, and for the same reason. Changing it after\n * mount does nothing.\n */\n wrap?: boolean;\n /**\n * Wrap the editor in the styled focus-ring chrome (Box + inset ring + surface background).\n * Default true. Set false for a bare surface.\n */\n chrome?: boolean;\n /** Class applied to the editor host (only meaningful when `chrome={false}`). */\n className?: string;\n /** Receives the `EditorView` on mount and `null` on unmount — for side-wiring\n * (e.g. pushing LSP notifications). */\n onView?: (view: EditorView | null) => void;\n}\n\nexport function CodeEditor(p: CodeEditorProps) {\n const container = useRef<HTMLDivElement>(null);\n const view = useRef<EditorView>(undefined);\n const [focused, setFocused] = useState(false);\n\n const props = useRef(p);\n props.current = p;\n\n const langSlot = useRef(new Compartment());\n const editable = useRef(new Compartment());\n const appearance = useRef(new Compartment());\n\n // Optional, like every other reader of the cascade in this package: without a provider the facet\n // stays false, which is where it sat before this existed, and the guard proves the `&light`\n // defaults that then apply are all overridden anyway.\n const dark = useKanzoThemeOptional()?.resolvedAppearance === \"dark\";\n const darkNow = useRef(dark);\n darkNow.current = dark;\n\n // **CodeMirror's panels, rendered by React.** A `Panel` is an object with a `dom`, and nothing\n // says who fills it — so we hand over an empty element and portal into it. The portals are\n // children of THIS tree, which is the reason the host lives here and not in the panel's own\n // module: a panel rendered from anywhere else loses every provider above the editor.\n //\n // `mount`/`destroy` are CodeMirror's, and they bracket the element's life in the document\n // exactly. `mount` runs before React has rendered anything into it, which is why a panel that\n // wants focus takes it in its own effect rather than relying on CodeMirror's.\n const [panels, setPanels] = useState<{ id: number; dom: HTMLElement; node: ReactNode }[]>([]);\n\n // Build the editor once; long-lived callbacks read the latest props via the ref.\n useEffect(() => {\n const basics = props.current.basics ?? true;\n let nextPanel = 0;\n const panelHost: ReactPanelHost = {\n panel: (node, opts) => {\n const dom = document.createElement(\"div\");\n const id = ++nextPanel;\n return {\n dom,\n top: opts?.top,\n mount: () => setPanels((open) => [...open, { id, dom, node }]),\n destroy: () => setPanels((open) => open.filter((entry) => entry.id !== id)),\n };\n },\n };\n const updateListener = EditorView.updateListener.of((u) => {\n if (u.focusChanged) setFocused(u.view.hasFocus);\n if (!u.docChanged) return;\n if (u.transactions.some((t) => t.annotation(External))) return; // our own reconcile\n props.current.onChange?.(u.state.doc.toString());\n });\n const wrap = props.current.wrap ?? true;\n const batteries: Extension[] = basics\n ? [\n history(),\n keymap.of([\n ...defaultKeymap,\n ...historyKeymap,\n ...searchKeymap,\n ...closeBracketsKeymap,\n ...completionKeymap,\n ...foldKeymap,\n ]),\n ...(wrap ? [EditorView.lineWrapping] : []),\n drawSelection(),\n dropCursor(),\n // `completionKeymap` was already bound below, but the extension itself was never\n // installed — so Ctrl-Space did nothing and the ~25 lines of\n // `.cm-tooltip-autocomplete` styling in this theme were dead CSS.\n autocompletion(),\n // Makes NBSP, zero-width and control characters visible. Without it they are\n // invisible in the document, which is a real footgun when editing data.\n highlightSpecialChars(),\n // Alt-drag column selection, and the crosshair cursor that signals it is available.\n rectangularSelection(),\n crosshairCursor(),\n highlightCaretLine,\n bracketMatching(),\n closeBrackets(),\n indentOnInput(),\n highlightSelectionMatches(),\n // **`search()` has to be in the configuration, and it was not.** `searchKeymap` was\n // bound below and nothing installed the extension, so `openSearchPanel` appended the\n // defaults itself the first time Mod-F was pressed — which works, and silently discards\n // any configuration, `createPanel` included. Same shape as the `autocompletion()` bug\n // noted further down: a keymap for an extension nobody added.\n kanzoSearch(panelHost),\n kanzoHighlighting,\n baseTheme,\n ]\n : [];\n const v = new EditorView({\n parent: container.current!,\n state: EditorState.create({\n doc: props.current.value ?? \"\",\n extensions: [\n // Multiple cursors. Off by default in CodeMirror, and table stakes in an editor.\n EditorState.allowMultipleSelections.of(true),\n ...batteries,\n ...(props.current.lineNumbers ? [cmLineNumbers()] : []),\n ...(basics && props.current.lineNumbers ? [highlightCaretLineGutter, foldGutter()] : []),\n ...(props.current.placeholder ? [cmPlaceholder(props.current.placeholder)] : []),\n updateListener,\n appearance.current.of(darkFacet(darkNow.current)),\n langSlot.current.of(props.current.extensions ?? []),\n editable.current.of([\n EditorView.editable.of(!props.current.readOnly),\n EditorState.readOnly.of(!!props.current.readOnly),\n ]),\n ],\n }),\n });\n view.current = v;\n props.current.onView?.(v);\n return () => {\n props.current.onView?.(null);\n v.destroy();\n };\n }, []);\n\n // Reconcile external value changes — but never clobber active typing.\n useEffect(() => {\n const v = view.current;\n if (!v || v.hasFocus) return;\n if (p.value !== v.state.doc.toString()) {\n v.dispatch({\n changes: { from: 0, to: v.state.doc.length, insert: p.value },\n annotations: External.of(true),\n });\n }\n }, [p.value]);\n\n // Swap the language extensions live (compartment reconfigure, no re-create).\n useEffect(() => {\n view.current?.dispatch({ effects: langSlot.current.reconfigure(p.extensions ?? []) });\n }, [p.extensions]);\n\n // Follow the page's side. Nothing of ours is keyed off the facet — our rules are unprefixed and\n // the tokens do the flipping — so what this moves is CodeMirror's own base theme and any theme a\n // caller's extensions bring.\n useEffect(() => {\n view.current?.dispatch({ effects: appearance.current.reconfigure(darkFacet(dark)) });\n }, [dark]);\n\n // Toggle editability when `readOnly` changes.\n useEffect(() => {\n view.current?.dispatch({\n effects: editable.current.reconfigure([\n EditorView.editable.of(!p.readOnly),\n EditorState.readOnly.of(!!p.readOnly),\n ]),\n });\n }, [p.readOnly]);\n\n // A portal contributes no DOM to the element it is written inside, so these are safe as children\n // of the very element CodeMirror owns: React mounts each node into the panel's `dom` and nothing\n // else. Written once and used by both branches below.\n const portals = panels.map((entry) => createPortal(entry.node, entry.dom, String(entry.id)));\n\n // Bare surface (caller owns theme/chrome).\n //\n // `flex flex-col` is LOAD-BEARING, not styling. The theme sizes the editor with\n // `\"&\": { flex: \"1 1 auto\", minHeight: 0 }`, which resolves only inside a flex container — and\n // this host was a plain block, so `.cm-editor` fell back to content height. A caller asking for\n // a full-height pane (`chrome={false} className=\"flex-1\"`) got a host that filled its parent\n // and an editor that did not fill the host: measured 467px of scroller inside an 883px pane,\n // with the rest dead. The chromed branch below never had the bug because its wrapper is\n // already a flex column.\n if (p.chrome === false) {\n return (\n <div\n className={cn(\"flex flex-col\", p.className)}\n data-slot=\"code-editor\"\n ref={container}\n style={{ minHeight: p.minHeight, maxHeight: p.maxHeight }}\n >\n {portals}\n </div>\n );\n }\n\n // A field, not an IDE pane: the surface wears the exact chrome as Textarea/Input — a\n // hairline `--input` border, `rounded-lg`, the transparent/`--field`-tinted surface, a\n // faint shadow, and the same focus/invalid treatment (border shifts colour + a 3px ring).\n // The ring is a `box-shadow` (Tailwind `ring`), drawn OUTSIDE the border box, so it is not\n // clipped by `overflow-hidden` and the gutter's own background cannot paint over it — the\n // failure the old inset approach worked around. Focus is driven off `data-focused`\n // (CodeMirror's contenteditable holds focus, not this wrapper, so `:focus-visible` can't).\n return (\n <div data-slot=\"code-editor\" style={{ flex: 1, width: \"100%\" }}>\n <div\n data-slot=\"code-editor-surface\"\n data-focused={focused || undefined}\n data-invalid={p.invalid || undefined}\n ref={container}\n className={cn(\n \"flex w-full flex-col overflow-hidden\",\n \"rounded-lg border border-input bg-transparent shadow-xs/5 bg-field\",\n \"transition-[color,box-shadow]\",\n \"data-focused:border-primary data-focused:ring-[3px] data-focused:ring-ring\",\n \"data-invalid:border-destructive data-invalid:ring-[3px] data-invalid:ring-destructive/24\",\n \"motion-reduce:transition-none!\"\n )}\n style={{ minHeight: p.minHeight, maxHeight: p.maxHeight }}\n >\n {portals}\n </div>\n </div>\n );\n}"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAsDA;AAmByD;AACuD;AACtC;AACW;AAAA;AAAA;AAGrC;AACQ;AAC6C;AAAA;AAAA;AAAA;AAIlD;AACoC;AAAA;AAET;AACgE;AAClC;AAC5B;AACC;AACN;AAAA;AAEX;AAChC;AACD;AACW;AACH;AACd;AAAA;AAEG;AACD;AACA;AAE3B;AAmBwD;AAA3B;AAClB;AAAe;AAC1B;AAIE;AACA;AACA;AACA;AACE;AACA;AAES;AAGX;AACF;AAEsC;AAC9B;AACJ;AAEE;AAAmC;AACrC;AAEE;AAAoE;AACtE;AAAA;AAGJ;AAKiD;AAA2B;AAE5E;AAEmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAMkF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBpG;AAAA;AAAA;AAAA;AAAA;AAKJ;AACF;AACK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWF;AACI;AACM;AACF;AACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOE;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF;AACA;AACF;AAAA;AAAA;AAGA;AACC;AAAA;AAAA;AAAA;AAIC;AAAA;AAEa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOZ;AAAA;AAAA;AAAA;AAID;AACJ;AACD;AAAA;AAAA;AAAA;AAI4B;AACf;AACC;AACX;AACD;AACE;AACH;AACI;AAAA;AAAA;AAAA;AAAA;AAAA;AAM6B;AACxB;AACV;AAAA;AAE0C;AACvB;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOb;AACD;AACL;AACC;AACM;AACH;AACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAM0C;AACI;AACD;AACxB;AACnB;AACD;AAAA;AAEyB;AAC3B;AACG;AAAA;AAEuC;AACvC;AACL;AAAA;AAEuB;AACH;AACpB;AACK;AACI;AAAA;AAEM;AACf;AACI;AACQ;AAAA;AAEoC;AAE3C;AACA;AACL;AACM;AAAA;AAE6B;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsB3B;AACH;AACL;AACC;AACM;AACL;AACA;AAAA;AAEY;AACR;AACF;AAAA;AAEC;AACA;AACL;AACC;AACM;AACG;AACR;AACD;AAAA;AAEwB;AACM;AACc;AACmB;AACT;AAC7B;AAAA;AAAA;AAIhB;AACA;AACR;AACK;AAAA;AAE2B;AACxB;AACR;AAAA;AAAA;AAIO;AACP;AACe;AACA;AACZ;AAAA;AAEoC;AACE;AACH;AACC;AACE;AAAA;AAGQ;AACL;AACd;AAC3B;AACE;AACN;AACQ;AAAA;AAE6B;AACjC;AACI;AAAA;AAEsC;AAAA;AAEP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS2B;AACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeiC;AACjC;AACV;AAAA;AAE4B;AAAA;AAAA;AAGb;AACL;AACV;AACK;AAAA;AAE0F;AAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUJ;AACuB;AAElE;AAwDO;;AACL;AAKA;AAEA;AASA;AAUA;AAGA;;AACE;AACA;AACA;AAAkC;AAE9B;AAEA;AAAO;AACL;AACW;AACkD;AACa;AAAA;AAE9E;;AAIA;;AAME;AACE;AACU;AACL;AACA;AACA;AACA;AACA;AACA;AACJ;AACsC;AACvC;AACA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMqB;AACrB;AACA;AAGmB;AACL;AACQ;AACI;AAChB;AAAA;AAEiC;AACxC;AACiD;AACiC;AACR;AAC7E;AACgD;AACE;AAC9B;AAC4B;AACE;AACjD;AAAA;AAEJ;AAEH;;AAGE;AACE;AACJ;AAKA;AACA;AAEa;AAC6C;AACzB;AAC9B;;AAMH;AAAiF;;AAOjF;AAAgF;;AAKhF;AAAuB;AACiB;AACF;AACE;AACrC;AAAA;AAOL;AAWA;AAEI;AAAC;AAAA;AAC2C;AAChC;AACL;AACyC;AAE7C;AAAA;AAcH;AAAC;AAAA;AACW;AACe;AACE;AACtB;AACM;AACT;AACA;AACA;AACA;AACA;AACA;AAAA;AAE4C;AAE7C;AAAA;AAIT;;;;;;"}
|