@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 @@
|
|
|
1
|
+
{"version":3,"file":"KanzoThemeProvider.js","sources":["../../src/theme/KanzoThemeProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport type {\n Appearance,\n AppearancePref,\n CorePrefKey,\n ThemeOption,\n PrefSources,\n ResolvedPref,\n SectionManifest,\n SectionPolicy,\n SectionPrefDecl,\n SectionPrefPolicy,\n} from \"@kanzo-tech/theme\";\nimport {\n AXES,\n CORE_NAMESPACE,\n CORE_PREFS,\n DEFAULT_PREFS,\n prefOptions,\n resolvePref,\n STORAGE_KEY,\n themeData,\n type ThemePrefs,\n} from \"@kanzo-tech/theme\";\nimport { ThemeContext, type FontOption, type ThemeContextValue } from \"./theme-context.js\";\n\nexport {\n useKanzoTheme,\n useKanzoThemeOptional,\n type FontOption,\n type ThemeContextValue,\n} from \"./theme-context.js\";\n\nexport type { ThemePrefs } from \"@kanzo-tech/theme\";\n\n/**\n * KanzoThemeProvider — owns the runtime theme PREFERENCES and applies them as `data-*`\n * attributes on `<html>`. It exposes the state via {@link useKanzoTheme} so a `Preferences`\n * selector drives the whole app live.\n *\n * It is framework-agnostic and works in two modes:\n * · **Controlled** — pass `value` + `onChange` (e.g. keasy bridges its server-persisted prefs).\n * · **Uncontrolled** — internal state persisted via a pluggable `storage` (default localStorage).\n *\n * **Colour is not a free preference.** A tenant's identity is a palette DOCUMENT, compiled to one\n * stylesheet the server inlines. Nothing here writes a colour VALUE: the six preferences are the\n * four non-colour axes, `appearance` (which of the document's two blocks applies) and `identity`\n * (which of the blocks the TENANT published applies). A user who has never been given a second\n * identity has the same five preferences they had before, and the same `<html>`.\n *\n * `.dark` therefore follows the PREFERENCE directly. It used to be derived from the applied\n * palette, so a partnerless palette could overrule the user; a document carries both modes, so\n * there is nothing left to contradict them. A host theme manager may supply the preference (see\n * {@link AppearanceController}) — if it also writes the class (next-themes with\n * `attribute: \"class\"`) it must be disabled, or the two fight over the same class.\n *\n * Attributes are written to `document.documentElement` (NOT a wrapper `<div>`): Ark overlays\n * (Dialog, Popover, Menu, Select, Tooltip…) portal to `document.body`, OUTSIDE any wrapper, so\n * the tokens must live on `<html>` for portaled surfaces to inherit them.\n */\n\n\n/**\n * A host theme manager (next-themes) as the source of the appearance PREFERENCE.\n *\n * A host that also writes `.dark` must be turned off (`RootProvider theme={{ enabled: false }}`\n * in fumadocs, `enableColorScheme: false` + no `attribute: \"class\"` elsewhere), or two owners\n * write the same class. What the controller provides is the preference and the OS resolution,\n * which is all this provider reads from it. Shape matches next-themes.\n */\nexport interface AppearanceController {\n /**\n * The host's preference, in the HOST's vocabulary; next-themes exposes this as `theme`.\n *\n * `string`, not `Appearance`, because this is where a foreign model enters. next-themes' third\n * value is the string `\"system\"`, ours is `\"\"`, and the translation happens once, below — no\n * other line in this package knows that `\"system\"` is a word.\n */\n theme?: string;\n /** The applied value (`light` | `dark`), already resolved against the OS by the host. */\n resolvedTheme?: string;\n setTheme: (theme: string) => void;\n}\n\n/** Pluggable persistence for the uncontrolled mode. */\nexport interface ThemeStorage {\n get: () => Partial<ThemePrefs> | null;\n /** What the user chose — sparse. A key is absent because nobody has written it. */\n set: (prefs: Partial<ThemePrefs>) => void;\n}\n\nconst localStorageAdapter = (key: string): ThemeStorage => ({\n get: () => {\n if (typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(key);\n return raw ? (JSON.parse(raw) as Partial<ThemePrefs>) : null;\n } catch {\n return null;\n }\n },\n set: (prefs) => {\n try {\n localStorage.setItem(key, JSON.stringify(prefs));\n } catch {\n /* storage unavailable — non-fatal */\n }\n },\n});\n\n/**\n * Cookie-backed persistence — use this in SSR apps so the SAME source the {@link themeScript}\n * reads before hydration is also written by the client, and the server can read it from the\n * request `Cookie` header to render the correct theme. Pair with `themeScript({ storageKey })`.\n */\nexport const cookieStorageAdapter = (\n key: string = STORAGE_KEY,\n { maxAgeDays = 365, path = \"/\", sameSite = \"Lax\" as const } = {},\n): ThemeStorage => ({\n get: () => {\n if (typeof document === \"undefined\") return null;\n try {\n const m = document.cookie.match(new RegExp(\"(?:^|; )\" + key + \"=([^;]*)\"));\n return m?.[1] ? (JSON.parse(decodeURIComponent(m[1])) as Partial<ThemePrefs>) : null;\n } catch {\n return null;\n }\n },\n set: (prefs) => {\n if (typeof document === \"undefined\") return;\n try {\n const value = encodeURIComponent(JSON.stringify(prefs));\n document.cookie = `${key}=${value}; Max-Age=${maxAgeDays * 864e2}; Path=${path}; SameSite=${sameSite}`;\n } catch {\n /* non-fatal */\n }\n },\n});\n\n/**\n * Only the keys that are still preferences.\n *\n * A stored blob is merged into state and written back whole, so a key that has been retired would\n * be re-persisted forever in every browser that ever saved one — `palette`, `accent`, `base`,\n * `baseTint`, `primary`, `scheme`, `schemeColors` all shipped. Whitelisting on READ is what ends\n * that: the next write drops them, and no colour can re-enter the model through storage.\n */\nconst PREF_KEYS = Object.keys(DEFAULT_PREFS) as (keyof ThemePrefs)[];\nfunction known(stored: Partial<ThemePrefs>): Partial<ThemePrefs> {\n const out: Partial<ThemePrefs> = {};\n for (const key of PREF_KEYS) if (stored[key] !== undefined) out[key] = stored[key] as never;\n return out;\n}\n\n/**\n * The shipped font options, off the declaration — names and order — and the generated stacks.\n *\n * They were typed here, and the copy had already drifted: the fallback this file wrote inside\n * `var(--font-geist-sans, …)` was a three-family shorthand where `themes.css` emits the full\n * system stack, so a host without the webfont got a different face from the panel's specimen than\n * from the page. Two spellings of one list, and the wrong one was the one a user looked at.\n */\nconst stacked = (key: \"font\" | \"monoFont\", stacks: Record<string, string>): FontOption[] =>\n (prefOptions(CORE_PREFS[key]) ?? []).map((option) => ({\n ...option,\n preview: stacks[option.value],\n }));\nconst DEFAULT_FONTS = stacked(\"font\", themeData.fonts);\nconst DEFAULT_MONO_FONTS = stacked(\"monoFont\", themeData.monoFonts);\n\n/**\n * A host that never wires `identities` gets this one, not a fresh `[]` per render — the context is\n * memoised on it, and a new array every render re-renders every consumer of the theme.\n */\nconst NO_THEMES: ThemeOption[] = [];\n// Same reason as the two above: a fresh literal per render is a new dependency every render, and\n// these feed a memo the whole context hangs off.\nconst NO_SECTIONS: SectionManifest[] = [];\nconst NO_POLICY: Record<string, SectionPolicy> = {};\nconst NO_SECTION_POLICY: SectionPolicy = {};\n/** A host in controlled mode who passes no `value` yet: one object, not a literal per render. */\nconst NO_STORED: Partial<ThemePrefs> = {};\n\n/**\n * \"The tenant no longer publishes what this user chose\" — for both axes that a tenant publishes.\n *\n * Written once for `identity` and generalised the moment `palette` arrived, because the two are the\n * same problem at different grain: somebody chose gold and is about to be looking at blue, and\n * silence makes that read as a bug in our product rather than a change in their client's. It clears\n * the preference, holds the retired id for the session — the place that says so may not be mounted\n * for another five minutes — and calls back exactly once.\n *\n * Three details are load-bearing and each has a test. It runs in an **effect**, never in the state\n * initialiser, which also runs on a server where no callback can fire and a cleared pref would be\n * discarded at hydration. It is guarded on `options.length > 0`, because \"the host has not wired the\n * prop\", \"is still fetching the document\" and \"published nothing\" are indistinguishable from here and\n * all three mean a valid preference must survive. And \"once\" is a `useRef` rather than the absence of\n * a condition: clearing the pref does erase the condition, but not before StrictMode's second\n * invocation has read the pre-clear state — and in controlled mode the clear is a *request*, so a\n * host that ignores `onChange` would otherwise be told on every render.\n */\nfunction useRetirement(\n value: string,\n options: readonly { value: string }[],\n /**\n * Put the preference back to \"defer to the document\".\n *\n * A callback rather than a key, because the two axes no longer clear the same way: `identity` is a\n * flat field and a palette is one side of a map. Passing the key meant this hook building a patch,\n * which is knowledge of the shape it has no reason to hold.\n */\n clear: () => void,\n onRetired?: (id: string) => void,\n): string | null {\n const [retired, setRetired] = React.useState<string | null>(null);\n const handled = React.useRef(false);\n\n React.useEffect(() => {\n if (handled.current || !value || options.length === 0) return;\n if (options.some((option) => option.value === value)) return;\n handled.current = true;\n setRetired(value);\n clear();\n onRetired?.(value);\n }, [clear, value, options, onRetired]);\n\n return retired;\n}\n\n\nexport interface KanzoThemeProviderProps {\n children: React.ReactNode;\n /** Override the built-in defaults (unpinned / md / system / system / default / the document's). */\n defaults?: Partial<ThemePrefs>;\n /** Controlled mode: supply value + onChange (host owns persistence). */\n value?: Partial<ThemePrefs>;\n onChange?: (next: Partial<ThemePrefs>) => void;\n /** Uncontrolled persistence. `undefined` = localStorage; `null` = no persistence. */\n storage?: ThemeStorage | null;\n storageKey?: string;\n /** Host-configurable option lists surfaced by the Preferences panel. */\n fonts?: FontOption[];\n monoFonts?: FontOption[];\n /**\n * The themes the TENANT published. Usually `themeIndex` from `@kanzo-tech/theme`, or a tenant's\n * own list mapped on the server.\n *\n * **Wiring this applies it.** A theme is a flat block of CSS that travels in the page under its\n * own `[data-theme]`, so this provider writes the attribute like any other axis. A host still has\n * to *load* the themes — import the sheets, or inline them — but it never chooses one per request,\n * and a user switching theme never needs a round trip.\n *\n * **It is one prop where there were two.** `palettes` carried documents and each document carried\n * its brands as `children`, so a host published a tree and the panel flattened it. A brand is a\n * theme, so the tree is a list.\n */\n themes?: ThemeOption[];\n /**\n * The name applied when the preference is empty. Defaults to the first published one.\n *\n * **A pair, when the two sides differ.** A theme carries its own light or dark palette, so one\n * name cannot answer for both sides: naming a night theme here paints it in daylight too, with\n * `.dark` off. Pass `{ light, dark }` to say which theme each side defers to — the same shape the\n * preference already stores, and the same reason it is a map there.\n */\n defaultTheme?: string | Partial<Record<Appearance, string>>;\n /** Called once, at most, when the stored theme is no longer published — somebody chose gold and is\n * about to be looking at blue, and silence makes that read as a bug in our product rather than a\n * change in their client's. The provider renders no notice itself; say it where the app says\n * things. */\n onThemeRetired?: (theme: string) => void;\n /**\n * The section manifests of the packages this host installed.\n *\n * **The host registers, and that is what keeps the one-way door shut.** Nothing in\n * `@kanzo-tech/theme` or in this file names an optional package, so the arrow points host → core:\n * a host that never installed the graph literally cannot pass its manifest, and\n * `packages/theme/src/boundary.test.ts` keeps passing because there is nothing to import.\n * Registration by import into the core would be the same mechanism with the dependency inverted.\n */\n sections?: SectionManifest[];\n /**\n * What the TENANT says about every choice — pinned, withheld, or merely started elsewhere.\n *\n * Keyed by namespace, and **the core is the namespace `theme`** ({@link CORE_NAMESPACE}):\n *\n * ```ts\n * policy={{ theme: { density: { default: \"compact\" }, radius: { pinned: \"sm\" } },\n * graph: { look: { hidden: true } } }}\n * ```\n *\n * This is the white-label half, and it used to reach only half the product: a tenant could pin the\n * graph's look and could not pin the radius, because the newer mechanism had a resolution chain\n * and the older one had a whitelist read. Now a client ships *our product is compact and square*\n * as the starting point their users move from — which is daisyUI's theme-carries-the-geometry,\n * expressed as a policy over declarations rather than as a second document format.\n *\n * It selects among the options a declaration published; it cannot author one. That line is the\n * same one the colour layer holds, and it is why this is not the retired runtime palette coming\n * back under a new name.\n */\n policy?: Record<string, SectionPolicy>;\n /** Delegate dark to a host theme manager (e.g. next-themes). Omit to use the built-in fallback. */\n appearance?: AppearanceController;\n}\n\nexport function KanzoThemeProvider({\n children,\n defaults,\n value,\n onChange,\n storage,\n storageKey = STORAGE_KEY,\n fonts = DEFAULT_FONTS,\n monoFonts = DEFAULT_MONO_FONTS,\n themes = NO_THEMES,\n // The first published one. `themeIndex` carries no `isDefault`\n // flag, but it belongs to the host's mapper: a `ThemeOption` is what a CONTROL needs, and a\n // control has no use for which one the server would have served anyway.\n defaultTheme = themes[0]?.value ?? \"\",\n onThemeRetired,\n sections = NO_SECTIONS,\n policy = NO_POLICY,\n appearance,\n}: KanzoThemeProviderProps) {\n const controlled = value !== undefined;\n const storageAdapter = React.useMemo(\n () => (storage === undefined ? localStorageAdapter(storageKey) : storage),\n [storage, storageKey],\n );\n\n /**\n * **What the user chose, and only that.** Sparse: a key is present because somebody wrote it.\n *\n * It used to be the merged blob — every axis filled in with its default and persisted that way —\n * and that is what made a tenant's starting point unreachable for the core: `stored.density` was\n * `\"default\"` for a user who had never touched density, so the chain's second link answered and\n * the third never ran. A client saying *our product is compact* would have been silently outvoted\n * by every browser that had ever opened the app.\n *\n * A sparse blob is also a smaller cookie, and it is what `themeScript` reads: an absent key there\n * takes exactly the same branch, so both sides fall through to the same policy.\n */\n const [internal, setInternal] = React.useState<Partial<ThemePrefs>>(() => {\n if (controlled) return { ...value };\n const raw = storageAdapter?.get() ?? null;\n return raw ? known(raw) : {};\n });\n\n const storedPrefs = controlled ? value ?? NO_STORED : internal;\n\n // Everything a reader needs with the gaps filled — the shape `ThemePrefs` promises, for the two\n // keys the chain does not answer for (`identityByPalette`, `sections`) and as the base the context\n // is built on. Memoised because it feeds both `set` and that context: an unstable `prefs`\n // re-renders every consumer on every render of the provider.\n const prefs: ThemePrefs = React.useMemo(\n () => ({ ...DEFAULT_PREFS, ...defaults, ...storedPrefs }),\n [defaults, storedPrefs],\n );\n\n /**\n * The latest written preferences, so that **two patches in one tick compose** instead of one\n * silently winning.\n *\n * `set` merges its patch onto what it read at render, and every setter below is one `set`. Two of\n * them in one handler therefore both merged onto the *same* snapshot, and the second overwrote\n * the first's key — with no error, no warning, and a control that looks like it half worked.\n *\n * It is not hypothetical and it was found in a browser, not in a test. A theme menu is one act\n * where the panel is two: `setTheme(name, { appearance })` files a theme under a side and\n * `setAppearance(side)` wears that side, so a menu calls both — and what landed was the side\n * alone, so the page switched to dark wearing whatever theme the dark side already held. The\n * panel never hit it because its two acts are two clicks.\n *\n * A ref rather than a functional `setInternal` updater, because the write has to reach three\n * places that a React updater may not: `onChange` in controlled mode, the storage adapter, and\n * the next call in the same tick. An updater runs during render — twice under StrictMode — and\n * putting a cookie write inside one is the impurity this avoids.\n */\n const latestPrefs = React.useRef(storedPrefs);\n latestPrefs.current = storedPrefs;\n\n const set = React.useCallback(\n (patch: Partial<ThemePrefs>) => {\n const next = { ...latestPrefs.current, ...patch };\n latestPrefs.current = next;\n if (controlled) {\n onChange?.(next);\n } else {\n setInternal(next);\n storageAdapter?.set(next);\n }\n },\n [controlled, onChange, storageAdapter],\n );\n\n /**\n * Unset every preference — the panel's Reset.\n *\n * It used to be `set(DEFAULT_PREFS)`, which was right while storage was the merged blob and is\n * wrong now: writing each axis's default explicitly would make \"reset\" the one act that PINS a\n * user against their tenant's document. Unset means unset, and where it lands is wherever the\n * chain says — the client's starting point when they published one, ours when they did not.\n */\n const reset = React.useCallback(() => {\n // The ref goes with it. It is the second writer of this state, so a `set` in the same tick as a\n // Reset would otherwise merge its patch onto the values Reset just cleared and put them back.\n latestPrefs.current = {};\n if (controlled) onChange?.({});\n else {\n setInternal({});\n storageAdapter?.set({});\n }\n }, [controlled, onChange, storageAdapter]);\n\n // What the tenant says about the CORE's own axes. One namespace of the same policy an optional\n // package's section is subject to, which is the whole of \"the core is a section like any other\".\n //\n // A host's `defaults` prop is the SAME LINK one rank lower — \"start here\" — so it is folded in\n // rather than given a mechanism of its own: the app's baseline, which the client's document may\n // move and the user overrides either way. Folding it in is also what keeps Reset honest, since\n // unsetting now lands on whichever of the two answered.\n const corePolicy = React.useMemo(() => {\n const tenant = policy[CORE_NAMESPACE] ?? NO_SECTION_POLICY;\n if (!defaults) return tenant;\n const out: Record<string, SectionPrefPolicy> = { ...tenant };\n for (const key of Object.keys(CORE_PREFS)) {\n const seed = defaults[key as CorePrefKey];\n // Only a string is a starting point. `paletteByAppearance` is a map, and a host seeding one\n // side of it is seeding a value this link has no way to name — it stays what it always was,\n // a member of the merged `prefs`.\n if (typeof seed !== \"string\" || out[key]?.default !== undefined) continue;\n out[key] = { ...out[key], default: seed };\n }\n return out;\n }, [defaults, policy]);\n\n // ── Appearance ──────────────────────────────────────────────────────────────────────────\n // A preference — a pinned side, or `\"\"` for \"ask the OS\" — and the side that resolves to.\n // Nothing else participates: the palette document publishes both modes, so no identity can\n // overrule the side the user asked for.\n\n const [systemDark, setSystemDark] = React.useState(\n () => typeof window !== \"undefined\" && !!window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches,\n );\n\n // The declared chain, over BOTH sources, which is what makes them one model. A pinned side is the\n // string `light` or `dark`; everything else resolves to the unset option: next-themes' `\"system\"`\n // (a foreign vocabulary), a corrupt value from a stored blob, a typo. There is no hand-written\n // whitelist here any more — `appearance` declares its three options, and `resolvePref` gates\n // against them. `themeScript` runs the identical chain, which is what keeps the two sides from\n // disagreeing on a blob a browser can hold but we would never write.\n //\n // A host that reports only `resolvedTheme` has no unpinned state to report, so it reads as pinned,\n // which is right: it is telling us a side and nothing else.\n //\n // It resolves before everything below it because it has to: the side is what a keyed axis is\n // indexed by, and `.dark` is what a document's second block keys off.\n const appearanceResolved = React.useMemo(\n () =>\n resolvePref(\n CORE_PREFS.appearance,\n appearance ? appearance.theme ?? appearance.resolvedTheme : storedPrefs.appearance,\n corePolicy.appearance,\n ),\n [appearance, corePolicy, storedPrefs.appearance],\n );\n const appearancePref = appearanceResolved.value as AppearancePref;\n\n // Track the OS scheme with a live listener while nothing is pinned. Not needed when a host is\n // wired: its `resolvedTheme` already is the resolution, and it re-renders us on change.\n React.useEffect(() => {\n if (appearance || appearancePref || typeof window === \"undefined\" || !window.matchMedia) return;\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const onChange = () => setSystemDark(mq.matches);\n onChange();\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n }, [appearance, appearancePref]);\n\n const resolvedAppearance: Appearance =\n appearancePref ||\n (appearance?.resolvedTheme === \"dark\" || (!appearance?.resolvedTheme && systemDark)\n ? \"dark\"\n : \"light\");\n\n // ── One resolution ──────────────────────────────────────────────────────────────────────\n //\n // Every core axis through the chain that `@kanzo-tech/theme` owns and a contributed section\n // already used: pinned, stored, the tenant's starting point, the declaration's default. What this\n // ends is that **a tenant could pin the graph's look and could not pin the radius** — the newer\n // mechanism had a resolution chain with a policy, and the older one read a stored blob.\n //\n // A keyed axis is indexed here, by the side that resolved above, so the chain always sees a value\n // and the write loop below never has to know that one axis stores a map.\n //\n // No `sources` are passed: see the identity block below for why the two axes a tenant publishes\n // are deliberately not gated against what they published.\n // The tenant's default for ONE side. A string answers for both; a map answers per side and falls\n // back to nothing, which is inert — an unknown `data-theme` matches no rule.\n const defaultThemeFor = React.useCallback(\n (side: Appearance) => (typeof defaultTheme === \"string\" ? defaultTheme : (defaultTheme[side] ?? \"\")),\n [defaultTheme],\n );\n type Entry = ResolvedPref & { decl: SectionPrefDecl };\n const corePrefs = React.useMemo(() => {\n const out: Record<string, Entry> = { appearance: { ...appearanceResolved, decl: CORE_PREFS.appearance } };\n for (const { key } of AXES) {\n const decl = CORE_PREFS[key as CorePrefKey];\n const raw = storedPrefs[key];\n const stored = decl.byAppearance\n ? (raw as Record<string, string> | undefined)?.[resolvedAppearance]\n : (raw as string | undefined);\n out[key] = { ...resolvePref(decl, stored, corePolicy[key]), decl };\n }\n return out;\n // Field by field, not `prefs`: in controlled mode `prefs` is a fresh literal on every render, so\n // depending on the object would re-resolve — and therefore re-apply every attribute — every\n // time. `KanzoThemeProvider.test.tsx` asserts that every axis in `AXES` is named here: one that\n // is applied but never watched resolves at mount and then silently stops following the\n // preference, which looks exactly like a control that does nothing. `data-palette` shipped that\n // way for one commit.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n appearanceResolved,\n corePolicy,\n resolvedAppearance,\n storedPrefs.radius,\n storedPrefs.font,\n storedPrefs.monoFont,\n storedPrefs.density,\n storedPrefs.themeByAppearance,\n ]);\n\n // ── Theme ───────────────────────────────────────────────────────────────────────────────\n // Which of the themes the tenant published is applied. An axis like any other: `AXES` carries\n // `data-theme` and the effect below writes it.\n //\n // **This block used to be two, and the second one was where the bugs lived.** A palette contained\n // identities, so choosing a palette had to file the brand you were leaving, restore the brand you\n // were entering, key both by the RESOLVED id because the default had two spellings, and not\n // overwrite a brand named in the same call. Every clause of that was a real defect once. None of\n // it exists now: a brand is a theme, so there is no containment to remember and nothing to carry\n // across. The memory it needed (`identityByPalette`) went with it.\n const resolvedTheme = corePrefs.themeByAppearance?.value || defaultThemeFor(resolvedAppearance);\n\n /**\n * Choose a theme for one side.\n *\n * The side defaults to the one being worn, which is what a control inside the page means. A\n * two-grid panel names the other one explicitly: choosing a night theme in daylight has to reach\n * the dark key without repainting what the reader is looking at.\n *\n * The keying lives here and not in every panel, the same way `setAppearance` owns translating a\n * host's `\"system\"`. Spelled at each call site it would be a spread of a map the caller has to\n * remember is keyed at all.\n */\n const setTheme = React.useCallback(\n (theme: string, options: { appearance?: Appearance } = {}) => {\n const side = options.appearance ?? resolvedAppearance;\n set({ themeByAppearance: { ...prefs.themeByAppearance, [side]: theme } });\n },\n [prefs.themeByAppearance, resolvedAppearance, set],\n );\n\n // **Not resolved against what the tenant published**, though the declaration names that source and\n // `resolvePref` would take it. Two reasons, and both are about keeping one behaviour rather than\n // adding a second: an attribute selector with no matching rule is INERT, so an unknown name falls\n // through to whatever `:root` paints, and the inline SSR script cannot know what the tenant\n // published, so gating here and not there is exactly how the two sides start disagreeing about\n // `<html>`. Retirement is already a mechanism, with a notice and a cleared preference; a silent\n // gate would be half of it, done twice.\n\n // The one list only a tenant can write, in the shape a declaration names it by — so a control for\n // `{ from: \"themes\" }` is filled from what this host actually published, and a package that\n // declares such a choice needs no prop of its own to receive it.\n const sources: PrefSources = React.useMemo(\n () => ({ themes: themes.map(({ label, value }) => ({ label, value })) }),\n [themes],\n );\n\n const retiredTheme = useRetirement(\n resolvedTheme,\n themes,\n React.useCallback(() => setTheme(\"\"), [setTheme]),\n onThemeRetired,\n );\n\n // To the DOM: the axes become `data-*` attributes on <html> (set when non-default, removed\n // otherwise), and `.dark` follows the resolved appearance.\n // `documentElement.style.colorScheme` is never written: an inline declaration outranks every\n // rule permanently, and each block of the compiled document carries its own `color-scheme`.\n React.useEffect(() => {\n const el = document.documentElement;\n for (const { attr, def, key } of AXES) {\n // What the chain answered, never the stored value — which is what makes a tenant's policy\n // reach the DOM. Removed at the default, so a host that changed nothing has the `<html>` it\n // had before any of this existed; the corrupt-blob case is refused upstream, in `resolvePref`.\n const v = corePrefs[key]?.value;\n if (v === undefined || v === def) el.removeAttribute(attr);\n else el.setAttribute(attr, v);\n }\n el.classList.toggle(\"dark\", resolvedAppearance === \"dark\");\n }, [corePrefs, resolvedAppearance]);\n\n // Clean the managed attributes off <html> only when the provider unmounts.\n // `.dark` is deliberately left alone: a host may own the class after we go, and removing it\n // repaints the page light for however long the next owner takes to put it back.\n React.useEffect(\n () => () => {\n const el = document.documentElement;\n for (const { attr } of AXES) el.removeAttribute(attr);\n },\n [],\n );\n\n // It takes the unset value because the preference has one, and the reverse translation lives here:\n // `\"\"` reaches a host as `\"system\"`, the only word next-themes has for it. A setter that could not\n // express its own type would leave a host reaching for `set({ appearance: \"\" })` and bypassing the\n // host controller entirely.\n const setAppearance = React.useCallback(\n (next: AppearancePref) => {\n if (appearance) appearance.setTheme(next || \"system\");\n else set({ appearance: next });\n },\n [appearance, set],\n );\n\n // ── Contributed preferences ─────────────────────────────────────────────────────────────\n //\n // One chain per declared preference, run in `@kanzo-tech/theme` rather than here: the order —\n // pinned, stored, the tenant's starting point, the manifest's default — is the section\n // mechanism's, and a second implementation of it in the provider is how the two halves of a\n // section would begin to disagree.\n //\n // These DO get the sources, where the core's two do not: a section's attribute is written by this\n // provider alone — the pre-hydration script knows only the axis table — so there is no second\n // writer to keep in step, and a stored value naming a brand the tenant withdrew can be declined\n // where it is read.\n const sectionPrefs = React.useMemo(() => {\n const out: Record<string, Record<string, Entry>> = {};\n for (const manifest of sections) {\n const stored = prefs.sections[manifest.namespace] ?? {};\n const section = policy[manifest.namespace] ?? NO_SECTION_POLICY;\n const resolved: Record<string, Entry> = {};\n for (const [key, decl] of Object.entries(manifest.prefs ?? {})) {\n resolved[key] = { ...resolvePref(decl, stored[key], section[key], sources), decl };\n }\n // A manifest that declares only tokens contributes no group. Skipping it here rather than in\n // the panel is what stops an empty legend appearing for a section that has nothing to ask.\n if (Object.keys(resolved).length > 0) out[manifest.namespace] = resolved;\n }\n return out;\n }, [prefs.sections, policy, sections, sources]);\n\n const setSectionPref = React.useCallback(\n (namespace: string, values: Readonly<Record<string, string | undefined>>) => {\n // **A record and not a key/value pair**, because one choice is sometimes several preferences.\n // A host offering named arrangements — *Nebula*, *Atlas* — writes four axes at once, and four\n // sequential calls in one handler each read the same pre-render `prefs.sections`, so three of\n // them are lost and the picture is wrong in a way that looks like a rendering bug.\n //\n // `undefined` REMOVES a key, which is how a section-scoped reset is expressed: storage holds\n // what a user chose, so unsetting lands wherever the chain says — the tenant's starting point\n // when they published one. `JSON.stringify` drops the key on the way to storage, and\n // `resolvePref` reads an absent key as \"nobody has chosen\".\n const section = { ...(prefs.sections[namespace] ?? {}) };\n for (const [key, value] of Object.entries(values)) {\n if (value === undefined) delete section[key];\n else section[key] = value;\n }\n // The whole map is rewritten, every other namespace spread through untouched. That is the\n // property the token half already has and the reason this lives under one key: a namespace\n // belonging to a package this host does not have installed rides through every write without\n // the core ever parsing it.\n set({ sections: { ...prefs.sections, [namespace]: section } });\n },\n [prefs.sections, set],\n );\n\n // To the DOM, for the few that ask. A declaration without `attr` writes nothing and costs nothing\n // — which is most of them, and is what keeps this from growing into a second axis table.\n React.useEffect(() => {\n const el = document.documentElement;\n const written: string[] = [];\n for (const manifest of sections) {\n for (const [key, decl] of Object.entries(manifest.prefs ?? {})) {\n if (!decl.attr) continue;\n written.push(decl.attr);\n const resolved = sectionPrefs[manifest.namespace]?.[key];\n // Removed at the default, set otherwise — the same rule the axes follow, so a host that\n // has changed nothing has the `<html>` it had before any of this existed.\n if (!resolved || resolved.value === decl.default) el.removeAttribute(decl.attr);\n else el.setAttribute(decl.attr, resolved.value);\n }\n }\n // Unregistering a section has to take its attribute with it. Without this, dropping an optional\n // peer leaves a `data-*` on `<html>` that nothing writes and nothing removes, and whatever CSS\n // it selected keeps applying.\n return () => {\n for (const attr of written) el.removeAttribute(attr);\n };\n }, [sectionPrefs, sections]);\n\n const ctx = React.useMemo<ThemeContextValue>(\n () => ({\n ...prefs,\n // The resolved values overwrite the stored ones, and that is the point of this phase: what a\n // control shows and what the page is painted with are the same number. A tenant pinning\n // `density` means every reader sees `\"compact\"`, while storage keeps whatever this user chose\n // and hands it back the day the tenant stops pinning it.\n ...Object.fromEntries(Object.entries(corePrefs).map(([key, { value }]) => [key, value])),\n // …except the one that is a map. `themeByAppearance` stores a side→theme map and the chain\n // answers for ONE side, so writing the resolved string over it would change the field's shape\n // under every reader. `resolvedTheme` is where the answer belongs, and it is below.\n themeByAppearance: prefs.themeByAppearance,\n corePrefs,\n sources,\n set,\n reset,\n fonts,\n monoFonts,\n sectionPrefs,\n setSectionPref,\n appearance: appearancePref,\n resolvedAppearance,\n setAppearance,\n themes,\n // The applied side's default. The pair is behind `defaultThemeFor`, because a panel drawing\n // the OTHER side needs that side's answer and a single string cannot give it.\n defaultTheme: defaultThemeFor(resolvedAppearance),\n defaultThemeFor,\n resolvedTheme,\n setTheme,\n retiredTheme,\n }),\n [\n prefs, set, fonts, monoFonts, appearancePref, resolvedAppearance, setAppearance,\n themes, defaultThemeFor, resolvedTheme, setTheme, retiredTheme,\n sectionPrefs, setSectionPref, corePrefs, sources, reset,\n ],\n );\n\n return <ThemeContext.Provider value={ctx}>{children}</ThemeContext.Provider>;\n}\n"],"names":["onChange"],"mappings":";;;;;;AA6FA;AAA4D;AAExD;AACA;AACE;AACA;AAAwD;AAExD;AAAO;AACT;AACF;AAEE;AACE;AAA+C;AACzC;AAER;AAEJ;AAUoB;AAEhB;AACA;AACE;AACA;AAAgF;AAEhF;AAAO;AACT;AACF;AAEE;AACA;AACE;AACA;AAAoG;AAC9F;AAER;AAEJ;AAWA;AACE;AACA;AACA;AACF;AAUA;AACwD;AACjD;AAEL;AAmCF;AAaE;AAGA;AACE;AAKY;AAIhB;AA+EO;AAA4B;AACjC;AACA;AACA;AACA;AACA;AACa;AACL;AACI;AACH;AAAA;AAAA;AAAA;AAI0B;AACnC;AACW;AACF;AAEX;;AACE;AAC6B;AACsC;AAC7C;AAgBpB;AACA;AACA;AAA0B;AASI;AACa;AACrB;AAuBxB;AAEA;AAAkB;AAEd;AACA;AAKsB;AAExB;AACqC;AAcrC;;;AAgBA;AACA;AACA;AACA;AACE;AAIA;AACmC;AAErC;AAAO;AAQiC;;AAClC;AAAuF;AAAA;AAe9D;AAE7B;AACa;AAC6D;AAC7D;AAAA;AAEgC;AAMjD;AACE;AACA;AAEAA;AAEsD;AAGxD;AAoB8B;AACoE;AACnF;AAIb;AACA;AACE;AAKA;AAA4D;AAE9D;AAAO;AAQN;AACD;AACA;AACA;AACY;AACA;AACA;AACA;AACA;AA0BS;AAEnB;AACA;AAAwE;AAC1E;AACiD;AAchB;AACmC;AAC7D;AAGY;AACnB;AACA;AACgD;AAChD;AAOF;;AACE;AACA;AAIE;AACA;AAC4B;AAE9B;AAAyD;AAMrD;AAEF;AACA;AAAoD;AACtD;AACA;AAOF;AAA4B;AAExB;AAC6B;AAC/B;AACgB;AAehB;AACA;AACE;AAGA;AACE;AAIF;AAAgE;AAElE;AAAO;AAGoB;AAWzB;AACA;AACE;AAOF;AAA6D;AAC/D;AACoB;AAKtB;;AACE;AAEA;AACE;AACE;AACA;AACA;AAGA;AAC8C;AAMlD;AACE;AAAmD;AACrD;AAGF;AAAkB;AACT;AACF;AAAA;AAAA;AAAA;AAAA;AAKoF;AAAA;AAAA;AAAA;AAI9D;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY;AACZ;AACA;AACA;AAAA;AAAA;AAGgD;AAChD;AACA;AACA;AACA;AAAA;AAEF;AACE;AAAO;AAAK;AAAO;AAAW;AAAgB;AAAoB;AAClE;AAAQ;AAAiB;AAAe;AAAU;AAClD;AAAc;AAAgB;AAAW;AAAS;AAAA;AAItD;AACF;;;;;;;"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Appearance, AppearancePref, ThemeOption, PrefSources, ResolvedPref, SectionPrefDecl, ThemePrefs } from '@kanzo-tech/theme';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* The theme context and its two readers, apart from the provider that fills it.
|
|
5
|
+
*
|
|
6
|
+
* Split out for a measured reason. `useThemeTick` in the charts subpath needs to know when the
|
|
7
|
+
* theme moved, and importing that from `KanzoThemeProvider.js` pulled the provider, its two
|
|
8
|
+
* storage adapters and the retirement hook into the analytics bundle — **66.59 kB against a 60 kB
|
|
9
|
+
* budget**, caught by `size-limit` rather than by anyone reading the diff. A context is a few bytes;
|
|
10
|
+
* the thing that fills it is not, and a consumer that only reads should pay for only the reading.
|
|
11
|
+
*
|
|
12
|
+
* `KanzoThemeProvider` re-exports everything here, so no import site outside this directory changes.
|
|
13
|
+
*/
|
|
14
|
+
export interface FontOption {
|
|
15
|
+
value: string;
|
|
16
|
+
label: string;
|
|
17
|
+
/** CSS font-family used to render the option's own label as a live preview. */
|
|
18
|
+
preview?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The provider spreads {@link ThemePrefs} into the context, and every axis it names is the value the
|
|
22
|
+
* chain ANSWERED — not the raw stored one.
|
|
23
|
+
*
|
|
24
|
+
* The distinction is the tenant's policy: a client who pinned *compact* has `density === "compact"`
|
|
25
|
+
* here whatever this user once chose, because that is what the page is painted with and a control
|
|
26
|
+
* reading anything else would draw a selection the page contradicts. What the user stored is still
|
|
27
|
+
* in storage, untouched, and comes back if the tenant stops pinning it.
|
|
28
|
+
*
|
|
29
|
+
* `corePrefs` is where the rest of the chain's answer lives — `via`, and `offered`, which is what a
|
|
30
|
+
* surface reads before drawing a control at all.
|
|
31
|
+
*/
|
|
32
|
+
export interface ThemeContextValue extends ThemePrefs {
|
|
33
|
+
set: (patch: Partial<ThemePrefs>) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Unset every preference — what the panel's Reset does.
|
|
36
|
+
*
|
|
37
|
+
* Not `set(DEFAULT_PREFS)`, which is what it used to be: storage holds what a user CHOSE, so
|
|
38
|
+
* writing each axis's default explicitly would make reset the one act that pins somebody against
|
|
39
|
+
* their tenant's document. Where unsetting lands is whatever the chain answers — the client's
|
|
40
|
+
* starting point when they published one, ours when they did not.
|
|
41
|
+
*/
|
|
42
|
+
reset: () => void;
|
|
43
|
+
fonts: FontOption[];
|
|
44
|
+
monoFonts: FontOption[];
|
|
45
|
+
/** The appearance PREFERENCE — a pinned side, or `""` while the OS decides. */
|
|
46
|
+
appearance: AppearancePref;
|
|
47
|
+
/**
|
|
48
|
+
* The APPLIED side. Always one of the two.
|
|
49
|
+
*
|
|
50
|
+
* Read this to draw anything; read `appearance` only to say whether the user pinned it. The pair
|
|
51
|
+
* is the same split as `theme` / `resolvedTheme`: a preference can be the absence of one.
|
|
52
|
+
*/
|
|
53
|
+
resolvedAppearance: Appearance;
|
|
54
|
+
setAppearance: (appearance: AppearancePref) => void;
|
|
55
|
+
/** The themes the tenant published. `[]` — never `undefined` — when the host wired nothing. */
|
|
56
|
+
themes: ThemeOption[];
|
|
57
|
+
/** The name the APPLIED side falls back to when the preference is empty; the panel needs it to
|
|
58
|
+
* show a selection. */
|
|
59
|
+
defaultTheme: string;
|
|
60
|
+
/** The same answer for either side. A tenant may publish a different default per side — a theme
|
|
61
|
+
* carries its own palette, so one name cannot serve both — and a panel that draws the side you
|
|
62
|
+
* are not wearing has to ask for that side. */
|
|
63
|
+
defaultThemeFor: (side: Appearance) => string;
|
|
64
|
+
/**
|
|
65
|
+
* The APPLIED theme — this side's preference, or `defaultTheme`.
|
|
66
|
+
*
|
|
67
|
+
* Mirrors `appearance` / `resolvedAppearance`: the preference is what the user asked for, and an
|
|
68
|
+
* empty one is not a value but a deferral to the tenant.
|
|
69
|
+
*/
|
|
70
|
+
resolvedTheme: string;
|
|
71
|
+
/**
|
|
72
|
+
* Choose a theme for one side — the applied one unless `appearance` names the other.
|
|
73
|
+
*
|
|
74
|
+
* The keying lives here rather than at every call site, the way `setAppearance` owns translating a
|
|
75
|
+
* host's `"system"`. **It no longer carries anything across.** While a palette contained brands
|
|
76
|
+
* this function also filed the outgoing brand and restored the remembered one, so writing
|
|
77
|
+
* `paletteByAppearance` through `set` got the attribute and lost the memory. A brand is a theme;
|
|
78
|
+
* there is nothing to file.
|
|
79
|
+
*/
|
|
80
|
+
setTheme: (theme: string, options?: {
|
|
81
|
+
appearance?: Appearance;
|
|
82
|
+
}) => void;
|
|
83
|
+
/** The theme the tenant retired out from under this user, once, for the rest of the session —
|
|
84
|
+
* read it to say so. It survives the pref being cleared because the place that says it (a panel,
|
|
85
|
+
* a toast) may not be mounted for another five minutes. */
|
|
86
|
+
retiredTheme: string | null;
|
|
87
|
+
/**
|
|
88
|
+
* Every preference the registered sections declare, resolved and paired with its declaration —
|
|
89
|
+
* keyed by namespace, then by preference, both in registration order.
|
|
90
|
+
*
|
|
91
|
+
* **The manifests are not exposed beside this, and the reason is a name collision worth keeping.**
|
|
92
|
+
* This interface extends `ThemePrefs`, whose `sections` is the *stored* map — opaque, keyed by
|
|
93
|
+
* namespace, and holding what the user chose. A second `sections` holding the *declarations* is
|
|
94
|
+
* two different things under one word, which `tsc` refused and was right to. Carrying `decl` here
|
|
95
|
+
* gives a panel the label, the options and the doc without a second field to keep in step.
|
|
96
|
+
*
|
|
97
|
+
* `offered` is what to read before drawing a control: a tenant may pin a choice or withhold it,
|
|
98
|
+
* and both mean *do not offer this*. `via` says which link of the chain answered, which is what a
|
|
99
|
+
* test asserts on.
|
|
100
|
+
*/
|
|
101
|
+
sectionPrefs: Record<string, Record<string, ResolvedPref & {
|
|
102
|
+
decl: SectionPrefDecl;
|
|
103
|
+
}>>;
|
|
104
|
+
/**
|
|
105
|
+
* Write some of one section's preferences. Every other namespace rides through untouched.
|
|
106
|
+
*
|
|
107
|
+
* A record rather than one key, because one choice is sometimes several preferences — a host
|
|
108
|
+
* offering named arrangements writes every axis that names it, and four sequential writes in one
|
|
109
|
+
* handler lose three. `undefined` removes a key, which is how a section resets to whatever the
|
|
110
|
+
* chain answers rather than to a value somebody wrote down.
|
|
111
|
+
*/
|
|
112
|
+
setSectionPref: (namespace: string, values: Readonly<Record<string, string | undefined>>) => void;
|
|
113
|
+
/**
|
|
114
|
+
* The core's own axes, resolved by the SAME chain and in the same shape as {@link sectionPrefs}.
|
|
115
|
+
*
|
|
116
|
+
* This is the phase where the two halves became one mechanism. The core used to read its
|
|
117
|
+
* preferences straight off a stored blob, so a tenant could pin a contributed choice and could not
|
|
118
|
+
* pin the radius — the newer mechanism had a resolution chain with a policy and the older one had
|
|
119
|
+
* a whitelist read. Now a client's document sets the starting point of every axis, colour and
|
|
120
|
+
* geometry alike, and a user preference is an override on top of it.
|
|
121
|
+
*
|
|
122
|
+
* Keyed by preference name, never by namespace: there is exactly one core.
|
|
123
|
+
*/
|
|
124
|
+
corePrefs: Record<string, ResolvedPref & {
|
|
125
|
+
decl: SectionPrefDecl;
|
|
126
|
+
}>;
|
|
127
|
+
/**
|
|
128
|
+
* What this host published, in the shape a declaration names it by — `themes`.
|
|
129
|
+
*
|
|
130
|
+
* A choice may name where its options come from instead of listing them, because a client's
|
|
131
|
+
* brands cannot be typed by whoever wrote the package. This is what fills such a control, and it
|
|
132
|
+
* is built once here rather than in every surface that draws one.
|
|
133
|
+
*/
|
|
134
|
+
sources: PrefSources;
|
|
135
|
+
}
|
|
136
|
+
export declare const ThemeContext: React.Context<ThemeContextValue | null>;
|
|
137
|
+
/**
|
|
138
|
+
* The theme, or `null` outside a provider.
|
|
139
|
+
*
|
|
140
|
+
* For readers that must work either way — `useThemeTick` is one, because a chart resolving tokens
|
|
141
|
+
* off the cascade has always been usable without this provider and must not start throwing now that
|
|
142
|
+
* it also wants to know when the theme moved.
|
|
143
|
+
*/
|
|
144
|
+
export declare function useKanzoThemeOptional(): ThemeContextValue | null;
|
|
145
|
+
export declare function useKanzoTheme(): ThemeContextValue;
|
|
146
|
+
//# sourceMappingURL=theme-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-context.d.ts","sourceRoot":"","sources":["../../src/theme/theme-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,EACf,UAAU,EACX,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC1C;;;;;;;OAOG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,+EAA+E;IAC/E,UAAU,EAAE,cAAc,CAAC;IAC3B;;;;;OAKG;IACH,kBAAkB,EAAE,UAAU,CAAC;IAC/B,aAAa,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,+FAA+F;IAC/F,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB;4BACwB;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB;;oDAEgD;IAChD,eAAe,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC;IAC9C;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IACzE;;gEAE4D;IAC5D,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B;;;;;;;;;;;;;OAaG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG;QAAE,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC,CAAC;IACvF;;;;;;;OAOG;IACH,cAAc,EAAE,CACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,KACjD,IAAI,CAAC;IACV;;;;;;;;;;OAUG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG;QAAE,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC,CAAC;IACpE;;;;;;OAMG;IACH,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,yCAAsD,CAAC;AAGhF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,GAAG,IAAI,CAEhE;AAED,wBAAgB,aAAa,IAAI,iBAAiB,CAIjD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as e from "react";
|
|
3
|
+
const t = e.createContext(null);
|
|
4
|
+
t.displayName = "KanzoThemeContext";
|
|
5
|
+
function o() {
|
|
6
|
+
return e.useContext(t);
|
|
7
|
+
}
|
|
8
|
+
function r() {
|
|
9
|
+
const n = e.useContext(t);
|
|
10
|
+
if (!n) throw new Error("useKanzoTheme must be used within a <KanzoThemeProvider>.");
|
|
11
|
+
return n;
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
t as ThemeContext,
|
|
15
|
+
r as useKanzoTheme,
|
|
16
|
+
o as useKanzoThemeOptional
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=theme-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-context.js","sources":["../../src/theme/theme-context.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport type {\n Appearance,\n AppearancePref,\n ThemeOption,\n PrefSources,\n ResolvedPref,\n SectionPrefDecl,\n ThemePrefs,\n} from \"@kanzo-tech/theme\";\n\n/**\n * The theme context and its two readers, apart from the provider that fills it.\n *\n * Split out for a measured reason. `useThemeTick` in the charts subpath needs to know when the\n * theme moved, and importing that from `KanzoThemeProvider.js` pulled the provider, its two\n * storage adapters and the retirement hook into the analytics bundle — **66.59 kB against a 60 kB\n * budget**, caught by `size-limit` rather than by anyone reading the diff. A context is a few bytes;\n * the thing that fills it is not, and a consumer that only reads should pay for only the reading.\n *\n * `KanzoThemeProvider` re-exports everything here, so no import site outside this directory changes.\n */\n\nexport interface FontOption {\n value: string;\n label: string;\n /** CSS font-family used to render the option's own label as a live preview. */\n preview?: string;\n}\n\n/**\n * The provider spreads {@link ThemePrefs} into the context, and every axis it names is the value the\n * chain ANSWERED — not the raw stored one.\n *\n * The distinction is the tenant's policy: a client who pinned *compact* has `density === \"compact\"`\n * here whatever this user once chose, because that is what the page is painted with and a control\n * reading anything else would draw a selection the page contradicts. What the user stored is still\n * in storage, untouched, and comes back if the tenant stops pinning it.\n *\n * `corePrefs` is where the rest of the chain's answer lives — `via`, and `offered`, which is what a\n * surface reads before drawing a control at all.\n */\nexport interface ThemeContextValue extends ThemePrefs {\n set: (patch: Partial<ThemePrefs>) => void;\n /**\n * Unset every preference — what the panel's Reset does.\n *\n * Not `set(DEFAULT_PREFS)`, which is what it used to be: storage holds what a user CHOSE, so\n * writing each axis's default explicitly would make reset the one act that pins somebody against\n * their tenant's document. Where unsetting lands is whatever the chain answers — the client's\n * starting point when they published one, ours when they did not.\n */\n reset: () => void;\n fonts: FontOption[];\n monoFonts: FontOption[];\n /** The appearance PREFERENCE — a pinned side, or `\"\"` while the OS decides. */\n appearance: AppearancePref;\n /**\n * The APPLIED side. Always one of the two.\n *\n * Read this to draw anything; read `appearance` only to say whether the user pinned it. The pair\n * is the same split as `theme` / `resolvedTheme`: a preference can be the absence of one.\n */\n resolvedAppearance: Appearance;\n setAppearance: (appearance: AppearancePref) => void;\n /** The themes the tenant published. `[]` — never `undefined` — when the host wired nothing. */\n themes: ThemeOption[];\n /** The name the APPLIED side falls back to when the preference is empty; the panel needs it to\n * show a selection. */\n defaultTheme: string;\n /** The same answer for either side. A tenant may publish a different default per side — a theme\n * carries its own palette, so one name cannot serve both — and a panel that draws the side you\n * are not wearing has to ask for that side. */\n defaultThemeFor: (side: Appearance) => string;\n /**\n * The APPLIED theme — this side's preference, or `defaultTheme`.\n *\n * Mirrors `appearance` / `resolvedAppearance`: the preference is what the user asked for, and an\n * empty one is not a value but a deferral to the tenant.\n */\n resolvedTheme: string;\n /**\n * Choose a theme for one side — the applied one unless `appearance` names the other.\n *\n * The keying lives here rather than at every call site, the way `setAppearance` owns translating a\n * host's `\"system\"`. **It no longer carries anything across.** While a palette contained brands\n * this function also filed the outgoing brand and restored the remembered one, so writing\n * `paletteByAppearance` through `set` got the attribute and lost the memory. A brand is a theme;\n * there is nothing to file.\n */\n setTheme: (theme: string, options?: { appearance?: Appearance }) => void;\n /** The theme the tenant retired out from under this user, once, for the rest of the session —\n * read it to say so. It survives the pref being cleared because the place that says it (a panel,\n * a toast) may not be mounted for another five minutes. */\n retiredTheme: string | null;\n\n /**\n * Every preference the registered sections declare, resolved and paired with its declaration —\n * keyed by namespace, then by preference, both in registration order.\n *\n * **The manifests are not exposed beside this, and the reason is a name collision worth keeping.**\n * This interface extends `ThemePrefs`, whose `sections` is the *stored* map — opaque, keyed by\n * namespace, and holding what the user chose. A second `sections` holding the *declarations* is\n * two different things under one word, which `tsc` refused and was right to. Carrying `decl` here\n * gives a panel the label, the options and the doc without a second field to keep in step.\n *\n * `offered` is what to read before drawing a control: a tenant may pin a choice or withhold it,\n * and both mean *do not offer this*. `via` says which link of the chain answered, which is what a\n * test asserts on.\n */\n sectionPrefs: Record<string, Record<string, ResolvedPref & { decl: SectionPrefDecl }>>;\n /**\n * Write some of one section's preferences. Every other namespace rides through untouched.\n *\n * A record rather than one key, because one choice is sometimes several preferences — a host\n * offering named arrangements writes every axis that names it, and four sequential writes in one\n * handler lose three. `undefined` removes a key, which is how a section resets to whatever the\n * chain answers rather than to a value somebody wrote down.\n */\n setSectionPref: (\n namespace: string,\n values: Readonly<Record<string, string | undefined>>,\n ) => void;\n /**\n * The core's own axes, resolved by the SAME chain and in the same shape as {@link sectionPrefs}.\n *\n * This is the phase where the two halves became one mechanism. The core used to read its\n * preferences straight off a stored blob, so a tenant could pin a contributed choice and could not\n * pin the radius — the newer mechanism had a resolution chain with a policy and the older one had\n * a whitelist read. Now a client's document sets the starting point of every axis, colour and\n * geometry alike, and a user preference is an override on top of it.\n *\n * Keyed by preference name, never by namespace: there is exactly one core.\n */\n corePrefs: Record<string, ResolvedPref & { decl: SectionPrefDecl }>;\n /**\n * What this host published, in the shape a declaration names it by — `themes`.\n *\n * A choice may name where its options come from instead of listing them, because a client's\n * brands cannot be typed by whoever wrote the package. This is what fills such a control, and it\n * is built once here rather than in every surface that draws one.\n */\n sources: PrefSources;\n}\n\nexport const ThemeContext = React.createContext<ThemeContextValue | null>(null);\nThemeContext.displayName = \"KanzoThemeContext\";\n\n/**\n * The theme, or `null` outside a provider.\n *\n * For readers that must work either way — `useThemeTick` is one, because a chart resolving tokens\n * off the cascade has always been usable without this provider and must not start throwing now that\n * it also wants to know when the theme moved.\n */\nexport function useKanzoThemeOptional(): ThemeContextValue | null {\n return React.useContext(ThemeContext);\n}\n\nexport function useKanzoTheme(): ThemeContextValue {\n const ctx = React.useContext(ThemeContext);\n if (!ctx) throw new Error(\"useKanzoTheme must be used within a <KanzoThemeProvider>.\");\n return ctx;\n}\n"],"names":["ThemeContext"],"mappings":";;AAmJO;AACPA;AASO;AACL;AACF;AAEO;AACL;AACA;AACA;AACF;;;;;;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SectionPolicy } from '@kanzo-tech/theme';
|
|
2
|
+
export interface ThemeScriptOptions {
|
|
3
|
+
/** Must match the provider's `storageKey` / the cookie adapter's key. */
|
|
4
|
+
storageKey?: string;
|
|
5
|
+
/**
|
|
6
|
+
* The TENANT's policy — the same object the provider takes, keyed by namespace.
|
|
7
|
+
*
|
|
8
|
+
* **Pass it if you pass it to the provider.** A pinned axis this script does not know about is a
|
|
9
|
+
* flash of the user's own value followed by the client's, which is the exact defect the script
|
|
10
|
+
* exists to prevent, arriving through the feature that was supposed to give a client control.
|
|
11
|
+
* Only the core's namespace is read here: a section's attribute is written after hydration.
|
|
12
|
+
*/
|
|
13
|
+
policy?: Record<string, SectionPolicy>;
|
|
14
|
+
}
|
|
15
|
+
/** Returns the IIFE source (a string) to inline before hydration. Safe to embed in HTML. */
|
|
16
|
+
export declare function themeScript({ storageKey, policy, }?: ThemeScriptOptions): string;
|
|
17
|
+
//# sourceMappingURL=theme-script.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-script.d.ts","sourceRoot":"","sources":["../../src/theme/theme-script.ts"],"names":[],"mappings":"AAgCA,OAAO,EAML,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACxC;AAED,4FAA4F;AAC5F,wBAAgB,WAAW,CAAC,EAC1B,UAAwB,EACxB,MAAW,GACZ,GAAE,kBAAuB,GAAG,MAAM,CAgDlC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AXES as f, CORE_NAMESPACE as v, STORAGE_KEY as k, CORE_PREFS as P, prefOptions as l } from "@kanzo-tech/theme";
|
|
2
|
+
function u({
|
|
3
|
+
storageKey: n = k,
|
|
4
|
+
policy: c = {}
|
|
5
|
+
} = {}) {
|
|
6
|
+
const r = (e) => {
|
|
7
|
+
var o;
|
|
8
|
+
const t = P[e];
|
|
9
|
+
return [e, t.attr ?? 0, t.default, t.byAppearance ?? 0, ((o = l(t)) == null ? void 0 : o.map((d) => d.value)) ?? 0];
|
|
10
|
+
}, i = JSON.stringify(f.map((e) => r(e.key))), s = JSON.stringify(r("appearance")), p = JSON.stringify(c[v] ?? {}), a = JSON.stringify(n);
|
|
11
|
+
return "(function(){try{var d=document.documentElement,P={};try{var c=document.cookie.match(new RegExp('(?:^|; )'+" + a + "+'=([^;]*)'));if(c&&c[1])P=JSON.parse(decodeURIComponent(c[1]));}catch(e){}if(!P||!Object.keys(P).length){try{var s=localStorage.getItem(" + a + ");if(s)P=JSON.parse(s);}catch(e){}}var PO=" + p + ";function ok(v,o){return typeof v==='string'&&(!o||o.indexOf(v)>=0);}function pick(p,s,df,o){return ok(p.pinned,o)?p.pinned:((!p.hidden&&ok(s,o))?s:(ok(p['default'],o)?p['default']:df));}var AP=" + s + ",av=pick(PO[AP[0]]||{},P[AP[0]],AP[2],AP[4]);var W=(av==='light'||av==='dark')?av:((window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches)?'dark':'light');var A=" + i + ";for(var i=0;i<A.length;i++){var r=A[i],k=r[0],s=r[3]?((P[k]||{})[W]):P[k],v=pick(PO[k]||{},s,r[2],r[4]);if(v===r[2]){d.removeAttribute(r[1]);}else{d.setAttribute(r[1],v);}}d.classList.toggle('dark',W==='dark');}catch(e){}})();";
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
u as themeScript
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=theme-script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-script.js","sources":["../../src/theme/theme-script.ts"],"sourcesContent":["// SSR anti-FOUC: a tiny inline script that applies the persisted theme to <html> BEFORE the\n// first paint, so the server-rendered markup never flashes the default theme then re-skins on\n// hydration. It reads the SAME source as the provider (cookie first — server-readable — then\n// localStorage), and mirrors the provider's \"remove attribute when default\" rule exactly.\n//\n// Usage:\n// • TanStack Start: <ScriptOnce>{themeScript()}</ScriptOnce> (in the root document)\n// • Next.js / RSC: inject via useServerInsertedHTML, or a <script dangerouslySetInnerHTML>\n// in the root layout <head>. (React 19 warns about <script> in the tree;\n// useServerInsertedHTML / dangerouslySetInnerHTML avoid that.)\n// • Plain HTML: <script>{themeScript()}</script> as the first thing in <head>.\n//\n// Pair with `cookieStorageAdapter(storageKey)` on the provider so client writes land where the\n// script (and the server) read from.\n//\n// It carries no colour VALUE. The tenant is known at request time, so the server inlines the\n// theme catalogue in the stylesheet — there is no colour maths, and no document to choose between\n// is sent, and there is no pairing table, no base tint and no primary override left to resolve\n// here. `data-theme` is the colour one it writes, and it writes it as a string\n// off the axis table like any other: choosing among the blocks that document already contains.\n//\n// MANDATORY under SSR, not an optimisation. Skipping it costs more than a flash: any control\n// whose markup depends on the resolved theme (`PreferencesColor`'s side cards) renders one value on the\n// server and another on hydration, which React reports as a mismatch and does not patch.\n//\n// This script must reach the SAME `class` + `data-*` as the provider from the same inputs —\n// theme-script.test.ts runs both under one set of stubs and diffs `<html>`, because a divergence\n// here IS the FOUC and the hydration mismatch the script exists to prevent.\n//\n// Hosting a theme manager already? Disable its class writer rather than pointing this at its\n// storage: two owners of `.dark` fight over the same class, and the loser wins at random.\n\nimport {\n AXES,\n CORE_NAMESPACE,\n CORE_PREFS,\n prefOptions,\n STORAGE_KEY,\n type SectionPolicy,\n} from \"@kanzo-tech/theme\";\n\nexport interface ThemeScriptOptions {\n /** Must match the provider's `storageKey` / the cookie adapter's key. */\n storageKey?: string;\n /**\n * The TENANT's policy — the same object the provider takes, keyed by namespace.\n *\n * **Pass it if you pass it to the provider.** A pinned axis this script does not know about is a\n * flash of the user's own value followed by the client's, which is the exact defect the script\n * exists to prevent, arriving through the feature that was supposed to give a client control.\n * Only the core's namespace is read here: a section's attribute is written after hydration.\n */\n policy?: Record<string, SectionPolicy>;\n}\n\n/** Returns the IIFE source (a string) to inline before hydration. Safe to embed in HTML. */\nexport function themeScript({\n storageKey = STORAGE_KEY,\n policy = {},\n}: ThemeScriptOptions = {}): string {\n // Only the serialisable part of each declaration is needed at runtime: key, attribute, default,\n // whether it is keyed by appearance, and the options to gate a stored value against.\n //\n // `prefOptions(decl)` with no sources answers `null` for the two axes whose options a TENANT\n // publishes, which becomes `0` here and means *do not gate*. That is not a shortcut around a\n // limitation of this script — the provider passes no sources for those two either, deliberately,\n // so that the value this writes before the first paint and the value React writes after\n // hydration cannot differ. See the theme block in `KanzoThemeProvider`.\n const row = (key: string) => {\n const decl = CORE_PREFS[key as keyof typeof CORE_PREFS];\n return [key, decl.attr ?? 0, decl.default, decl.byAppearance ?? 0, prefOptions(decl)?.map((o) => o.value) ?? 0];\n };\n const axes = JSON.stringify(AXES.map((a) => row(a.key)));\n // Appearance is resolved before the loop because the loop needs the side it resolves to: a keyed\n // axis is indexed by it. Same order the provider runs in, for the same reason.\n const appearance = JSON.stringify(row(\"appearance\"));\n const pol = JSON.stringify(policy[CORE_NAMESPACE] ?? {});\n const sk = JSON.stringify(storageKey);\n return (\n \"(function(){try{\" +\n \"var d=document.documentElement,P={};\" +\n // cookie first (server-readable), then localStorage\n \"try{var c=document.cookie.match(new RegExp('(?:^|; )'+\" + sk + \"+'=([^;]*)'));if(c&&c[1])P=JSON.parse(decodeURIComponent(c[1]));}catch(e){}\" +\n \"if(!P||!Object.keys(P).length){try{var s=localStorage.getItem(\" + sk + \");if(s)P=JSON.parse(s);}catch(e){}}\" +\n // ONE chain, four links, and it is `resolvePref`'s: pinned, stored, the tenant's starting\n // point, the declaration's default. Written out here rather than imported because this is a\n // string of JavaScript in a `<script>` tag — but it is the same order, gated the same way, and\n // `theme-script.test.ts` runs both sides under one set of stubs and diffs `<html>`.\n \"var PO=\" + pol + \";\" +\n \"function ok(v,o){return typeof v==='string'&&(!o||o.indexOf(v)>=0);}\" +\n \"function pick(p,s,df,o){return ok(p.pinned,o)?p.pinned:((!p.hidden&&ok(s,o))?s:(ok(p['default'],o)?p['default']:df));}\" +\n // Appearance first: it decides `.dark`, and it decides which side a keyed axis is indexed by.\n // Anything that is not an explicit side means \"ask the OS\" — which is why the last line here\n // never changed when `\"system\"` left the model. It was always the whole resolution.\n \"var AP=\" + appearance + \",av=pick(PO[AP[0]]||{},P[AP[0]],AP[2],AP[4]);\" +\n \"var W=(av==='light'||av==='dark')?av:((window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches)?'dark':'light');\" +\n // every axis, from the table itself. `data-theme` carries no option list and\n // so are written VERBATIM, never checked against what the tenant published: an attribute\n // selector with no matching rule is inert and the cascade falls through to `:root`, which is the\n // default. Validating here would mean knowing the document, and the two sides would stop\n // agreeing the moment they disagreed about it.\n \"var A=\" + axes + \";for(var i=0;i<A.length;i++){var r=A[i],k=r[0],s=r[3]?((P[k]||{})[W]):P[k],v=pick(PO[k]||{},s,r[2],r[4]);if(v===r[2]){d.removeAttribute(r[1]);}else{d.setAttribute(r[1],v);}}\" +\n // `style.colorScheme` is never written: an inline declaration outranks every rule permanently,\n // and each theme file carries its own `color-scheme`.\n \"d.classList.toggle('dark',W==='dark');\" +\n \"}catch(e){}})();\"\n );\n}\n"],"names":["themeScript","storageKey","STORAGE_KEY","policy","row","key","decl","CORE_PREFS","_a","prefOptions","o","axes","AXES","a","appearance","pol","CORE_NAMESPACE","sk"],"mappings":";AAwDO,SAASA,EAAY;AAAA,EAC1B,YAAAC,IAAaC;AAAA,EACb,QAAAC,IAAS,CAAA;AACX,IAAwB,IAAY;AASlC,QAAMC,IAAM,CAACC,MAAgB;;AAC3B,UAAMC,IAAOC,EAAWF,CAA8B;AACtD,WAAO,CAACA,GAAKC,EAAK,QAAQ,GAAGA,EAAK,SAASA,EAAK,gBAAgB,KAAGE,IAAAC,EAAYH,CAAI,MAAhB,gBAAAE,EAAmB,IAAI,CAACE,MAAMA,EAAE,WAAU,CAAC;AAAA,EAChH,GACMC,IAAO,KAAK,UAAUC,EAAK,IAAI,CAACC,MAAMT,EAAIS,EAAE,GAAG,CAAC,CAAC,GAGjDC,IAAa,KAAK,UAAUV,EAAI,YAAY,CAAC,GAC7CW,IAAM,KAAK,UAAUZ,EAAOa,CAAc,KAAK,EAAE,GACjDC,IAAK,KAAK,UAAUhB,CAAU;AACpC,SACE,+GAG2DgB,IAAK,8IACGA,IAAK,+CAK5DF,IAAM,uMAMND,IAAa,6LAOdH,IAAO;AAMtB;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kanzo-tech/ui",
|
|
3
|
+
"version": "0.0.1-alpha",
|
|
4
|
+
"description": "Kanzo shared UI — Ark UI + tailwind-variants primitives (Level 1) and domain-free shells (Level 2), token-themed.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"sideEffects": [
|
|
8
|
+
"**/*.css"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./editor": {
|
|
22
|
+
"types": "./dist/editor.d.ts",
|
|
23
|
+
"import": "./dist/editor.js"
|
|
24
|
+
},
|
|
25
|
+
"./table": {
|
|
26
|
+
"types": "./dist/table.d.ts",
|
|
27
|
+
"import": "./dist/table.js"
|
|
28
|
+
},
|
|
29
|
+
"./analytics": {
|
|
30
|
+
"types": "./dist/analytics.d.ts",
|
|
31
|
+
"import": "./dist/analytics.js"
|
|
32
|
+
},
|
|
33
|
+
"./styles.css": "./dist/styles.css",
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"@codemirror/autocomplete": ">=6",
|
|
38
|
+
"@codemirror/commands": ">=6",
|
|
39
|
+
"@codemirror/language": ">=6",
|
|
40
|
+
"@codemirror/search": ">=6",
|
|
41
|
+
"@codemirror/state": ">=6",
|
|
42
|
+
"@codemirror/view": ">=6",
|
|
43
|
+
"@duckdb/duckdb-wasm": "^1.33.1-dev57.0",
|
|
44
|
+
"@lezer/highlight": ">=1",
|
|
45
|
+
"@tanstack/react-table": ">=8",
|
|
46
|
+
"@uwdata/mosaic-core": "^0.29.2",
|
|
47
|
+
"@uwdata/mosaic-sql": "^0.29.0",
|
|
48
|
+
"@uwdata/vgplot": "^0.29.2",
|
|
49
|
+
"lucide-react": ">=1",
|
|
50
|
+
"react": ">=19",
|
|
51
|
+
"react-dom": ">=19"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"@tanstack/react-table": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"@uwdata/vgplot": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"@uwdata/mosaic-core": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@uwdata/mosaic-sql": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"@duckdb/duckdb-wasm": {
|
|
67
|
+
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"@codemirror/autocomplete": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"@codemirror/commands": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"@codemirror/language": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"@codemirror/search": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"@codemirror/state": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"@codemirror/view": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"@lezer/highlight": {
|
|
88
|
+
"optional": true
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"dependencies": {
|
|
92
|
+
"@ark-ui/react": "^5.37.2",
|
|
93
|
+
"@internationalized/date": "^3.12.2",
|
|
94
|
+
"clsx": "^2.1.1",
|
|
95
|
+
"tailwind-merge": "^3.6.0",
|
|
96
|
+
"tailwind-variants": "^3.2.2",
|
|
97
|
+
"@kanzo-tech/theme": "0.0.1-alpha"
|
|
98
|
+
},
|
|
99
|
+
"devDependencies": {
|
|
100
|
+
"@codemirror/autocomplete": "^6.18.6",
|
|
101
|
+
"@codemirror/commands": "^6.10.3",
|
|
102
|
+
"@codemirror/language": "^6.12.4",
|
|
103
|
+
"@codemirror/search": "^6.5.11",
|
|
104
|
+
"@codemirror/state": "^6.6.0",
|
|
105
|
+
"@codemirror/view": "^6.43.1",
|
|
106
|
+
"@lezer/highlight": "^1.2.3",
|
|
107
|
+
"@tailwindcss/cli": "4",
|
|
108
|
+
"@tailwindcss/typography": "^0.5.20",
|
|
109
|
+
"@tanstack/react-table": "^8.21.3",
|
|
110
|
+
"@testing-library/dom": "^10.4.1",
|
|
111
|
+
"@testing-library/react": "^16.3.2",
|
|
112
|
+
"@testing-library/user-event": "^14.6.1",
|
|
113
|
+
"@types/react": "^19.0.0",
|
|
114
|
+
"@types/react-dom": "^19.0.0",
|
|
115
|
+
"@uwdata/mosaic-core": "^0.29.2",
|
|
116
|
+
"@uwdata/mosaic-sql": "^0.29.0",
|
|
117
|
+
"@uwdata/vgplot": "^0.29.2",
|
|
118
|
+
"jsdom": "^29.1.1",
|
|
119
|
+
"lucide-react": "^1.23.0",
|
|
120
|
+
"react": "^19.0.0",
|
|
121
|
+
"react-dom": "^19.0.0",
|
|
122
|
+
"rollup-plugin-preserve-directives": "^0.4.0",
|
|
123
|
+
"tailwindcss": "4",
|
|
124
|
+
"tw-animate-css": "^1.4.0"
|
|
125
|
+
},
|
|
126
|
+
"//size-limit": "Budgets OUR shipped code only. `ignore` mirrors the build's `external` list in vite.config.ts — anything externalised resolves from the consumer's node_modules, so counting it here measures the ecosystem, not us; keep the two lists in sync. Barrel measured at 35.27 kB brotlied, budget set just above so real growth trips the gate. The analytics budget (then spelled `charts`) went 4 kB -> 6 kB when the five preset charts became a composable grammar (measured 5.47 kB), then 6 kB -> 60 kB when ChartFilter/ChartSearch/ChartSlider brought Select, Combobox, Input, Field and Slider into the subpath (measured 56.01 kB). That last jump is mostly an artefact of measuring a subpath in isolation: in an app that also imports the root barrel those modules are the same files and dedupe, so the incremental cost is far smaller. The root barrel went 38 kB -> 42 kB (measured 40.66 kB) for the AI-assist compounds: real growth, and growth nobody downloads unless they import it. That is the point -- this gauge measures the WHOLE library, not what a consumer pays. The gauge that measures the latter is 'one component (tree-shaken)' below: Button resolves to 1.08 kB and three of our modules, with no trace of the AI code, so tree-shaking is doing its job. Treat this budget as a change detector for the library's total size and that one as the regression gate for consumer cost. Rebaselined 2026-07-31: analytics measured 66.30 kB against a stale 60 kB budget, so the gate was already red before the colour work touched it -- measured by removing that work's only addition to the subpath (`useThemeTick` reading the palette through the theme context), which moves the figure by 0.03 kB. The growth is somebody else's and is not attributed here, because the minified bundle does not say and a note that guessed would be worse than one that does not: what is recorded is the number and the fact that it predates this branch. Budget set to 68 kB, just above the measurement, so the next real growth trips it again. Rebaselined 2026-08-18: the root barrel went 42 kB -> 42.5 kB (measured 42.12 kB, against 41.54 kB at fb8e5b5) when the core's axes became a generated declaration the barrel carries -- the JSON is 302 B -> 648 B of it, brotlied on its own, and the rest is the one resolution chain. The other three gauges did not move at all, `one component` included, so no consumer of a component pays for it; see `/docs/design/colour` for the four figures and how to re-derive them. Measured again 2026-08-20, and NOT rebaselined: 42.12 kB -> 42.32 kB across one branch that took four modules OUT of the barrel (`complete`, `suggest`, `use-ai` and the `Suggestion` type left for @kanzo-tech/ai) and put two IN (`Diagnostic`, `Questionnaire`). Net +0.20 kB, which is the honest reading and the only one available: the two movements cannot be separated from a single minified bundle, and a note that guessed at the split would be worse than one that says it did not. The AI compounds' arrival is recorded above as 38 -> 42 kB, so their departure is worth about that much and the two new components spent it. Still under the 43 kB gate, so the gate is untouched.",
|
|
127
|
+
"size-limit": [
|
|
128
|
+
{
|
|
129
|
+
"name": "root barrel (JS)",
|
|
130
|
+
"path": "dist/index.js",
|
|
131
|
+
"limit": "43.5 kB",
|
|
132
|
+
"ignore": [
|
|
133
|
+
"react",
|
|
134
|
+
"react-dom",
|
|
135
|
+
"react/jsx-runtime",
|
|
136
|
+
"@kanzo-tech/theme",
|
|
137
|
+
"@ark-ui/react",
|
|
138
|
+
"@internationalized/date",
|
|
139
|
+
"lucide-react",
|
|
140
|
+
"tailwind-variants",
|
|
141
|
+
"tailwind-merge",
|
|
142
|
+
"clsx",
|
|
143
|
+
"@codemirror/state",
|
|
144
|
+
"@codemirror/view",
|
|
145
|
+
"@codemirror/commands",
|
|
146
|
+
"@codemirror/language",
|
|
147
|
+
"@codemirror/search",
|
|
148
|
+
"@codemirror/autocomplete",
|
|
149
|
+
"@lezer/highlight",
|
|
150
|
+
"@tanstack/react-table"
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": "analytics subpath (JS)",
|
|
155
|
+
"path": "dist/analytics.js",
|
|
156
|
+
"limit": "68 kB",
|
|
157
|
+
"ignore": [
|
|
158
|
+
"react",
|
|
159
|
+
"react-dom",
|
|
160
|
+
"react/jsx-runtime",
|
|
161
|
+
"@kanzo-tech/theme",
|
|
162
|
+
"tailwind-merge",
|
|
163
|
+
"clsx",
|
|
164
|
+
"@uwdata/vgplot",
|
|
165
|
+
"@uwdata/mosaic-core",
|
|
166
|
+
"@uwdata/mosaic-sql",
|
|
167
|
+
"@duckdb/duckdb-wasm"
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"name": "one component (tree-shaken)",
|
|
172
|
+
"path": "dist/index.js",
|
|
173
|
+
"import": "{ Button }",
|
|
174
|
+
"limit": "2 kB",
|
|
175
|
+
"ignore": [
|
|
176
|
+
"react",
|
|
177
|
+
"react-dom",
|
|
178
|
+
"react/jsx-runtime",
|
|
179
|
+
"@kanzo-tech/theme",
|
|
180
|
+
"@ark-ui/react",
|
|
181
|
+
"@internationalized/date",
|
|
182
|
+
"lucide-react",
|
|
183
|
+
"tailwind-variants",
|
|
184
|
+
"tailwind-merge",
|
|
185
|
+
"clsx"
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "stylesheet",
|
|
190
|
+
"path": "dist/styles.css",
|
|
191
|
+
"limit": "40 kB"
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
"scripts": {
|
|
195
|
+
"build": "vite build && pnpm build:css",
|
|
196
|
+
"build:css": "tailwindcss -i src/styles.css -o dist/styles.css --minify",
|
|
197
|
+
"typecheck": "tsc --noEmit",
|
|
198
|
+
"test": "vitest run",
|
|
199
|
+
"size": "size-limit"
|
|
200
|
+
}
|
|
201
|
+
}
|