@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,518 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findTemplate,
|
|
3
|
+
isInlineTemplate,
|
|
4
|
+
humanize,
|
|
5
|
+
shapeKindOf,
|
|
6
|
+
componentForScalarRule,
|
|
7
|
+
componentForScalarArrayRule,
|
|
8
|
+
winningScalarArrayComponent,
|
|
9
|
+
resolveTemplate,
|
|
10
|
+
declaredComponentKey,
|
|
11
|
+
readOptionsOverride,
|
|
12
|
+
readCropOverride,
|
|
13
|
+
} from './templates.js'
|
|
14
|
+
import { fieldPropertyFor } from './form-rules.js'
|
|
15
|
+
|
|
16
|
+
// The visible label for a file field is the basename of its URL value; the
|
|
17
|
+
// bound leaf still carries the full URL in href so it round-trips byte-stable.
|
|
18
|
+
export function fileNameFromUrl(url) {
|
|
19
|
+
if (!url) return ''
|
|
20
|
+
const clean = String(url).split(/[?#]/)[0]
|
|
21
|
+
const base = clean.split('/').pop() || clean
|
|
22
|
+
try {
|
|
23
|
+
return decodeURIComponent(base)
|
|
24
|
+
} catch {
|
|
25
|
+
return base
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function buildForm({ pageRules, formRules: _formRules, data, doc }) {
|
|
30
|
+
const fragment = doc.createDocumentFragment()
|
|
31
|
+
const root = buildNode(pageRules, [], data, doc, pageRules)
|
|
32
|
+
if (root) fragment.appendChild(root)
|
|
33
|
+
return fragment
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// pageRules rides alongside doc so a scalar bound to its own context element
|
|
37
|
+
// ("." / "@attr") can resolve the row that carries its named control; doc alone
|
|
38
|
+
// cannot answer that, because the row is only knowable from the enclosing array
|
|
39
|
+
// rule. deriveFormRules resolves it from the same pair, which is what keeps the
|
|
40
|
+
// built form and the derived rules in lockstep.
|
|
41
|
+
export function buildItem({ shape, itemShape, pathArr, data, doc, itemKey, pageRules }) {
|
|
42
|
+
if (shape === 'object-array-item') {
|
|
43
|
+
return buildObjectArrayItem(itemShape, pathArr, data, doc, pageRules)
|
|
44
|
+
}
|
|
45
|
+
if (shape === 'scalar-array-item') {
|
|
46
|
+
return buildScalarArrayItem(pathArr, data, doc, itemKey || null)
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`hypercms: buildItem called with unknown shape "${shape}"`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildNode(rule, pathArr, data, doc, pageRules) {
|
|
52
|
+
const kind = shapeKindOf(rule)
|
|
53
|
+
if (kind === 'scalar') return buildScalar(rule, pathArr, data, doc, pageRules)
|
|
54
|
+
if (kind === 'object') return buildObject(rule, pathArr, data, doc, pageRules)
|
|
55
|
+
if (kind === 'object-array') return buildObjectArray(rule, pathArr, data, doc, pageRules)
|
|
56
|
+
if (kind === 'scalar-array') return buildScalarArray(rule, pathArr, data, doc)
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function buildScalar(rule, pathArr, data, doc, pageRules) {
|
|
61
|
+
// Opt-in components select a richer template off the bound rule (explicit
|
|
62
|
+
// data-hcms-component, then @prop inference); plain scalars stay @scalar.
|
|
63
|
+
// A path-bound template override still wins inside resolveTemplate.
|
|
64
|
+
const componentKey = componentForScalarRule(rule, doc, pathArr, pageRules)
|
|
65
|
+
const tpl = resolveTemplate(pathArr, componentKey, doc)
|
|
66
|
+
if (!tpl) throw new Error(`hypercms: missing template for scalar at "${pathArr.join('.')}"`)
|
|
67
|
+
const declaredKey = declaredComponentKey(rule, doc, pathArr, pageRules)
|
|
68
|
+
// A value-guard fell back to text: say so, or "where did my number input /
|
|
69
|
+
// checkbox go" has no answer.
|
|
70
|
+
if (declaredKey === '@number' && componentKey === '@scalar') {
|
|
71
|
+
console.info(
|
|
72
|
+
`[hypercms] field "${pathArr.join('.')}" declares component "@number" but its value isn't a plain number; rendering a text input so the value is preserved`
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
if ((declaredKey === '@checkbox' || declaredKey === '@toggle') && componentKey === '@scalar') {
|
|
76
|
+
console.info(
|
|
77
|
+
`[hypercms] field "${pathArr.join('.')}" declares component "${declaredKey}" but its value isn't true/false; rendering a text input so the value is preserved`
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
noteShadowedComponent(tpl, declaredKey === componentKey ? declaredKey : null, pathArr)
|
|
81
|
+
const node = cloneTemplate(tpl, doc)
|
|
82
|
+
stampPath(node, pathArr)
|
|
83
|
+
// Component-specific setup runs only when the component's own template won —
|
|
84
|
+
// a custom path/wildcard template that shadows it is the author's UI, and
|
|
85
|
+
// injecting options, dropping radio rows, or stamping crop into it would
|
|
86
|
+
// corrupt that UI.
|
|
87
|
+
const winnerKey = tpl.getAttribute?.('data-hcms-tpl')
|
|
88
|
+
if ((componentKey === '@select' || componentKey === '@radio') && winnerKey === componentKey) {
|
|
89
|
+
populateOptions(node, rule, pathArr, data, doc, componentKey, pageRules)
|
|
90
|
+
}
|
|
91
|
+
if (componentKey === '@image' && winnerKey === '@image') {
|
|
92
|
+
const crop = readCropOverride(rule, doc, pathArr, pageRules)
|
|
93
|
+
if (crop != null && !node.hasAttribute('data-hcms-crop')) node.setAttribute('data-hcms-crop', crop)
|
|
94
|
+
}
|
|
95
|
+
// Stamp leaf input(s) FIRST so the container's data-hcms-field doesn't
|
|
96
|
+
// make stampScalarField early-return (which would leave the input without
|
|
97
|
+
// a key).
|
|
98
|
+
stampScalarField(node, lastKey(pathArr))
|
|
99
|
+
// Then stamp the wrapping container so engine selectors can scope by key.
|
|
100
|
+
stampContainerField(node, lastKey(pathArr))
|
|
101
|
+
setLabel(node, lastKey(pathArr))
|
|
102
|
+
populateScalarValue(node, data)
|
|
103
|
+
if (componentKey === '@file') syncFileLeafText(node)
|
|
104
|
+
return node
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// A custom template (exact or wildcard path) outranks a named component, by
|
|
108
|
+
// design: the author's template is the stronger signal. Surface the shadowing
|
|
109
|
+
// so "my data-hcms-component does nothing" has a visible answer — but only for
|
|
110
|
+
// EXPLICITLY declared components (declaredKey non-null): a custom template
|
|
111
|
+
// quietly outranking @src/@checked inference is unremarkable.
|
|
112
|
+
function noteShadowedComponent(tpl, declaredKey, pathArr) {
|
|
113
|
+
if (!declaredKey) return
|
|
114
|
+
const winner = tpl.getAttribute?.('data-hcms-tpl')
|
|
115
|
+
if (winner && winner !== declaredKey) {
|
|
116
|
+
console.info(
|
|
117
|
+
`[hypercms] field "${pathArr.join('.')}" declares component "${declaredKey}" but custom template "${winner}" wins`
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Fill a @select's <select> with <option>s, or clone a @radio's prototype row
|
|
123
|
+
// per option, from the page element's data-hcms-options tokens. The current
|
|
124
|
+
// page value is prepended when it isn't in the list, so opening the editor
|
|
125
|
+
// never silently changes data. Radio inputs get a per-field name derived from
|
|
126
|
+
// the path so sibling fields (and array items) never cross-group.
|
|
127
|
+
function populateOptions(node, rule, pathArr, data, doc, componentKey, pageRules) {
|
|
128
|
+
const provided = readOptionsOverride(rule, doc, pathArr, pageRules)
|
|
129
|
+
const values = provided ? [...provided] : []
|
|
130
|
+
const current = data == null ? '' : String(data)
|
|
131
|
+
if (current !== '' && !values.includes(current)) values.unshift(current)
|
|
132
|
+
if (!provided) {
|
|
133
|
+
// Missing data-hcms-options is an authoring error: surface it ALWAYS, not
|
|
134
|
+
// just when the page value is empty too. When a value exists, fall through
|
|
135
|
+
// and render it as the single option so the data still round-trips while
|
|
136
|
+
// the attribute is missing.
|
|
137
|
+
setFieldError(node, 'data-hcms-options required (space-separated values)')
|
|
138
|
+
if (values.length === 0) {
|
|
139
|
+
// No options AND no value: drop the radio prototype so no phantom empty
|
|
140
|
+
// row renders. The null/'' extract this leaves behind applies as ''
|
|
141
|
+
// (writePropOrAttr), matching the already empty page value, so no data
|
|
142
|
+
// moves.
|
|
143
|
+
node.querySelector('.mirk-radio')?.remove()
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (componentKey === '@select') {
|
|
148
|
+
const select = node.querySelector('select[data-hcms-field]')
|
|
149
|
+
if (!select) return
|
|
150
|
+
for (const v of values) {
|
|
151
|
+
const opt = doc.createElement('option')
|
|
152
|
+
opt.value = v
|
|
153
|
+
opt.textContent = humanize(v)
|
|
154
|
+
select.appendChild(opt)
|
|
155
|
+
}
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
const proto = node.querySelector('.mirk-radio')
|
|
159
|
+
if (!proto || !proto.parentNode) return
|
|
160
|
+
const name = radioGroupName(pathArr.join('.'))
|
|
161
|
+
for (const v of values) {
|
|
162
|
+
const row = proto.cloneNode(true)
|
|
163
|
+
const input = row.querySelector('input[type="radio"]')
|
|
164
|
+
if (input) {
|
|
165
|
+
input.value = v
|
|
166
|
+
input.name = name
|
|
167
|
+
}
|
|
168
|
+
const label = row.querySelector('.mirk-radio__label')
|
|
169
|
+
if (label) label.textContent = humanize(v)
|
|
170
|
+
proto.parentNode.insertBefore(row, proto)
|
|
171
|
+
}
|
|
172
|
+
proto.remove()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// The radio group name a field at this dot-path gets. Shared with the restamp
|
|
176
|
+
// machinery in events.js: names derive from paths, so when a remove/move
|
|
177
|
+
// restamps paths, the names must be recomputed with the same formula or
|
|
178
|
+
// sibling items end up sharing a group.
|
|
179
|
+
export function radioGroupName(pathStr) {
|
|
180
|
+
return 'hcms-' + String(pathStr).replace(/[^A-Za-z0-9_-]/g, '-')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function setFieldError(node, message) {
|
|
184
|
+
const slot = node.querySelector ? node.querySelector('.hcms-error') : null
|
|
185
|
+
if (!slot) return
|
|
186
|
+
slot.textContent = message
|
|
187
|
+
slot.hidden = false
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// The @file leaf is an <a> whose value is the href; populateScalarValue sets
|
|
191
|
+
// href but not the visible text, so derive the filename here. Empty href leaves
|
|
192
|
+
// the anchor empty, which the theme's :empty placeholder dresses as "No file
|
|
193
|
+
// chosen". Scoped to the default chrome's .mirk-file__name so author overrides
|
|
194
|
+
// keep their own text.
|
|
195
|
+
function syncFileLeafText(node) {
|
|
196
|
+
const a = node.querySelector ? node.querySelector('a.mirk-file__name[data-hcms-field]') : null
|
|
197
|
+
if (a) a.textContent = fileNameFromUrl(a.getAttribute('href'))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function buildObject(rule, pathArr, data, doc, pageRules) {
|
|
201
|
+
const tpl = resolveTemplate(pathArr, '@object', doc)
|
|
202
|
+
if (!tpl) throw new Error(`hypercms: missing template for object at "${pathArr.join('.')}"`)
|
|
203
|
+
const node = cloneTemplate(tpl, doc)
|
|
204
|
+
stampPath(node, pathArr)
|
|
205
|
+
stampContainerField(node, lastKey(pathArr))
|
|
206
|
+
setLabel(node, lastKey(pathArr))
|
|
207
|
+
|
|
208
|
+
if (isInlineTemplate(tpl)) {
|
|
209
|
+
stampInlineFieldPaths(node, rule, pathArr)
|
|
210
|
+
populateInlineFields(node, rule, data)
|
|
211
|
+
return node
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const slot = requireSlot(node, '.hcms-object-fields', tpl, pathArr)
|
|
215
|
+
for (const [k, child] of Object.entries(rule)) {
|
|
216
|
+
const childData = data == null ? null : data[k]
|
|
217
|
+
const childNode = buildNode(child, [...pathArr, k], childData, doc, pageRules)
|
|
218
|
+
if (childNode) slot.appendChild(childNode)
|
|
219
|
+
}
|
|
220
|
+
return node
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function buildObjectArray(rule, pathArr, data, doc, pageRules) {
|
|
224
|
+
const tpl = resolveTemplate(pathArr, '@object-array', doc)
|
|
225
|
+
if (!tpl) throw new Error(`hypercms: missing template for object-array at "${pathArr.join('.')}"`)
|
|
226
|
+
const node = cloneTemplate(tpl, doc)
|
|
227
|
+
stampPath(node, pathArr)
|
|
228
|
+
stampContainerField(node, lastKey(pathArr))
|
|
229
|
+
setLabel(node, lastKey(pathArr))
|
|
230
|
+
copyArrayConstraintAttrs(node, tpl)
|
|
231
|
+
wireSortable(node, tpl, pathArr)
|
|
232
|
+
|
|
233
|
+
const slot = requireSlot(node, '.hcms-array-items', tpl, pathArr)
|
|
234
|
+
const [, itemShape] = rule
|
|
235
|
+
const items = Array.isArray(data) ? data : []
|
|
236
|
+
items.forEach((itemData, i) => {
|
|
237
|
+
const itemNode = buildObjectArrayItem(itemShape, [...pathArr, i], itemData, doc, pageRules)
|
|
238
|
+
if (itemNode) slot.appendChild(itemNode)
|
|
239
|
+
})
|
|
240
|
+
applyConstraintVisibility(node)
|
|
241
|
+
return node
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function buildObjectArrayItem(itemShape, pathArr, data, doc, pageRules) {
|
|
245
|
+
const tpl = resolveItemTemplate(pathArr, 'object-array-item', doc)
|
|
246
|
+
if (!tpl) throw new Error(`hypercms: missing item template for "${pathArr.join('.')}"`)
|
|
247
|
+
const node = cloneTemplate(tpl, doc)
|
|
248
|
+
node.setAttribute('data-hcms-card', '')
|
|
249
|
+
if (!node.classList.contains('hcms-card')) node.classList.add('hcms-card')
|
|
250
|
+
stampPath(node, pathArr)
|
|
251
|
+
|
|
252
|
+
if (isInlineTemplate(tpl)) {
|
|
253
|
+
if (itemShape && typeof itemShape === 'object' && !Array.isArray(itemShape)) {
|
|
254
|
+
stampInlineFieldPaths(node, itemShape, pathArr)
|
|
255
|
+
populateInlineFields(node, itemShape, data)
|
|
256
|
+
}
|
|
257
|
+
return node
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const slot = requireSlot(node, '.hcms-card-fields', tpl, pathArr)
|
|
261
|
+
if (itemShape && typeof itemShape === 'object' && !Array.isArray(itemShape)) {
|
|
262
|
+
for (const [k, child] of Object.entries(itemShape)) {
|
|
263
|
+
const childData = data == null ? null : data[k]
|
|
264
|
+
const childNode = buildNode(child, [...pathArr, k], childData, doc, pageRules)
|
|
265
|
+
if (childNode) slot.appendChild(childNode)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return node
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function buildScalarArray(rule, pathArr, data, doc) {
|
|
272
|
+
// The chips component swaps the scalar-array chrome (data-hcms-component=
|
|
273
|
+
// "chips" on the list container or an item ancestor). A path-bound template
|
|
274
|
+
// still wins inside resolveTemplate — and when it does, `comp` is null
|
|
275
|
+
// (winningScalarArrayComponent shares that verdict with deriveFormRules, so
|
|
276
|
+
// the item chrome and the derived item selector can never diverge) and the
|
|
277
|
+
// custom template's own UI is left untouched.
|
|
278
|
+
const declared = componentForScalarArrayRule(rule, doc)
|
|
279
|
+
const comp = winningScalarArrayComponent(rule, pathArr, doc)
|
|
280
|
+
const defaultKey = declared ? declared.array : '@scalar-array'
|
|
281
|
+
const tpl = resolveTemplate(pathArr, defaultKey, doc)
|
|
282
|
+
if (!tpl) throw new Error(`hypercms: missing template for scalar-array at "${pathArr.join('.')}"`)
|
|
283
|
+
// chips is always an explicit declaration (attr-driven), so always notable.
|
|
284
|
+
noteShadowedComponent(tpl, declared ? declared.array : null, pathArr)
|
|
285
|
+
const node = cloneTemplate(tpl, doc)
|
|
286
|
+
stampPath(node, pathArr)
|
|
287
|
+
stampContainerField(node, lastKey(pathArr))
|
|
288
|
+
setLabel(node, lastKey(pathArr))
|
|
289
|
+
copyArrayConstraintAttrs(node, tpl)
|
|
290
|
+
wireSortable(node, tpl, pathArr)
|
|
291
|
+
// Record the resolved item-template key so onAdd (which has no rule context)
|
|
292
|
+
// builds new items with the same component chrome.
|
|
293
|
+
if (comp) node.setAttribute('data-hcms-item-tpl', comp.item)
|
|
294
|
+
|
|
295
|
+
const slot = requireSlot(node, '.hcms-array-items', tpl, pathArr)
|
|
296
|
+
const items = Array.isArray(data) ? data : []
|
|
297
|
+
items.forEach((itemValue, i) => {
|
|
298
|
+
const itemNode = buildScalarArrayItem([...pathArr, i], itemValue, doc, comp ? comp.item : null)
|
|
299
|
+
if (itemNode) slot.appendChild(itemNode)
|
|
300
|
+
})
|
|
301
|
+
applyConstraintVisibility(node)
|
|
302
|
+
return node
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function buildScalarArrayItem(pathArr, value, doc, itemKey) {
|
|
306
|
+
const tpl = resolveItemTemplate(pathArr, 'scalar-array-item', doc, itemKey)
|
|
307
|
+
if (!tpl) throw new Error(`hypercms: missing item template for "${pathArr.join('.')}"`)
|
|
308
|
+
const node = cloneTemplate(tpl, doc)
|
|
309
|
+
node.setAttribute('data-hcms-array-item', '')
|
|
310
|
+
if (!node.classList.contains('hcms-array-item')) node.classList.add('hcms-array-item')
|
|
311
|
+
stampPath(node, pathArr)
|
|
312
|
+
|
|
313
|
+
populateScalarValue(node, value)
|
|
314
|
+
return node
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function resolveItemTemplate(pathArr, defaultShape, doc, itemKey) {
|
|
318
|
+
const wildcardKey = pathArr.map((s) => (typeof s === 'number' ? '*' : s)).join('.')
|
|
319
|
+
return (
|
|
320
|
+
findTemplate(doc, wildcardKey) ||
|
|
321
|
+
(itemKey && findTemplate(doc, itemKey)) ||
|
|
322
|
+
findTemplate(doc, '@' + defaultShape)
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function cloneTemplate(tpl, doc) {
|
|
327
|
+
const content = tpl.content || tpl
|
|
328
|
+
const wrapper = doc.createElement('div')
|
|
329
|
+
wrapper.appendChild(content.cloneNode(true))
|
|
330
|
+
return wrapper.firstElementChild || wrapper
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function stampPath(node, pathArr) {
|
|
334
|
+
node.setAttribute('data-hcms-path', pathArr.join('.'))
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function stampScalarField(node, key) {
|
|
338
|
+
const targetKey = key == null ? '' : String(key)
|
|
339
|
+
if (node.matches && node.matches('[data-hcms-field]')) {
|
|
340
|
+
if (!node.getAttribute('data-hcms-field')) node.setAttribute('data-hcms-field', targetKey)
|
|
341
|
+
return
|
|
342
|
+
}
|
|
343
|
+
// Stamp every descendant input that's marked as a field but missing its key
|
|
344
|
+
// (radio groups have multiple inputs sharing the same key).
|
|
345
|
+
const fields = node.querySelectorAll ? node.querySelectorAll('[data-hcms-field]') : []
|
|
346
|
+
fields.forEach((field) => {
|
|
347
|
+
if (!field.getAttribute('data-hcms-field')) field.setAttribute('data-hcms-field', targetKey)
|
|
348
|
+
})
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Stamp data-hcms-field on the WRAPPING container so engine selectors can
|
|
352
|
+
// scope by key (e.g. nested arrays sharing a terminal name). The leaf input's
|
|
353
|
+
// data-hcms-field carries the same key — form-rules selectors use tag-specific
|
|
354
|
+
// qualifiers (`input[data-hcms-field=...]`) so the container doesn't shadow.
|
|
355
|
+
function stampContainerField(node, key) {
|
|
356
|
+
if (key == null || key === '' || !node.setAttribute) return
|
|
357
|
+
// Don't overwrite an existing data-hcms-field attribute (e.g. when the
|
|
358
|
+
// template author already stamped it deliberately).
|
|
359
|
+
if (node.hasAttribute?.('data-hcms-field')) return
|
|
360
|
+
node.setAttribute('data-hcms-field', String(key))
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function setLabel(node, key) {
|
|
364
|
+
if (key == null || key === '') return
|
|
365
|
+
const labels = node.querySelectorAll
|
|
366
|
+
? node.querySelectorAll('[data-hcms-label]')
|
|
367
|
+
: []
|
|
368
|
+
labels.forEach((el) => {
|
|
369
|
+
const t = el.textContent || ''
|
|
370
|
+
if (t.trim() === '') el.textContent = humanize(String(key))
|
|
371
|
+
})
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function copyArrayConstraintAttrs(node, tpl) {
|
|
375
|
+
;['data-hcms-no-add', 'data-hcms-no-remove', 'data-hcms-no-reorder'].forEach((attr) => {
|
|
376
|
+
if (tpl.hasAttribute(attr)) node.setAttribute(attr, '')
|
|
377
|
+
})
|
|
378
|
+
;['data-hcms-min-items', 'data-hcms-max-items'].forEach((attr) => {
|
|
379
|
+
if (tpl.hasAttribute(attr)) node.setAttribute(attr, tpl.getAttribute(attr))
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function applyConstraintVisibility(arrayEl) {
|
|
384
|
+
const slot = arrayEl.querySelector ? arrayEl.querySelector('.hcms-array-items') : null
|
|
385
|
+
if (!slot) return
|
|
386
|
+
const items = Array.from(slot.querySelectorAll(':scope > [data-hcms-card], :scope > [data-hcms-array-item]'))
|
|
387
|
+
const count = items.length
|
|
388
|
+
const max = readIntAttr(arrayEl, 'data-hcms-max-items')
|
|
389
|
+
const min = readIntAttr(arrayEl, 'data-hcms-min-items')
|
|
390
|
+
const noAdd = arrayEl.hasAttribute('data-hcms-no-add')
|
|
391
|
+
const noRemove = arrayEl.hasAttribute('data-hcms-no-remove')
|
|
392
|
+
const noReorder = arrayEl.hasAttribute('data-hcms-no-reorder')
|
|
393
|
+
const addBtn = arrayEl.querySelector('[data-hcms-action="add"]')
|
|
394
|
+
if (addBtn) addBtn.hidden = noAdd || (max != null && count >= max)
|
|
395
|
+
items.forEach((item, i) => {
|
|
396
|
+
const rm = item.querySelector('[data-hcms-action="remove"]')
|
|
397
|
+
if (rm) rm.hidden = noRemove || (min != null && count <= min)
|
|
398
|
+
const up = item.querySelector('[data-hcms-action="move-up"]')
|
|
399
|
+
if (up) up.hidden = noReorder || i === 0
|
|
400
|
+
const dn = item.querySelector('[data-hcms-action="move-down"]')
|
|
401
|
+
if (dn) dn.hidden = noReorder || i === count - 1
|
|
402
|
+
})
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function readIntAttr(el, name) {
|
|
406
|
+
if (!el || !el.hasAttribute(name)) return null
|
|
407
|
+
const n = parseInt(el.getAttribute(name), 10)
|
|
408
|
+
return Number.isFinite(n) ? n : null
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function wireSortable(node, tpl, pathArr) {
|
|
412
|
+
if (node.hasAttribute('data-hcms-no-reorder') || tpl.hasAttribute('data-hcms-no-reorder')) return
|
|
413
|
+
const slot = node.querySelector('.hcms-array-items')
|
|
414
|
+
if (!slot) return
|
|
415
|
+
const groupName = 'hcms-' + pathArr.join('.')
|
|
416
|
+
slot.setAttribute('sortable', groupName)
|
|
417
|
+
// hyperclayjs's [sortable] attribute compiles `onsorted` as a code body
|
|
418
|
+
// (new Function), so we invoke a top-level callable instead of pointing at
|
|
419
|
+
// a function reference. The callable is installed by hypercms.js open().
|
|
420
|
+
slot.setAttribute('onsorted', 'hypercmsCommit && hypercmsCommit()')
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function lastKey(pathArr) {
|
|
424
|
+
if (!pathArr.length) return null
|
|
425
|
+
return pathArr[pathArr.length - 1]
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function populateScalarValue(node, value) {
|
|
429
|
+
// Radio groups have multiple <input data-hcms-field>s; writeValue handles
|
|
430
|
+
// each radio individually (checks against its `value`). Write to ALL leaf
|
|
431
|
+
// fields under the wrapper, skipping the wrapper itself if it happens to
|
|
432
|
+
// carry data-hcms-field too.
|
|
433
|
+
const targets = collectLeafFields(node)
|
|
434
|
+
if (targets.length === 0) return
|
|
435
|
+
for (const t of targets) writeValue(t, value)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function collectLeafFields(node) {
|
|
439
|
+
if (!node) return []
|
|
440
|
+
const out = []
|
|
441
|
+
// The node itself is a leaf only if it's a recognized leaf tag (input,
|
|
442
|
+
// textarea, select, img, a, or contenteditable). Container shapes — even
|
|
443
|
+
// shape="scalar" wrappers — have child inputs we should target instead.
|
|
444
|
+
if (node.matches?.('[data-hcms-field]') && isLeafFieldEl(node)) {
|
|
445
|
+
out.push(node)
|
|
446
|
+
}
|
|
447
|
+
const descendants = node.querySelectorAll
|
|
448
|
+
? node.querySelectorAll('input[data-hcms-field], textarea[data-hcms-field], select[data-hcms-field], img[data-hcms-field], a[data-hcms-field], [contenteditable][data-hcms-field]')
|
|
449
|
+
: []
|
|
450
|
+
descendants.forEach((d) => out.push(d))
|
|
451
|
+
return out
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function isLeafFieldEl(el) {
|
|
455
|
+
const tag = (el.tagName || '').toUpperCase()
|
|
456
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || tag === 'IMG' || tag === 'A') return true
|
|
457
|
+
if (el.hasAttribute?.('contenteditable')) return true
|
|
458
|
+
return false
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function populateInlineFields(node, shape, data) {
|
|
462
|
+
const fields = node.querySelectorAll ? node.querySelectorAll('[data-hcms-field]') : []
|
|
463
|
+
fields.forEach((el) => {
|
|
464
|
+
const key = el.getAttribute('data-hcms-field')
|
|
465
|
+
if (!key) return
|
|
466
|
+
if (!shape || typeof shape !== 'object' || !(key in shape)) {
|
|
467
|
+
console.warn(`[hypercms] inline template field "${key}" is not in the rule shape; ignoring`)
|
|
468
|
+
return
|
|
469
|
+
}
|
|
470
|
+
const childValue = data == null ? null : data[key]
|
|
471
|
+
writeValue(el, childValue)
|
|
472
|
+
})
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function stampInlineFieldPaths(node, shape, parentPath) {
|
|
476
|
+
if (!node.querySelectorAll) return
|
|
477
|
+
const fields = node.querySelectorAll('[data-hcms-field]')
|
|
478
|
+
fields.forEach((el) => {
|
|
479
|
+
const key = el.getAttribute('data-hcms-field')
|
|
480
|
+
if (!key) return
|
|
481
|
+
if (shape && typeof shape === 'object' && !(key in shape)) return
|
|
482
|
+
const childPath = [...parentPath, key].join('.')
|
|
483
|
+
el.setAttribute('data-hcms-path', childPath)
|
|
484
|
+
})
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function requireSlot(node, slotSelector, tpl, pathArr) {
|
|
488
|
+
if (!node.querySelector) return node
|
|
489
|
+
const slot = node.querySelector(slotSelector)
|
|
490
|
+
if (slot) return slot
|
|
491
|
+
// Slotted templates must declare their slot. Inline-template detection has
|
|
492
|
+
// already short-circuited above, so missing slot here is a real authoring bug.
|
|
493
|
+
const id = tpl?.getAttribute?.('data-hcms-tpl') || pathArr.join('.')
|
|
494
|
+
throw new Error(
|
|
495
|
+
`hypercms: template "${id}" is in slotted mode but has no ${slotSelector} element`
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function writeValue(el, value) {
|
|
500
|
+
const prop = fieldPropertyFor(el)
|
|
501
|
+
const tag = (el.tagName || '').toUpperCase()
|
|
502
|
+
const type = (el.getAttribute('type') || '').toLowerCase()
|
|
503
|
+
if (tag === 'INPUT' && type === 'radio') {
|
|
504
|
+
el.checked = el.value != null && String(el.value) === String(value ?? '')
|
|
505
|
+
return
|
|
506
|
+
}
|
|
507
|
+
if (prop === 'checked') {
|
|
508
|
+
// Coerce strings "true"/"false" the same way coerceBooleans does, so even
|
|
509
|
+
// raw page-extract values (which engine stringifies) don't flip false → true.
|
|
510
|
+
el.checked = value === true || value === 'true'
|
|
511
|
+
return
|
|
512
|
+
}
|
|
513
|
+
if (prop) {
|
|
514
|
+
el[prop] = value == null ? '' : String(value)
|
|
515
|
+
return
|
|
516
|
+
}
|
|
517
|
+
el.textContent = value == null ? '' : String(value)
|
|
518
|
+
}
|