@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,10 @@
|
|
|
1
|
+
export function scaffold(shape) {
|
|
2
|
+
if (typeof shape === 'string') return shape.endsWith('[]') ? [] : ''
|
|
3
|
+
if (Array.isArray(shape)) return []
|
|
4
|
+
if (typeof shape === 'object' && shape !== null) {
|
|
5
|
+
const out = {}
|
|
6
|
+
for (const [k, v] of Object.entries(shape)) out[k] = scaffold(v)
|
|
7
|
+
return out
|
|
8
|
+
}
|
|
9
|
+
return ''
|
|
10
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// The session core: everything an editing session is, independent of the chrome
|
|
2
|
+
// that renders it. Rule resolution, the ctx object every module reads, the first
|
|
3
|
+
// extract, the observer / undo / live-sync subscriptions, the global sortable
|
|
4
|
+
// wiring, event dispatch, and one idempotent teardown. A view (src/views/*)
|
|
5
|
+
// supplies the DOM; the session owns the state and the page.
|
|
6
|
+
|
|
7
|
+
import { engine } from 'hyper-html-api'
|
|
8
|
+
import { injectDefaults, injectComponents } from './templates.js'
|
|
9
|
+
import { deriveFormRules } from './form-rules.js'
|
|
10
|
+
import { warnUnmatchedTemplates } from './diagnostics.js'
|
|
11
|
+
import { findUnresolved, stripReadOnly } from './unresolved.js'
|
|
12
|
+
import { rowIdentitySeeder } from './row-identity.js'
|
|
13
|
+
import {
|
|
14
|
+
commit,
|
|
15
|
+
commitWithUndo,
|
|
16
|
+
suppressUndo,
|
|
17
|
+
extractFormData,
|
|
18
|
+
stableStringify,
|
|
19
|
+
restampAllSiblings,
|
|
20
|
+
coerceBooleans,
|
|
21
|
+
} from './events.js'
|
|
22
|
+
import { installObserver } from './refresh.js'
|
|
23
|
+
import { platform, onPlatformEvent, LIVESYNC_APPLIED } from './platform.js'
|
|
24
|
+
|
|
25
|
+
const ENGINE_OPTS = { skip: '[data-hcms-shell]', templateAttr: 'cms-template' }
|
|
26
|
+
|
|
27
|
+
export const state = {
|
|
28
|
+
isOpen: false,
|
|
29
|
+
ctx: null,
|
|
30
|
+
opts: null,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Build the session for one open(): resolve the rules, hand them to the view for
|
|
34
|
+
// its own preparation, derive the form schema, and take the first read of the
|
|
35
|
+
// page. The view is not mounted yet — ctx reads its DOM handles lazily, so the
|
|
36
|
+
// mount can stay inside open()'s try block.
|
|
37
|
+
export function createSession({ view, doc, pageRoot, opts = {}, onCloseRequested, onViewRequested }) {
|
|
38
|
+
// Resolve rules via the union: an explicit rules object, a token string, or
|
|
39
|
+
// the default token "cms". findRules is document-scoped, so a head-mounted
|
|
40
|
+
// rules tag is found even though pageRoot defaults to <body>.
|
|
41
|
+
const source = opts.rules !== undefined ? opts.rules : 'cms'
|
|
42
|
+
const found = engine.findRules(doc, source)
|
|
43
|
+
if (!found) {
|
|
44
|
+
const what = typeof source === 'string' ? `data-rules-name~="${source}"` : 'the provided rules object'
|
|
45
|
+
throw new Error(`hypercms: no rules found for ${what}`)
|
|
46
|
+
}
|
|
47
|
+
// The view's rule seam. The sidebar applies the rich-text upgrade (default on):
|
|
48
|
+
// bare scalar rules whose page element contains child elements are rebound
|
|
49
|
+
// through @innerHTML so links and inline formatting survive the round-trip, and
|
|
50
|
+
// their form fields render the @richtext component.
|
|
51
|
+
const pageRules = view.prepareRules(found.rules)
|
|
52
|
+
const rulesTagNode = found.tagNode
|
|
53
|
+
|
|
54
|
+
injectDefaults(doc)
|
|
55
|
+
injectComponents(doc, pageRules)
|
|
56
|
+
warnUnmatchedTemplates(doc, pageRules)
|
|
57
|
+
const formRules = deriveFormRules(pageRules, doc)
|
|
58
|
+
// The write half of the rules; see stripReadOnly. The form and every extract
|
|
59
|
+
// keep the full tree.
|
|
60
|
+
const writeRules = stripReadOnly(pageRules)
|
|
61
|
+
// Runs before the first extract so a rule with invalid CSS names its field
|
|
62
|
+
// instead of throwing a bare SyntaxError out of querySelectorAll.
|
|
63
|
+
const unresolved = findUnresolved(pageRoot, pageRules)
|
|
64
|
+
// Bind each form row to the page row it stands for while the two are still
|
|
65
|
+
// known to correspond, which is now: the form the view builds comes from
|
|
66
|
+
// exactly this read. Without it the first structural operation of a session has
|
|
67
|
+
// no identity to go on and falls back to content matching.
|
|
68
|
+
const seeder = rowIdentitySeeder()
|
|
69
|
+
const data = coerceBooleans(engine.extract(pageRoot, pageRules, { ...ENGINE_OPTS, ...seeder.hooks }), pageRules)
|
|
70
|
+
|
|
71
|
+
const ctx = {
|
|
72
|
+
doc,
|
|
73
|
+
pageRoot,
|
|
74
|
+
pageRules,
|
|
75
|
+
writeRules,
|
|
76
|
+
formRules,
|
|
77
|
+
rulesTagNode,
|
|
78
|
+
rulesSource: source,
|
|
79
|
+
richText: view.richText,
|
|
80
|
+
view,
|
|
81
|
+
seeder,
|
|
82
|
+
initialData: data,
|
|
83
|
+
get formRoot() { return view.formRoot },
|
|
84
|
+
get shellRoot() { return view.root },
|
|
85
|
+
get errorEl() { return view.errorEl },
|
|
86
|
+
get noticeEl() { return view.noticeEl },
|
|
87
|
+
unresolved,
|
|
88
|
+
lastTwinSignature: null,
|
|
89
|
+
lastFingerprint: null,
|
|
90
|
+
lastData: null,
|
|
91
|
+
observerHandle: null,
|
|
92
|
+
undoUnsub: null,
|
|
93
|
+
livesyncUnsub: null,
|
|
94
|
+
onChange: opts.onChange,
|
|
95
|
+
onError: opts.onError,
|
|
96
|
+
confirmRemove: opts.confirmRemove,
|
|
97
|
+
previouslyFocused: doc.activeElement,
|
|
98
|
+
dispatch(name, detail) {
|
|
99
|
+
const Ctor = (doc.defaultView && doc.defaultView.CustomEvent) || (typeof CustomEvent !== 'undefined' ? CustomEvent : null)
|
|
100
|
+
if (!Ctor) return
|
|
101
|
+
// Every event carries the page it belongs to and which view is rendering
|
|
102
|
+
// it, so a document-level listener can tell a sidebar session from an
|
|
103
|
+
// inline one without inspecting the DOM. Merged into the caller's detail
|
|
104
|
+
// rather than replacing it: hcms:change still carries .data, hcms:error
|
|
105
|
+
// still carries .error.
|
|
106
|
+
const payload = { ...(detail || {}), pageRoot, view: view.name }
|
|
107
|
+
const ev = new Ctor(name, { bubbles: true, cancelable: name === 'hcms:change', detail: payload })
|
|
108
|
+
// A full-document morph (live sync, a version restore) can replace the
|
|
109
|
+
// view root between mount and dispatch. Falling back to the page keeps the
|
|
110
|
+
// event on the document instead of firing it into a detached tree where no
|
|
111
|
+
// listener will ever see it.
|
|
112
|
+
const target = view.root && view.root.isConnected !== false ? view.root : pageRoot
|
|
113
|
+
target.dispatchEvent(ev)
|
|
114
|
+
},
|
|
115
|
+
onCloseRequested,
|
|
116
|
+
// How a view asks to be rendered as a different one. The switch runs through
|
|
117
|
+
// open({ view }), which carries this session's options across it, so the
|
|
118
|
+
// request changes the presentation and not the session.
|
|
119
|
+
onViewRequested,
|
|
120
|
+
}
|
|
121
|
+
ctx.updateFingerprint = () => {
|
|
122
|
+
ctx.lastFingerprint = stableStringify(extractFormData(ctx))
|
|
123
|
+
}
|
|
124
|
+
view.ctx = ctx
|
|
125
|
+
return ctx
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Everything that outlives the mount: the fingerprint the commit path compares
|
|
129
|
+
// against, and the three external subscriptions plus the global sortable hook.
|
|
130
|
+
// Runs after the view is mounted, so a throw here is caught by open() and routed
|
|
131
|
+
// through teardownSession.
|
|
132
|
+
export function startSession(ctx) {
|
|
133
|
+
ctx.updateFingerprint()
|
|
134
|
+
|
|
135
|
+
ctx.observerHandle = installObserver({
|
|
136
|
+
onRefresh: (changes) => ctx.view.refresh('observer', changes),
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// Undo/redo is a deliberate local action (unlike livesync or in-flight typing),
|
|
140
|
+
// so the focused form field SHOULD snap to the reverted value. The observer above
|
|
141
|
+
// is source-blind, so subscribe to the undo scope and force a non-ignoring refresh.
|
|
142
|
+
// Fires synchronously before the debounced observer refresh, which then no-ops on
|
|
143
|
+
// the active field. Guarded so it degrades to today's behavior when undo isn't loaded.
|
|
144
|
+
const u = platform('undo')
|
|
145
|
+
if (u && typeof u.on === 'function') {
|
|
146
|
+
const onRevert = () => {
|
|
147
|
+
if (state.ctx !== ctx) return
|
|
148
|
+
resyncForm(ctx, 'undo')
|
|
149
|
+
// A reverted change the consumer persists through onChange (e.g. the
|
|
150
|
+
// collection dashboard PUTs the record, not the page) would otherwise lag
|
|
151
|
+
// the undo: refreshForm re-syncs the form but never fires onChange, and a
|
|
152
|
+
// commit() here would be fingerprint-skipped (refreshForm already updated
|
|
153
|
+
// it). Extract the reverted state from the PAGE (the source of truth after
|
|
154
|
+
// an undo/redo; the form can lag a morph) and fire onChange directly, but
|
|
155
|
+
// only when it actually changed — guards spurious PUTs on undo/redo of
|
|
156
|
+
// unrelated edits elsewhere on the page.
|
|
157
|
+
const data = coerceBooleans(
|
|
158
|
+
engine.extract(ctx.pageRoot, ctx.pageRules, ENGINE_OPTS),
|
|
159
|
+
ctx.pageRules
|
|
160
|
+
)
|
|
161
|
+
if (stableStringify(data) !== stableStringify(ctx.lastData)) {
|
|
162
|
+
ctx.lastData = data
|
|
163
|
+
ctx.onChange?.(data, { path: '', structural: false })
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
u.on('undo', onRevert)
|
|
167
|
+
u.on('redo', onRevert)
|
|
168
|
+
ctx.undoUnsub = () => { u.off('undo', onRevert); u.off('redo', onRevert) }
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Live-sync / version-restore / any framework-applied full-document morph runs
|
|
172
|
+
// inside window.hyperclay.Mutation.pause(), which the source-blind observer
|
|
173
|
+
// above is deaf to — so without this the form stays stale after a remote edit
|
|
174
|
+
// and the next local commit re-applies the stale data, clobbering the remote
|
|
175
|
+
// change. Subscribe to the morph-applied signal live-sync emits and re-extract
|
|
176
|
+
// with ignoreActiveValue:true (preserve the user's in-progress field). Same
|
|
177
|
+
// document live-sync dispatches on; unsubscribed in teardownSession.
|
|
178
|
+
const onLivesync = () => resyncForm(ctx, 'livesync')
|
|
179
|
+
ctx.livesyncUnsub = onPlatformEvent(ctx.doc, LIVESYNC_APPLIED, onLivesync)
|
|
180
|
+
|
|
181
|
+
// Wire global sortable callback to current ctx (cleared by teardownSession).
|
|
182
|
+
globalCommitTarget.ctx = ctx
|
|
183
|
+
installGlobalSortableCommit(ctx.doc)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Re-sync the view to the page after a change hypercms did NOT originate.
|
|
187
|
+
// `reason` selects whether the field the user is currently typing in snaps:
|
|
188
|
+
// 'undo' / 'redo' — the user's own deliberate action, so the focused field
|
|
189
|
+
// SHOULD snap to the reverted value (ignoreActiveValue:false).
|
|
190
|
+
// 'livesync' — someone else's / the framework's change, so the user's
|
|
191
|
+
// in-progress focused field must NOT be yanked away
|
|
192
|
+
// (ignoreActiveValue:true). morphForm re-extracts every
|
|
193
|
+
// other field to the new page value, killing the stale-form
|
|
194
|
+
// clobber, while leaving the active field alone until blur.
|
|
195
|
+
// Both reasons route through the view's one refresh entry point.
|
|
196
|
+
function resyncForm(ctx, reason) {
|
|
197
|
+
// open() may have moved on (closed, or reopened with a new ctx) between an
|
|
198
|
+
// async morph completing and this firing.
|
|
199
|
+
if (state.ctx !== ctx) return
|
|
200
|
+
ctx.view.refresh(reason)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// The one teardown. close(), the failed-open path inside open(), and (later) a
|
|
204
|
+
// view switch all route through it; the options say only which of the three
|
|
205
|
+
// close-specific side effects apply.
|
|
206
|
+
export function teardownSession(ctx, { dispatch = true, restoreFocus = true, updateUrl = true, reason = 'close' } = {}) {
|
|
207
|
+
if (!ctx || ctx.closed) return
|
|
208
|
+
// Mark this ctx dead so any in-flight async work (e.g. an upload awaiting the
|
|
209
|
+
// host uploader) bails instead of mutating the page / firing onChange after
|
|
210
|
+
// teardown. Mirrors the state.ctx !== ctx guards on the undo/livesync paths.
|
|
211
|
+
ctx.closed = true
|
|
212
|
+
// An upload still in flight is torn down like any other subscription. The
|
|
213
|
+
// ctx.closed check above already stops it writing; this stops it running.
|
|
214
|
+
for (const controller of ctx.uploads || []) { try { controller.abort() } catch {} }
|
|
215
|
+
ctx.uploads?.clear()
|
|
216
|
+
const previouslyFocused = ctx.previouslyFocused
|
|
217
|
+
if (dispatch) ctx.dispatch('hcms:close', { reason })
|
|
218
|
+
if (updateUrl) toggleCloseParam()
|
|
219
|
+
ctx.observerHandle?.unsubscribe?.()
|
|
220
|
+
ctx.undoUnsub?.()
|
|
221
|
+
ctx.livesyncUnsub?.()
|
|
222
|
+
ctx.detachEvents?.()
|
|
223
|
+
// destroy() removes the chrome-only body classes; suppress so the inverse
|
|
224
|
+
// class removal doesn't enter the undo stack either.
|
|
225
|
+
suppressUndo(() => ctx.view.destroy())
|
|
226
|
+
clearState()
|
|
227
|
+
if (restoreFocus && typeof previouslyFocused?.focus === 'function') {
|
|
228
|
+
try { previouslyFocused.focus() } catch (_) {}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function clearState() {
|
|
233
|
+
state.isOpen = false
|
|
234
|
+
state.ctx = null
|
|
235
|
+
state.opts = null
|
|
236
|
+
globalCommitTarget.ctx = null
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const globalCommitTarget = { ctx: null }
|
|
240
|
+
|
|
241
|
+
function installGlobalSortableCommit(doc) {
|
|
242
|
+
const win = doc.defaultView || (typeof globalThis !== 'undefined' ? globalThis : null)
|
|
243
|
+
if (!win) return
|
|
244
|
+
const hypercmsCommitFn = function hypercmsCommitGlobal() {
|
|
245
|
+
const ctx = globalCommitTarget.ctx
|
|
246
|
+
if (!ctx) return
|
|
247
|
+
restampAllSiblings(ctx.formRoot)
|
|
248
|
+
// Route through commitWithUndo so a drag-reorder lands as a labeled
|
|
249
|
+
// 'Reorder' commit (not a generic idle 'Edit') and a failed apply's
|
|
250
|
+
// mutate+rollback is never recorded as a no-op commit. No-op pass-through
|
|
251
|
+
// when undo isn't loaded.
|
|
252
|
+
return commitWithUndo('Reorder', () =>
|
|
253
|
+
commit(extractFormData(ctx), { path: '', structural: true }, ctx)
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
if (typeof win.hypercmsCommit !== 'function') win.hypercmsCommit = hypercmsCommitFn
|
|
257
|
+
// Also mirror to globalThis so non-window contexts (Node tests, workers)
|
|
258
|
+
// can resolve the bare name from `new Function('hypercmsCommit()')`.
|
|
259
|
+
if (typeof globalThis !== 'undefined' && typeof globalThis.hypercmsCommit !== 'function') {
|
|
260
|
+
globalThis.hypercmsCommit = hypercmsCommitFn
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// The query param that drives ?cms=true auto-open. Closing the CMS rewrites it
|
|
265
|
+
// to cms=false (param kept) so a refresh/share of the post-close URL does not
|
|
266
|
+
// auto-reopen.
|
|
267
|
+
const AUTO_OPEN_PARAM = 'cms'
|
|
268
|
+
|
|
269
|
+
// Pure: given a location.search string, return the search string after a close.
|
|
270
|
+
// Only rewrites when cms=true is present; every other param + ordering is
|
|
271
|
+
// preserved, and a search without cms (or already cms=false) is returned
|
|
272
|
+
// unchanged so we never inject the param into a page that never carried it.
|
|
273
|
+
export function nextSearchAfterClose(search) {
|
|
274
|
+
const str = typeof search === 'string' ? search : ''
|
|
275
|
+
const qIndex = str.indexOf('?')
|
|
276
|
+
const query = qIndex === -1 ? str : str.slice(qIndex + 1)
|
|
277
|
+
if (!query) return str
|
|
278
|
+
const params = new URLSearchParams(query)
|
|
279
|
+
if (params.get(AUTO_OPEN_PARAM) !== 'true') return str
|
|
280
|
+
params.set(AUTO_OPEN_PARAM, 'false')
|
|
281
|
+
return '?' + params.toString()
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Pure: should the CMS auto-open for this location.search? Exactly 'true'.
|
|
285
|
+
export function shouldAutoOpenFromSearch(search) {
|
|
286
|
+
const str = typeof search === 'string' ? search : ''
|
|
287
|
+
const qIndex = str.indexOf('?')
|
|
288
|
+
const query = qIndex === -1 ? str : str.slice(qIndex + 1)
|
|
289
|
+
if (!query) return false
|
|
290
|
+
return new URLSearchParams(query).get(AUTO_OPEN_PARAM) === 'true'
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Rewrite ?cms=true → ?cms=false via history.replaceState (no reload, hash and
|
|
294
|
+
// every other param preserved). No-op when the param isn't present or the
|
|
295
|
+
// History API is unavailable.
|
|
296
|
+
function toggleCloseParam() {
|
|
297
|
+
if (typeof window === 'undefined' || !window.location || !window.history) return
|
|
298
|
+
if (typeof window.history.replaceState !== 'function') return
|
|
299
|
+
const current = window.location.search
|
|
300
|
+
const next = nextSearchAfterClose(current)
|
|
301
|
+
if (next === current) return
|
|
302
|
+
window.history.replaceState(window.history.state, '', next + window.location.hash)
|
|
303
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
const SHELL_STYLE_ID = 'hcms-shell-styles'
|
|
2
|
+
const SHELL_BUNDLED_FLAG = 'hcms-bundled-styles-installed'
|
|
3
|
+
// "A session of either kind is open", so a page (or the toggle) can style off
|
|
4
|
+
// open state without reaching for hcms-open, which describes only this panel's
|
|
5
|
+
// page shift and is absent for an inline session. Additive: hcms-open keeps its
|
|
6
|
+
// meaning exactly. Both views add it on mount and drop it on destroy.
|
|
7
|
+
export const SESSION_OPEN_CLASS = 'hcms-session-open'
|
|
8
|
+
const FOCUSABLE = 'a[href], area[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
9
|
+
|
|
10
|
+
const styledDocs = new WeakSet()
|
|
11
|
+
let cssText = ''
|
|
12
|
+
|
|
13
|
+
export function setShellStyles(text) {
|
|
14
|
+
cssText = text
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function markStylesBundled(doc) {
|
|
18
|
+
// Bundler emits a <style data-hcms-bundled-styles> tag and sets this so
|
|
19
|
+
// the link-based path doesn't double-install.
|
|
20
|
+
if (!doc) return
|
|
21
|
+
styledDocs.add(doc)
|
|
22
|
+
doc[SHELL_BUNDLED_FLAG] = true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function markSessionOpen(doc) {
|
|
26
|
+
doc?.body?.classList.add(SESSION_OPEN_CLASS)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function clearSessionOpen(doc) {
|
|
30
|
+
doc?.body?.classList.remove(SESSION_OPEN_CLASS)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let titleIdCounter = 0
|
|
34
|
+
|
|
35
|
+
function escapeHtml(s) {
|
|
36
|
+
return String(s).replace(/[&<>"]/g, (c) => (
|
|
37
|
+
{ '&': '&', '<': '<', '>': '>', '"': '"' }[c]
|
|
38
|
+
))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function mountShell({
|
|
42
|
+
mountTo,
|
|
43
|
+
side = 'right',
|
|
44
|
+
overlay = false,
|
|
45
|
+
showSaveButton = false,
|
|
46
|
+
title = 'Page content',
|
|
47
|
+
eyebrow = 'Edit',
|
|
48
|
+
theme = null,
|
|
49
|
+
doc,
|
|
50
|
+
}) {
|
|
51
|
+
ensureStyles(doc)
|
|
52
|
+
const titleId = `hcms-shell-title-${++titleIdCounter}`
|
|
53
|
+
const root = doc.createElement('div')
|
|
54
|
+
root.setAttribute('data-hcms-shell', '')
|
|
55
|
+
root.setAttribute('save-remove', '')
|
|
56
|
+
root.setAttribute('save-ignore', '')
|
|
57
|
+
root.setAttribute('tabindex', '-1')
|
|
58
|
+
// Dialog semantics: focus is trapped + body scrolling locked, so screen
|
|
59
|
+
// readers should announce this as a modal dialog with the shell title as
|
|
60
|
+
// its accessible name.
|
|
61
|
+
root.setAttribute('role', 'dialog')
|
|
62
|
+
root.setAttribute('aria-modal', 'true')
|
|
63
|
+
root.setAttribute('aria-labelledby', titleId)
|
|
64
|
+
// pixel-quiet is the baked-in look; an optional theme pins light/dark
|
|
65
|
+
// (otherwise the panel follows the OS via prefers-color-scheme).
|
|
66
|
+
const themeClass = theme === 'dark' ? ' dark' : theme === 'light' ? ' light' : ''
|
|
67
|
+
root.className =
|
|
68
|
+
'hcms-shell pixel-quiet hcms-panel hcms-side-' + side + (overlay ? ' hcms-overlay' : '') + themeClass
|
|
69
|
+
const titleHtml = escapeHtml(title)
|
|
70
|
+
const eyebrowHtml = escapeHtml(eyebrow)
|
|
71
|
+
// Pixel Quiet shell: a scroll-away header + in-flow Save inside .hcms-shell-body,
|
|
72
|
+
// with a condensed minibar pinned to the panel top once the header scrolls out.
|
|
73
|
+
// Close + Save are real mirk buttons. The .hcms-* hooks stay so the engine and
|
|
74
|
+
// events bind exactly as before; only the chrome shape changed.
|
|
75
|
+
// The Save button has no wiring here: [trigger-save] is the hyperclayjs save
|
|
76
|
+
// attribute — its save system (or its view-mode notice) handles the click.
|
|
77
|
+
// Standalone hosts delegate their own [trigger-save] click listener.
|
|
78
|
+
root.innerHTML = `
|
|
79
|
+
<div class="hcms-shell-minibar" aria-hidden="true">
|
|
80
|
+
<span class="hcms-shell-minibar-title">${titleHtml}</span>
|
|
81
|
+
<button type="button" class="hcms-shell-close mirk-button mirk-button--small" data-hcms-action="close" aria-label="Close">
|
|
82
|
+
<span class="mirk-button__label">×</span>
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="hcms-shell-body">
|
|
86
|
+
<header class="hcms-shell-header">
|
|
87
|
+
<div class="hcms-shell-heading">
|
|
88
|
+
<div class="hcms-shell-eyebrow">${eyebrowHtml}</div>
|
|
89
|
+
<h2 class="hcms-shell-title" id="${titleId}">${titleHtml}</h2>
|
|
90
|
+
</div>
|
|
91
|
+
<button type="button" class="hcms-shell-close mirk-button mirk-button--small" data-hcms-action="close" aria-label="Close">
|
|
92
|
+
<span class="mirk-button__label">×</span>
|
|
93
|
+
</button>
|
|
94
|
+
</header>
|
|
95
|
+
<div class="hcms-shell-notice" role="status" hidden></div>
|
|
96
|
+
<div class="hcms-shell-error" role="alert" hidden></div>
|
|
97
|
+
<div data-hcms-form-root class="hcms-form"></div>
|
|
98
|
+
<footer class="hcms-shell-footer"${showSaveButton ? '' : ' hidden'}>
|
|
99
|
+
<button type="button" class="hcms-shell-save mirk-button" trigger-save>
|
|
100
|
+
<span class="mirk-button__label">Save</span>
|
|
101
|
+
</button>
|
|
102
|
+
</footer>
|
|
103
|
+
</div>
|
|
104
|
+
`
|
|
105
|
+
|
|
106
|
+
// mountTo may be a nested element inside pageRoot. Use it as-is for the
|
|
107
|
+
// visual hierarchy; engine reads/writes pass { skip: '[data-hcms-shell]' }
|
|
108
|
+
// so the engine never traverses into the form regardless of where it's mounted.
|
|
109
|
+
const host = mountTo || doc.body
|
|
110
|
+
host.appendChild(root)
|
|
111
|
+
|
|
112
|
+
const body = doc.body
|
|
113
|
+
body.classList.add('hcms-open')
|
|
114
|
+
markSessionOpen(doc)
|
|
115
|
+
if (overlay) body.classList.add('hcms-overlay')
|
|
116
|
+
if (side === 'left') body.classList.add('hcms-side-left')
|
|
117
|
+
|
|
118
|
+
const focusTrap = installFocusTrap(root, doc)
|
|
119
|
+
const condense = installCondenseOnScroll(root)
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
root,
|
|
123
|
+
formRoot: root.querySelector('[data-hcms-form-root]'),
|
|
124
|
+
noticeEl: root.querySelector('.hcms-shell-notice'),
|
|
125
|
+
errorEl: root.querySelector('.hcms-shell-error'),
|
|
126
|
+
saveButton: root.querySelector('.hcms-shell-save'),
|
|
127
|
+
destroy() {
|
|
128
|
+
focusTrap.detach()
|
|
129
|
+
condense.detach()
|
|
130
|
+
root.remove()
|
|
131
|
+
body.classList.remove('hcms-open', 'hcms-overlay', 'hcms-side-left')
|
|
132
|
+
clearSessionOpen(doc)
|
|
133
|
+
},
|
|
134
|
+
// Re-assert the shell's out-of-subtree chrome after a full-document morph
|
|
135
|
+
// (e.g. a live-sync apply) wipes it: the stylesheet lives in <head> and the
|
|
136
|
+
// body classes live on <body>, both outside the save-ignore shell element,
|
|
137
|
+
// so hyper-morph's head-merge / class reconciliation can strip them.
|
|
138
|
+
restoreChrome() {
|
|
139
|
+
reensureStyles(doc)
|
|
140
|
+
body.classList.add('hcms-open')
|
|
141
|
+
markSessionOpen(doc)
|
|
142
|
+
if (overlay) body.classList.add('hcms-overlay')
|
|
143
|
+
if (side === 'left') body.classList.add('hcms-side-left')
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Re-inject the shell stylesheet if a morph (or anything else) removed it.
|
|
149
|
+
// Unlike ensureStyles, this does NOT trust the styledDocs WeakSet: a morph can
|
|
150
|
+
// remove the <style> tag while the WeakSet still marks the doc as "styled", so
|
|
151
|
+
// a naive ensureStyles() call would no-op. Re-check the live DOM, clear the
|
|
152
|
+
// stale mark, and let ensureStyles rebuild from cssText.
|
|
153
|
+
export function reensureStyles(doc) {
|
|
154
|
+
if (!doc) return
|
|
155
|
+
if (doc.getElementById(SHELL_STYLE_ID) ||
|
|
156
|
+
doc.querySelector('style[data-hcms-bundled-styles]')) return
|
|
157
|
+
styledDocs.delete(doc)
|
|
158
|
+
ensureStyles(doc)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function ensureStyles(doc) {
|
|
162
|
+
if (!doc) return
|
|
163
|
+
if (styledDocs.has(doc)) return
|
|
164
|
+
if (doc[SHELL_BUNDLED_FLAG]) {
|
|
165
|
+
styledDocs.add(doc)
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
if (doc.getElementById(SHELL_STYLE_ID) || doc.querySelector('style[data-hcms-bundled-styles]')) {
|
|
169
|
+
styledDocs.add(doc)
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
if (cssText) {
|
|
173
|
+
const style = doc.createElement('style')
|
|
174
|
+
style.id = SHELL_STYLE_ID
|
|
175
|
+
style.setAttribute('save-remove', '')
|
|
176
|
+
// save-ignore mirrors the shell root so a full-document morph (e.g. a live-sync
|
|
177
|
+
// head-merge) preserves the stylesheet instead of stripping it; without it the
|
|
178
|
+
// style survives only via restoreChrome's reactive re-injection.
|
|
179
|
+
style.setAttribute('save-ignore', '')
|
|
180
|
+
style.textContent = cssText
|
|
181
|
+
;(doc.head || doc.documentElement).appendChild(style)
|
|
182
|
+
styledDocs.add(doc)
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
// No bundled CSS — try resolving the sibling generated theme via
|
|
186
|
+
// import.meta.url. Browsers ESM-resolved imports place a co-located
|
|
187
|
+
// theme.generated.css next to hypercms.js. Falls back silently if resolution
|
|
188
|
+
// fails (e.g., bundlers without an asset emitter).
|
|
189
|
+
try {
|
|
190
|
+
const href = new URL('./theme.generated.css', import.meta.url).href
|
|
191
|
+
const link = doc.createElement('link')
|
|
192
|
+
link.rel = 'stylesheet'
|
|
193
|
+
link.id = SHELL_STYLE_ID
|
|
194
|
+
link.setAttribute('save-remove', '')
|
|
195
|
+
link.setAttribute('save-ignore', '')
|
|
196
|
+
link.href = href
|
|
197
|
+
;(doc.head || doc.documentElement).appendChild(link)
|
|
198
|
+
styledDocs.add(doc)
|
|
199
|
+
} catch (_) {
|
|
200
|
+
// No bundled CSS and no resolvable co-located theme (e.g. the IIFE bundle,
|
|
201
|
+
// where import.meta is undefined). Warn loudly rather than mount a silently
|
|
202
|
+
// unstyled shell — the host must call installStyles(themeText) before opening.
|
|
203
|
+
console.warn(
|
|
204
|
+
'hypercms: shell stylesheet not applied — cssText is empty and the ' +
|
|
205
|
+
'co-located theme fallback is unavailable. Call installStyles(themeText) ' +
|
|
206
|
+
'before opening the CMS.'
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Reveal the condensed minibar once the full header scrolls out of the body
|
|
212
|
+
// (pixel-quiet decision 0003). Passive listener; toggles .is-condensed on the
|
|
213
|
+
// shell root when scrollTop passes the header height. No-op if the body or
|
|
214
|
+
// header is missing (e.g. a custom mount that omits them).
|
|
215
|
+
function installCondenseOnScroll(root) {
|
|
216
|
+
const bodyEl = root.querySelector('.hcms-shell-body')
|
|
217
|
+
const header = root.querySelector('.hcms-shell-header')
|
|
218
|
+
if (!bodyEl || !header || typeof bodyEl.addEventListener !== 'function') {
|
|
219
|
+
return { detach() {} }
|
|
220
|
+
}
|
|
221
|
+
const reveal = () => {
|
|
222
|
+
const trigger = (header.offsetHeight || 0) - 12
|
|
223
|
+
root.classList.toggle('is-condensed', bodyEl.scrollTop > trigger)
|
|
224
|
+
}
|
|
225
|
+
bodyEl.addEventListener('scroll', reveal, { passive: true })
|
|
226
|
+
reveal()
|
|
227
|
+
return { detach() { bodyEl.removeEventListener('scroll', reveal) } }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function installFocusTrap(root, doc) {
|
|
231
|
+
function onKeyDown(e) {
|
|
232
|
+
if (e.key !== 'Tab') return
|
|
233
|
+
if (!root.contains(doc.activeElement)) return
|
|
234
|
+
const focusables = Array.from(root.querySelectorAll(FOCUSABLE))
|
|
235
|
+
if (focusables.length === 0) return
|
|
236
|
+
const first = focusables[0]
|
|
237
|
+
const last = focusables[focusables.length - 1]
|
|
238
|
+
if (e.shiftKey && doc.activeElement === first) {
|
|
239
|
+
e.preventDefault()
|
|
240
|
+
last.focus()
|
|
241
|
+
} else if (!e.shiftKey && doc.activeElement === last) {
|
|
242
|
+
e.preventDefault()
|
|
243
|
+
first.focus()
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
doc.addEventListener('keydown', onKeyDown)
|
|
247
|
+
return { detach: () => doc.removeEventListener('keydown', onKeyDown) }
|
|
248
|
+
}
|