@next-buildr/editor 2.0.0 → 3.0.0-rc.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/README.md +7 -0
- package/UPGRADING.md +322 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/app/builder-editor.test.js +223 -18
- package/dist/app/config.d.ts +27 -4
- package/dist/app/config.d.ts.map +1 -1
- package/dist/app/config.js +4 -3
- package/dist/app/contracts.d.ts +40 -0
- package/dist/app/contracts.d.ts.map +1 -0
- package/dist/app/contracts.js +4 -0
- package/dist/app/editor-app.d.ts.map +1 -1
- package/dist/app/editor-app.js +316 -24
- package/dist/app/editor-app.test.js +144 -6
- package/dist/app/layout.d.ts +11 -2
- package/dist/app/layout.d.ts.map +1 -1
- package/dist/app/layout.js +170 -9
- package/dist/app/manifest.d.ts +7 -2
- package/dist/app/manifest.d.ts.map +1 -1
- package/dist/app/manifest.js +16 -4
- package/dist/app/shell-panels.d.ts +15 -0
- package/dist/app/shell-panels.d.ts.map +1 -1
- package/dist/app/small-screen.test.js +2 -2
- package/dist/app/stage-slots.d.ts +9 -0
- package/dist/app/stage-slots.d.ts.map +1 -0
- package/dist/app/stage-slots.js +10 -0
- package/dist/app/status-info.d.ts +2 -3
- package/dist/app/status-info.d.ts.map +1 -1
- package/dist/app/status-info.js +49 -16
- package/dist/canvas-host/canvas-frame.d.ts +13 -1
- package/dist/canvas-host/canvas-frame.d.ts.map +1 -1
- package/dist/canvas-host/canvas-frame.js +96 -8
- package/dist/canvas-host/canvas-frame.test.js +156 -3
- package/dist/canvas-host/host.d.ts +6 -0
- package/dist/canvas-host/host.d.ts.map +1 -1
- package/dist/canvas-host/host.js +116 -4
- package/dist/canvas-host/host.test.js +195 -6
- package/dist/clipboard/clipboard.d.ts +1 -1
- package/dist/clipboard/clipboard.d.ts.map +1 -1
- package/dist/clipboard/clipboard.js +5 -0
- package/dist/clipboard/clipboard.test.js +21 -1
- package/dist/clipboard/format.d.ts +3 -1
- package/dist/clipboard/format.d.ts.map +1 -1
- package/dist/clipboard/react.d.ts +1 -1
- package/dist/clipboard/react.d.ts.map +1 -1
- package/dist/clipboard/react.js +49 -3
- package/dist/dialogs/external-source.d.ts +15 -0
- package/dist/dialogs/external-source.d.ts.map +1 -0
- package/dist/dialogs/external-source.js +18 -0
- package/dist/dialogs/index.d.ts +4 -0
- package/dist/dialogs/index.d.ts.map +1 -1
- package/dist/dialogs/index.js +2 -0
- package/dist/dialogs/media-picker/index.d.ts +2 -2
- package/dist/dialogs/media-picker/index.d.ts.map +1 -1
- package/dist/dialogs/media-picker/index.js +1 -1
- package/dist/dialogs/media-picker/media-picker.d.ts +5 -0
- package/dist/dialogs/media-picker/media-picker.d.ts.map +1 -1
- package/dist/dialogs/media-picker/media-picker.js +67 -5
- package/dist/dialogs/media-picker/media-picker.test.js +72 -1
- package/dist/dialogs/media-picker/media-ref.d.ts +15 -0
- package/dist/dialogs/media-picker/media-ref.d.ts.map +1 -1
- package/dist/dialogs/media-picker/media-ref.js +29 -0
- package/dist/dialogs/remove-confirm.d.ts +14 -0
- package/dist/dialogs/remove-confirm.d.ts.map +1 -0
- package/dist/dialogs/remove-confirm.js +42 -0
- package/dist/dialogs/remove-confirm.test.d.ts +2 -0
- package/dist/dialogs/remove-confirm.test.d.ts.map +1 -0
- package/dist/dialogs/remove-confirm.test.js +118 -0
- package/dist/dnd/dnd-react.test.js +11 -2
- package/dist/dnd/dnd.test.js +23 -0
- package/dist/dnd/engine.d.ts +4 -2
- package/dist/dnd/engine.d.ts.map +1 -1
- package/dist/dnd/engine.js +6 -0
- package/dist/dnd/move-to-dialog.d.ts +4 -3
- package/dist/dnd/move-to-dialog.d.ts.map +1 -1
- package/dist/dnd/move-to-dialog.js +67 -10
- package/dist/dnd/react.d.ts.map +1 -1
- package/dist/dnd/react.js +5 -0
- package/dist/i18n/diagnostics.d.ts +22 -0
- package/dist/i18n/diagnostics.d.ts.map +1 -0
- package/dist/i18n/diagnostics.js +153 -0
- package/dist/i18n/diagnostics.test.d.ts +2 -0
- package/dist/i18n/diagnostics.test.d.ts.map +1 -0
- package/dist/i18n/diagnostics.test.js +74 -0
- package/dist/i18n/label-catalog.d.ts +20 -0
- package/dist/i18n/label-catalog.d.ts.map +1 -0
- package/dist/i18n/label-catalog.js +1 -0
- package/dist/i18n/locale-name.d.ts +7 -0
- package/dist/i18n/locale-name.d.ts.map +1 -0
- package/dist/i18n/locale-name.js +31 -0
- package/dist/i18n/localize-manifest.d.ts +11 -0
- package/dist/i18n/localize-manifest.d.ts.map +1 -0
- package/dist/i18n/localize-manifest.js +78 -0
- package/dist/i18n/localize-manifest.test.d.ts +2 -0
- package/dist/i18n/localize-manifest.test.d.ts.map +1 -0
- package/dist/i18n/localize-manifest.test.js +71 -0
- package/dist/messages/catalogs.test.d.ts +2 -0
- package/dist/messages/catalogs.test.d.ts.map +1 -0
- package/dist/messages/catalogs.test.js +80 -0
- package/dist/messages/en/app.d.ts +8 -0
- package/dist/messages/en/app.d.ts.map +1 -0
- package/dist/messages/en/app.js +7 -0
- package/dist/messages/en/blocks.d.ts +54 -0
- package/dist/messages/en/blocks.d.ts.map +1 -0
- package/dist/messages/en/blocks.js +53 -0
- package/dist/messages/en/canvas.d.ts +31 -0
- package/dist/messages/en/canvas.d.ts.map +1 -0
- package/dist/messages/en/canvas.js +30 -0
- package/dist/messages/en/clipboard.d.ts +13 -0
- package/dist/messages/en/clipboard.d.ts.map +1 -0
- package/dist/messages/en/clipboard.js +12 -0
- package/dist/messages/en/colorPicker.d.ts +20 -0
- package/dist/messages/en/colorPicker.d.ts.map +1 -0
- package/dist/messages/en/colorPicker.js +19 -0
- package/dist/messages/en/diagnostics.d.ts +40 -0
- package/dist/messages/en/diagnostics.d.ts.map +1 -0
- package/dist/messages/en/diagnostics.js +39 -0
- package/dist/messages/en/dialogs/common.d.ts +6 -0
- package/dist/messages/en/dialogs/common.d.ts.map +1 -0
- package/dist/messages/en/dialogs/common.js +5 -0
- package/dist/messages/en/dialogs/conflict.d.ts +15 -0
- package/dist/messages/en/dialogs/conflict.d.ts.map +1 -0
- package/dist/messages/en/dialogs/conflict.js +14 -0
- package/dist/messages/en/dialogs/delete.d.ts +19 -0
- package/dist/messages/en/dialogs/delete.d.ts.map +1 -0
- package/dist/messages/en/dialogs/delete.js +18 -0
- package/dist/messages/en/dialogs/pageOptions.d.ts +9 -0
- package/dist/messages/en/dialogs/pageOptions.d.ts.map +1 -0
- package/dist/messages/en/dialogs/pageOptions.js +8 -0
- package/dist/messages/en/dialogs/publish.d.ts +15 -0
- package/dist/messages/en/dialogs/publish.d.ts.map +1 -0
- package/dist/messages/en/dialogs/publish.js +14 -0
- package/dist/messages/en/dnd.d.ts +19 -0
- package/dist/messages/en/dnd.d.ts.map +1 -0
- package/dist/messages/en/dnd.js +18 -0
- package/dist/messages/en/editor.d.ts +30 -0
- package/dist/messages/en/editor.d.ts.map +1 -0
- package/dist/messages/en/editor.js +29 -0
- package/dist/messages/en/external.d.ts +6 -0
- package/dist/messages/en/external.d.ts.map +1 -0
- package/dist/messages/en/external.js +5 -0
- package/dist/messages/en/insert.d.ts +25 -0
- package/dist/messages/en/insert.d.ts.map +1 -0
- package/dist/messages/en/insert.js +24 -0
- package/dist/messages/en/inspector.d.ts +176 -0
- package/dist/messages/en/inspector.d.ts.map +1 -0
- package/dist/messages/en/inspector.js +175 -0
- package/dist/messages/en/issues.d.ts +36 -0
- package/dist/messages/en/issues.d.ts.map +1 -0
- package/dist/messages/en/issues.js +35 -0
- package/dist/messages/en/layers.d.ts +29 -0
- package/dist/messages/en/layers.d.ts.map +1 -0
- package/dist/messages/en/layers.js +28 -0
- package/dist/messages/en/leftPanel.d.ts +15 -0
- package/dist/messages/en/leftPanel.d.ts.map +1 -0
- package/dist/messages/en/leftPanel.js +14 -0
- package/dist/messages/en/list.d.ts +9 -0
- package/dist/messages/en/list.d.ts.map +1 -0
- package/dist/messages/en/list.js +8 -0
- package/dist/messages/en/locale.d.ts +4 -0
- package/dist/messages/en/locale.d.ts.map +1 -0
- package/dist/messages/en/locale.js +3 -0
- package/dist/messages/en/media.d.ts +51 -0
- package/dist/messages/en/media.d.ts.map +1 -0
- package/dist/messages/en/media.js +50 -0
- package/dist/messages/en/menu.d.ts +12 -0
- package/dist/messages/en/menu.d.ts.map +1 -0
- package/dist/messages/en/menu.js +11 -0
- package/dist/messages/en/patterns.d.ts +24 -0
- package/dist/messages/en/patterns.d.ts.map +1 -0
- package/dist/messages/en/patterns.js +23 -0
- package/dist/messages/en/preview.d.ts +8 -0
- package/dist/messages/en/preview.d.ts.map +1 -0
- package/dist/messages/en/preview.js +7 -0
- package/dist/messages/en/publish.d.ts +19 -0
- package/dist/messages/en/publish.d.ts.map +1 -0
- package/dist/messages/en/publish.js +18 -0
- package/dist/messages/en/richText.d.ts +21 -0
- package/dist/messages/en/richText.d.ts.map +1 -0
- package/dist/messages/en/richText.js +20 -0
- package/dist/messages/en/sample.d.ts +5 -0
- package/dist/messages/en/sample.d.ts.map +1 -0
- package/dist/messages/en/sample.js +4 -0
- package/dist/messages/en/save.d.ts +15 -0
- package/dist/messages/en/save.d.ts.map +1 -0
- package/dist/messages/en/save.js +14 -0
- package/dist/messages/en/shortcut.d.ts +36 -0
- package/dist/messages/en/shortcut.d.ts.map +1 -0
- package/dist/messages/en/shortcut.js +35 -0
- package/dist/messages/en/statusBar.d.ts +14 -0
- package/dist/messages/en/statusBar.d.ts.map +1 -0
- package/dist/messages/en/statusBar.js +13 -0
- package/dist/messages/en/structure.d.ts +28 -0
- package/dist/messages/en/structure.d.ts.map +1 -0
- package/dist/messages/en/structure.js +27 -0
- package/dist/messages/en/style.d.ts +168 -0
- package/dist/messages/en/style.d.ts.map +1 -0
- package/dist/messages/en/style.js +167 -0
- package/dist/messages/en/styleField.d.ts +301 -0
- package/dist/messages/en/styleField.d.ts.map +1 -0
- package/dist/messages/en/styleField.js +300 -0
- package/dist/messages/en/styleOption.d.ts +128 -0
- package/dist/messages/en/styleOption.d.ts.map +1 -0
- package/dist/messages/en/styleOption.js +127 -0
- package/dist/messages/en/styleSection.d.ts +16 -0
- package/dist/messages/en/styleSection.d.ts.map +1 -0
- package/dist/messages/en/styleSection.js +15 -0
- package/dist/messages/en/toast.d.ts +22 -0
- package/dist/messages/en/toast.d.ts.map +1 -0
- package/dist/messages/en/toast.js +21 -0
- package/dist/messages/en/toolbar.d.ts +47 -0
- package/dist/messages/en/toolbar.d.ts.map +1 -0
- package/dist/messages/en/toolbar.js +46 -0
- package/dist/messages/en/translation.d.ts +7 -0
- package/dist/messages/en/translation.d.ts.map +1 -0
- package/dist/messages/en/translation.js +6 -0
- package/dist/messages/en/ui.d.ts +4 -0
- package/dist/messages/en/ui.d.ts.map +1 -0
- package/dist/messages/en/ui.js +3 -0
- package/dist/messages/en/values.d.ts +45 -0
- package/dist/messages/en/values.d.ts.map +1 -0
- package/dist/messages/en/values.js +44 -0
- package/dist/messages/en.d.ts +1298 -202
- package/dist/messages/en.d.ts.map +1 -1
- package/dist/messages/en.js +82 -330
- package/dist/messages/index.d.ts +12 -0
- package/dist/messages/index.d.ts.map +1 -1
- package/dist/messages/index.js +28 -1
- package/dist/messages/pl/app.d.ts +8 -0
- package/dist/messages/pl/app.d.ts.map +1 -0
- package/dist/messages/pl/app.js +7 -0
- package/dist/messages/pl/blocks.d.ts +54 -0
- package/dist/messages/pl/blocks.d.ts.map +1 -0
- package/dist/messages/pl/blocks.js +53 -0
- package/dist/messages/pl/canvas.d.ts +31 -0
- package/dist/messages/pl/canvas.d.ts.map +1 -0
- package/dist/messages/pl/canvas.js +30 -0
- package/dist/messages/pl/clipboard.d.ts +13 -0
- package/dist/messages/pl/clipboard.d.ts.map +1 -0
- package/dist/messages/pl/clipboard.js +12 -0
- package/dist/messages/pl/colorPicker.d.ts +20 -0
- package/dist/messages/pl/colorPicker.d.ts.map +1 -0
- package/dist/messages/pl/colorPicker.js +19 -0
- package/dist/messages/pl/componentLabels.d.ts +9 -0
- package/dist/messages/pl/componentLabels.d.ts.map +1 -0
- package/dist/messages/pl/componentLabels.js +308 -0
- package/dist/messages/pl/diagnostics.d.ts +39 -0
- package/dist/messages/pl/diagnostics.d.ts.map +1 -0
- package/dist/messages/pl/diagnostics.js +38 -0
- package/dist/messages/pl/dialogs/common.d.ts +6 -0
- package/dist/messages/pl/dialogs/common.d.ts.map +1 -0
- package/dist/messages/pl/dialogs/common.js +5 -0
- package/dist/messages/pl/dialogs/conflict.d.ts +15 -0
- package/dist/messages/pl/dialogs/conflict.d.ts.map +1 -0
- package/dist/messages/pl/dialogs/conflict.js +14 -0
- package/dist/messages/pl/dialogs/delete.d.ts +19 -0
- package/dist/messages/pl/dialogs/delete.d.ts.map +1 -0
- package/dist/messages/pl/dialogs/delete.js +18 -0
- package/dist/messages/pl/dialogs/pageOptions.d.ts +9 -0
- package/dist/messages/pl/dialogs/pageOptions.d.ts.map +1 -0
- package/dist/messages/pl/dialogs/pageOptions.js +8 -0
- package/dist/messages/pl/dialogs/publish.d.ts +15 -0
- package/dist/messages/pl/dialogs/publish.d.ts.map +1 -0
- package/dist/messages/pl/dialogs/publish.js +14 -0
- package/dist/messages/pl/dnd.d.ts +19 -0
- package/dist/messages/pl/dnd.d.ts.map +1 -0
- package/dist/messages/pl/dnd.js +18 -0
- package/dist/messages/pl/editor.d.ts +30 -0
- package/dist/messages/pl/editor.d.ts.map +1 -0
- package/dist/messages/pl/editor.js +29 -0
- package/dist/messages/pl/external.d.ts +6 -0
- package/dist/messages/pl/external.d.ts.map +1 -0
- package/dist/messages/pl/external.js +5 -0
- package/dist/messages/pl/insert.d.ts +25 -0
- package/dist/messages/pl/insert.d.ts.map +1 -0
- package/dist/messages/pl/insert.js +24 -0
- package/dist/messages/pl/inspector.d.ts +176 -0
- package/dist/messages/pl/inspector.d.ts.map +1 -0
- package/dist/messages/pl/inspector.js +175 -0
- package/dist/messages/pl/issues.d.ts +36 -0
- package/dist/messages/pl/issues.d.ts.map +1 -0
- package/dist/messages/pl/issues.js +35 -0
- package/dist/messages/pl/layers.d.ts +29 -0
- package/dist/messages/pl/layers.d.ts.map +1 -0
- package/dist/messages/pl/layers.js +28 -0
- package/dist/messages/pl/leftPanel.d.ts +15 -0
- package/dist/messages/pl/leftPanel.d.ts.map +1 -0
- package/dist/messages/pl/leftPanel.js +14 -0
- package/dist/messages/pl/list.d.ts +9 -0
- package/dist/messages/pl/list.d.ts.map +1 -0
- package/dist/messages/pl/list.js +8 -0
- package/dist/messages/pl/locale.d.ts +4 -0
- package/dist/messages/pl/locale.d.ts.map +1 -0
- package/dist/messages/pl/locale.js +3 -0
- package/dist/messages/pl/media.d.ts +51 -0
- package/dist/messages/pl/media.d.ts.map +1 -0
- package/dist/messages/pl/media.js +50 -0
- package/dist/messages/pl/menu.d.ts +12 -0
- package/dist/messages/pl/menu.d.ts.map +1 -0
- package/dist/messages/pl/menu.js +11 -0
- package/dist/messages/pl/patterns.d.ts +24 -0
- package/dist/messages/pl/patterns.d.ts.map +1 -0
- package/dist/messages/pl/patterns.js +23 -0
- package/dist/messages/pl/preview.d.ts +8 -0
- package/dist/messages/pl/preview.d.ts.map +1 -0
- package/dist/messages/pl/preview.js +7 -0
- package/dist/messages/pl/publish.d.ts +19 -0
- package/dist/messages/pl/publish.d.ts.map +1 -0
- package/dist/messages/pl/publish.js +18 -0
- package/dist/messages/pl/richText.d.ts +21 -0
- package/dist/messages/pl/richText.d.ts.map +1 -0
- package/dist/messages/pl/richText.js +20 -0
- package/dist/messages/pl/sample.d.ts +5 -0
- package/dist/messages/pl/sample.d.ts.map +1 -0
- package/dist/messages/pl/sample.js +4 -0
- package/dist/messages/pl/save.d.ts +15 -0
- package/dist/messages/pl/save.d.ts.map +1 -0
- package/dist/messages/pl/save.js +14 -0
- package/dist/messages/pl/shortcut.d.ts +36 -0
- package/dist/messages/pl/shortcut.d.ts.map +1 -0
- package/dist/messages/pl/shortcut.js +35 -0
- package/dist/messages/pl/statusBar.d.ts +14 -0
- package/dist/messages/pl/statusBar.d.ts.map +1 -0
- package/dist/messages/pl/statusBar.js +13 -0
- package/dist/messages/pl/structure.d.ts +28 -0
- package/dist/messages/pl/structure.d.ts.map +1 -0
- package/dist/messages/pl/structure.js +27 -0
- package/dist/messages/pl/style.d.ts +168 -0
- package/dist/messages/pl/style.d.ts.map +1 -0
- package/dist/messages/pl/style.js +167 -0
- package/dist/messages/pl/styleField.d.ts +301 -0
- package/dist/messages/pl/styleField.d.ts.map +1 -0
- package/dist/messages/pl/styleField.js +300 -0
- package/dist/messages/pl/styleOption.d.ts +128 -0
- package/dist/messages/pl/styleOption.d.ts.map +1 -0
- package/dist/messages/pl/styleOption.js +127 -0
- package/dist/messages/pl/styleSection.d.ts +16 -0
- package/dist/messages/pl/styleSection.d.ts.map +1 -0
- package/dist/messages/pl/styleSection.js +15 -0
- package/dist/messages/pl/toast.d.ts +22 -0
- package/dist/messages/pl/toast.d.ts.map +1 -0
- package/dist/messages/pl/toast.js +21 -0
- package/dist/messages/pl/toolbar.d.ts +47 -0
- package/dist/messages/pl/toolbar.d.ts.map +1 -0
- package/dist/messages/pl/toolbar.js +46 -0
- package/dist/messages/pl/translation.d.ts +7 -0
- package/dist/messages/pl/translation.d.ts.map +1 -0
- package/dist/messages/pl/translation.js +6 -0
- package/dist/messages/pl/ui.d.ts +4 -0
- package/dist/messages/pl/ui.d.ts.map +1 -0
- package/dist/messages/pl/ui.js +3 -0
- package/dist/messages/pl/values.d.ts +45 -0
- package/dist/messages/pl/values.d.ts.map +1 -0
- package/dist/messages/pl/values.js +44 -0
- package/dist/messages/pl.d.ts.map +1 -1
- package/dist/messages/pl.js +82 -325
- package/dist/messages/plural.test.d.ts +2 -0
- package/dist/messages/plural.test.d.ts.map +1 -0
- package/dist/messages/plural.test.js +50 -0
- package/dist/panels/breadcrumbs/breadcrumbs.d.ts +1 -1
- package/dist/panels/breadcrumbs/breadcrumbs.d.ts.map +1 -1
- package/dist/panels/breadcrumbs/breadcrumbs.js +10 -3
- package/dist/panels/breadcrumbs/breadcrumbs.test.js +9 -2
- package/dist/panels/index.d.ts +3 -0
- package/dist/panels/index.d.ts.map +1 -1
- package/dist/panels/index.js +1 -0
- package/dist/panels/insert/catalog.d.ts +21 -1
- package/dist/panels/insert/catalog.d.ts.map +1 -1
- package/dist/panels/insert/catalog.js +85 -3
- package/dist/panels/insert/catalog.order.test.js +106 -1
- package/dist/panels/insert/index.d.ts +1 -0
- package/dist/panels/insert/index.d.ts.map +1 -1
- package/dist/panels/insert/insert-panel.d.ts +14 -4
- package/dist/panels/insert/insert-panel.d.ts.map +1 -1
- package/dist/panels/insert/insert-panel.js +128 -69
- package/dist/panels/insert/insert-panel.test.js +278 -37
- package/dist/panels/insert/target.d.ts +5 -1
- package/dist/panels/insert/target.d.ts.map +1 -1
- package/dist/panels/insert/target.js +11 -1
- package/dist/panels/inspector/author-fields.d.ts +21 -0
- package/dist/panels/inspector/author-fields.d.ts.map +1 -0
- package/dist/panels/inspector/author-fields.js +191 -0
- package/dist/panels/inspector/author-fields.test.d.ts +2 -0
- package/dist/panels/inspector/author-fields.test.d.ts.map +1 -0
- package/dist/panels/inspector/author-fields.test.js +237 -0
- package/dist/panels/inspector/controls/external-link.d.ts +24 -0
- package/dist/panels/inspector/controls/external-link.d.ts.map +1 -0
- package/dist/panels/inspector/controls/external-link.js +43 -0
- package/dist/panels/inspector/controls/external-link.test.d.ts +2 -0
- package/dist/panels/inspector/controls/external-link.test.d.ts.map +1 -0
- package/dist/panels/inspector/controls/external-link.test.js +105 -0
- package/dist/panels/inspector/controls/index.d.ts +1 -0
- package/dist/panels/inspector/controls/index.d.ts.map +1 -1
- package/dist/panels/inspector/controls/index.js +1 -0
- package/dist/panels/inspector/controls/media.d.ts +3 -1
- package/dist/panels/inspector/controls/media.d.ts.map +1 -1
- package/dist/panels/inspector/controls/media.js +8 -3
- package/dist/panels/inspector/controls/rich-text.d.ts.map +1 -1
- package/dist/panels/inspector/controls/rich-text.js +36 -6
- package/dist/panels/inspector/controls/textarea.d.ts +7 -2
- package/dist/panels/inspector/controls/textarea.d.ts.map +1 -1
- package/dist/panels/inspector/controls/textarea.js +37 -2
- package/dist/panels/inspector/default-hint.d.ts +13 -0
- package/dist/panels/inspector/default-hint.d.ts.map +1 -0
- package/dist/panels/inspector/default-hint.js +30 -0
- package/dist/panels/inspector/default-hint.test.d.ts +2 -0
- package/dist/panels/inspector/default-hint.test.d.ts.map +1 -0
- package/dist/panels/inspector/default-hint.test.js +46 -0
- package/dist/panels/inspector/index.d.ts +3 -3
- package/dist/panels/inspector/index.d.ts.map +1 -1
- package/dist/panels/inspector/index.js +2 -2
- package/dist/panels/inspector/inspector.d.ts +20 -2
- package/dist/panels/inspector/inspector.d.ts.map +1 -1
- package/dist/panels/inspector/inspector.js +246 -26
- package/dist/panels/inspector/inspector.test.js +276 -11
- package/dist/panels/inspector/props-panel.d.ts +36 -0
- package/dist/panels/inspector/props-panel.d.ts.map +1 -1
- package/dist/panels/inspector/props-panel.js +99 -17
- package/dist/panels/inspector/props-panel.test.d.ts +2 -0
- package/dist/panels/inspector/props-panel.test.d.ts.map +1 -0
- package/dist/panels/inspector/props-panel.test.js +17 -0
- package/dist/panels/inspector/scrub-label.d.ts +14 -0
- package/dist/panels/inspector/scrub-label.d.ts.map +1 -0
- package/dist/panels/inspector/scrub-label.js +75 -0
- package/dist/panels/inspector/scrub-label.test.d.ts +2 -0
- package/dist/panels/inspector/scrub-label.test.d.ts.map +1 -0
- package/dist/panels/inspector/scrub-label.test.js +132 -0
- package/dist/panels/inspector/styles/background-media.d.ts +28 -0
- package/dist/panels/inspector/styles/background-media.d.ts.map +1 -0
- package/dist/panels/inspector/styles/background-media.js +78 -0
- package/dist/panels/inspector/styles/box-model.d.ts +13 -16
- package/dist/panels/inspector/styles/box-model.d.ts.map +1 -1
- package/dist/panels/inspector/styles/box-model.js +10 -25
- package/dist/panels/inspector/styles/color-input.d.ts +3 -0
- package/dist/panels/inspector/styles/color-input.d.ts.map +1 -0
- package/dist/panels/inspector/styles/color-input.js +72 -0
- package/dist/panels/inspector/styles/gradient-fields.d.ts +9 -0
- package/dist/panels/inspector/styles/gradient-fields.d.ts.map +1 -0
- package/dist/panels/inspector/styles/gradient-fields.js +50 -0
- package/dist/panels/inspector/styles/index.d.ts +2 -0
- package/dist/panels/inspector/styles/index.d.ts.map +1 -1
- package/dist/panels/inspector/styles/index.js +2 -0
- package/dist/panels/inspector/styles/model.d.ts +27 -5
- package/dist/panels/inspector/styles/model.d.ts.map +1 -1
- package/dist/panels/inspector/styles/model.js +101 -3
- package/dist/panels/inspector/styles/motion-rows.d.ts +17 -0
- package/dist/panels/inspector/styles/motion-rows.d.ts.map +1 -0
- package/dist/panels/inspector/styles/motion-rows.js +117 -0
- package/dist/panels/inspector/styles/number-input.d.ts +4 -0
- package/dist/panels/inspector/styles/number-input.d.ts.map +1 -0
- package/dist/panels/inspector/styles/number-input.js +12 -0
- package/dist/panels/inspector/styles/option-label.d.ts +7 -0
- package/dist/panels/inspector/styles/option-label.d.ts.map +1 -0
- package/dist/panels/inspector/styles/option-label.js +9 -0
- package/dist/panels/inspector/styles/property-label.d.ts +9 -0
- package/dist/panels/inspector/styles/property-label.d.ts.map +1 -0
- package/dist/panels/inspector/styles/property-label.js +11 -0
- package/dist/panels/inspector/styles/section-state.d.ts +22 -0
- package/dist/panels/inspector/styles/section-state.d.ts.map +1 -0
- package/dist/panels/inspector/styles/section-state.js +96 -0
- package/dist/panels/inspector/styles/section.d.ts +25 -0
- package/dist/panels/inspector/styles/section.d.ts.map +1 -0
- package/dist/panels/inspector/styles/section.js +43 -0
- package/dist/panels/inspector/styles/sections-context.d.ts +13 -0
- package/dist/panels/inspector/styles/sections-context.d.ts.map +1 -0
- package/dist/panels/inspector/styles/sections-context.js +19 -0
- package/dist/panels/inspector/styles/sections-context.test.d.ts +2 -0
- package/dist/panels/inspector/styles/sections-context.test.d.ts.map +1 -0
- package/dist/panels/inspector/styles/sections-context.test.js +18 -0
- package/dist/panels/inspector/styles/sections-toggle.d.ts +6 -0
- package/dist/panels/inspector/styles/sections-toggle.d.ts.map +1 -0
- package/dist/panels/inspector/styles/sections-toggle.js +18 -0
- package/dist/panels/inspector/styles/segments.d.ts +3 -0
- package/dist/panels/inspector/styles/segments.d.ts.map +1 -1
- package/dist/panels/inspector/styles/segments.js +11 -4
- package/dist/panels/inspector/styles/sides-editor.d.ts +1 -1
- package/dist/panels/inspector/styles/sides-editor.d.ts.map +1 -1
- package/dist/panels/inspector/styles/sides-editor.js +33 -4
- package/dist/panels/inspector/styles/style-inspector.d.ts +3 -1
- package/dist/panels/inspector/styles/style-inspector.d.ts.map +1 -1
- package/dist/panels/inspector/styles/style-inspector.js +610 -42
- package/dist/panels/inspector/styles/style-inspector.test.js +694 -14
- package/dist/panels/inspector/styles/token-picker.d.ts +1 -1
- package/dist/panels/inspector/styles/token-picker.d.ts.map +1 -1
- package/dist/panels/inspector/styles/token-picker.js +10 -3
- package/dist/panels/inspector/styles/widgets.d.ts +116 -0
- package/dist/panels/inspector/styles/widgets.d.ts.map +1 -0
- package/dist/panels/inspector/styles/widgets.js +304 -0
- package/dist/panels/inspector/styles/widgets.test.d.ts +2 -0
- package/dist/panels/inspector/styles/widgets.test.d.ts.map +1 -0
- package/dist/panels/inspector/styles/widgets.test.js +247 -0
- package/dist/panels/inspector/values/value-editor.d.ts +1 -1
- package/dist/panels/inspector/values/value-editor.d.ts.map +1 -1
- package/dist/panels/inspector/values/value-editor.js +9 -8
- package/dist/panels/inspector/values/values.test.js +9 -3
- package/dist/panels/issues/collect.d.ts +2 -0
- package/dist/panels/issues/collect.d.ts.map +1 -1
- package/dist/panels/issues/collect.js +1 -0
- package/dist/panels/issues/index.d.ts +1 -0
- package/dist/panels/issues/index.d.ts.map +1 -1
- package/dist/panels/issues/index.js +1 -0
- package/dist/panels/issues/issues-panel.d.ts +4 -3
- package/dist/panels/issues/issues-panel.d.ts.map +1 -1
- package/dist/panels/issues/issues-panel.js +22 -35
- package/dist/panels/issues/path.d.ts +7 -0
- package/dist/panels/issues/path.d.ts.map +1 -0
- package/dist/panels/issues/path.js +21 -0
- package/dist/panels/layers/flatten.d.ts +16 -2
- package/dist/panels/layers/flatten.d.ts.map +1 -1
- package/dist/panels/layers/flatten.js +48 -4
- package/dist/panels/layers/layers-panel.d.ts +5 -2
- package/dist/panels/layers/layers-panel.d.ts.map +1 -1
- package/dist/panels/layers/layers-panel.js +177 -35
- package/dist/panels/layers/layers-panel.test.js +173 -15
- package/dist/panels/left-panel.d.ts +17 -0
- package/dist/panels/left-panel.d.ts.map +1 -0
- package/dist/panels/left-panel.js +47 -0
- package/dist/panels/left-panel.test.d.ts +2 -0
- package/dist/panels/left-panel.test.d.ts.map +1 -0
- package/dist/panels/left-panel.test.js +77 -0
- package/dist/persistence/persistence.test.js +9 -3
- package/dist/persistence/react.d.ts.map +1 -1
- package/dist/persistence/react.js +2 -2
- package/dist/preview/preview.d.ts +8 -0
- package/dist/preview/preview.d.ts.map +1 -1
- package/dist/preview/preview.js +21 -1
- package/dist/preview/preview.test.js +18 -1
- package/dist/shortcuts/actions.d.ts +13 -2
- package/dist/shortcuts/actions.d.ts.map +1 -1
- package/dist/shortcuts/actions.js +70 -15
- package/dist/shortcuts/help.d.ts +11 -0
- package/dist/shortcuts/help.d.ts.map +1 -0
- package/dist/shortcuts/help.js +77 -0
- package/dist/shortcuts/index.d.ts +5 -2
- package/dist/shortcuts/index.d.ts.map +1 -1
- package/dist/shortcuts/index.js +3 -1
- package/dist/shortcuts/map.d.ts +1 -1
- package/dist/shortcuts/map.d.ts.map +1 -1
- package/dist/shortcuts/map.js +14 -8
- package/dist/shortcuts/navigation.d.ts +13 -0
- package/dist/shortcuts/navigation.d.ts.map +1 -0
- package/dist/shortcuts/navigation.js +48 -0
- package/dist/shortcuts/shortcuts.d.ts +12 -1
- package/dist/shortcuts/shortcuts.d.ts.map +1 -1
- package/dist/shortcuts/shortcuts.js +61 -14
- package/dist/shortcuts/shortcuts.test.js +206 -5
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +19 -1
- package/dist/store/index.d.ts +4 -1
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +3 -1
- package/dist/store/react.d.ts +4 -0
- package/dist/store/react.d.ts.map +1 -1
- package/dist/store/react.js +7 -0
- package/dist/store/store.test.js +24 -0
- package/dist/store/structure-lock.d.ts +16 -0
- package/dist/store/structure-lock.d.ts.map +1 -0
- package/dist/store/structure-lock.js +43 -0
- package/dist/store/structure-lock.test.d.ts +2 -0
- package/dist/store/structure-lock.test.d.ts.map +1 -0
- package/dist/store/structure-lock.test.js +49 -0
- package/dist/store/types.d.ts +9 -0
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/view.d.ts +20 -0
- package/dist/store/view.d.ts.map +1 -0
- package/dist/store/view.js +17 -0
- package/dist/store/view.test.d.ts +2 -0
- package/dist/store/view.test.d.ts.map +1 -0
- package/dist/store/view.test.js +103 -0
- package/dist/styles/tokens.test.js +88 -9
- package/dist/styles.css +4112 -586
- package/dist/toolbar/brand.d.ts +2 -2
- package/dist/toolbar/brand.d.ts.map +1 -1
- package/dist/toolbar/brand.js +4 -4
- package/dist/toolbar/breakpoint-control.d.ts +4 -0
- package/dist/toolbar/breakpoint-control.d.ts.map +1 -1
- package/dist/toolbar/breakpoint-control.js +11 -4
- package/dist/toolbar/editable-title.d.ts +4 -1
- package/dist/toolbar/editable-title.d.ts.map +1 -1
- package/dist/toolbar/editable-title.js +2 -2
- package/dist/toolbar/editable-title.test.js +10 -0
- package/dist/toolbar/locale-chip.d.ts +10 -0
- package/dist/toolbar/locale-chip.d.ts.map +1 -0
- package/dist/toolbar/locale-chip.js +27 -0
- package/dist/toolbar/locale-switcher.d.ts.map +1 -1
- package/dist/toolbar/locale-switcher.js +4 -1
- package/dist/toolbar/more-menu.d.ts +26 -4
- package/dist/toolbar/more-menu.d.ts.map +1 -1
- package/dist/toolbar/more-menu.js +60 -13
- package/dist/toolbar/page-chip.d.ts +10 -0
- package/dist/toolbar/page-chip.d.ts.map +1 -0
- package/dist/toolbar/page-chip.js +12 -0
- package/dist/toolbar/page-options-dialog.d.ts +16 -0
- package/dist/toolbar/page-options-dialog.d.ts.map +1 -0
- package/dist/toolbar/page-options-dialog.js +13 -0
- package/dist/toolbar/panel-toggles.d.ts +3 -2
- package/dist/toolbar/panel-toggles.d.ts.map +1 -1
- package/dist/toolbar/panel-toggles.js +9 -4
- package/dist/toolbar/publish-dialog.d.ts +3 -0
- package/dist/toolbar/publish-dialog.d.ts.map +1 -1
- package/dist/toolbar/publish-dialog.js +34 -7
- package/dist/toolbar/publish.test.js +63 -19
- package/dist/toolbar/safe-history.d.ts +3 -0
- package/dist/toolbar/safe-history.d.ts.map +1 -0
- package/dist/toolbar/safe-history.js +5 -0
- package/dist/toolbar/sample-picker.d.ts +24 -4
- package/dist/toolbar/sample-picker.d.ts.map +1 -1
- package/dist/toolbar/sample-picker.js +42 -18
- package/dist/toolbar/toolbar-centre.d.ts +3 -11
- package/dist/toolbar/toolbar-centre.d.ts.map +1 -1
- package/dist/toolbar/toolbar-centre.js +4 -5
- package/dist/toolbar/toolbar-left.d.ts +4 -7
- package/dist/toolbar/toolbar-left.d.ts.map +1 -1
- package/dist/toolbar/toolbar-left.js +13 -11
- package/dist/toolbar/toolbar-right.d.ts +21 -6
- package/dist/toolbar/toolbar-right.d.ts.map +1 -1
- package/dist/toolbar/toolbar-right.js +28 -14
- package/dist/toolbar/toolbar.d.ts +23 -17
- package/dist/toolbar/toolbar.d.ts.map +1 -1
- package/dist/toolbar/toolbar.js +28 -11
- package/dist/toolbar/toolbar.test.js +238 -23
- package/dist/toolbar/use-overflow-level.d.ts +2 -1
- package/dist/toolbar/use-overflow-level.d.ts.map +1 -1
- package/dist/toolbar/use-overflow-level.js +9 -3
- package/dist/toolbar/zoom-menu.d.ts +5 -1
- package/dist/toolbar/zoom-menu.d.ts.map +1 -1
- package/dist/toolbar/zoom-menu.js +3 -2
- package/dist/ui/icon.d.ts +53 -0
- package/dist/ui/icon.d.ts.map +1 -1
- package/dist/ui/icon.js +58 -1
- package/dist/ui/icon.test.js +101 -3
- package/dist/ui/index.d.ts +4 -3
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +3 -2
- package/dist/ui/primitives.d.ts +97 -14
- package/dist/ui/primitives.d.ts.map +1 -1
- package/dist/ui/primitives.js +108 -22
- package/dist/ui/primitives.test.js +204 -3
- package/dist/ui/structure-locked.d.ts +9 -0
- package/dist/ui/structure-locked.d.ts.map +1 -0
- package/dist/ui/structure-locked.js +28 -0
- package/dist/ui/toast.d.ts +3 -1
- package/dist/ui/toast.d.ts.map +1 -1
- package/dist/ui/toast.js +21 -5
- package/dist/ui/toast.test.js +34 -0
- package/package.json +6 -4
|
@@ -7,9 +7,12 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
|
7
7
|
import { axe } from 'vitest-axe';
|
|
8
8
|
import * as matchers from 'vitest-axe/matchers';
|
|
9
9
|
import { ManifestProvider } from '../../app/manifest.js';
|
|
10
|
+
import { ClipboardProvider } from '../../clipboard/index.js';
|
|
10
11
|
import { MessagesProvider } from '../../messages/index.js';
|
|
12
|
+
import { ShortcutProvider } from '../../shortcuts/index.js';
|
|
11
13
|
import { createEditorStore, EditorStoreProvider } from '../../store/index.js';
|
|
12
|
-
import {
|
|
14
|
+
import { ToastProvider } from '../../ui/index.js';
|
|
15
|
+
import { filterTree, flattenTree } from './flatten.js';
|
|
13
16
|
import { LayersPanel } from './layers-panel.js';
|
|
14
17
|
expect.extend(matchers);
|
|
15
18
|
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
@@ -69,14 +72,15 @@ afterEach(() => {
|
|
|
69
72
|
act(() => root.unmount());
|
|
70
73
|
document.body.innerHTML = '';
|
|
71
74
|
});
|
|
72
|
-
async function mount(doc = fixture()) {
|
|
75
|
+
async function mount(doc = fixture(), connected = false, canUnlock) {
|
|
73
76
|
const store = createEditorStore({
|
|
77
|
+
...(canUnlock === undefined ? {} : { canUnlock }),
|
|
74
78
|
doc,
|
|
75
79
|
registry,
|
|
76
80
|
generateId: createSeededIdGenerator(9),
|
|
77
81
|
validationDelayMs: null,
|
|
78
82
|
});
|
|
79
|
-
await act(async () => root.render(_jsx(MessagesProvider, { locale: "en", children: _jsx(ManifestProvider, { manifest: toManifest(registry), children: _jsx(EditorStoreProvider, { store: store, children: _jsx(LayersPanel, {}) }) }) })));
|
|
83
|
+
await act(async () => root.render(_jsx(MessagesProvider, { locale: "en", children: _jsx(ManifestProvider, { manifest: toManifest(registry), children: _jsx(EditorStoreProvider, { store: store, children: connected ? (_jsx(ToastProvider, { children: _jsx(ClipboardProvider, { children: _jsx(ShortcutProvider, { children: _jsx(LayersPanel, {}) }) }) })) : (_jsx(LayersPanel, {})) }) }) })));
|
|
80
84
|
return store;
|
|
81
85
|
}
|
|
82
86
|
const tree = () => container.querySelector('[role=tree]');
|
|
@@ -121,15 +125,23 @@ describe('flattenTree', () => {
|
|
|
121
125
|
describe('LayersPanel', () => {
|
|
122
126
|
it('is an ARIA tree with names from the manifest and no accessibility violations', async () => {
|
|
123
127
|
await mount();
|
|
124
|
-
expect(tree().getAttribute('aria-label')).toBe('
|
|
128
|
+
expect(tree().getAttribute('aria-label')).toBe('Page structure');
|
|
125
129
|
expect(labels()).toEqual(['page', 'Hero', 'Box']);
|
|
126
130
|
const [, hero] = items();
|
|
127
131
|
expect(hero?.getAttribute('aria-level')).toBe('2');
|
|
132
|
+
expect(hero?.style.height).toBe('32px');
|
|
133
|
+
expect(hero?.querySelector('[data-row-actions]')).not.toBeNull();
|
|
134
|
+
expect(hero?.querySelector('[data-row-actions]')?.querySelectorAll('button')).toHaveLength(3);
|
|
128
135
|
expect(hero?.getAttribute('aria-posinset')).toBe('1');
|
|
129
136
|
expect(hero?.getAttribute('aria-setsize')).toBe('2');
|
|
130
137
|
expect(hero?.getAttribute('aria-expanded')).toBe('false');
|
|
131
138
|
expect(await axe(container)).toHaveNoViolations();
|
|
132
139
|
});
|
|
140
|
+
it('shows a muted type label only on a renamed block', async () => {
|
|
141
|
+
await mount();
|
|
142
|
+
const types = items().map((item) => item.querySelector('.bd-layer-type')?.textContent ?? null);
|
|
143
|
+
expect(types).toEqual([null, 'Box', null]);
|
|
144
|
+
});
|
|
133
145
|
it('draws an svg icon per row: the named one, or the neutral box, never a letter', async () => {
|
|
134
146
|
await mount();
|
|
135
147
|
const icons = items().map((item) => item.querySelector('.bd-layer-icon svg'));
|
|
@@ -143,10 +155,59 @@ describe('LayersPanel', () => {
|
|
|
143
155
|
expect(icons[2]?.hasAttribute('data-fallback')).toBe(false);
|
|
144
156
|
expect(items().every((item) => item.querySelector('.bd-layer-icon')?.textContent === '')).toBe(true);
|
|
145
157
|
});
|
|
146
|
-
it('shows
|
|
158
|
+
it('shows a locked node as a pressed lock toggle', async () => {
|
|
147
159
|
await mount();
|
|
148
160
|
const [, , locked] = items();
|
|
149
|
-
|
|
161
|
+
const lock = locked?.querySelector('button[aria-label="Unlock"]');
|
|
162
|
+
expect(lock?.getAttribute('aria-pressed')).toBe('true');
|
|
163
|
+
});
|
|
164
|
+
it('hides a node in the editor through the view store, not the document', async () => {
|
|
165
|
+
const store = await mount();
|
|
166
|
+
const before = store.getState().doc;
|
|
167
|
+
const row = items().find((i) => i.dataset['nodeId'] === 'boxNode001');
|
|
168
|
+
const eye = row?.querySelector('button[aria-label="Hide in editor"]');
|
|
169
|
+
expect(eye?.getAttribute('aria-pressed')).toBe('false');
|
|
170
|
+
await act(async () => eye?.click());
|
|
171
|
+
expect(store.view.getState().hiddenIds).toEqual(['boxNode001']);
|
|
172
|
+
expect(store.getState().doc).toBe(before);
|
|
173
|
+
expect(items()
|
|
174
|
+
.find((i) => i.dataset['nodeId'] === 'boxNode001')
|
|
175
|
+
?.querySelector('button[aria-label="Show in editor"]')
|
|
176
|
+
?.getAttribute('aria-pressed')).toBe('true');
|
|
177
|
+
});
|
|
178
|
+
it('locks a node with the document command', async () => {
|
|
179
|
+
const store = await mount();
|
|
180
|
+
const row = items().find((i) => i.dataset['nodeId'] === 'boxNode001');
|
|
181
|
+
await act(async () => row?.querySelector('button[aria-label="Lock"]')?.click());
|
|
182
|
+
expect(store.getState().doc.nodes['boxNode001']?.lock).toEqual({
|
|
183
|
+
structure: true,
|
|
184
|
+
content: true,
|
|
185
|
+
style: true,
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
it('unlocks a locked node when the host allows it', async () => {
|
|
189
|
+
const store = await mount(fixture(), false, () => true);
|
|
190
|
+
const row = items().find((i) => i.dataset['nodeId'] === 'boxNode002');
|
|
191
|
+
await act(async () => row?.querySelector('button[aria-label="Unlock"]')?.click());
|
|
192
|
+
expect(store.getState().doc.nodes['boxNode002']?.lock).toBeUndefined();
|
|
193
|
+
expect(container.querySelector('.bd-layers-notice')?.textContent).toBe('');
|
|
194
|
+
});
|
|
195
|
+
it('says so, and keeps the lock, when the host does not allow unlocking', async () => {
|
|
196
|
+
const store = await mount();
|
|
197
|
+
const row = items().find((i) => i.dataset['nodeId'] === 'boxNode002');
|
|
198
|
+
await act(async () => row?.querySelector('button[aria-label="Unlock"]')?.click());
|
|
199
|
+
expect(store.getState().doc.nodes['boxNode002']?.lock).toEqual({ content: true });
|
|
200
|
+
expect(container.querySelector('.bd-layers-notice')?.textContent).toBe('You are not allowed to unlock this block.');
|
|
201
|
+
});
|
|
202
|
+
it('only points to the Structure panel when unlocking is possible', async () => {
|
|
203
|
+
const store = await mount(fixture(), true);
|
|
204
|
+
const row = items().find((i) => i.dataset['nodeId'] === 'boxNode001');
|
|
205
|
+
await act(async () => row?.querySelector('button[aria-label="Lock"]')?.click());
|
|
206
|
+
await pick(store, 'boxNode001');
|
|
207
|
+
await act(async () => tree().focus());
|
|
208
|
+
await press('Delete');
|
|
209
|
+
expect(container.textContent).toContain('This block is locked.');
|
|
210
|
+
expect(container.textContent).not.toContain('Unlock it in the Structure panel');
|
|
150
211
|
});
|
|
151
212
|
it('is operable with the keyboard alone', async () => {
|
|
152
213
|
const store = await mount();
|
|
@@ -176,7 +237,7 @@ describe('LayersPanel', () => {
|
|
|
176
237
|
await pick(store, 'boxNode002');
|
|
177
238
|
await act(async () => tree().focus());
|
|
178
239
|
await press('F2');
|
|
179
|
-
const input = container.querySelector('input');
|
|
240
|
+
const input = container.querySelector('[role=tree] input');
|
|
180
241
|
expect(input.getAttribute('aria-label')).toBe('Layer name');
|
|
181
242
|
await act(async () => {
|
|
182
243
|
input.value = 'Footer';
|
|
@@ -184,10 +245,10 @@ describe('LayersPanel', () => {
|
|
|
184
245
|
});
|
|
185
246
|
expect(store.getState().doc.nodes['boxNode002']?.name).toBe('Footer');
|
|
186
247
|
expect(store.getState().undoLabel).toBe('node.setAttr');
|
|
187
|
-
expect(container.querySelector('input')).toBeNull();
|
|
248
|
+
expect(container.querySelector('[role=tree] input')).toBeNull();
|
|
188
249
|
await press('F2');
|
|
189
250
|
await act(async () => {
|
|
190
|
-
const again = container.querySelector('input');
|
|
251
|
+
const again = container.querySelector('[role=tree] input');
|
|
191
252
|
again.value = 'Nope';
|
|
192
253
|
again.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
193
254
|
});
|
|
@@ -204,6 +265,23 @@ describe('LayersPanel', () => {
|
|
|
204
265
|
expect(store.getState().doc.nodes['boxNode001']).toBeUndefined();
|
|
205
266
|
expect(labels()).toEqual(['page', 'Box']);
|
|
206
267
|
});
|
|
268
|
+
it('keeps a locked block in place: Delete and the menu say why and change nothing', async () => {
|
|
269
|
+
const store = await mount(fixture(), true, () => true);
|
|
270
|
+
const row = items().find((i) => i.dataset['nodeId'] === 'boxNode001');
|
|
271
|
+
await act(async () => row?.querySelector('button[aria-label="Lock"]')?.click());
|
|
272
|
+
const locked = store.getState().doc;
|
|
273
|
+
await pick(store, 'boxNode001');
|
|
274
|
+
await act(async () => tree().focus());
|
|
275
|
+
await press('Delete');
|
|
276
|
+
const message = 'This block is locked. Unlock it in the Structure panel.';
|
|
277
|
+
expect(container.textContent).toContain(message);
|
|
278
|
+
expect(store.getState().doc).toBe(locked);
|
|
279
|
+
// An unlocked sibling still goes.
|
|
280
|
+
await pick(store, 'boxNode002');
|
|
281
|
+
await act(async () => tree().focus());
|
|
282
|
+
await press('Delete');
|
|
283
|
+
expect(store.getState().doc.nodes['boxNode002']).toBeUndefined();
|
|
284
|
+
});
|
|
207
285
|
it('opens the ancestors of a node selected elsewhere, and marks it selected', async () => {
|
|
208
286
|
const store = await mount();
|
|
209
287
|
expect(labels()).toEqual(['page', 'Hero', 'Box']);
|
|
@@ -245,14 +323,46 @@ describe('LayersPanel', () => {
|
|
|
245
323
|
expect(store.getState().selectedIds).toEqual(['boxNode001']);
|
|
246
324
|
const menu = document.body.querySelector('[role=menu]');
|
|
247
325
|
expect(menu?.getAttribute('aria-label')).toBe('Layer actions');
|
|
248
|
-
const names = [...(menu?.querySelectorAll('[role=menuitem]') ?? [])].map((i) => i.textContent);
|
|
249
|
-
expect(names).toEqual([
|
|
250
|
-
|
|
326
|
+
const names = [...(menu?.querySelectorAll('[role=menuitem]') ?? [])].map((i) => i.querySelector('.bd-menu-item-label')?.textContent);
|
|
327
|
+
expect(names).toEqual([
|
|
328
|
+
'Rename',
|
|
329
|
+
'Duplicate',
|
|
330
|
+
'Copy',
|
|
331
|
+
'Paste',
|
|
332
|
+
'Wrap in container',
|
|
333
|
+
'Unwrap',
|
|
334
|
+
'Hide in editor',
|
|
335
|
+
'Lock',
|
|
336
|
+
'Delete',
|
|
337
|
+
]);
|
|
338
|
+
const duplicate = [...(menu?.querySelectorAll('[role=menuitem]') ?? [])].find((i) => i.querySelector('.bd-menu-item-label')?.textContent === 'Duplicate');
|
|
251
339
|
await act(async () => {
|
|
252
340
|
duplicate.click();
|
|
253
341
|
});
|
|
254
342
|
expect(store.getState().doc.nodes['root']?.slots?.['default']).toHaveLength(3);
|
|
255
343
|
});
|
|
344
|
+
it('copies through the shared clipboard and pastes as an undoable command', async () => {
|
|
345
|
+
const store = await mount({ ...fixture(), components: { 'buildr/page': 1, 'buildr/box': 1, 'buildr/text': 1 } }, true);
|
|
346
|
+
const open = async () => act(async () => {
|
|
347
|
+
items()
|
|
348
|
+
.find((i) => i.dataset['nodeId'] === 'boxNode001')
|
|
349
|
+
?.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true }));
|
|
350
|
+
});
|
|
351
|
+
const action = (label) => [...document.querySelectorAll('[role=menuitem]')].find((i) => i.querySelector('.bd-menu-item-label')?.textContent === label);
|
|
352
|
+
const before = store.getState().doc;
|
|
353
|
+
await open();
|
|
354
|
+
await act(async () => action('Copy').click());
|
|
355
|
+
expect(store.getState().doc).toBe(before);
|
|
356
|
+
await open();
|
|
357
|
+
expect(await axe(document.querySelector('[role=menu]'))).toHaveNoViolations();
|
|
358
|
+
await act(async () => action('Paste').click());
|
|
359
|
+
expect(store.getState().doc.nodes['root']?.slots?.['default']).toHaveLength(3);
|
|
360
|
+
expect(store.getState().undoLabel).toBe('node.insert');
|
|
361
|
+
await act(async () => {
|
|
362
|
+
store.undo();
|
|
363
|
+
});
|
|
364
|
+
expect(store.getState().doc).toEqual(before);
|
|
365
|
+
});
|
|
256
366
|
it('opens the same context menu from the hover "more" button, without starting a rename', async () => {
|
|
257
367
|
const store = await mount();
|
|
258
368
|
const more = items()[1]?.querySelector('[data-more] button');
|
|
@@ -263,7 +373,7 @@ describe('LayersPanel', () => {
|
|
|
263
373
|
expect(store.getState().selectedIds).toEqual(['boxNode001']);
|
|
264
374
|
const menu = document.body.querySelector('[role=menu]');
|
|
265
375
|
expect(menu?.getAttribute('aria-label')).toBe('Layer actions');
|
|
266
|
-
expect(container.querySelector('input')).toBeNull();
|
|
376
|
+
expect(container.querySelector('[role=tree] input')).toBeNull();
|
|
267
377
|
});
|
|
268
378
|
it('does not offer changes in a read-only document', async () => {
|
|
269
379
|
const store = await mount();
|
|
@@ -273,7 +383,7 @@ describe('LayersPanel', () => {
|
|
|
273
383
|
await press('Delete');
|
|
274
384
|
await press('F2');
|
|
275
385
|
expect(store.getState().doc.nodes['boxNode001']).toBeDefined();
|
|
276
|
-
expect(container.querySelector('input')).toBeNull();
|
|
386
|
+
expect(container.querySelector('[role=tree] input')).toBeNull();
|
|
277
387
|
});
|
|
278
388
|
});
|
|
279
389
|
describe('a large document', () => {
|
|
@@ -304,7 +414,7 @@ describe('a large document', () => {
|
|
|
304
414
|
expect(items().length).toBeLessThan(40);
|
|
305
415
|
expect(elapsed).toBeLessThan(500);
|
|
306
416
|
const list = container.querySelector('.bd-layers-list');
|
|
307
|
-
expect(list.style.height).toBe(`${1001 *
|
|
417
|
+
expect(list.style.height).toBe(`${1001 * 32}px`);
|
|
308
418
|
});
|
|
309
419
|
it('scrolls the row of a far selection into view', async () => {
|
|
310
420
|
const store = await mount(big());
|
|
@@ -313,3 +423,51 @@ describe('a large document', () => {
|
|
|
313
423
|
expect(present).toContain('n000000900');
|
|
314
424
|
});
|
|
315
425
|
});
|
|
426
|
+
describe('structure filter and expand all (PB-157)', () => {
|
|
427
|
+
const field = () => container.querySelector('.bd-layers-filter input');
|
|
428
|
+
const typeFilter = (value) => act(async () => {
|
|
429
|
+
Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set?.call(field(), value);
|
|
430
|
+
field().dispatchEvent(new Event('input', { bubbles: true }));
|
|
431
|
+
});
|
|
432
|
+
const tool = (label) => container.querySelector(`button[aria-label="${label}"]`);
|
|
433
|
+
it('filterTree keeps the ancestors of a match and opens them', () => {
|
|
434
|
+
const doc = fixture();
|
|
435
|
+
const { only, open } = filterTree(doc, (n) => n.id === 'textNodeB1');
|
|
436
|
+
expect([...only].sort()).toEqual(['boxNode001', 'root', 'textNodeB1']);
|
|
437
|
+
expect(open.has('boxNode001')).toBe(true);
|
|
438
|
+
const rows = flattenTree(doc, open, only);
|
|
439
|
+
expect(rows.map((r) => r.id)).toEqual(['root', 'boxNode001', 'textNodeB1']);
|
|
440
|
+
});
|
|
441
|
+
it('shows only the matching blocks with their ancestors, and says when nothing matches', async () => {
|
|
442
|
+
await mount();
|
|
443
|
+
await typeFilter('hero');
|
|
444
|
+
expect(labels()).toEqual(['page', 'Hero']);
|
|
445
|
+
await typeFilter('text');
|
|
446
|
+
expect(labels()).toContain('Hero');
|
|
447
|
+
expect(items().length).toBe(4);
|
|
448
|
+
await typeFilter('zzz');
|
|
449
|
+
expect(items().length).toBe(0);
|
|
450
|
+
expect(container.querySelector('.bd-layers-empty')?.textContent).toBe('No blocks match the filter.');
|
|
451
|
+
await typeFilter('');
|
|
452
|
+
expect(container.querySelector('.bd-layers-empty')).toBeNull();
|
|
453
|
+
});
|
|
454
|
+
it('collapses and expands the whole tree, and is off while filtering', async () => {
|
|
455
|
+
await mount();
|
|
456
|
+
await act(async () => tool('Collapse all').click());
|
|
457
|
+
expect(items().length).toBe(3);
|
|
458
|
+
await act(async () => tool('Expand all').click());
|
|
459
|
+
expect(items().length).toBe(5);
|
|
460
|
+
await typeFilter('a');
|
|
461
|
+
expect(tool('Expand all').disabled).toBe(true);
|
|
462
|
+
expect(tool('Collapse all').disabled).toBe(true);
|
|
463
|
+
});
|
|
464
|
+
it('moves from the filter field into the tree with the down arrow', async () => {
|
|
465
|
+
await mount();
|
|
466
|
+
field().focus();
|
|
467
|
+
await act(async () => {
|
|
468
|
+
field().dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
|
|
469
|
+
});
|
|
470
|
+
expect(container.contains(document.activeElement)).toBe(true);
|
|
471
|
+
expect(document.activeElement).not.toBe(field());
|
|
472
|
+
});
|
|
473
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type LeftPanelTab } from '../app/contracts.ts';
|
|
3
|
+
export interface LeftPanelProps {
|
|
4
|
+
readonly tab: LeftPanelTab;
|
|
5
|
+
readonly onTabChange: (tab: LeftPanelTab) => void;
|
|
6
|
+
readonly onCollapse: () => void;
|
|
7
|
+
/** The Blocks tab (`InsertPanel`). */
|
|
8
|
+
readonly blocks: ReactNode;
|
|
9
|
+
/** The Structure tab (`LayersPanel`). */
|
|
10
|
+
readonly structure: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The left panel: Blocks and Structure tabs (a tablist with arrow-key roving), a collapse button
|
|
14
|
+
* and the active tab's body. Only the active body is mounted.
|
|
15
|
+
*/
|
|
16
|
+
export declare function LeftPanel({ tab, onTabChange, onCollapse, blocks, structure }: LeftPanelProps): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=left-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"left-panel.d.ts","sourceRoot":"","sources":["../../src/panels/left-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAiB,MAAM,OAAO,CAAC;AAC1E,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIzE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAChC,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B;AAOD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,cAAc,+BAwE5F"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId, useRef } from 'react';
|
|
3
|
+
import { LEFT_PANEL_TABS } from '../app/contracts.js';
|
|
4
|
+
import { useT } from '../messages/index.js';
|
|
5
|
+
import { Icon, IconButton } from '../ui/index.js';
|
|
6
|
+
const TAB_ICON = {
|
|
7
|
+
blocks: 'layout-grid',
|
|
8
|
+
structure: 'list-tree',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The left panel: Blocks and Structure tabs (a tablist with arrow-key roving), a collapse button
|
|
12
|
+
* and the active tab's body. Only the active body is mounted.
|
|
13
|
+
*/
|
|
14
|
+
export function LeftPanel({ tab, onTabChange, onCollapse, blocks, structure }) {
|
|
15
|
+
const t = useT();
|
|
16
|
+
const base = useId();
|
|
17
|
+
const refs = useRef(new Map());
|
|
18
|
+
const tabId = (value) => `${base}-tab-${value}`;
|
|
19
|
+
const panelId = `${base}-panel`;
|
|
20
|
+
const onKeyDown = (event) => {
|
|
21
|
+
const index = LEFT_PANEL_TABS.indexOf(tab);
|
|
22
|
+
const last = LEFT_PANEL_TABS.length - 1;
|
|
23
|
+
let next;
|
|
24
|
+
if (event.key === 'ArrowRight')
|
|
25
|
+
next = index === last ? 0 : index + 1;
|
|
26
|
+
else if (event.key === 'ArrowLeft')
|
|
27
|
+
next = index === 0 ? last : index - 1;
|
|
28
|
+
else if (event.key === 'Home')
|
|
29
|
+
next = 0;
|
|
30
|
+
else if (event.key === 'End')
|
|
31
|
+
next = last;
|
|
32
|
+
else
|
|
33
|
+
return;
|
|
34
|
+
event.preventDefault();
|
|
35
|
+
const value = LEFT_PANEL_TABS[next];
|
|
36
|
+
if (value === undefined)
|
|
37
|
+
return;
|
|
38
|
+
onTabChange(value);
|
|
39
|
+
refs.current.get(value)?.focus();
|
|
40
|
+
};
|
|
41
|
+
return (_jsxs("aside", { className: "bd-left-panel", "aria-label": t('leftPanel.label'), children: [_jsxs("div", { className: "bd-left-panel-head", children: [_jsx("div", { role: "tablist", "aria-label": t('leftPanel.tablistLabel'), className: "bd-tabs-list", onKeyDown: onKeyDown, children: LEFT_PANEL_TABS.map((value) => (_jsxs("button", { ref: (node) => {
|
|
42
|
+
if (node === null)
|
|
43
|
+
refs.current.delete(value);
|
|
44
|
+
else
|
|
45
|
+
refs.current.set(value, node);
|
|
46
|
+
}, type: "button", role: "tab", id: tabId(value), className: "bd-tab", "data-state": tab === value ? 'active' : 'inactive', "aria-selected": tab === value, "aria-controls": tab === value ? panelId : undefined, tabIndex: tab === value ? 0 : -1, onClick: () => onTabChange(value), children: [_jsx(Icon, { name: TAB_ICON[value] }), t(`leftPanel.tab.${value}`)] }, value))) }), _jsx(IconButton, { size: "sm", icon: "chevrons-left", label: t('leftPanel.collapse'), onClick: onCollapse })] }), _jsx("div", { role: "tabpanel", id: panelId, "aria-labelledby": tabId(tab), className: "bd-left-panel-body", "data-tab": tab, children: tab === 'blocks' ? blocks : structure })] }));
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"left-panel.test.d.ts","sourceRoot":"","sources":["../../src/panels/left-panel.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @vitest-environment jsdom
|
|
3
|
+
import { act, useState } from 'react';
|
|
4
|
+
import { createRoot } from 'react-dom/client';
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { axe } from 'vitest-axe';
|
|
7
|
+
import * as matchers from 'vitest-axe/matchers';
|
|
8
|
+
import { MessagesProvider } from '../messages/index.js';
|
|
9
|
+
import { LeftPanel } from './left-panel.js';
|
|
10
|
+
expect.extend(matchers);
|
|
11
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
12
|
+
let container;
|
|
13
|
+
let root;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
container = document.createElement('div');
|
|
16
|
+
document.body.append(container);
|
|
17
|
+
root = createRoot(container);
|
|
18
|
+
});
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
act(() => root.unmount());
|
|
21
|
+
document.body.innerHTML = '';
|
|
22
|
+
});
|
|
23
|
+
function Harness({ onCollapse }) {
|
|
24
|
+
const [tab, setTab] = useState('blocks');
|
|
25
|
+
return (_jsx(LeftPanel, { tab: tab, onTabChange: setTab, onCollapse: onCollapse, blocks: _jsx("p", { children: "blocks body" }), structure: _jsx("p", { children: "structure body" }) }));
|
|
26
|
+
}
|
|
27
|
+
async function mount(locale = 'en', onCollapse = () => { }) {
|
|
28
|
+
await act(async () => root.render(_jsx(MessagesProvider, { locale: locale, children: _jsx(Harness, { onCollapse: onCollapse }) })));
|
|
29
|
+
}
|
|
30
|
+
const tabs = () => [...container.querySelectorAll('[role=tab]')];
|
|
31
|
+
const key = (el, k) => act(async () => {
|
|
32
|
+
el.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true, cancelable: true }));
|
|
33
|
+
});
|
|
34
|
+
describe('LeftPanel', () => {
|
|
35
|
+
it('is a labelled tablist with a tabpanel and no accessibility violations', async () => {
|
|
36
|
+
await mount();
|
|
37
|
+
expect(container.querySelector('[role=tablist]')?.getAttribute('aria-label')).toBe('Left panel');
|
|
38
|
+
expect(tabs().map((t) => t.textContent)).toEqual(['Blocks', 'Structure']);
|
|
39
|
+
expect(tabs().map((t) => t.getAttribute('aria-selected'))).toEqual(['true', 'false']);
|
|
40
|
+
expect(tabs().map((t) => t.tabIndex)).toEqual([0, -1]);
|
|
41
|
+
const panel = container.querySelector('[role=tabpanel]');
|
|
42
|
+
expect(panel.textContent).toBe('blocks body');
|
|
43
|
+
expect(panel.getAttribute('aria-labelledby')).toBe(tabs()[0]?.id);
|
|
44
|
+
expect(tabs()[0]?.getAttribute('aria-controls')).toBe(panel.id);
|
|
45
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
46
|
+
});
|
|
47
|
+
it('switches by click and by arrow keys, wrapping, moving focus', async () => {
|
|
48
|
+
await mount();
|
|
49
|
+
await act(async () => tabs()[1]?.click());
|
|
50
|
+
expect(container.querySelector('[role=tabpanel]')?.textContent).toBe('structure body');
|
|
51
|
+
await key(tabs()[1], 'ArrowRight');
|
|
52
|
+
expect(tabs()[0]?.getAttribute('aria-selected')).toBe('true');
|
|
53
|
+
expect(document.activeElement).toBe(tabs()[0]);
|
|
54
|
+
await key(tabs()[0], 'ArrowLeft');
|
|
55
|
+
expect(tabs()[1]?.getAttribute('aria-selected')).toBe('true');
|
|
56
|
+
await key(tabs()[1], 'Home');
|
|
57
|
+
expect(tabs()[0]?.getAttribute('aria-selected')).toBe('true');
|
|
58
|
+
await key(tabs()[0], 'End');
|
|
59
|
+
expect(tabs()[1]?.getAttribute('aria-selected')).toBe('true');
|
|
60
|
+
});
|
|
61
|
+
it('collapses with the collapse button', async () => {
|
|
62
|
+
const onCollapse = vi.fn();
|
|
63
|
+
await mount('en', onCollapse);
|
|
64
|
+
const button = container.querySelector('button[aria-label="Collapse panel"]');
|
|
65
|
+
await act(async () => button.click());
|
|
66
|
+
expect(onCollapse).toHaveBeenCalledOnce();
|
|
67
|
+
});
|
|
68
|
+
it('uses the Polish labels', async () => {
|
|
69
|
+
await mount('pl');
|
|
70
|
+
expect(tabs().map((t) => t.textContent)).toEqual(['Bloki', 'Struktura']);
|
|
71
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
72
|
+
await act(async () => tabs()[1]?.click());
|
|
73
|
+
expect(container.querySelector('[role=tabpanel]')?.getAttribute('aria-labelledby')).toBe(tabs()[1]?.id);
|
|
74
|
+
expect(container.querySelector('[role=tabpanel] input')).toBeNull();
|
|
75
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -466,18 +466,24 @@ describe('PersistenceProvider', () => {
|
|
|
466
466
|
expect(banner()?.textContent).toBe('');
|
|
467
467
|
expect(controller.state.getState().revision).toBe(2);
|
|
468
468
|
});
|
|
469
|
-
it('asks the author to choose in a conflict', async () => {
|
|
469
|
+
it('asks the author to choose in a conflict, as an alert dialog, and gives focus back', async () => {
|
|
470
470
|
const fake = fakeAdapter();
|
|
471
471
|
fake.next = () => ({ ok: false, kind: 'conflict', currentRevision: 9 });
|
|
472
472
|
const { store, controller } = await mount(fake);
|
|
473
|
+
const opener = document.createElement('button');
|
|
474
|
+
document.body.append(opener);
|
|
475
|
+
opener.focus();
|
|
473
476
|
edit(store);
|
|
474
477
|
await advance(2000);
|
|
475
|
-
const dialog = document.querySelector('[role=
|
|
478
|
+
const dialog = document.querySelector('[role=alertdialog]');
|
|
476
479
|
expect(dialog?.textContent).toContain('This page was changed elsewhere');
|
|
480
|
+
expect(dialog?.getAttribute('aria-describedby')).not.toBeNull();
|
|
481
|
+
expect(dialog?.querySelector('.bd-dialog-icon[data-tone="warning"]')).not.toBeNull();
|
|
477
482
|
fake.next = () => ({ ok: true, revision: 10, updatedAt: 't10' });
|
|
478
483
|
const overwrite = [...(dialog?.querySelectorAll('button') ?? [])].find((b) => b.textContent?.includes('Overwrite'));
|
|
479
484
|
await act(async () => overwrite?.click());
|
|
480
485
|
expect(status(controller)).toBe('clean');
|
|
481
|
-
expect(document.querySelector('[role=
|
|
486
|
+
expect(document.querySelector('[role=alertdialog]')).toBeNull();
|
|
487
|
+
await vi.waitFor(() => expect(document.activeElement).toBe(opener));
|
|
482
488
|
});
|
|
483
489
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/persistence/react.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAyB,MAAM,OAAO,CAAC;AAK7E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAgB,cAAc,IAAI,qBAAqB,CAMtD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,CAAC,GAAG,CAAC,CAElF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B,+BA8BA;AAED,wGAAwG;AACxG,wBAAgB,aAAa,IAAI,MAAM,OAAO,CAM7C;
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/persistence/react.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAyB,MAAM,OAAO,CAAC;AAK7E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,wBAAgB,cAAc,IAAI,qBAAqB,CAMtD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,CAAC,GAAG,CAAC,CAElF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B,+BA8BA;AAED,wGAAwG;AACxG,wBAAgB,aAAa,IAAI,MAAM,OAAO,CAM7C;AA6DD,8FAA8F;AAC9F,wBAAgB,UAAU,gCAqBzB"}
|
|
@@ -85,9 +85,9 @@ function ConflictDialog() {
|
|
|
85
85
|
const t = useT();
|
|
86
86
|
const controller = usePersistence();
|
|
87
87
|
const status = usePersistenceState((state) => state.status);
|
|
88
|
-
return (_jsx(Dialog, { open: status === 'conflict', hideClose: true,
|
|
88
|
+
return (_jsx(Dialog, { open: status === 'conflict', hideClose: true, alert: true, icon: "triangle-alert", tone: "warning",
|
|
89
89
|
// The choice is the only way out: closing without one would leave the editor stuck in conflict.
|
|
90
|
-
onOpenChange: () => undefined, title: t('save.conflict.title'), description: t('save.conflict.description'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => void controller.reload(), children: t('save.conflict.reload') }), _jsx(Button, { variant: "
|
|
90
|
+
onOpenChange: () => undefined, title: t('save.conflict.title'), description: t('save.conflict.description'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => void controller.reload(), children: t('save.conflict.reload') }), _jsx(Button, { variant: "primary", onClick: () => void controller.overwrite(), children: t('save.conflict.overwrite') })] }), children: _jsx("p", { children: t('dialog.conflict.note') }) }));
|
|
91
91
|
}
|
|
92
92
|
/** A short status line for the toolbar (PB-083): saved, unsaved, saving, failed, conflict. */
|
|
93
93
|
export function SaveStatus() {
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import { type DocumentAdapter, type DocumentRef } from '../persistence/index.ts';
|
|
3
|
+
/**
|
|
4
|
+
* The preview frame's sandbox. `allow-same-origin` is kept only for a preview served from the
|
|
5
|
+
* editor's own origin (the playground's `/preview` reads the draft from `sessionStorage`, which a
|
|
6
|
+
* sandboxed, opaque origin cannot). A preview on another origin has its own storage and needs no
|
|
7
|
+
* access to the editor's, so the flag is left out; with both `allow-scripts` and
|
|
8
|
+
* `allow-same-origin` a same-origin page could otherwise remove its own sandbox.
|
|
9
|
+
*/
|
|
10
|
+
export declare function previewSandbox(url: string, base?: string): string;
|
|
3
11
|
export interface PreviewOverlayProps {
|
|
4
12
|
readonly url: string;
|
|
5
13
|
readonly onExit: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/preview/preview.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAoC,MAAM,OAAO,CAAC;AAEzE,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAkB,MAAM,yBAAyB,CAAC;AAIjG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,mBAAmB,+BA0BlE;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;IAChD,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACrD;AAED,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CA6BjE"}
|
|
1
|
+
{"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/preview/preview.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAoC,MAAM,OAAO,CAAC;AAEzE,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAkB,MAAM,yBAAyB,CAAC;AAIjG;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAWjE;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,mBAAmB,+BA0BlE;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;IAChD,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACrD;AAED,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CA6BjE"}
|
package/dist/preview/preview.js
CHANGED
|
@@ -4,6 +4,26 @@ import { useT } from '../messages/index.js';
|
|
|
4
4
|
import { usePersistence } from '../persistence/index.js';
|
|
5
5
|
import { Button } from '../ui/index.js';
|
|
6
6
|
import { preparePreview } from './prepare.js';
|
|
7
|
+
/**
|
|
8
|
+
* The preview frame's sandbox. `allow-same-origin` is kept only for a preview served from the
|
|
9
|
+
* editor's own origin (the playground's `/preview` reads the draft from `sessionStorage`, which a
|
|
10
|
+
* sandboxed, opaque origin cannot). A preview on another origin has its own storage and needs no
|
|
11
|
+
* access to the editor's, so the flag is left out; with both `allow-scripts` and
|
|
12
|
+
* `allow-same-origin` a same-origin page could otherwise remove its own sandbox.
|
|
13
|
+
*/
|
|
14
|
+
export function previewSandbox(url, base) {
|
|
15
|
+
const flags = ['allow-scripts', 'allow-forms', 'allow-popups'];
|
|
16
|
+
try {
|
|
17
|
+
const here = base ?? globalThis.location?.href;
|
|
18
|
+
if (here !== undefined && new URL(url, here).origin === new URL(here).origin) {
|
|
19
|
+
flags.splice(1, 0, 'allow-same-origin');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// An unparseable URL is treated as foreign: no same-origin access.
|
|
24
|
+
}
|
|
25
|
+
return flags.join(' ');
|
|
26
|
+
}
|
|
7
27
|
/** The page as visitors get it, over the whole editor; Escape or the button leaves it. */
|
|
8
28
|
export function PreviewOverlay({ url, onExit }) {
|
|
9
29
|
const t = useT();
|
|
@@ -15,7 +35,7 @@ export function PreviewOverlay({ url, onExit }) {
|
|
|
15
35
|
window.addEventListener('keydown', onKey);
|
|
16
36
|
return () => window.removeEventListener('keydown', onKey);
|
|
17
37
|
}, [onExit]);
|
|
18
|
-
return (_jsxs("div", { className: "bd-preview", role: "dialog", "aria-modal": "true", "aria-label": t('preview.title'), children: [_jsxs("div", { className: "bd-preview-bar", children: [_jsx("span", { children: t('preview.title') }), _jsx(Button, { variant: "primary", onClick: onExit, autoFocus: true, children: t('preview.exit') })] }), _jsx("iframe", { className: "bd-preview-frame", title: t('preview.frame'), src: url, sandbox:
|
|
38
|
+
return (_jsxs("div", { className: "bd-preview", role: "dialog", "aria-modal": "true", "aria-label": t('preview.title'), children: [_jsxs("div", { className: "bd-preview-bar", children: [_jsx("span", { children: t('preview.title') }), _jsx(Button, { variant: "primary", onClick: onExit, autoFocus: true, children: t('preview.exit') })] }), _jsx("iframe", { className: "bd-preview-frame", title: t('preview.frame'), src: url, sandbox: previewSandbox(url), referrerPolicy: "no-referrer" })] }));
|
|
19
39
|
}
|
|
20
40
|
/** Saves, then shows the preview (docs/editor.md#preview). */
|
|
21
41
|
export function usePreview(options) {
|
|
@@ -9,7 +9,7 @@ import { createPersistence, PersistenceProvider } from '../persistence/index.js'
|
|
|
9
9
|
import { createEditorStore, EditorStoreProvider } from '../store/index.js';
|
|
10
10
|
import { ToastProvider } from '../ui/index.js';
|
|
11
11
|
import { isSafePreviewUrl } from './prepare.js';
|
|
12
|
-
import { usePreview } from './preview.js';
|
|
12
|
+
import { previewSandbox, usePreview } from './preview.js';
|
|
13
13
|
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
14
14
|
const item = {
|
|
15
15
|
type: 'buildr/item',
|
|
@@ -127,3 +127,20 @@ describe('preview', () => {
|
|
|
127
127
|
expect(container.textContent).toContain('not a web address');
|
|
128
128
|
});
|
|
129
129
|
});
|
|
130
|
+
describe('previewSandbox', () => {
|
|
131
|
+
const editor = 'https://editor.example/app';
|
|
132
|
+
it('keeps allow-same-origin only for a preview on the editor origin', () => {
|
|
133
|
+
expect(previewSandbox('/preview?x=1', editor)).toBe('allow-scripts allow-same-origin allow-forms allow-popups');
|
|
134
|
+
expect(previewSandbox('https://editor.example/preview', editor)).toContain('allow-same-origin');
|
|
135
|
+
});
|
|
136
|
+
it('omits it for another origin, another port or an unparseable URL', () => {
|
|
137
|
+
for (const url of [
|
|
138
|
+
'https://site.example/p',
|
|
139
|
+
'https://editor.example:8443/p',
|
|
140
|
+
'http://editor.example/p',
|
|
141
|
+
]) {
|
|
142
|
+
expect(previewSandbox(url, editor)).toBe('allow-scripts allow-forms allow-popups');
|
|
143
|
+
}
|
|
144
|
+
expect(previewSandbox('http://[bad', editor)).toBe('allow-scripts allow-forms allow-popups');
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type NodeId } from '@next-buildr/core';
|
|
2
|
+
import type { RemoveRequest, ShortcutCallbacks } from '../app/contracts.ts';
|
|
3
|
+
import { type EditorStore } from '../store/index.ts';
|
|
2
4
|
import type { ShortcutRegistry } from './registry.ts';
|
|
3
5
|
/** What the editor's own shortcuts need from outside: the actions of other modules (PB-085, PB-087). */
|
|
4
6
|
export interface ExternalActions {
|
|
@@ -7,11 +9,20 @@ export interface ExternalActions {
|
|
|
7
9
|
readonly paste?: () => boolean | undefined;
|
|
8
10
|
readonly save?: () => boolean | undefined;
|
|
9
11
|
}
|
|
12
|
+
/** The UI-only and removal hooks of the host, read on every key press so they may change between renders. */
|
|
13
|
+
export interface HostHooks {
|
|
14
|
+
readonly callbacks?: () => Partial<ShortcutCallbacks> | undefined;
|
|
15
|
+
readonly onRemove?: () => ((request: RemoveRequest) => void) | undefined;
|
|
16
|
+
/** Whether the UI-only keys may run for the key press being handled (`false` for a key aimed outside the editor). */
|
|
17
|
+
readonly uiAllowed?: () => boolean;
|
|
18
|
+
/** Tells the person why a structure-locked block was not removed, moved or duplicated. */
|
|
19
|
+
readonly onLocked?: () => ((ids?: readonly NodeId[]) => void) | undefined;
|
|
20
|
+
}
|
|
10
21
|
/**
|
|
11
22
|
* Binds the shortcuts that act on the store (undo, redo, duplicate, delete, move, select, clear)
|
|
12
23
|
* and the ones other modules provide. Returns the function that unbinds them all. An action that
|
|
13
24
|
* cannot run (nothing selected, a locked node the command refuses) returns `false`, so the key is
|
|
14
25
|
* not swallowed.
|
|
15
26
|
*/
|
|
16
|
-
export declare function bindEditorActions(registry: ShortcutRegistry, store: EditorStore, external?: ExternalActions): () => void;
|
|
27
|
+
export declare function bindEditorActions(registry: ShortcutRegistry, store: EditorStore, external?: ExternalActions, host?: HostHooks): () => void;
|
|
17
28
|
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/shortcuts/actions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/shortcuts/actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,KAAK,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,wGAAwG;AACxG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;CAC3C;AAED,6GAA6G;AAC7G,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzE,qHAAqH;IACrH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC,0FAA0F;IAC1F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC3E;AAyDD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,WAAW,EAClB,QAAQ,GAAE,eAAoB,EAC9B,IAAI,GAAE,SAAc,GACnB,MAAM,IAAI,CA+EZ"}
|