@panphora/bevel 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +16 -0
- package/README.md +226 -0
- package/bevel-fonts.css +16 -0
- package/bevel.css +3075 -0
- package/bevel.js +2126 -0
- package/dist/react/components/activity-feed.d.ts +89 -0
- package/dist/react/components/activity-feed.js +54 -0
- package/dist/react/components/alert-dialog.d.ts +14 -0
- package/dist/react/components/alert-dialog.js +19 -0
- package/dist/react/components/app-shell.d.ts +98 -0
- package/dist/react/components/app-shell.js +86 -0
- package/dist/react/components/app-toolbar.d.ts +19 -0
- package/dist/react/components/app-toolbar.js +22 -0
- package/dist/react/components/avatar-group.d.ts +67 -0
- package/dist/react/components/avatar-group.js +49 -0
- package/dist/react/components/badge-and-pill.d.ts +34 -0
- package/dist/react/components/badge-and-pill.js +12 -0
- package/dist/react/components/breadcrumbs.d.ts +56 -0
- package/dist/react/components/breadcrumbs.js +44 -0
- package/dist/react/components/bulk-bar.d.ts +22 -0
- package/dist/react/components/bulk-bar.js +59 -0
- package/dist/react/components/button.d.ts +15 -0
- package/dist/react/components/button.js +20 -0
- package/dist/react/components/callout-and-hint.d.ts +17 -0
- package/dist/react/components/callout-and-hint.js +8 -0
- package/dist/react/components/checkbox.d.ts +5 -0
- package/dist/react/components/checkbox.js +13 -0
- package/dist/react/components/chip.d.ts +149 -0
- package/dist/react/components/chip.js +29 -0
- package/dist/react/components/code-block.d.ts +50 -0
- package/dist/react/components/code-block.js +77 -0
- package/dist/react/components/code-editor.d.ts +122 -0
- package/dist/react/components/code-editor.js +695 -0
- package/dist/react/components/column-manager.d.ts +28 -0
- package/dist/react/components/column-manager.js +85 -0
- package/dist/react/components/combobox.d.ts +32 -0
- package/dist/react/components/combobox.js +37 -0
- package/dist/react/components/data-grid.d.ts +108 -0
- package/dist/react/components/data-grid.js +159 -0
- package/dist/react/components/data-table.d.ts +2 -0
- package/dist/react/components/data-table.js +6 -0
- package/dist/react/components/date.d.ts +23 -0
- package/dist/react/components/date.js +11 -0
- package/dist/react/components/details.d.ts +13 -0
- package/dist/react/components/details.js +20 -0
- package/dist/react/components/dialog.d.ts +74 -0
- package/dist/react/components/dialog.js +31 -0
- package/dist/react/components/diff-view.d.ts +73 -0
- package/dist/react/components/diff-view.js +68 -0
- package/dist/react/components/documents.d.ts +70 -0
- package/dist/react/components/documents.js +10 -0
- package/dist/react/components/drawer.d.ts +45 -0
- package/dist/react/components/drawer.js +35 -0
- package/dist/react/components/editable-grid-cells.d.ts +32 -0
- package/dist/react/components/editable-grid-cells.js +116 -0
- package/dist/react/components/eyebrow-kicker-lede-pull-quote.d.ts +39 -0
- package/dist/react/components/eyebrow-kicker-lede-pull-quote.js +12 -0
- package/dist/react/components/field.d.ts +32 -0
- package/dist/react/components/field.js +27 -0
- package/dist/react/components/file-tree.d.ts +75 -0
- package/dist/react/components/file-tree.js +247 -0
- package/dist/react/components/file.d.ts +43 -0
- package/dist/react/components/file.js +73 -0
- package/dist/react/components/files-table.d.ts +174 -0
- package/dist/react/components/files-table.js +237 -0
- package/dist/react/components/filter-builder.d.ts +37 -0
- package/dist/react/components/filter-builder.js +109 -0
- package/dist/react/components/form-error-summary.d.ts +16 -0
- package/dist/react/components/form-error-summary.js +49 -0
- package/dist/react/components/icon-button.d.ts +8 -0
- package/dist/react/components/icon-button.js +14 -0
- package/dist/react/components/icon.d.ts +7 -0
- package/dist/react/components/icon.js +15 -0
- package/dist/react/components/image.d.ts +72 -0
- package/dist/react/components/image.js +24 -0
- package/dist/react/components/inline-edit.d.ts +70 -0
- package/dist/react/components/inline-edit.js +149 -0
- package/dist/react/components/input.d.ts +29 -0
- package/dist/react/components/input.js +20 -0
- package/dist/react/components/kanban-board.d.ts +140 -0
- package/dist/react/components/kanban-board.js +374 -0
- package/dist/react/components/layout.d.ts +51 -0
- package/dist/react/components/layout.js +28 -0
- package/dist/react/components/list.d.ts +28 -0
- package/dist/react/components/list.js +6 -0
- package/dist/react/components/masthead-and-verdict.d.ts +60 -0
- package/dist/react/components/masthead-and-verdict.js +8 -0
- package/dist/react/components/menu.d.ts +26 -0
- package/dist/react/components/menu.js +31 -0
- package/dist/react/components/multi-select-picker.d.ts +49 -0
- package/dist/react/components/multi-select-picker.js +20 -0
- package/dist/react/components/note.d.ts +33 -0
- package/dist/react/components/note.js +8 -0
- package/dist/react/components/number-field.d.ts +16 -0
- package/dist/react/components/number-field.js +17 -0
- package/dist/react/components/pagination.d.ts +45 -0
- package/dist/react/components/pagination.js +87 -0
- package/dist/react/components/persistent-action-banner.d.ts +71 -0
- package/dist/react/components/persistent-action-banner.js +39 -0
- package/dist/react/components/popconfirm.d.ts +42 -0
- package/dist/react/components/popconfirm.js +59 -0
- package/dist/react/components/popover.d.ts +16 -0
- package/dist/react/components/popover.js +21 -0
- package/dist/react/components/progress-and-gauge.d.ts +44 -0
- package/dist/react/components/progress-and-gauge.js +19 -0
- package/dist/react/components/radio.d.ts +7 -0
- package/dist/react/components/radio.js +13 -0
- package/dist/react/components/rich-text-toolbar.d.ts +26 -0
- package/dist/react/components/rich-text-toolbar.js +64 -0
- package/dist/react/components/rows-and-card.d.ts +88 -0
- package/dist/react/components/rows-and-card.js +10 -0
- package/dist/react/components/save-status-indicator.d.ts +11 -0
- package/dist/react/components/save-status-indicator.js +33 -0
- package/dist/react/components/segmented-control.d.ts +21 -0
- package/dist/react/components/segmented-control.js +15 -0
- package/dist/react/components/select.d.ts +29 -0
- package/dist/react/components/select.js +29 -0
- package/dist/react/components/selectable-cards.d.ts +30 -0
- package/dist/react/components/selectable-cards.js +29 -0
- package/dist/react/components/settings-rows.d.ts +51 -0
- package/dist/react/components/settings-rows.js +8 -0
- package/dist/react/components/sidebar-nav.d.ts +77 -0
- package/dist/react/components/sidebar-nav.js +41 -0
- package/dist/react/components/skeleton-and-empty.d.ts +51 -0
- package/dist/react/components/skeleton-and-empty.js +14 -0
- package/dist/react/components/slider.d.ts +19 -0
- package/dist/react/components/slider.js +17 -0
- package/dist/react/components/small-charts.d.ts +60 -0
- package/dist/react/components/small-charts.js +76 -0
- package/dist/react/components/sortable.d.ts +30 -0
- package/dist/react/components/sortable.js +85 -0
- package/dist/react/components/split-button.d.ts +38 -0
- package/dist/react/components/split-button.js +43 -0
- package/dist/react/components/split-panes.d.ts +35 -0
- package/dist/react/components/split-panes.js +102 -0
- package/dist/react/components/stat-tiles.d.ts +54 -0
- package/dist/react/components/stat-tiles.js +8 -0
- package/dist/react/components/steps.d.ts +11 -0
- package/dist/react/components/steps.js +13 -0
- package/dist/react/components/switch.d.ts +6 -0
- package/dist/react/components/switch.js +13 -0
- package/dist/react/components/table.d.ts +61 -0
- package/dist/react/components/table.js +6 -0
- package/dist/react/components/tabs.d.ts +7 -0
- package/dist/react/components/tabs.js +13 -0
- package/dist/react/components/tags.d.ts +33 -0
- package/dist/react/components/tags.js +83 -0
- package/dist/react/components/textarea.d.ts +10 -0
- package/dist/react/components/textarea.js +6 -0
- package/dist/react/components/toast.d.ts +35 -0
- package/dist/react/components/toast.js +90 -0
- package/dist/react/components/tooltip-and-key.d.ts +20 -0
- package/dist/react/components/tooltip-and-key.js +20 -0
- package/dist/react/components/tree-view.d.ts +34 -0
- package/dist/react/components/tree-view.js +118 -0
- package/dist/react/components/upload-dropzone.d.ts +92 -0
- package/dist/react/components/upload-dropzone.js +116 -0
- package/dist/react/components/wizard-shell.d.ts +78 -0
- package/dist/react/components/wizard-shell.js +176 -0
- package/dist/react/fonts.css.d.ts +1 -0
- package/dist/react/index.d.ts +76 -0
- package/dist/react/index.js +77 -0
- package/dist/react/integrations/quickcrop.d.ts +58 -0
- package/dist/react/integrations/quickcrop.js +137 -0
- package/dist/react/integrations/richclay.d.ts +43 -0
- package/dist/react/integrations/richclay.js +129 -0
- package/dist/react/internal/classes.d.ts +3 -0
- package/dist/react/internal/classes.js +10 -0
- package/dist/react/internal/close-mark.d.ts +1 -0
- package/dist/react/internal/close-mark.js +10 -0
- package/dist/react/internal/controllable-state.d.ts +9 -0
- package/dist/react/internal/controllable-state.js +22 -0
- package/dist/react/internal/drop-effect.d.ts +28 -0
- package/dist/react/internal/drop-effect.js +8 -0
- package/dist/react/internal/form-reset.d.ts +2 -0
- package/dist/react/internal/form-reset.js +22 -0
- package/dist/react/internal/format.d.ts +1 -0
- package/dist/react/internal/format.js +14 -0
- package/dist/react/internal/link.d.ts +2 -0
- package/dist/react/internal/link.js +8 -0
- package/dist/react/internal/part.d.ts +20 -0
- package/dist/react/internal/part.js +47 -0
- package/dist/react/internal/pointer-session.d.ts +8 -0
- package/dist/react/internal/pointer-session.js +60 -0
- package/dist/react/internal/refs.d.ts +2 -0
- package/dist/react/internal/refs.js +22 -0
- package/dist/react/internal/rich-text.d.ts +28 -0
- package/dist/react/internal/rich-text.js +4 -0
- package/dist/react/internal/table-context.d.ts +39 -0
- package/dist/react/internal/table-context.js +12 -0
- package/dist/react/internal/use-object-url.d.ts +1 -0
- package/dist/react/internal/use-object-url.js +15 -0
- package/dist/react/layout.css +274 -0
- package/dist/react/layout.css.d.ts +1 -0
- package/dist/react/models/filter.d.ts +31 -0
- package/dist/react/models/filter.js +79 -0
- package/dist/react/models/kanban.d.ts +51 -0
- package/dist/react/models/kanban.js +35 -0
- package/dist/react/models/reorder.d.ts +9 -0
- package/dist/react/models/reorder.js +23 -0
- package/dist/react/models/table.d.ts +85 -0
- package/dist/react/models/table.js +144 -0
- package/dist/react/models/tree.d.ts +16 -0
- package/dist/react/models/tree.js +26 -0
- package/dist/react/provider.d.ts +18 -0
- package/dist/react/provider.js +31 -0
- package/dist/react/recipes/context-hypercms.d.ts +17 -0
- package/dist/react/recipes/context-hypercms.js +71 -0
- package/dist/react/recipes/context-quickcrop.d.ts +8 -0
- package/dist/react/recipes/context-quickcrop.js +49 -0
- package/dist/react/theme.css +8004 -0
- package/dist/react/theme.css.d.ts +1 -0
- package/examples/README.md +34 -0
- package/examples/components/activity-feed.html +28 -0
- package/examples/components/app-shell.html +12 -0
- package/examples/components/app-toolbar.html +38 -0
- package/examples/components/avatar-group.html +27 -0
- package/examples/components/breadcrumbs.html +26 -0
- package/examples/components/bulk-bar.html +22 -0
- package/examples/components/code-block.html +12 -0
- package/examples/components/code-editor.html +25 -0
- package/examples/components/column-manager.html +9 -0
- package/examples/components/combobox.html +13 -0
- package/examples/components/context-hypercms.css +41 -0
- package/examples/components/context-hypercms.html +40 -0
- package/examples/components/context-hypercms.js +62 -0
- package/examples/components/context-quickcrop.html +137 -0
- package/examples/components/diff-view.html +9 -0
- package/examples/components/drawer.html +11 -0
- package/examples/components/editable-grid-cells.html +9 -0
- package/examples/components/file-browser.html +53 -0
- package/examples/components/file-tree.html +34 -0
- package/examples/components/files-table.html +80 -0
- package/examples/components/filter-builder.html +11 -0
- package/examples/components/form-error-summary.html +11 -0
- package/examples/components/index.html +51 -0
- package/examples/components/inline-edit.html +42 -0
- package/examples/components/kanban-board.html +42 -0
- package/examples/components/manifest.json +3279 -0
- package/examples/components/modal.html +11 -0
- package/examples/components/multi-select-picker.html +13 -0
- package/examples/components/pagination.html +32 -0
- package/examples/components/persistent-action-banner.html +23 -0
- package/examples/components/popconfirm.html +13 -0
- package/examples/components/popover-menu.html +13 -0
- package/examples/components/reference/baseline/DECISIONS.md +85 -0
- package/examples/components/reference/baseline/README.md +58 -0
- package/examples/components/reference/baseline/bevel-fonts.css +16 -0
- package/examples/components/reference/baseline/bevel.css +1339 -0
- package/examples/components/reference/baseline/bevel.js +496 -0
- package/examples/components/reference/baseline/fonts/LICENSE-ibm-plex-mono.txt +93 -0
- package/examples/components/reference/baseline/fonts/LICENSE-ibm-plex-sans.txt +93 -0
- package/examples/components/reference/baseline/fonts/LICENSE-newsreader.txt +93 -0
- package/examples/components/reference/baseline/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/examples/components/reference/baseline/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/examples/components/reference/baseline/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- package/examples/components/reference/baseline/fonts/ibm-plex-sans-latin-400-italic.woff2 +0 -0
- package/examples/components/reference/baseline/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/examples/components/reference/baseline/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/examples/components/reference/baseline/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/examples/components/reference/baseline/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
- package/examples/components/reference/baseline/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
- package/examples/components/reference/fable/IMPROVEMENTS.md +106 -0
- package/examples/components/reference/fable/PARENT-REPAIRS.md +17 -0
- package/examples/components/reference/fable/__pycache__/build_repairs.cpython-311.pyc +0 -0
- package/examples/components/reference/fable/__pycache__/kanban.cpython-311.pyc +0 -0
- package/examples/components/reference/fable/as-authored/IMPROVEMENTS-completed.md +106 -0
- package/examples/components/reference/fable/as-authored/base-astra.css +17 -0
- package/examples/components/reference/fable/as-authored/base-parent.css +416 -0
- package/examples/components/reference/fable/as-authored/build.py +858 -0
- package/examples/components/reference/fable/as-authored/fable.css +823 -0
- package/examples/components/reference/fable/as-authored/kanban-completed.css +235 -0
- package/examples/components/reference/fable/as-authored/kanban-completed.html +53 -0
- package/examples/components/reference/fable/as-authored/kanban-completed.py +212 -0
- package/examples/components/reference/fable/as-authored/kanban.py +207 -0
- package/examples/components/reference/fable/base-astra.css +17 -0
- package/examples/components/reference/fable/base-parent.css +416 -0
- package/examples/components/reference/fable/build.py +858 -0
- package/examples/components/reference/fable/build_repairs.py +25 -0
- package/examples/components/reference/fable/components/activity-feed.html +3 -0
- package/examples/components/reference/fable/components/app-toolbar.html +3 -0
- package/examples/components/reference/fable/components/avatar-group.html +4 -0
- package/examples/components/reference/fable/components/breadcrumbs.html +3 -0
- package/examples/components/reference/fable/components/code-block.html +9 -0
- package/examples/components/reference/fable/components/column-manager.html +3 -0
- package/examples/components/reference/fable/components/combobox.html +6 -0
- package/examples/components/reference/fable/components/context-hypercms.html +3 -0
- package/examples/components/reference/fable/components/context-quickcrop.html +4 -0
- package/examples/components/reference/fable/components/diff-view.html +13 -0
- package/examples/components/reference/fable/components/drawer.html +3 -0
- package/examples/components/reference/fable/components/editable-grid-cells.html +3 -0
- package/examples/components/reference/fable/components/filter-builder.html +3 -0
- package/examples/components/reference/fable/components/form-error-summary.html +4 -0
- package/examples/components/reference/fable/components/inline-edit.html +3 -0
- package/examples/components/reference/fable/components/kanban-board.html +53 -0
- package/examples/components/reference/fable/components/modal.html +3 -0
- package/examples/components/reference/fable/components/multi-select-picker.html +5 -0
- package/examples/components/reference/fable/components/pagination.html +3 -0
- package/examples/components/reference/fable/components/persistent-action-banner.html +4 -0
- package/examples/components/reference/fable/components/popconfirm.html +5 -0
- package/examples/components/reference/fable/components/popover-menu.html +3 -0
- package/examples/components/reference/fable/components/rich-text-toolbar.html +3 -0
- package/examples/components/reference/fable/components/save-status-indicator.html +2 -0
- package/examples/components/reference/fable/components/selectable-cards.html +3 -0
- package/examples/components/reference/fable/components/settings-rows.html +3 -0
- package/examples/components/reference/fable/components/sidebar-nav.html +4 -0
- package/examples/components/reference/fable/components/small-charts.html +5 -0
- package/examples/components/reference/fable/components/split-button.html +4 -0
- package/examples/components/reference/fable/components/split-panes.html +8 -0
- package/examples/components/reference/fable/components/stat-tiles.html +3 -0
- package/examples/components/reference/fable/components/toast-stack.html +5 -0
- package/examples/components/reference/fable/components/tree-view.html +4 -0
- package/examples/components/reference/fable/components/upload-dropzone.html +6 -0
- package/examples/components/reference/fable/components/wizard-shell.html +3 -0
- package/examples/components/reference/fable/coverage.json +414 -0
- package/examples/components/reference/fable/fable.css +823 -0
- package/examples/components/reference/fable/index.html +5 -0
- package/examples/components/reference/fable/kanban.css +237 -0
- package/examples/components/reference/fable/kanban.py +212 -0
- package/examples/components/reference/fable/parent-repairs.css +9 -0
- package/examples/components/reference/fixtures/data.json +102 -0
- package/examples/components/reference/fixtures/host.js +47 -0
- package/examples/components/reference/fixtures/static-host.js +39 -0
- package/examples/components/reference/fixtures/workspace.jpg +0 -0
- package/examples/components/reference/parent/CHANGES.md +179 -0
- package/examples/components/reference/parent/__pycache__/kanban.cpython-311.pyc +0 -0
- package/examples/components/reference/parent/base-astra.css +17 -0
- package/examples/components/reference/parent/base-parent.css +416 -0
- package/examples/components/reference/parent/build.py +148 -0
- package/examples/components/reference/parent/components/activity-feed.html +2 -0
- package/examples/components/reference/parent/components/app-toolbar.html +2 -0
- package/examples/components/reference/parent/components/avatar-group.html +4 -0
- package/examples/components/reference/parent/components/breadcrumbs.html +2 -0
- package/examples/components/reference/parent/components/code-block.html +8 -0
- package/examples/components/reference/parent/components/column-manager.html +2 -0
- package/examples/components/reference/parent/components/combobox.html +6 -0
- package/examples/components/reference/parent/components/context-hypercms.html +2 -0
- package/examples/components/reference/parent/components/context-quickcrop.html +4 -0
- package/examples/components/reference/parent/components/diff-view.html +4 -0
- package/examples/components/reference/parent/components/drawer.html +2 -0
- package/examples/components/reference/parent/components/editable-grid-cells.html +2 -0
- package/examples/components/reference/parent/components/filter-builder.html +2 -0
- package/examples/components/reference/parent/components/form-error-summary.html +2 -0
- package/examples/components/reference/parent/components/inline-edit.html +2 -0
- package/examples/components/reference/parent/components/kanban-board.html +84 -0
- package/examples/components/reference/parent/components/modal.html +2 -0
- package/examples/components/reference/parent/components/multi-select-picker.html +5 -0
- package/examples/components/reference/parent/components/pagination.html +2 -0
- package/examples/components/reference/parent/components/persistent-action-banner.html +4 -0
- package/examples/components/reference/parent/components/popconfirm.html +5 -0
- package/examples/components/reference/parent/components/popover-menu.html +2 -0
- package/examples/components/reference/parent/components/rich-text-toolbar.html +2 -0
- package/examples/components/reference/parent/components/save-status-indicator.html +2 -0
- package/examples/components/reference/parent/components/selectable-cards.html +2 -0
- package/examples/components/reference/parent/components/settings-rows.html +2 -0
- package/examples/components/reference/parent/components/sidebar-nav.html +4 -0
- package/examples/components/reference/parent/components/small-charts.html +2 -0
- package/examples/components/reference/parent/components/split-button.html +5 -0
- package/examples/components/reference/parent/components/split-panes.html +8 -0
- package/examples/components/reference/parent/components/stat-tiles.html +2 -0
- package/examples/components/reference/parent/components/toast-stack.html +5 -0
- package/examples/components/reference/parent/components/tree-view.html +4 -0
- package/examples/components/reference/parent/components/upload-dropzone.html +6 -0
- package/examples/components/reference/parent/components/wizard-shell.html +2 -0
- package/examples/components/reference/parent/coverage.json +414 -0
- package/examples/components/reference/parent/index.html +1 -0
- package/examples/components/reference/parent/kanban.css +114 -0
- package/examples/components/reference/parent/kanban.py +55 -0
- package/examples/components/reference/parent/refinement.css +53 -0
- package/examples/components/reference/selected/build.py +70 -0
- package/examples/components/reference/selected/components/activity-feed.html +3 -0
- package/examples/components/reference/selected/components/app-toolbar.html +3 -0
- package/examples/components/reference/selected/components/avatar-group.html +4 -0
- package/examples/components/reference/selected/components/breadcrumbs.html +3 -0
- package/examples/components/reference/selected/components/code-block.html +9 -0
- package/examples/components/reference/selected/components/column-manager.html +3 -0
- package/examples/components/reference/selected/components/combobox.html +6 -0
- package/examples/components/reference/selected/components/context-hypercms.html +3 -0
- package/examples/components/reference/selected/components/context-quickcrop.html +4 -0
- package/examples/components/reference/selected/components/diff-view.html +13 -0
- package/examples/components/reference/selected/components/drawer.html +3 -0
- package/examples/components/reference/selected/components/editable-grid-cells.html +3 -0
- package/examples/components/reference/selected/components/filter-builder.html +3 -0
- package/examples/components/reference/selected/components/form-error-summary.html +4 -0
- package/examples/components/reference/selected/components/inline-edit.html +3 -0
- package/examples/components/reference/selected/components/kanban-board.html +53 -0
- package/examples/components/reference/selected/components/modal.html +2 -0
- package/examples/components/reference/selected/components/multi-select-picker.html +5 -0
- package/examples/components/reference/selected/components/pagination.html +3 -0
- package/examples/components/reference/selected/components/persistent-action-banner.html +4 -0
- package/examples/components/reference/selected/components/popconfirm.html +5 -0
- package/examples/components/reference/selected/components/popover-menu.html +3 -0
- package/examples/components/reference/selected/components/rich-text-toolbar.html +3 -0
- package/examples/components/reference/selected/components/save-status-indicator.html +2 -0
- package/examples/components/reference/selected/components/selectable-cards.html +3 -0
- package/examples/components/reference/selected/components/settings-rows.html +3 -0
- package/examples/components/reference/selected/components/sidebar-nav.html +4 -0
- package/examples/components/reference/selected/components/small-charts.html +5 -0
- package/examples/components/reference/selected/components/split-button.html +4 -0
- package/examples/components/reference/selected/components/split-panes.html +8 -0
- package/examples/components/reference/selected/components/stat-tiles.html +3 -0
- package/examples/components/reference/selected/components/toast-stack.html +5 -0
- package/examples/components/reference/selected/components/tree-view.html +4 -0
- package/examples/components/reference/selected/components/upload-dropzone.html +6 -0
- package/examples/components/reference/selected/components/wizard-shell.html +3 -0
- package/examples/components/reference/selected/corrections.css +11 -0
- package/examples/components/reference/selected/coverage.json +413 -0
- package/examples/components/reference/selected/gallery-build.mjs +49 -0
- package/examples/components/reference/selected/gallery-spec.json +12 -0
- package/examples/components/reference/selected/index.html +1 -0
- package/examples/components/reference/selected/kanban-comparison.json +6 -0
- package/examples/components/reference/selected/manifest.json +476 -0
- package/examples/components/reference/sha256.json +142 -0
- package/examples/components/reference/sources/diagonal-close.svg +1 -0
- package/examples/components/reference/sources/hyperclay/public-assets/css/hyperclay-app-source.css +614 -0
- package/examples/components/reference/sources/hyperclay/public-assets/js/app.js +94 -0
- package/examples/components/reference/sources/hyperclayjs/src/ui/theModal.js +897 -0
- package/examples/components/reference/sources/hypercms/scripts/build-theme.js +203 -0
- package/examples/components/reference/sources/hypercms/src/anchor.js +24 -0
- package/examples/components/reference/sources/hypercms/src/apply-loop.js +167 -0
- package/examples/components/reference/sources/hypercms/src/diagnostics.js +44 -0
- package/examples/components/reference/sources/hypercms/src/enhance.js +173 -0
- package/examples/components/reference/sources/hypercms/src/events.js +955 -0
- package/examples/components/reference/sources/hypercms/src/form-builder.js +518 -0
- package/examples/components/reference/sources/hypercms/src/form-rules.js +208 -0
- package/examples/components/reference/sources/hypercms/src/hooks.js +100 -0
- package/examples/components/reference/sources/hypercms/src/hypercms-bundle.js +10 -0
- package/examples/components/reference/sources/hypercms/src/hypercms.js +347 -0
- package/examples/components/reference/sources/hypercms/src/morph.js +10 -0
- package/examples/components/reference/sources/hypercms/src/path.js +61 -0
- package/examples/components/reference/sources/hypercms/src/place.js +131 -0
- package/examples/components/reference/sources/hypercms/src/platform.js +131 -0
- package/examples/components/reference/sources/hypercms/src/refresh.js +87 -0
- package/examples/components/reference/sources/hypercms/src/richclay-bridge.js +140 -0
- package/examples/components/reference/sources/hypercms/src/row-identity.js +111 -0
- package/examples/components/reference/sources/hypercms/src/scaffold.js +10 -0
- package/examples/components/reference/sources/hypercms/src/session.js +303 -0
- package/examples/components/reference/sources/hypercms/src/shell.js +248 -0
- package/examples/components/reference/sources/hypercms/src/styles.css +298 -0
- package/examples/components/reference/sources/hypercms/src/targets.js +144 -0
- package/examples/components/reference/sources/hypercms/src/templates.js +656 -0
- package/examples/components/reference/sources/hypercms/src/theme/pixel-quiet.overrides.css +761 -0
- package/examples/components/reference/sources/hypercms/src/theme.generated.css +1772 -0
- package/examples/components/reference/sources/hypercms/src/toggle.js +666 -0
- package/examples/components/reference/sources/hypercms/src/unresolved.js +211 -0
- package/examples/components/reference/sources/hypercms/src/vendor/mirk.vendor.js +212 -0
- package/examples/components/reference/sources/hypercms/src/views/inline-layer.js +421 -0
- package/examples/components/reference/sources/hypercms/src/views/inline.js +1072 -0
- package/examples/components/reference/sources/hypercms/src/views/sidebar.js +97 -0
- package/examples/components/reference/sources/modal-reference.html +301 -0
- package/examples/components/reference/sources/quickcrop/quickcrop.css +124 -0
- package/examples/components/reference/sources/quickcrop/quickcrop.js +400 -0
- package/examples/components/reference/sources/richclay/richclay.css +416 -0
- package/examples/components/reference/sources/richclay/richclay.js +2962 -0
- package/examples/components/reference/sources/richclay/src/a11y.js +67 -0
- package/examples/components/reference/sources/richclay/src/browser-global.js +7 -0
- package/examples/components/reference/sources/richclay/src/buttons.js +254 -0
- package/examples/components/reference/sources/richclay/src/hyperclay.js +470 -0
- package/examples/components/reference/sources/richclay/src/normalize.js +380 -0
- package/examples/components/reference/sources/richclay/src/richclay.js +1356 -0
- package/examples/components/reference/sources/richclay/src/sanitize.js +189 -0
- package/examples/components/reference/sources/richclay/src/styles.js +23 -0
- package/examples/components/reference/sources/richclay/src/toolbar-float.js +175 -0
- package/examples/components/reference/sources/richclay/src/toolbar.js +394 -0
- package/examples/components/reference/sources/richclay/src/vendor-bundle.js +15 -0
- package/examples/components/reference/sources/richclay/vendor/DOMPURIFY-LICENSE +202 -0
- package/examples/components/reference/sources/richclay/vendor/DOMPURIFY-LICENSE-MPL +373 -0
- package/examples/components/reference/sources/richclay/vendor/SQUIRE-LICENSE +21 -0
- package/examples/components/reference/sources/richclay/vendor/purify.es.mjs +2249 -0
- package/examples/components/reference/sources/richclay/vendor/purify.min.js +3 -0
- package/examples/components/reference/sources/richclay/vendor/squire.js +22 -0
- package/examples/components/reference/sources/richclay/vendor/squire.mjs +22 -0
- package/examples/components/reference/sources/richclay/vendor/squire.provenance.json +19 -0
- package/examples/components/rich-text-toolbar.html +43 -0
- package/examples/components/save-status-indicator.html +11 -0
- package/examples/components/selectable-cards.html +9 -0
- package/examples/components/settings-rows.html +10 -0
- package/examples/components/sidebar-nav.html +9 -0
- package/examples/components/small-charts.html +21 -0
- package/examples/components/split-button.html +13 -0
- package/examples/components/split-panes-editor.html +6 -0
- package/examples/components/split-panes.html +9 -0
- package/examples/components/stat-tiles.html +23 -0
- package/examples/components/toast-stack.html +21 -0
- package/examples/components/tree-view.html +9 -0
- package/examples/components/upload-dropzone.html +88 -0
- package/examples/components/wizard-shell.html +50 -0
- package/examples/datastar/index.html +38 -0
- package/examples/datastar/server.mjs +31 -0
- package/examples/fixtures/field-guide.pdf +14 -0
- package/examples/fixtures/workspace.jpg +0 -0
- package/examples/setup-peers.mjs +35 -0
- package/fonts/LICENSE-ibm-plex-mono.txt +93 -0
- package/fonts/LICENSE-ibm-plex-sans.txt +93 -0
- package/fonts/LICENSE-newsreader.txt +93 -0
- package/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-400-italic.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
- package/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
- package/icons/LICENSE +21 -0
- package/icons/house.json +71 -0
- package/icons/icons.d.ts +17 -0
- package/icons/icons.js +648 -0
- package/icons/icons.svg +126 -0
- package/icons/marks/build-tray.source.mjs +45 -0
- package/icons/marks/hyperclay-local.svg +11 -0
- package/icons/phosphor.json +53 -0
- package/icons/round.json +8 -0
- package/integrations/datastar.js +202 -0
- package/integrations/quickcrop.css +26 -0
- package/integrations/quickcrop.js +56 -0
- package/integrations/richclay.css +100 -0
- package/integrations/richclay.js +131 -0
- package/package.json +630 -0
- package/react/README.md +244 -0
- package/src/README.md +83 -0
- package/vendor/datastar/datastar-1.0.3.js +10 -0
- package/vendor/datastar/provenance.json +6 -0
- package/vendor/floating-ui/LICENSE-core +20 -0
- package/vendor/floating-ui/LICENSE-dom +20 -0
- package/vendor/floating-ui/floating-ui.core.umd.min.js +1 -0
- package/vendor/floating-ui/floating-ui.dom.umd.min.js +1 -0
- package/vendor/floating-ui/provenance.json +17 -0
- package/vendor/richclay/LICENSE +16 -0
- package/vendor/richclay/THIRD-PARTY-NOTICES.md +45 -0
- package/vendor/richclay/provenance.json +17 -0
- package/vendor/richclay/richclay.css +404 -0
- package/vendor/richclay/richclay.js +2940 -0
- package/vendor/richclay/vendor/DOMPURIFY-LICENSE +202 -0
- package/vendor/richclay/vendor/DOMPURIFY-LICENSE-MPL +373 -0
- package/vendor/richclay/vendor/SQUIRE-LICENSE +21 -0
- package/vendor/richclay/vendor/purify.min.js +3 -0
- package/vendor/richclay/vendor/squire.js +22 -0
- package/vendor/richclay/vendor/squire.provenance.json +30 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* build-theme.js — generate hypercms's pixel-quiet shell stylesheet.
|
|
4
|
+
*
|
|
5
|
+
* mirk.css styles a whole document (:root tokens, body font, universal
|
|
6
|
+
* box-sizing, a relative @font-face url). hypercms injects a sidebar into an
|
|
7
|
+
* arbitrary host page, so mirk must be SCOPED to .hcms-shell or it would
|
|
8
|
+
* repaint the host body, change its box model, and fail to load the font.
|
|
9
|
+
*
|
|
10
|
+
* This reads the canonical mirk.css (single source of truth in mirk-interface),
|
|
11
|
+
* scopes every rule to .hcms-shell, rewrites the font url to the absolute CDN,
|
|
12
|
+
* then appends the hypercms-owned pixel-quiet overrides. Output:
|
|
13
|
+
* src/theme.generated.css, which the bundle entry installs as the shell CSS.
|
|
14
|
+
*
|
|
15
|
+
* Also vendors mirk.js (the delegated component runtime) into src/vendor so the
|
|
16
|
+
* bundle can import it for its side effect.
|
|
17
|
+
*
|
|
18
|
+
* Run: npm run build:theme (also runs first in `npm run build`).
|
|
19
|
+
*/
|
|
20
|
+
import fs from 'fs'
|
|
21
|
+
import path from 'path'
|
|
22
|
+
import { fileURLToPath } from 'url'
|
|
23
|
+
|
|
24
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
25
|
+
const root = path.join(__dirname, '..')
|
|
26
|
+
|
|
27
|
+
// mirk-interface normally sits next to the hypercms checkout, but in a git
|
|
28
|
+
// worktree (.claude/worktrees/<name>) the repo root is nested deeper, so walk
|
|
29
|
+
// up until a directory contains mirk-interface/mirk.css.
|
|
30
|
+
function findMirkRepo(from) {
|
|
31
|
+
for (let dir = from; ; dir = path.dirname(dir)) {
|
|
32
|
+
const candidate = path.join(dir, 'mirk-interface')
|
|
33
|
+
if (fs.existsSync(path.join(candidate, 'mirk.css'))) return candidate
|
|
34
|
+
if (path.dirname(dir) === dir) throw new Error('mirk-interface/mirk.css not found above ' + from)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const mirkRepo = findMirkRepo(root)
|
|
38
|
+
|
|
39
|
+
const MIRK_VERSION = '2.2.0'
|
|
40
|
+
const FONT_CDN =
|
|
41
|
+
`https://cdn.jsdelivr.net/npm/mirk-interface@${MIRK_VERSION}/fonts/DepartureMono-1.500/DepartureMono-Regular.woff2`
|
|
42
|
+
|
|
43
|
+
const SCOPE = '.hcms-shell'
|
|
44
|
+
|
|
45
|
+
// ---- selector scoping -------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
// Split a string on a top-level separator, ignoring separators inside () or [].
|
|
48
|
+
function splitTopLevel(str, sep) {
|
|
49
|
+
const out = []
|
|
50
|
+
let depth = 0
|
|
51
|
+
let buf = ''
|
|
52
|
+
for (const ch of str) {
|
|
53
|
+
if (ch === '(' || ch === '[') depth++
|
|
54
|
+
else if (ch === ')' || ch === ']') depth--
|
|
55
|
+
if (ch === sep && depth === 0) {
|
|
56
|
+
out.push(buf)
|
|
57
|
+
buf = ''
|
|
58
|
+
} else {
|
|
59
|
+
buf += ch
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (buf.trim() !== '') out.push(buf)
|
|
63
|
+
return out
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function stripComments(s) {
|
|
67
|
+
return s.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Map one mirk selector to its .hcms-shell-scoped form. Root-level selectors
|
|
71
|
+
// (:root / body / html, and the theme flags .light / .dark / [data-theme]) bind
|
|
72
|
+
// to the shell element itself; everything else binds to a descendant.
|
|
73
|
+
function scopeOne(sel) {
|
|
74
|
+
sel = stripComments(sel).trim()
|
|
75
|
+
if (!sel) return ''
|
|
76
|
+
if (sel === ':root' || sel === 'body' || sel === 'html') return SCOPE
|
|
77
|
+
if (sel === '*') return `${SCOPE} *`
|
|
78
|
+
if (sel === '::before') return `${SCOPE} *::before`
|
|
79
|
+
if (sel === '::after') return `${SCOPE} *::after`
|
|
80
|
+
if (/^\.light\b/.test(sel) || /^\.dark\b/.test(sel) || sel.startsWith('[data-theme')) {
|
|
81
|
+
return SCOPE + sel
|
|
82
|
+
}
|
|
83
|
+
return `${SCOPE} ${sel}`
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function scopeSelectorList(list) {
|
|
87
|
+
return splitTopLevel(list, ',').map(scopeOne).filter(Boolean).join(', ')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function rewriteFontFace(body) {
|
|
91
|
+
return body.replace(
|
|
92
|
+
/url\(\s*(['"]?)[^)'"]*DepartureMono-Regular\.woff2\1\s*\)/,
|
|
93
|
+
`url('${FONT_CDN}')`
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ---- block walker -----------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
// Transform a sequence of rules (a stylesheet, or the inside of an at-rule
|
|
100
|
+
// block). Style rules get their selector list scoped; nested at-rules recurse.
|
|
101
|
+
function transformBlock(css) {
|
|
102
|
+
let i = 0
|
|
103
|
+
let out = ''
|
|
104
|
+
const n = css.length
|
|
105
|
+
while (i < n) {
|
|
106
|
+
const ch = css[i]
|
|
107
|
+
if (/\s/.test(ch)) { out += ch; i++; continue }
|
|
108
|
+
if (ch === '/' && css[i + 1] === '*') {
|
|
109
|
+
const end = css.indexOf('*/', i + 2)
|
|
110
|
+
const stop = end === -1 ? n : end + 2
|
|
111
|
+
out += css.slice(i, stop)
|
|
112
|
+
i = stop
|
|
113
|
+
continue
|
|
114
|
+
}
|
|
115
|
+
// Read the prelude up to a top-level '{' or ';'.
|
|
116
|
+
let j = i
|
|
117
|
+
let depth = 0
|
|
118
|
+
while (j < n) {
|
|
119
|
+
const c = css[j]
|
|
120
|
+
if (c === '/' && css[j + 1] === '*') { const e = css.indexOf('*/', j + 2); j = e === -1 ? n : e + 2; continue }
|
|
121
|
+
if (c === '{' && depth === 0) break
|
|
122
|
+
if (c === ';' && depth === 0) break
|
|
123
|
+
if (c === '(' || c === '[') depth++
|
|
124
|
+
else if (c === ')' || c === ']') depth--
|
|
125
|
+
j++
|
|
126
|
+
}
|
|
127
|
+
if (j >= n) { out += css.slice(i); break }
|
|
128
|
+
const prelude = css.slice(i, j)
|
|
129
|
+
if (css[j] === ';') {
|
|
130
|
+
// statement at-rule, e.g. `@layer base, components;`
|
|
131
|
+
out += prelude + ';'
|
|
132
|
+
i = j + 1
|
|
133
|
+
continue
|
|
134
|
+
}
|
|
135
|
+
// css[j] === '{' — find the matching close brace.
|
|
136
|
+
const bodyStart = j + 1
|
|
137
|
+
let d = 1
|
|
138
|
+
let k = bodyStart
|
|
139
|
+
while (k < n && d > 0) {
|
|
140
|
+
const c = css[k]
|
|
141
|
+
if (c === '/' && css[k + 1] === '*') { const e = css.indexOf('*/', k + 2); k = e === -1 ? n : e + 2; continue }
|
|
142
|
+
if (c === '{') d++
|
|
143
|
+
else if (c === '}') { d--; if (d === 0) break }
|
|
144
|
+
k++
|
|
145
|
+
}
|
|
146
|
+
const body = css.slice(bodyStart, k)
|
|
147
|
+
i = k + 1
|
|
148
|
+
const trimmed = prelude.trim()
|
|
149
|
+
if (trimmed.startsWith('@')) {
|
|
150
|
+
const atName = trimmed.split(/[\s({]/)[0]
|
|
151
|
+
if (atName === '@font-face') {
|
|
152
|
+
out += prelude + '{' + rewriteFontFace(body) + '}'
|
|
153
|
+
} else if (atName === '@keyframes' || atName === '@-webkit-keyframes') {
|
|
154
|
+
out += prelude + '{' + body + '}'
|
|
155
|
+
} else {
|
|
156
|
+
// @media / @layer / @supports / @scope — recurse into inner rules.
|
|
157
|
+
out += prelude + '{' + transformBlock(body) + '}'
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
out += scopeSelectorList(prelude) + ' {' + body + '}'
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return out
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ---- main -------------------------------------------------------------------
|
|
167
|
+
|
|
168
|
+
function read(p) { return fs.readFileSync(p, 'utf8') }
|
|
169
|
+
|
|
170
|
+
const mirkCss = read(path.join(mirkRepo, 'mirk.css'))
|
|
171
|
+
const scopedMirk = transformBlock(mirkCss)
|
|
172
|
+
const overrides = read(path.join(root, 'src', 'theme', 'pixel-quiet.overrides.css'))
|
|
173
|
+
|
|
174
|
+
const banner =
|
|
175
|
+
'/* GENERATED by scripts/build-theme.js from mirk-interface/mirk.css — DO NOT EDIT.\n' +
|
|
176
|
+
' Source of truth: mirk-interface/mirk.css + src/theme/pixel-quiet.overrides.css.\n' +
|
|
177
|
+
' Regenerate with: npm run build:theme */\n\n'
|
|
178
|
+
|
|
179
|
+
const themeOut =
|
|
180
|
+
banner +
|
|
181
|
+
'/* ===== mirk-interface@' + MIRK_VERSION + ', scoped to .hcms-shell ===== */\n' +
|
|
182
|
+
scopedMirk.trim() + '\n\n' +
|
|
183
|
+
'/* ===== pixel-quiet overrides (hypercms-owned) ===== */\n' +
|
|
184
|
+
overrides.trim() + '\n'
|
|
185
|
+
|
|
186
|
+
fs.writeFileSync(path.join(root, 'src', 'theme.generated.css'), themeOut, 'utf8')
|
|
187
|
+
console.log('✓ wrote src/theme.generated.css (' + themeOut.length + ' bytes)')
|
|
188
|
+
|
|
189
|
+
// Vendor the mirk.js delegated runtime so the bundle can import it.
|
|
190
|
+
const vendorDir = path.join(root, 'src', 'vendor')
|
|
191
|
+
fs.mkdirSync(vendorDir, { recursive: true })
|
|
192
|
+
const mirkJs = read(path.join(mirkRepo, 'mirk.js'))
|
|
193
|
+
const vendorBanner =
|
|
194
|
+
'/* VENDORED from mirk-interface/mirk.js — DO NOT EDIT. Regenerate: npm run build:theme */\n'
|
|
195
|
+
// Guard so this is import-safe in non-browser realms (e.g. Node tests that load
|
|
196
|
+
// hypercms before a jsdom window exists). In the browser the guard is a no-op.
|
|
197
|
+
const guarded =
|
|
198
|
+
vendorBanner +
|
|
199
|
+
'if (typeof window !== "undefined" && typeof document !== "undefined") {\n' +
|
|
200
|
+
mirkJs.trimEnd() + '\n' +
|
|
201
|
+
'}\n'
|
|
202
|
+
fs.writeFileSync(path.join(vendorDir, 'mirk.vendor.js'), guarded, 'utf8')
|
|
203
|
+
console.log('✓ wrote src/vendor/mirk.vendor.js')
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Can the inline view hang a control on this page element right now?
|
|
2
|
+
//
|
|
3
|
+
// Deliberately a question about the CURRENT state, never a cached verdict. A
|
|
4
|
+
// target inside a closed <details> or an inactive tab answers false now and
|
|
5
|
+
// true the moment the page reveals it, which is why the inline view re-runs
|
|
6
|
+
// this on every visibility change instead of classifying once at open.
|
|
7
|
+
//
|
|
8
|
+
// The area floor is not cosmetic padding and it is not redundant with
|
|
9
|
+
// IntersectionObserver. Measured in Chrome: an empty inline <span> reports
|
|
10
|
+
// isIntersecting true, ratio 1, on a zero-width box. Without the floor that
|
|
11
|
+
// draws a camera handle on a 0px target.
|
|
12
|
+
export const MIN_ANCHOR_PX = 8
|
|
13
|
+
|
|
14
|
+
// [cms-template] is the hidden list seed; [data-hcms-shell] is the CMS's own
|
|
15
|
+
// chrome, which both the sidebar panel and the inline host carry. Neither is
|
|
16
|
+
// page content, so neither ever gets a control.
|
|
17
|
+
const NEVER_ANCHOR = '[cms-template], [data-hcms-shell]'
|
|
18
|
+
|
|
19
|
+
export function isAnchorable(el) {
|
|
20
|
+
if (!el || typeof el.getBoundingClientRect !== 'function') return false
|
|
21
|
+
if (typeof el.closest === 'function' && el.closest(NEVER_ANCHOR)) return false
|
|
22
|
+
const r = el.getBoundingClientRect()
|
|
23
|
+
return r.width >= MIN_ANCHOR_PX && r.height >= MIN_ANCHOR_PX
|
|
24
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { engine } from 'hyper-html-api'
|
|
2
|
+
import { fromString as pathFromString, getRuleAtPath } from './path.js'
|
|
3
|
+
import { rowIdentityHooks } from './row-identity.js'
|
|
4
|
+
|
|
5
|
+
const ENGINE_OPTS = { skip: '[data-hcms-shell]', templateAttr: 'cms-template' }
|
|
6
|
+
|
|
7
|
+
// Engine reads/writes against pageRoot pass skip + templateAttr so the
|
|
8
|
+
// engine never traverses into the form's own DOM, and so [cms-template]
|
|
9
|
+
// nodes are treated as seed templates (not real data). Scalar applies skip
|
|
10
|
+
// snapshot — string user input can't produce a ShapeMismatch and the focused
|
|
11
|
+
// input must survive every keystroke.
|
|
12
|
+
//
|
|
13
|
+
// Structural applies (add/remove/reorder) can hit EmptyListInsert and other
|
|
14
|
+
// engine errors. We snapshot just the affected array container's slot so
|
|
15
|
+
// rollback restores only the failing subtree; listeners and state elsewhere
|
|
16
|
+
// on the page survive.
|
|
17
|
+
export function applyWithRollback(pageRoot, pageRules, newData, options = {}) {
|
|
18
|
+
const { observerHandle, shellRoot, structural, structuralPath, formRoot } = options
|
|
19
|
+
// The form's own row elements are the only stable handle across an apply, so
|
|
20
|
+
// when we have the form we let it say which page row each item is. Without it
|
|
21
|
+
// the engine matches by content, which is exact except between two rows that
|
|
22
|
+
// read identically.
|
|
23
|
+
const engineOpts = formRoot ? { ...ENGINE_OPTS, ...rowIdentityHooks(formRoot) } : ENGINE_OPTS
|
|
24
|
+
observerHandle?.pause?.()
|
|
25
|
+
try {
|
|
26
|
+
if (!structural) {
|
|
27
|
+
try {
|
|
28
|
+
engine.apply(pageRoot, pageRules, newData, engineOpts)
|
|
29
|
+
return { ok: true }
|
|
30
|
+
} catch (err) {
|
|
31
|
+
return { ok: false, error: err }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Structural path: snapshot the smallest container that the change
|
|
36
|
+
// touches, falling back to non-shell page content if we can't resolve
|
|
37
|
+
// a specific container.
|
|
38
|
+
const target = resolveStructuralTarget(pageRoot, pageRules, structuralPath)
|
|
39
|
+
const subtreeSnapshot = target ? captureChildren(target) : null
|
|
40
|
+
const pageSnapshot = target ? null : captureNonShellSnapshot(pageRoot, shellRoot)
|
|
41
|
+
try {
|
|
42
|
+
engine.apply(pageRoot, pageRules, newData, engineOpts)
|
|
43
|
+
return { ok: true }
|
|
44
|
+
} catch (err) {
|
|
45
|
+
if (subtreeSnapshot) {
|
|
46
|
+
restoreChildren(target, subtreeSnapshot)
|
|
47
|
+
} else if (pageSnapshot) {
|
|
48
|
+
restoreNonShellSnapshot(pageRoot, shellRoot, pageSnapshot)
|
|
49
|
+
}
|
|
50
|
+
return { ok: false, error: err }
|
|
51
|
+
}
|
|
52
|
+
} finally {
|
|
53
|
+
observerHandle?.resume?.()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Walk pageRules along structuralPath to find the array rule that the change
|
|
58
|
+
// targets, then ask the engine to locate its matching container in pageRoot.
|
|
59
|
+
// Returns the live container element (so its child cards can be snapshotted),
|
|
60
|
+
// or null if the path doesn't resolve to a single array container.
|
|
61
|
+
function resolveStructuralTarget(pageRoot, pageRules, structuralPath) {
|
|
62
|
+
if (!structuralPath || !pageRoot) return null
|
|
63
|
+
const segs = pathFromString(structuralPath)
|
|
64
|
+
// Walk to the array rule. Add/remove paths can be either the array itself
|
|
65
|
+
// ("products") or an item path ("products.0"); both resolve to the same
|
|
66
|
+
// array container.
|
|
67
|
+
let arrPath = []
|
|
68
|
+
let node = pageRules
|
|
69
|
+
for (const seg of segs) {
|
|
70
|
+
if (typeof node === 'string' || node == null) break
|
|
71
|
+
if (Array.isArray(node)) {
|
|
72
|
+
// We're at an array — this segment is the index; stop walking, we have
|
|
73
|
+
// the container.
|
|
74
|
+
break
|
|
75
|
+
}
|
|
76
|
+
if (typeof node === 'object' && seg in node) {
|
|
77
|
+
arrPath.push(seg)
|
|
78
|
+
node = node[seg]
|
|
79
|
+
if (Array.isArray(node) || (typeof node === 'string' && node.endsWith('[]'))) break
|
|
80
|
+
} else {
|
|
81
|
+
return null
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!Array.isArray(node) && !(typeof node === 'string' && node.endsWith('[]'))) return null
|
|
85
|
+
// arrPath is the prefix that leads to the array. Walk pageRoot via the
|
|
86
|
+
// engine using a stripped pageRules so we land on the container.
|
|
87
|
+
return resolveContainerByPath(pageRoot, pageRules, arrPath)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Walk pageRoot by following each parent rule's selector until we reach the
|
|
91
|
+
// array container. For paths with no parent (root-level array), use pageRoot
|
|
92
|
+
// itself; otherwise descend through each named rule.
|
|
93
|
+
function resolveContainerByPath(pageRoot, pageRules, arrPath) {
|
|
94
|
+
if (arrPath.length === 0) return null
|
|
95
|
+
let ctx = pageRoot
|
|
96
|
+
let rule = pageRules
|
|
97
|
+
for (let i = 0; i < arrPath.length; i++) {
|
|
98
|
+
const key = arrPath[i]
|
|
99
|
+
if (!rule || typeof rule !== 'object' || Array.isArray(rule)) return null
|
|
100
|
+
const sub = rule[key]
|
|
101
|
+
if (sub == null) return null
|
|
102
|
+
if (i === arrPath.length - 1) {
|
|
103
|
+
// Final step: the array's selector resolves to ITEMS, not the
|
|
104
|
+
// container. Walk to the items' shared parent so the snapshot covers
|
|
105
|
+
// the whole list (cards/scalars siblings). Without this, an object
|
|
106
|
+
// array's selector like `.product` returns the first item, and
|
|
107
|
+
// rollback restores only that item's children — leaving any earlier
|
|
108
|
+
// list-level insert/reorder mutated.
|
|
109
|
+
if (Array.isArray(sub)) {
|
|
110
|
+
const [selector] = sub
|
|
111
|
+
const first = ctx.querySelector?.(selector)
|
|
112
|
+
return first?.parentElement || null
|
|
113
|
+
}
|
|
114
|
+
if (typeof sub === 'string' && sub.endsWith('[]')) {
|
|
115
|
+
const selector = sub.slice(0, -2)
|
|
116
|
+
const first = ctx.querySelector?.(selector)
|
|
117
|
+
return first?.parentElement || null
|
|
118
|
+
}
|
|
119
|
+
return null
|
|
120
|
+
}
|
|
121
|
+
// Intermediate: must be an object subrule. Engine extract treats objects
|
|
122
|
+
// as same-ctx, so we don't narrow ctx.
|
|
123
|
+
rule = sub
|
|
124
|
+
}
|
|
125
|
+
return null
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function captureChildren(parent) {
|
|
129
|
+
const clones = []
|
|
130
|
+
for (const child of Array.from(parent.childNodes)) {
|
|
131
|
+
clones.push(child.cloneNode(true))
|
|
132
|
+
}
|
|
133
|
+
return clones
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function restoreChildren(parent, clones) {
|
|
137
|
+
while (parent.firstChild) parent.removeChild(parent.firstChild)
|
|
138
|
+
for (const clone of clones) parent.appendChild(clone)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function captureNonShellSnapshot(pageRoot, shellRoot) {
|
|
142
|
+
const clones = []
|
|
143
|
+
for (const child of Array.from(pageRoot.childNodes)) {
|
|
144
|
+
if (child === shellRoot || (shellRoot && child.contains?.(shellRoot))) continue
|
|
145
|
+
clones.push(child.cloneNode(true))
|
|
146
|
+
}
|
|
147
|
+
return clones
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function restoreNonShellSnapshot(pageRoot, shellRoot, clones) {
|
|
151
|
+
for (const child of Array.from(pageRoot.childNodes)) {
|
|
152
|
+
if (child === shellRoot || (shellRoot && child.contains?.(shellRoot))) continue
|
|
153
|
+
pageRoot.removeChild(child)
|
|
154
|
+
}
|
|
155
|
+
const host = findShellHostChild(pageRoot, shellRoot)
|
|
156
|
+
for (const clone of clones) {
|
|
157
|
+
pageRoot.insertBefore(clone, host || null)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function findShellHostChild(pageRoot, shellRoot) {
|
|
162
|
+
if (!shellRoot) return null
|
|
163
|
+
for (const child of Array.from(pageRoot.childNodes)) {
|
|
164
|
+
if (child === shellRoot || child.contains?.(shellRoot)) return child
|
|
165
|
+
}
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { shapeKindOf } from './templates.js'
|
|
2
|
+
|
|
3
|
+
const PREFIX = '[hypercms]'
|
|
4
|
+
|
|
5
|
+
export function warnUnmatchedTemplates(doc, pageRules) {
|
|
6
|
+
if (!doc || !doc.querySelectorAll || !pageRules) return
|
|
7
|
+
const validKeys = collectValidKeys(pageRules)
|
|
8
|
+
const tpls = doc.querySelectorAll('template[data-hcms-tpl]')
|
|
9
|
+
tpls.forEach((tpl) => {
|
|
10
|
+
const key = tpl.getAttribute('data-hcms-tpl')
|
|
11
|
+
if (!key) return
|
|
12
|
+
if (key.startsWith('@')) return
|
|
13
|
+
if (!validKeys.has(key)) {
|
|
14
|
+
console.warn(`${PREFIX} template "${key}" doesn't match any rule path; ignored`)
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function collectValidKeys(pageRules) {
|
|
20
|
+
const keys = new Set()
|
|
21
|
+
walk([], pageRules)
|
|
22
|
+
return keys
|
|
23
|
+
|
|
24
|
+
function walk(pathArr, rule) {
|
|
25
|
+
const pathStr = pathArr.join('.')
|
|
26
|
+
const wildcardKey = pathArr.map((s) => (typeof s === 'number' ? '*' : s)).join('.')
|
|
27
|
+
if (pathStr) keys.add(pathStr)
|
|
28
|
+
if (wildcardKey) keys.add(wildcardKey)
|
|
29
|
+
const shape = shapeKindOf(rule)
|
|
30
|
+
if (shape === 'object') {
|
|
31
|
+
for (const [k, child] of Object.entries(rule)) walk([...pathArr, k], child)
|
|
32
|
+
} else if (shape === 'object-array' || shape === 'scalar-array') {
|
|
33
|
+
const itemPath = [...pathArr, '*']
|
|
34
|
+
const itemWildcardKey = itemPath.map((s) => (typeof s === 'number' ? '*' : s)).join('.')
|
|
35
|
+
keys.add(itemWildcardKey)
|
|
36
|
+
if (shape === 'object-array') {
|
|
37
|
+
const itemRule = rule[1]
|
|
38
|
+
if (itemRule && typeof itemRule === 'object' && !Array.isArray(itemRule)) {
|
|
39
|
+
for (const [k, child] of Object.entries(itemRule)) walk([...itemPath, k], child)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// Post-mount field enhancements + the rich-text rule upgrade.
|
|
2
|
+
//
|
|
3
|
+
// Bare scalar rules bind textContent, which flattens inline HTML (links,
|
|
4
|
+
// bold, code) on extract and destroys it on the first apply. When the bound
|
|
5
|
+
// page element actually contains child elements, the rule is upgraded to
|
|
6
|
+
// @innerHTML so the round-trip preserves markup and the form renders the
|
|
7
|
+
// @richtext component (a contenteditable surface, richclay-powered when the
|
|
8
|
+
// host page ships richclay). Explicit @prop rules, array rules, and rules
|
|
9
|
+
// whose element holds only text are left untouched. Hosts opt out with
|
|
10
|
+
// cms.open({ richText: false }).
|
|
11
|
+
|
|
12
|
+
import { BOUND_ATTR, resolveRichClay } from './richclay-bridge.js'
|
|
13
|
+
import { ruleAttrIndex } from 'hyper-html-api/engine'
|
|
14
|
+
|
|
15
|
+
export function upgradeRichTextRules(rules, pageRoot) {
|
|
16
|
+
if (!pageRoot || rules == null) return rules
|
|
17
|
+
return walk(rules)
|
|
18
|
+
|
|
19
|
+
function walk(rule) {
|
|
20
|
+
if (typeof rule === 'string') {
|
|
21
|
+
if (rule.endsWith('[]')) return rule
|
|
22
|
+
if (ruleAttrIndex(rule) !== -1) return rule
|
|
23
|
+
let el = null
|
|
24
|
+
try {
|
|
25
|
+
el = pageRoot.querySelector(rule)
|
|
26
|
+
} catch (_) {
|
|
27
|
+
return rule
|
|
28
|
+
}
|
|
29
|
+
return el && el.children.length > 0 ? rule + '@innerHTML' : rule
|
|
30
|
+
}
|
|
31
|
+
// Array rules ([itemSelector, shape]) scope their inner selectors per
|
|
32
|
+
// item; a document-level querySelector can't answer "does THIS item's
|
|
33
|
+
// element hold markup", so array subtrees are never upgraded.
|
|
34
|
+
if (Array.isArray(rule)) return rule
|
|
35
|
+
if (rule && typeof rule === 'object') {
|
|
36
|
+
const out = Object.create(null)
|
|
37
|
+
for (const [k, v] of Object.entries(rule)) out[k] = walk(v)
|
|
38
|
+
return out
|
|
39
|
+
}
|
|
40
|
+
return rule
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// The inline view's upgrade. Identical to the one above for a scalar or an
|
|
45
|
+
// object rule, and different for the one case that one deliberately refuses:
|
|
46
|
+
// the rules inside an array.
|
|
47
|
+
//
|
|
48
|
+
// The narrow version cannot answer "does THIS row's element hold markup" from a
|
|
49
|
+
// document-level querySelector, so it leaves array subtrees alone. Here the item
|
|
50
|
+
// elements are resolved first, so the question IS answerable — once per rule
|
|
51
|
+
// rather than once per row, because the rule language has no per-row rule. ANY
|
|
52
|
+
// row holding markup upgrades the rule for every row, and that costs nothing:
|
|
53
|
+
// @innerHTML round-trips plain text unchanged.
|
|
54
|
+
//
|
|
55
|
+
// It matters because the inline view binds rich text to the row element itself.
|
|
56
|
+
// A row left on textContent loses its links and its bold on the first commit.
|
|
57
|
+
export function upgradeInlineTextRules(rules, pageRoot) {
|
|
58
|
+
if (!pageRoot || rules == null) return rules
|
|
59
|
+
return walk(rules, [pageRoot])
|
|
60
|
+
|
|
61
|
+
function walk(rule, contexts) {
|
|
62
|
+
if (typeof rule === 'string') {
|
|
63
|
+
if (rule.endsWith('[]')) return rule
|
|
64
|
+
if (ruleAttrIndex(rule) !== -1) return rule
|
|
65
|
+
return contexts.some((ctx) => holdsMarkup(ctx, rule)) ? rule + '@innerHTML' : rule
|
|
66
|
+
}
|
|
67
|
+
if (Array.isArray(rule)) {
|
|
68
|
+
const [selector, shape] = rule
|
|
69
|
+
if (typeof selector !== 'string' || !selector) return rule
|
|
70
|
+
const items = queryAll(pageRoot, selector)
|
|
71
|
+
if (!items.length) return rule
|
|
72
|
+
return [selector, walk(shape, items)]
|
|
73
|
+
}
|
|
74
|
+
if (rule && typeof rule === 'object') {
|
|
75
|
+
const out = Object.create(null)
|
|
76
|
+
for (const [k, v] of Object.entries(rule)) out[k] = walk(v, contexts)
|
|
77
|
+
return out
|
|
78
|
+
}
|
|
79
|
+
return rule
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function holdsMarkup(context, selector) {
|
|
84
|
+
let el = null
|
|
85
|
+
try {
|
|
86
|
+
el = context.querySelector(selector)
|
|
87
|
+
} catch (_) {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
if (!el) return false
|
|
91
|
+
// An element hypercms has an editor on cannot answer this from its live DOM.
|
|
92
|
+
// Squire wraps the content of a block it binds in a <div>, so a plain
|
|
93
|
+
// paragraph grows a child the instant someone clicks it, and reading that
|
|
94
|
+
// back as author markup upgrades the rule to @innerHTML and turns a
|
|
95
|
+
// plain-text field into a rich-text one just by being clicked. The marker
|
|
96
|
+
// carries the verdict from before the editor arrived, which is the only
|
|
97
|
+
// moment the question had an honest answer. Measured in Chrome: the wrapper
|
|
98
|
+
// lands at t+0 and the upgrade followed on the next observer batch.
|
|
99
|
+
if (el.hasAttribute(BOUND_ATTR)) return el.getAttribute(BOUND_ATTR) === 'rich'
|
|
100
|
+
return el.children.length > 0
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function queryAll(root, selector) {
|
|
104
|
+
try {
|
|
105
|
+
return [...root.querySelectorAll(selector)]
|
|
106
|
+
} catch (_) {
|
|
107
|
+
return []
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Grow a form textarea to fit its content. Browsers with `field-sizing:
|
|
112
|
+
// content` handle this in CSS (the theme sets it); everywhere else the
|
|
113
|
+
// height is pinned to scrollHeight on populate and on every input.
|
|
114
|
+
export function autosizeTextarea(el) {
|
|
115
|
+
if (!el || el.tagName !== 'TEXTAREA') return
|
|
116
|
+
const win = el.ownerDocument.defaultView || (typeof window !== 'undefined' ? window : null)
|
|
117
|
+
if (win && win.CSS && win.CSS.supports && win.CSS.supports('field-sizing: content')) return
|
|
118
|
+
el.style.height = 'auto'
|
|
119
|
+
el.style.height = el.scrollHeight + 'px'
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Runs after any form (or form fragment) lands in the live DOM: sizes the
|
|
123
|
+
// autosize fallback and mounts richclay on rich-text surfaces when the host
|
|
124
|
+
// page ships it (window.richclay / window.hyperclay.RichClay). Without
|
|
125
|
+
// richclay the surface stays a plain contenteditable bound via @innerHTML,
|
|
126
|
+
// which still round-trips markup — richclay only adds the editing chrome.
|
|
127
|
+
//
|
|
128
|
+
// `formRichText` is the view's, read off view.enhanceFormRichText. The inline
|
|
129
|
+
// view passes false: its form fields are never focused (rich text is edited on
|
|
130
|
+
// the page element itself), and each instance installs five document-level
|
|
131
|
+
// capture listeners that test event.target against their element on every
|
|
132
|
+
// keydown, beforeinput, cut, paste and drop. Twenty rich fields is a hundred
|
|
133
|
+
// dead listeners. The autosize pass runs either way — the popover shows those
|
|
134
|
+
// same fields for every non-text target.
|
|
135
|
+
export function enhanceFields(root, doc, formRichText = true) {
|
|
136
|
+
if (!root || !root.querySelectorAll) return
|
|
137
|
+
root.querySelectorAll('textarea[data-hcms-field]').forEach(autosizeTextarea)
|
|
138
|
+
if (formRichText === false) return
|
|
139
|
+
|
|
140
|
+
const win = (doc && doc.defaultView) || (typeof window !== 'undefined' ? window : null)
|
|
141
|
+
const RichClay = resolveRichClay(win)
|
|
142
|
+
if (!RichClay) return
|
|
143
|
+
|
|
144
|
+
root.querySelectorAll('[contenteditable][data-hcms-field]').forEach((el) => {
|
|
145
|
+
if (el.__hcmsRichclay) return
|
|
146
|
+
let editor
|
|
147
|
+
try {
|
|
148
|
+
// hyperclay:false keeps the form field out of the page's save/undo
|
|
149
|
+
// machinery (page writes go through commit) and activates the editor
|
|
150
|
+
// regardless of the host's edit-mode signal.
|
|
151
|
+
editor = new RichClay(el, {
|
|
152
|
+
inline: true,
|
|
153
|
+
hyperclay: false,
|
|
154
|
+
toolbar: ['bold', 'italic', 'link', 'undo', 'redo'],
|
|
155
|
+
})
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.warn('[hypercms] richclay activation failed; field stays plain contenteditable', err)
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
el.__hcmsRichclay = editor
|
|
161
|
+
// Toolbar commands mutate the DOM through squire, which doesn't always
|
|
162
|
+
// fire a native input event; mirror squire's own input signal so the
|
|
163
|
+
// form's delegated listener commits the change. Duplicate events are
|
|
164
|
+
// harmless — commits are fingerprinted.
|
|
165
|
+
const squire = editor && editor.squire
|
|
166
|
+
if (squire && typeof squire.addEventListener === 'function') {
|
|
167
|
+
squire.addEventListener('input', () => {
|
|
168
|
+
const Ev = (win && win.Event) || Event
|
|
169
|
+
el.dispatchEvent(new Ev('input', { bubbles: true }))
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
}
|