@next-buildr/editor 0.0.0-stage → 2.0.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 +21 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/app/builder-editor.d.ts +8 -0
- package/dist/app/builder-editor.d.ts.map +1 -0
- package/dist/app/builder-editor.js +14 -0
- package/dist/app/builder-editor.test.d.ts +2 -0
- package/dist/app/builder-editor.test.d.ts.map +1 -0
- package/dist/app/builder-editor.test.js +199 -0
- package/dist/app/config.d.ts +59 -0
- package/dist/app/config.d.ts.map +1 -0
- package/dist/app/config.js +18 -0
- package/dist/app/content-language.test.d.ts +2 -0
- package/dist/app/content-language.test.d.ts.map +1 -0
- package/dist/app/content-language.test.js +157 -0
- package/dist/app/editor-app.d.ts +17 -0
- package/dist/app/editor-app.d.ts.map +1 -0
- package/dist/app/editor-app.js +206 -0
- package/dist/app/editor-app.test.d.ts +2 -0
- package/dist/app/editor-app.test.d.ts.map +1 -0
- package/dist/app/editor-app.test.js +135 -0
- package/dist/app/layout.d.ts +32 -0
- package/dist/app/layout.d.ts.map +1 -0
- package/dist/app/layout.js +82 -0
- package/dist/app/manifest.d.ts +12 -0
- package/dist/app/manifest.d.ts.map +1 -0
- package/dist/app/manifest.js +17 -0
- package/dist/app/shell-panels.d.ts +15 -0
- package/dist/app/shell-panels.d.ts.map +1 -0
- package/dist/app/shell-panels.js +5 -0
- package/dist/app/small-screen.d.ts +12 -0
- package/dist/app/small-screen.d.ts.map +1 -0
- package/dist/app/small-screen.js +33 -0
- package/dist/app/small-screen.test.d.ts +2 -0
- package/dist/app/small-screen.test.d.ts.map +1 -0
- package/dist/app/small-screen.test.js +108 -0
- package/dist/app/status-info.d.ts +14 -0
- package/dist/app/status-info.d.ts.map +1 -0
- package/dist/app/status-info.js +34 -0
- package/dist/app/use-resizable.d.ts +34 -0
- package/dist/app/use-resizable.d.ts.map +1 -0
- package/dist/app/use-resizable.js +84 -0
- package/dist/canvas-host/canvas-frame.d.ts +53 -0
- package/dist/canvas-host/canvas-frame.d.ts.map +1 -0
- package/dist/canvas-host/canvas-frame.js +146 -0
- package/dist/canvas-host/canvas-frame.test.d.ts +2 -0
- package/dist/canvas-host/canvas-frame.test.d.ts.map +1 -0
- package/dist/canvas-host/canvas-frame.test.js +91 -0
- package/dist/canvas-host/host.d.ts +109 -0
- package/dist/canvas-host/host.d.ts.map +1 -0
- package/dist/canvas-host/host.js +293 -0
- package/dist/canvas-host/host.test.d.ts +2 -0
- package/dist/canvas-host/host.test.d.ts.map +1 -0
- package/dist/canvas-host/host.test.js +398 -0
- package/dist/canvas-host/index.d.ts +5 -0
- package/dist/canvas-host/index.d.ts.map +1 -0
- package/dist/canvas-host/index.js +2 -0
- package/dist/clipboard/clipboard.d.ts +38 -0
- package/dist/clipboard/clipboard.d.ts.map +1 -0
- package/dist/clipboard/clipboard.js +160 -0
- package/dist/clipboard/clipboard.test.d.ts +2 -0
- package/dist/clipboard/clipboard.test.d.ts.map +1 -0
- package/dist/clipboard/clipboard.test.js +457 -0
- package/dist/clipboard/format.d.ts +27 -0
- package/dist/clipboard/format.d.ts.map +1 -0
- package/dist/clipboard/format.js +37 -0
- package/dist/clipboard/index.d.ts +6 -0
- package/dist/clipboard/index.d.ts.map +1 -0
- package/dist/clipboard/index.js +3 -0
- package/dist/clipboard/react.d.ts +20 -0
- package/dist/clipboard/react.d.ts.map +1 -0
- package/dist/clipboard/react.js +71 -0
- package/dist/dialogs/index.d.ts +2 -0
- package/dist/dialogs/index.d.ts.map +1 -0
- package/dist/dialogs/index.js +1 -0
- package/dist/dialogs/media-picker/index.d.ts +7 -0
- package/dist/dialogs/media-picker/index.d.ts.map +1 -0
- package/dist/dialogs/media-picker/index.js +3 -0
- package/dist/dialogs/media-picker/library.d.ts +17 -0
- package/dist/dialogs/media-picker/library.d.ts.map +1 -0
- package/dist/dialogs/media-picker/library.js +9 -0
- package/dist/dialogs/media-picker/media-picker.d.ts +18 -0
- package/dist/dialogs/media-picker/media-picker.d.ts.map +1 -0
- package/dist/dialogs/media-picker/media-picker.js +99 -0
- package/dist/dialogs/media-picker/media-picker.test.d.ts +2 -0
- package/dist/dialogs/media-picker/media-picker.test.d.ts.map +1 -0
- package/dist/dialogs/media-picker/media-picker.test.js +161 -0
- package/dist/dialogs/media-picker/media-ref.d.ts +28 -0
- package/dist/dialogs/media-picker/media-ref.d.ts.map +1 -0
- package/dist/dialogs/media-picker/media-ref.js +52 -0
- package/dist/dnd/check.d.ts +8 -0
- package/dist/dnd/check.d.ts.map +1 -0
- package/dist/dnd/check.js +12 -0
- package/dist/dnd/destinations.d.ts +15 -0
- package/dist/dnd/destinations.d.ts.map +1 -0
- package/dist/dnd/destinations.js +43 -0
- package/dist/dnd/dnd-react.test.d.ts +2 -0
- package/dist/dnd/dnd-react.test.d.ts.map +1 -0
- package/dist/dnd/dnd-react.test.js +93 -0
- package/dist/dnd/dnd.test.d.ts +2 -0
- package/dist/dnd/dnd.test.d.ts.map +1 -0
- package/dist/dnd/dnd.test.js +327 -0
- package/dist/dnd/engine.d.ts +85 -0
- package/dist/dnd/engine.d.ts.map +1 -0
- package/dist/dnd/engine.js +185 -0
- package/dist/dnd/fragment.d.ts +6 -0
- package/dist/dnd/fragment.d.ts.map +1 -0
- package/dist/dnd/fragment.js +18 -0
- package/dist/dnd/geometry.d.ts +30 -0
- package/dist/dnd/geometry.d.ts.map +1 -0
- package/dist/dnd/geometry.js +31 -0
- package/dist/dnd/index.d.ts +14 -0
- package/dist/dnd/index.d.ts.map +1 -0
- package/dist/dnd/index.js +7 -0
- package/dist/dnd/move-to-dialog.d.ts +13 -0
- package/dist/dnd/move-to-dialog.d.ts.map +1 -0
- package/dist/dnd/move-to-dialog.js +30 -0
- package/dist/dnd/react.d.ts +43 -0
- package/dist/dnd/react.d.ts.map +1 -0
- package/dist/dnd/react.js +185 -0
- package/dist/dnd/tree-target.d.ts +29 -0
- package/dist/dnd/tree-target.d.ts.map +1 -0
- package/dist/dnd/tree-target.js +97 -0
- package/dist/fonts/LICENSE-inter.txt +93 -0
- package/dist/fonts/inter-latin-400-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-500-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-600-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-ext-400-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-ext-500-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-ext-600-normal.woff2 +0 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/messages/en.d.ts +335 -0
- package/dist/messages/en.d.ts.map +1 -0
- package/dist/messages/en.js +332 -0
- package/dist/messages/index.d.ts +16 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +22 -0
- package/dist/messages/pl.d.ts +3 -0
- package/dist/messages/pl.d.ts.map +1 -0
- package/dist/messages/pl.js +327 -0
- package/dist/panels/breadcrumbs/breadcrumbs.d.ts +6 -0
- package/dist/panels/breadcrumbs/breadcrumbs.d.ts.map +1 -0
- package/dist/panels/breadcrumbs/breadcrumbs.js +24 -0
- package/dist/panels/breadcrumbs/breadcrumbs.test.d.ts +2 -0
- package/dist/panels/breadcrumbs/breadcrumbs.test.d.ts.map +1 -0
- package/dist/panels/breadcrumbs/breadcrumbs.test.js +56 -0
- package/dist/panels/index.d.ts +9 -0
- package/dist/panels/index.d.ts.map +1 -0
- package/dist/panels/index.js +6 -0
- package/dist/panels/insert/catalog.d.ts +30 -0
- package/dist/panels/insert/catalog.d.ts.map +1 -0
- package/dist/panels/insert/catalog.js +76 -0
- package/dist/panels/insert/catalog.order.test.d.ts +2 -0
- package/dist/panels/insert/catalog.order.test.d.ts.map +1 -0
- package/dist/panels/insert/catalog.order.test.js +17 -0
- package/dist/panels/insert/category-name.d.ts +4 -0
- package/dist/panels/insert/category-name.d.ts.map +1 -0
- package/dist/panels/insert/category-name.js +8 -0
- package/dist/panels/insert/index.d.ts +3 -0
- package/dist/panels/insert/index.d.ts.map +1 -0
- package/dist/panels/insert/index.js +2 -0
- package/dist/panels/insert/insert-panel.d.ts +7 -0
- package/dist/panels/insert/insert-panel.d.ts.map +1 -0
- package/dist/panels/insert/insert-panel.js +155 -0
- package/dist/panels/insert/insert-panel.test.d.ts +2 -0
- package/dist/panels/insert/insert-panel.test.d.ts.map +1 -0
- package/dist/panels/insert/insert-panel.test.js +323 -0
- package/dist/panels/insert/target.d.ts +17 -0
- package/dist/panels/insert/target.d.ts.map +1 -0
- package/dist/panels/insert/target.js +48 -0
- package/dist/panels/inspector/controls/boolean.d.ts +4 -0
- package/dist/panels/inspector/controls/boolean.d.ts.map +1 -0
- package/dist/panels/inspector/controls/boolean.js +4 -0
- package/dist/panels/inspector/controls/compound.d.ts +15 -0
- package/dist/panels/inspector/controls/compound.d.ts.map +1 -0
- package/dist/panels/inspector/controls/compound.js +99 -0
- package/dist/panels/inspector/controls/compound.test.d.ts +2 -0
- package/dist/panels/inspector/controls/compound.test.d.ts.map +1 -0
- package/dist/panels/inspector/controls/compound.test.js +195 -0
- package/dist/panels/inspector/controls/icon.d.ts +5 -0
- package/dist/panels/inspector/controls/icon.d.ts.map +1 -0
- package/dist/panels/inspector/controls/icon.js +6 -0
- package/dist/panels/inspector/controls/index.d.ts +13 -0
- package/dist/panels/inspector/controls/index.d.ts.map +1 -0
- package/dist/panels/inspector/controls/index.js +11 -0
- package/dist/panels/inspector/controls/label.d.ts +4 -0
- package/dist/panels/inspector/controls/label.d.ts.map +1 -0
- package/dist/panels/inspector/controls/label.js +8 -0
- package/dist/panels/inspector/controls/link.d.ts +5 -0
- package/dist/panels/inspector/controls/link.d.ts.map +1 -0
- package/dist/panels/inspector/controls/link.js +6 -0
- package/dist/panels/inspector/controls/media.d.ts +9 -0
- package/dist/panels/inspector/controls/media.d.ts.map +1 -0
- package/dist/panels/inspector/controls/media.js +21 -0
- package/dist/panels/inspector/controls/number.d.ts +10 -0
- package/dist/panels/inspector/controls/number.d.ts.map +1 -0
- package/dist/panels/inspector/controls/number.js +33 -0
- package/dist/panels/inspector/controls/rich-text-model.d.ts +20 -0
- package/dist/panels/inspector/controls/rich-text-model.d.ts.map +1 -0
- package/dist/panels/inspector/controls/rich-text-model.js +91 -0
- package/dist/panels/inspector/controls/rich-text.d.ts +10 -0
- package/dist/panels/inspector/controls/rich-text.d.ts.map +1 -0
- package/dist/panels/inspector/controls/rich-text.js +159 -0
- package/dist/panels/inspector/controls/select.d.ts +5 -0
- package/dist/panels/inspector/controls/select.d.ts.map +1 -0
- package/dist/panels/inspector/controls/select.js +16 -0
- package/dist/panels/inspector/controls/select.test.d.ts +2 -0
- package/dist/panels/inspector/controls/select.test.d.ts.map +1 -0
- package/dist/panels/inspector/controls/select.test.js +43 -0
- package/dist/panels/inspector/controls/text.d.ts +4 -0
- package/dist/panels/inspector/controls/text.d.ts.map +1 -0
- package/dist/panels/inspector/controls/text.js +5 -0
- package/dist/panels/inspector/controls/textarea.d.ts +4 -0
- package/dist/panels/inspector/controls/textarea.d.ts.map +1 -0
- package/dist/panels/inspector/controls/textarea.js +4 -0
- package/dist/panels/inspector/controls/types.d.ts +16 -0
- package/dist/panels/inspector/controls/types.d.ts.map +1 -0
- package/dist/panels/inspector/controls/types.js +1 -0
- package/dist/panels/inspector/index.d.ts +17 -0
- package/dist/panels/inspector/index.d.ts.map +1 -0
- package/dist/panels/inspector/index.js +9 -0
- package/dist/panels/inspector/inspector.d.ts +16 -0
- package/dist/panels/inspector/inspector.d.ts.map +1 -0
- package/dist/panels/inspector/inspector.js +116 -0
- package/dist/panels/inspector/inspector.test.d.ts +2 -0
- package/dist/panels/inspector/inspector.test.d.ts.map +1 -0
- package/dist/panels/inspector/inspector.test.js +328 -0
- package/dist/panels/inspector/props-panel.d.ts +26 -0
- package/dist/panels/inspector/props-panel.d.ts.map +1 -0
- package/dist/panels/inspector/props-panel.js +117 -0
- package/dist/panels/inspector/styles/box-model.d.ts +20 -0
- package/dist/panels/inspector/styles/box-model.d.ts.map +1 -0
- package/dist/panels/inspector/styles/box-model.js +31 -0
- package/dist/panels/inspector/styles/index.d.ts +5 -0
- package/dist/panels/inspector/styles/index.d.ts.map +1 -0
- package/dist/panels/inspector/styles/index.js +2 -0
- package/dist/panels/inspector/styles/model.d.ts +55 -0
- package/dist/panels/inspector/styles/model.d.ts.map +1 -0
- package/dist/panels/inspector/styles/model.js +111 -0
- package/dist/panels/inspector/styles/segments.d.ts +18 -0
- package/dist/panels/inspector/styles/segments.d.ts.map +1 -0
- package/dist/panels/inspector/styles/segments.js +75 -0
- package/dist/panels/inspector/styles/sides-editor.d.ts +34 -0
- package/dist/panels/inspector/styles/sides-editor.d.ts.map +1 -0
- package/dist/panels/inspector/styles/sides-editor.js +86 -0
- package/dist/panels/inspector/styles/style-inspector.d.ts +15 -0
- package/dist/panels/inspector/styles/style-inspector.d.ts.map +1 -0
- package/dist/panels/inspector/styles/style-inspector.js +219 -0
- package/dist/panels/inspector/styles/style-inspector.test.d.ts +2 -0
- package/dist/panels/inspector/styles/style-inspector.test.d.ts.map +1 -0
- package/dist/panels/inspector/styles/style-inspector.test.js +265 -0
- package/dist/panels/inspector/styles/token-picker.d.ts +15 -0
- package/dist/panels/inspector/styles/token-picker.d.ts.map +1 -0
- package/dist/panels/inspector/styles/token-picker.js +23 -0
- package/dist/panels/inspector/styles/use-style-value.d.ts +28 -0
- package/dist/panels/inspector/styles/use-style-value.d.ts.map +1 -0
- package/dist/panels/inspector/styles/use-style-value.js +51 -0
- package/dist/panels/inspector/value.d.ts +20 -0
- package/dist/panels/inspector/value.d.ts.map +1 -0
- package/dist/panels/inspector/value.js +32 -0
- package/dist/panels/inspector/values/analyze.d.ts +49 -0
- package/dist/panels/inspector/values/analyze.d.ts.map +1 -0
- package/dist/panels/inspector/values/analyze.js +115 -0
- package/dist/panels/inspector/values/data.d.ts +18 -0
- package/dist/panels/inspector/values/data.d.ts.map +1 -0
- package/dist/panels/inspector/values/data.js +10 -0
- package/dist/panels/inspector/values/translation.d.ts +20 -0
- package/dist/panels/inspector/values/translation.d.ts.map +1 -0
- package/dist/panels/inspector/values/translation.js +25 -0
- package/dist/panels/inspector/values/value-editor.d.ts +30 -0
- package/dist/panels/inspector/values/value-editor.d.ts.map +1 -0
- package/dist/panels/inspector/values/value-editor.js +191 -0
- package/dist/panels/inspector/values/values.test.d.ts +2 -0
- package/dist/panels/inspector/values/values.test.d.ts.map +1 -0
- package/dist/panels/inspector/values/values.test.js +173 -0
- package/dist/panels/issues/collect.d.ts +70 -0
- package/dist/panels/issues/collect.d.ts.map +1 -0
- package/dist/panels/issues/collect.js +96 -0
- package/dist/panels/issues/index.d.ts +5 -0
- package/dist/panels/issues/index.d.ts.map +1 -0
- package/dist/panels/issues/index.js +2 -0
- package/dist/panels/issues/issues-panel.d.ts +17 -0
- package/dist/panels/issues/issues-panel.d.ts.map +1 -0
- package/dist/panels/issues/issues-panel.js +77 -0
- package/dist/panels/layers/flatten.d.ts +28 -0
- package/dist/panels/layers/flatten.d.ts.map +1 -0
- package/dist/panels/layers/flatten.js +61 -0
- package/dist/panels/layers/layers-panel.d.ts +14 -0
- package/dist/panels/layers/layers-panel.d.ts.map +1 -0
- package/dist/panels/layers/layers-panel.js +428 -0
- package/dist/panels/layers/layers-panel.test.d.ts +2 -0
- package/dist/panels/layers/layers-panel.test.d.ts.map +1 -0
- package/dist/panels/layers/layers-panel.test.js +315 -0
- package/dist/persistence/controller.d.ts +55 -0
- package/dist/persistence/controller.d.ts.map +1 -0
- package/dist/persistence/controller.js +341 -0
- package/dist/persistence/index.d.ts +6 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +3 -0
- package/dist/persistence/load.d.ts +35 -0
- package/dist/persistence/load.d.ts.map +1 -0
- package/dist/persistence/load.js +67 -0
- package/dist/persistence/persistence.test.d.ts +2 -0
- package/dist/persistence/persistence.test.d.ts.map +1 -0
- package/dist/persistence/persistence.test.js +483 -0
- package/dist/persistence/react.d.ts +18 -0
- package/dist/persistence/react.d.ts.map +1 -0
- package/dist/persistence/react.js +105 -0
- package/dist/persistence/types.d.ts +182 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +1 -0
- package/dist/preview/index.d.ts +3 -0
- package/dist/preview/index.d.ts.map +1 -0
- package/dist/preview/index.js +2 -0
- package/dist/preview/prepare.d.ts +16 -0
- package/dist/preview/prepare.d.ts.map +1 -0
- package/dist/preview/prepare.js +21 -0
- package/dist/preview/preview.d.ts +27 -0
- package/dist/preview/preview.d.ts.map +1 -0
- package/dist/preview/preview.js +51 -0
- package/dist/preview/preview.test.d.ts +2 -0
- package/dist/preview/preview.test.d.ts.map +1 -0
- package/dist/preview/preview.test.js +129 -0
- package/dist/shortcuts/actions.d.ts +17 -0
- package/dist/shortcuts/actions.d.ts.map +1 -0
- package/dist/shortcuts/actions.js +85 -0
- package/dist/shortcuts/index.d.ts +11 -0
- package/dist/shortcuts/index.d.ts.map +1 -0
- package/dist/shortcuts/index.js +5 -0
- package/dist/shortcuts/keys.d.ts +29 -0
- package/dist/shortcuts/keys.d.ts.map +1 -0
- package/dist/shortcuts/keys.js +100 -0
- package/dist/shortcuts/map.d.ts +17 -0
- package/dist/shortcuts/map.d.ts.map +1 -0
- package/dist/shortcuts/map.js +31 -0
- package/dist/shortcuts/registry.d.ts +32 -0
- package/dist/shortcuts/registry.d.ts.map +1 -0
- package/dist/shortcuts/registry.js +53 -0
- package/dist/shortcuts/shortcuts.d.ts +32 -0
- package/dist/shortcuts/shortcuts.d.ts.map +1 -0
- package/dist/shortcuts/shortcuts.js +95 -0
- package/dist/shortcuts/shortcuts.test.d.ts +2 -0
- package/dist/shortcuts/shortcuts.test.d.ts.map +1 -0
- package/dist/shortcuts/shortcuts.test.js +263 -0
- package/dist/store/create-store.d.ts +13 -0
- package/dist/store/create-store.d.ts.map +1 -0
- package/dist/store/create-store.js +248 -0
- package/dist/store/index.d.ts +9 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +5 -0
- package/dist/store/locale.d.ts +23 -0
- package/dist/store/locale.d.ts.map +1 -0
- package/dist/store/locale.js +31 -0
- package/dist/store/react.d.ts +17 -0
- package/dist/store/react.d.ts.map +1 -0
- package/dist/store/react.js +32 -0
- package/dist/store/selection.d.ts +32 -0
- package/dist/store/selection.d.ts.map +1 -0
- package/dist/store/selection.js +84 -0
- package/dist/store/selection.test.d.ts +2 -0
- package/dist/store/selection.test.d.ts.map +1 -0
- package/dist/store/selection.test.js +95 -0
- package/dist/store/selectors.d.ts +18 -0
- package/dist/store/selectors.d.ts.map +1 -0
- package/dist/store/selectors.js +39 -0
- package/dist/store/store.test.d.ts +2 -0
- package/dist/store/store.test.d.ts.map +1 -0
- package/dist/store/store.test.js +331 -0
- package/dist/store/types.d.ts +114 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +1 -0
- package/dist/styles/tokens.test.d.ts +2 -0
- package/dist/styles/tokens.test.d.ts.map +1 -0
- package/dist/styles/tokens.test.js +199 -0
- package/dist/styles.css +2885 -0
- package/dist/toolbar/brand.d.ts +7 -0
- package/dist/toolbar/brand.d.ts.map +1 -0
- package/dist/toolbar/brand.js +11 -0
- package/dist/toolbar/breakpoint-control.d.ts +9 -0
- package/dist/toolbar/breakpoint-control.d.ts.map +1 -0
- package/dist/toolbar/breakpoint-control.js +23 -0
- package/dist/toolbar/editable-title.d.ts +14 -0
- package/dist/toolbar/editable-title.d.ts.map +1 -0
- package/dist/toolbar/editable-title.js +46 -0
- package/dist/toolbar/editable-title.test.d.ts +2 -0
- package/dist/toolbar/editable-title.test.d.ts.map +1 -0
- package/dist/toolbar/editable-title.test.js +53 -0
- package/dist/toolbar/index.d.ts +12 -0
- package/dist/toolbar/index.d.ts.map +1 -0
- package/dist/toolbar/index.js +5 -0
- package/dist/toolbar/locale-switcher.d.ts +10 -0
- package/dist/toolbar/locale-switcher.d.ts.map +1 -0
- package/dist/toolbar/locale-switcher.js +20 -0
- package/dist/toolbar/more-menu.d.ts +12 -0
- package/dist/toolbar/more-menu.d.ts.map +1 -0
- package/dist/toolbar/more-menu.js +47 -0
- package/dist/toolbar/panel-toggles.d.ts +9 -0
- package/dist/toolbar/panel-toggles.d.ts.map +1 -0
- package/dist/toolbar/panel-toggles.js +19 -0
- package/dist/toolbar/publish-dialog.d.ts +18 -0
- package/dist/toolbar/publish-dialog.d.ts.map +1 -0
- package/dist/toolbar/publish-dialog.js +49 -0
- package/dist/toolbar/publish.test.d.ts +2 -0
- package/dist/toolbar/publish.test.d.ts.map +1 -0
- package/dist/toolbar/publish.test.js +258 -0
- package/dist/toolbar/sample-picker.d.ts +18 -0
- package/dist/toolbar/sample-picker.d.ts.map +1 -0
- package/dist/toolbar/sample-picker.js +72 -0
- package/dist/toolbar/sample-picker.test.d.ts +2 -0
- package/dist/toolbar/sample-picker.test.d.ts.map +1 -0
- package/dist/toolbar/sample-picker.test.js +78 -0
- package/dist/toolbar/save-indicator.d.ts +8 -0
- package/dist/toolbar/save-indicator.d.ts.map +1 -0
- package/dist/toolbar/save-indicator.js +30 -0
- package/dist/toolbar/theme.d.ts +22 -0
- package/dist/toolbar/theme.d.ts.map +1 -0
- package/dist/toolbar/theme.js +46 -0
- package/dist/toolbar/theme.test.d.ts +2 -0
- package/dist/toolbar/theme.test.d.ts.map +1 -0
- package/dist/toolbar/theme.test.js +49 -0
- package/dist/toolbar/toolbar-centre.d.ts +13 -0
- package/dist/toolbar/toolbar-centre.d.ts.map +1 -0
- package/dist/toolbar/toolbar-centre.js +7 -0
- package/dist/toolbar/toolbar-left.d.ts +12 -0
- package/dist/toolbar/toolbar-left.d.ts.map +1 -0
- package/dist/toolbar/toolbar-left.js +16 -0
- package/dist/toolbar/toolbar-right.d.ts +19 -0
- package/dist/toolbar/toolbar-right.d.ts.map +1 -0
- package/dist/toolbar/toolbar-right.js +21 -0
- package/dist/toolbar/toolbar.d.ts +38 -0
- package/dist/toolbar/toolbar.d.ts.map +1 -0
- package/dist/toolbar/toolbar.js +27 -0
- package/dist/toolbar/toolbar.test.d.ts +2 -0
- package/dist/toolbar/toolbar.test.d.ts.map +1 -0
- package/dist/toolbar/toolbar.test.js +289 -0
- package/dist/toolbar/use-overflow-level.d.ts +9 -0
- package/dist/toolbar/use-overflow-level.d.ts.map +1 -0
- package/dist/toolbar/use-overflow-level.js +40 -0
- package/dist/toolbar/zoom-menu.d.ts +10 -0
- package/dist/toolbar/zoom-menu.d.ts.map +1 -0
- package/dist/toolbar/zoom-menu.js +17 -0
- package/dist/ui/icon.d.ts +102 -0
- package/dist/ui/icon.d.ts.map +1 -0
- package/dist/ui/icon.js +182 -0
- package/dist/ui/icon.test.d.ts +2 -0
- package/dist/ui/icon.test.d.ts.map +1 -0
- package/dist/ui/icon.test.js +115 -0
- package/dist/ui/index.d.ts +11 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +5 -0
- package/dist/ui/panel.d.ts +18 -0
- package/dist/ui/panel.d.ts.map +1 -0
- package/dist/ui/panel.js +21 -0
- package/dist/ui/portal.d.ts +14 -0
- package/dist/ui/portal.d.ts.map +1 -0
- package/dist/ui/portal.js +14 -0
- package/dist/ui/primitives.d.ts +190 -0
- package/dist/ui/primitives.d.ts.map +1 -0
- package/dist/ui/primitives.js +164 -0
- package/dist/ui/primitives.test.d.ts +2 -0
- package/dist/ui/primitives.test.d.ts.map +1 -0
- package/dist/ui/primitives.test.js +215 -0
- package/dist/ui/toast.d.ts +39 -0
- package/dist/ui/toast.d.ts.map +1 -0
- package/dist/ui/toast.js +76 -0
- package/dist/ui/toast.test.d.ts +2 -0
- package/dist/ui/toast.test.d.ts.map +1 -0
- package/dist/ui/toast.test.js +95 -0
- package/package.json +66 -3
- package/README.md +0 -3
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @vitest-environment jsdom
|
|
3
|
+
import { act } from 'react';
|
|
4
|
+
import { createRoot, hydrateRoot } from 'react-dom/client';
|
|
5
|
+
import { renderToString } from 'react-dom/server';
|
|
6
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import { MessagesProvider } from '../messages/index.js';
|
|
8
|
+
import { SmallScreenNotice, useViewportTooNarrow } from './small-screen.js';
|
|
9
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
10
|
+
let root;
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
act(() => root?.unmount());
|
|
13
|
+
vi.unstubAllGlobals();
|
|
14
|
+
});
|
|
15
|
+
/** A window `width` wide whose width can change, answering `(max-width: Npx)` queries. */
|
|
16
|
+
function stubWindow(initial) {
|
|
17
|
+
let width = initial;
|
|
18
|
+
const listeners = new Set();
|
|
19
|
+
vi.stubGlobal('matchMedia', (query) => {
|
|
20
|
+
const max = Number(/max-width: (\d+)px/.exec(query)?.[1]);
|
|
21
|
+
return {
|
|
22
|
+
get matches() {
|
|
23
|
+
return width <= max;
|
|
24
|
+
},
|
|
25
|
+
addEventListener: (_, fn) => listeners.add(fn),
|
|
26
|
+
removeEventListener: (_, fn) => listeners.delete(fn),
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
return (next) => {
|
|
30
|
+
width = next;
|
|
31
|
+
for (const fn of listeners)
|
|
32
|
+
fn();
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function Probe({ min }) {
|
|
36
|
+
const narrow = useViewportTooNarrow(min);
|
|
37
|
+
return _jsx("p", { children: narrow === undefined ? 'unknown' : narrow ? 'narrow' : 'wide' });
|
|
38
|
+
}
|
|
39
|
+
const mount = async (node) => {
|
|
40
|
+
const container = document.createElement('div');
|
|
41
|
+
document.body.append(container);
|
|
42
|
+
root = createRoot(container);
|
|
43
|
+
await act(async () => root?.render(node));
|
|
44
|
+
return container;
|
|
45
|
+
};
|
|
46
|
+
describe('useViewportTooNarrow', () => {
|
|
47
|
+
it('is true below the minimum and follows the window as it is resized', async () => {
|
|
48
|
+
const resize = stubWindow(700);
|
|
49
|
+
const view = await mount(_jsx(Probe, { min: 1024 }));
|
|
50
|
+
expect(view.textContent).toBe('narrow');
|
|
51
|
+
await act(async () => resize(1280));
|
|
52
|
+
expect(view.textContent).toBe('wide');
|
|
53
|
+
await act(async () => resize(820));
|
|
54
|
+
expect(view.textContent).toBe('narrow');
|
|
55
|
+
});
|
|
56
|
+
it('treats the minimum itself as wide enough, and 0 turns the check off', async () => {
|
|
57
|
+
stubWindow(1024);
|
|
58
|
+
expect((await mount(_jsx(Probe, { min: 1024 }))).textContent).toBe('wide');
|
|
59
|
+
act(() => root?.unmount());
|
|
60
|
+
stubWindow(300);
|
|
61
|
+
expect((await mount(_jsx(Probe, { min: 0 }))).textContent).toBe('wide');
|
|
62
|
+
});
|
|
63
|
+
it('is false where matchMedia does not exist', async () => {
|
|
64
|
+
vi.stubGlobal('matchMedia', undefined);
|
|
65
|
+
expect((await mount(_jsx(Probe, { min: 1024 }))).textContent).toBe('wide');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
/** What `EditorApp` shows: loading while unknown, the notice when narrow, else the editor. */
|
|
69
|
+
function Gate({ min }) {
|
|
70
|
+
const narrow = useViewportTooNarrow(min);
|
|
71
|
+
if (narrow === undefined)
|
|
72
|
+
return _jsx("p", { role: "status", children: "loading" });
|
|
73
|
+
return narrow ? (_jsx(MessagesProvider, { locale: "en", children: _jsx(SmallScreenNotice, {}) })) : (_jsx("p", { children: "editor" }));
|
|
74
|
+
}
|
|
75
|
+
describe('useViewportTooNarrow on the server and while hydrating', () => {
|
|
76
|
+
it('is unknown on the server, whatever the window would say', () => {
|
|
77
|
+
stubWindow(700);
|
|
78
|
+
const html = renderToString(_jsx(Gate, { min: 1024 }));
|
|
79
|
+
expect(html).toContain('loading');
|
|
80
|
+
expect(html).not.toContain('role="alert"');
|
|
81
|
+
});
|
|
82
|
+
it('hydrates a narrow window without a mismatch, then shows the notice', async () => {
|
|
83
|
+
stubWindow(700);
|
|
84
|
+
const html = renderToString(_jsx(Gate, { min: 1024 }));
|
|
85
|
+
const container = document.createElement('div');
|
|
86
|
+
document.body.append(container);
|
|
87
|
+
container.innerHTML = html;
|
|
88
|
+
const errors = [];
|
|
89
|
+
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
90
|
+
await act(async () => {
|
|
91
|
+
root = hydrateRoot(container, _jsx(Gate, { min: 1024 }), {
|
|
92
|
+
onRecoverableError: (error) => errors.push(error),
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
expect(errors).toEqual([]);
|
|
96
|
+
expect(consoleError).not.toHaveBeenCalled();
|
|
97
|
+
consoleError.mockRestore();
|
|
98
|
+
expect(container.querySelector('[role="alert"]')).not.toBeNull();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
describe('SmallScreenNotice', () => {
|
|
102
|
+
it('asks for a computer, in the interface language, as an alert', async () => {
|
|
103
|
+
const view = await mount(_jsx(MessagesProvider, { locale: "pl", children: _jsx(SmallScreenNotice, {}) }));
|
|
104
|
+
const alert = view.querySelector('[role="alert"]');
|
|
105
|
+
expect(alert?.querySelector('h1')?.textContent).toBe('Edytor wymaga większego ekranu');
|
|
106
|
+
expect(alert?.textContent).toContain('na komputerze');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CanvasHost } from '../canvas-host/index.ts';
|
|
2
|
+
import type { BreakpointConfig } from './config.ts';
|
|
3
|
+
export interface StatusInfoProps {
|
|
4
|
+
readonly host: CanvasHost | null;
|
|
5
|
+
readonly breakpoints: readonly BreakpointConfig[];
|
|
6
|
+
readonly breakpoint: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The status bar's read-only facts (PB-122): the active breakpoint and its width, the canvas
|
|
10
|
+
* zoom and the save state. They come from the host, the store and the persistence controller;
|
|
11
|
+
* the save state is plain text (the toolbar's status carries the live region).
|
|
12
|
+
*/
|
|
13
|
+
export declare function StatusInfo({ host, breakpoints, breakpoint }: StatusInfoProps): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=status-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-info.d.ts","sourceRoot":"","sources":["../../src/app/status-info.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAI1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAkBD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,eAAe,+BA2B5E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useSyncExternalStore } from 'react';
|
|
3
|
+
import { useT } from '../messages/index.js';
|
|
4
|
+
import { usePersistenceState } from '../persistence/index.js';
|
|
5
|
+
import { useEditorState } from '../store/index.js';
|
|
6
|
+
const BREAKPOINT_LABELS = {
|
|
7
|
+
desktop: 'toolbar.breakpoint.desktop',
|
|
8
|
+
tablet: 'toolbar.breakpoint.tablet',
|
|
9
|
+
mobile: 'toolbar.breakpoint.mobile',
|
|
10
|
+
};
|
|
11
|
+
const NO_ZOOM = 'fit';
|
|
12
|
+
function useZoom(host) {
|
|
13
|
+
return useSyncExternalStore((notify) => (host === null ? () => undefined : host.state.subscribe(notify)), () => host?.state.getState().zoom ?? NO_ZOOM, () => NO_ZOOM);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The status bar's read-only facts (PB-122): the active breakpoint and its width, the canvas
|
|
17
|
+
* zoom and the save state. They come from the host, the store and the persistence controller;
|
|
18
|
+
* the save state is plain text (the toolbar's status carries the live region).
|
|
19
|
+
*/
|
|
20
|
+
export function StatusInfo({ host, breakpoints, breakpoint }) {
|
|
21
|
+
const t = useT();
|
|
22
|
+
const zoom = useZoom(host);
|
|
23
|
+
const status = usePersistenceState((state) => state.status);
|
|
24
|
+
const error = usePersistenceState((state) => state.error);
|
|
25
|
+
const readOnly = useEditorState((state) => state.readOnly);
|
|
26
|
+
const active = breakpoints.find((item) => item.id === breakpoint);
|
|
27
|
+
const key = BREAKPOINT_LABELS[breakpoint];
|
|
28
|
+
const save = readOnly
|
|
29
|
+
? t('save.readOnly')
|
|
30
|
+
: status === 'error' && error?.kind === 'invalid'
|
|
31
|
+
? t('save.invalid')
|
|
32
|
+
: t(`save.${status}`);
|
|
33
|
+
return (_jsxs(_Fragment, { children: [_jsxs("span", { className: "bd-status-item", title: t('editor.status.breakpoint'), children: [key === undefined ? breakpoint : t(key), active === undefined ? '' : ` ${active.width}px`] }), _jsx("span", { className: "bd-status-item bd-tabular", title: t('editor.status.zoom'), children: zoom === 'fit' ? t('editor.status.fit') : `${Math.round(zoom * 100)}%` }), _jsx("span", { className: "bd-status-item", "data-status": readOnly ? 'readOnly' : status, children: save })] }));
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type KeyboardEvent, type MouseEvent, type PointerEvent } from 'react';
|
|
2
|
+
export interface ResizableOptions {
|
|
3
|
+
readonly initial: number;
|
|
4
|
+
readonly min: number;
|
|
5
|
+
readonly max: number;
|
|
6
|
+
/** Which way dragging to the right moves the size: `1` for a panel on the left, `-1` on the right. */
|
|
7
|
+
readonly direction: 1 | -1;
|
|
8
|
+
/** How far an arrow key moves it. */
|
|
9
|
+
readonly step?: number;
|
|
10
|
+
/** Remembers the size in `localStorage` under this key (a failing storage is ignored). */
|
|
11
|
+
readonly storageKey?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Resizable {
|
|
14
|
+
readonly size: number;
|
|
15
|
+
readonly dragging: boolean;
|
|
16
|
+
readonly bind: {
|
|
17
|
+
onPointerDown(event: PointerEvent<HTMLElement>): void;
|
|
18
|
+
onPointerMove(event: PointerEvent<HTMLElement>): void;
|
|
19
|
+
onPointerUp(event: PointerEvent<HTMLElement>): void;
|
|
20
|
+
onPointerCancel(event: PointerEvent<HTMLElement>): void;
|
|
21
|
+
onKeyDown(event: KeyboardEvent<HTMLElement>): void;
|
|
22
|
+
onDoubleClick(event: MouseEvent<HTMLElement>): void;
|
|
23
|
+
};
|
|
24
|
+
/** Sets the size, kept within its limits. */
|
|
25
|
+
set(size: number): void;
|
|
26
|
+
/** Back to the initial size. */
|
|
27
|
+
reset(): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The state and events of one splitter: drag it with a pointer, or move it with the arrow keys,
|
|
31
|
+
* Home and End; double-click puts it back to the initial size. The size can be remembered.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useResizable(options: ResizableOptions): Resizable;
|
|
34
|
+
//# sourceMappingURL=use-resizable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-resizable.d.ts","sourceRoot":"","sources":["../../src/app/use-resizable.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,YAAY,EAKlB,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sGAAsG;IACtG,QAAQ,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,qCAAqC;IACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0FAA0F;IAC1F,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE;QACb,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;QACtD,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;QACtD,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;QACpD,eAAe,CAAC,KAAK,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;QACxD,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;QACnD,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;KACrD,CAAC;IACF,6CAA6C;IAC7C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gCAAgC;IAChC,KAAK,IAAI,IAAI,CAAC;CACf;AAuBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CA2DjE"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
2
|
+
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
3
|
+
function readStored(key) {
|
|
4
|
+
if (key === undefined)
|
|
5
|
+
return undefined;
|
|
6
|
+
try {
|
|
7
|
+
const raw = window.localStorage.getItem(key);
|
|
8
|
+
const value = raw === null ? Number.NaN : Number(raw);
|
|
9
|
+
return Number.isFinite(value) ? value : undefined;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function writeStored(key, size) {
|
|
16
|
+
try {
|
|
17
|
+
window.localStorage.setItem(key, String(size));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Storage is unavailable (private mode, quota): the size just is not remembered.
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The state and events of one splitter: drag it with a pointer, or move it with the arrow keys,
|
|
25
|
+
* Home and End; double-click puts it back to the initial size. The size can be remembered.
|
|
26
|
+
*/
|
|
27
|
+
export function useResizable(options) {
|
|
28
|
+
const { min, max, direction, step = 16, storageKey } = options;
|
|
29
|
+
const [size, setSize] = useState(() => clamp(readStored(storageKey) ?? options.initial, min, max));
|
|
30
|
+
const [dragging, setDragging] = useState(false);
|
|
31
|
+
const start = useRef(null);
|
|
32
|
+
const changed = useRef(false);
|
|
33
|
+
const set = useCallback((next) => {
|
|
34
|
+
changed.current = true;
|
|
35
|
+
setSize(clamp(next, min, max));
|
|
36
|
+
}, [min, max]);
|
|
37
|
+
// Remember the size once a change is done (not on every pointer move, not on the first render).
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (storageKey === undefined || dragging || !changed.current)
|
|
40
|
+
return;
|
|
41
|
+
writeStored(storageKey, size);
|
|
42
|
+
}, [storageKey, size, dragging]);
|
|
43
|
+
const bind = {
|
|
44
|
+
onPointerDown(event) {
|
|
45
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
46
|
+
start.current = { x: event.clientX, size };
|
|
47
|
+
setDragging(true);
|
|
48
|
+
},
|
|
49
|
+
onPointerMove(event) {
|
|
50
|
+
const from = start.current;
|
|
51
|
+
if (from === null)
|
|
52
|
+
return;
|
|
53
|
+
set(from.size + (event.clientX - from.x) * direction);
|
|
54
|
+
},
|
|
55
|
+
onPointerUp(event) {
|
|
56
|
+
start.current = null;
|
|
57
|
+
setDragging(false);
|
|
58
|
+
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
59
|
+
},
|
|
60
|
+
onPointerCancel() {
|
|
61
|
+
start.current = null;
|
|
62
|
+
setDragging(false);
|
|
63
|
+
},
|
|
64
|
+
onKeyDown(event) {
|
|
65
|
+
const grow = direction === 1 ? 'ArrowRight' : 'ArrowLeft';
|
|
66
|
+
const shrink = direction === 1 ? 'ArrowLeft' : 'ArrowRight';
|
|
67
|
+
if (event.key === grow)
|
|
68
|
+
set(size + step);
|
|
69
|
+
else if (event.key === shrink)
|
|
70
|
+
set(size - step);
|
|
71
|
+
else if (event.key === 'Home')
|
|
72
|
+
set(min);
|
|
73
|
+
else if (event.key === 'End')
|
|
74
|
+
set(max);
|
|
75
|
+
else
|
|
76
|
+
return;
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
},
|
|
79
|
+
onDoubleClick() {
|
|
80
|
+
set(options.initial);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
return { size, dragging, bind, set, reset: () => set(options.initial) };
|
|
84
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { BreakpointConfig } from '../app/config.ts';
|
|
2
|
+
import { type CanvasHost, type CanvasHostOptions } from './host.ts';
|
|
3
|
+
export interface CanvasFrameProps {
|
|
4
|
+
/** The canvas route (`@next-buildr/react/canvas` runs there). */
|
|
5
|
+
readonly canvasUrl: string;
|
|
6
|
+
/** `RegistryManifest.hash` of the registry the editor knows. */
|
|
7
|
+
readonly manifestHash: string;
|
|
8
|
+
readonly locales: CanvasHostOptions['locales'];
|
|
9
|
+
readonly breakpoints: readonly BreakpointConfig[];
|
|
10
|
+
readonly breakpoint?: string;
|
|
11
|
+
readonly locale?: string;
|
|
12
|
+
readonly contextRef?: string | null;
|
|
13
|
+
readonly handshakeTimeoutMs?: number;
|
|
14
|
+
/** Gets the host once the frame is mounted (and `null` when it goes), for the toolbar and the drag-and-drop engine. */
|
|
15
|
+
readonly onHost?: (host: CanvasHost | null) => void;
|
|
16
|
+
readonly callbacks?: Pick<CanvasHostOptions, 'onKeyDown' | 'onContextMenu' | 'onNodeDoubleClick' | 'onDropTarget' | 'onCommandError'>;
|
|
17
|
+
}
|
|
18
|
+
/** A random nonce for the canvas URL: 32 hex characters, unguessable by the page in the frame's neighbours. */
|
|
19
|
+
export declare function createSession(): string;
|
|
20
|
+
/** The canvas URL with the session in it, and the one origin it is served from. */
|
|
21
|
+
export declare function canvasSource(canvasUrl: string, session: string): {
|
|
22
|
+
src: string;
|
|
23
|
+
origin: string;
|
|
24
|
+
};
|
|
25
|
+
export interface StageMetrics {
|
|
26
|
+
/** The scale applied to the iframe. */
|
|
27
|
+
readonly scale: number;
|
|
28
|
+
/** The iframe's own (unscaled) CSS height: the visible height divided by the scale (0: unknown). */
|
|
29
|
+
readonly frameHeight: number;
|
|
30
|
+
/** The width the scaled page takes on the stage. */
|
|
31
|
+
readonly stageWidth: number;
|
|
32
|
+
/** The visible height of the stage (0: unknown). */
|
|
33
|
+
readonly stageHeight: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The stage arithmetic (A8): the frame is scaled with `transform`, which does not change its
|
|
37
|
+
* layout box, so the frame's height is the visible height divided by the scale; the scaled
|
|
38
|
+
* page then fills the visible stage exactly. `room` and `roomHeight` are the stage area in CSS
|
|
39
|
+
* pixels (0 while not measured); with no height known the frame fills its parent.
|
|
40
|
+
*/
|
|
41
|
+
export declare function stageMetrics(input: {
|
|
42
|
+
readonly width: number;
|
|
43
|
+
readonly room: number;
|
|
44
|
+
readonly roomHeight: number;
|
|
45
|
+
readonly zoom: 'fit' | number;
|
|
46
|
+
}): StageMetrics;
|
|
47
|
+
/**
|
|
48
|
+
* The canvas iframe, its channel and its status screens. A "Reload canvas" button (or a fatal
|
|
49
|
+
* error) mounts a new frame with a new session; nothing is lost, because the store holds the
|
|
50
|
+
* state and the new canvas is initialized from it.
|
|
51
|
+
*/
|
|
52
|
+
export declare function CanvasFrame(props: CanvasFrameProps): import("react").JSX.Element;
|
|
53
|
+
//# sourceMappingURL=canvas-frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-frame.d.ts","sourceRoot":"","sources":["../../src/canvas-host/canvas-frame.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIzD,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAoB,MAAM,WAAW,CAAC;AAEtF,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC/C,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,uHAAuH;IACvH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CACvB,iBAAiB,EACjB,WAAW,GAAG,eAAe,GAAG,mBAAmB,GAAG,cAAc,GAAG,gBAAgB,CACxF,CAAC;CACH;AAED,+GAA+G;AAC/G,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAIhG;AAED,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oGAAoG;IACpG,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;CAC/B,GAAG,YAAY,CAUf;AAQD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BA4IlD"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createParentTransport } from '@next-buildr/core/protocol';
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { useT } from '../messages/index.js';
|
|
5
|
+
import { useEditor } from '../store/index.js';
|
|
6
|
+
import { Button, Icon } from '../ui/index.js';
|
|
7
|
+
import { createCanvasHost } from './host.js';
|
|
8
|
+
/** A random nonce for the canvas URL: 32 hex characters, unguessable by the page in the frame's neighbours. */
|
|
9
|
+
export function createSession() {
|
|
10
|
+
const bytes = new Uint8Array(16);
|
|
11
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
12
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
13
|
+
}
|
|
14
|
+
/** The canvas URL with the session in it, and the one origin it is served from. */
|
|
15
|
+
export function canvasSource(canvasUrl, session) {
|
|
16
|
+
const url = new URL(canvasUrl, globalThis.location?.href);
|
|
17
|
+
url.searchParams.set('session', session);
|
|
18
|
+
return { src: url.toString(), origin: url.origin };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The stage arithmetic (A8): the frame is scaled with `transform`, which does not change its
|
|
22
|
+
* layout box, so the frame's height is the visible height divided by the scale; the scaled
|
|
23
|
+
* page then fills the visible stage exactly. `room` and `roomHeight` are the stage area in CSS
|
|
24
|
+
* pixels (0 while not measured); with no height known the frame fills its parent.
|
|
25
|
+
*/
|
|
26
|
+
export function stageMetrics(input) {
|
|
27
|
+
const { width, room, roomHeight, zoom } = input;
|
|
28
|
+
const raw = zoom === 'fit' ? (room > 0 ? Math.min(1, room / width) : 1) : zoom;
|
|
29
|
+
const scale = Number.isFinite(raw) && raw > 0 ? raw : 1;
|
|
30
|
+
return {
|
|
31
|
+
scale,
|
|
32
|
+
frameHeight: roomHeight > 0 ? roomHeight / scale : 0,
|
|
33
|
+
stageWidth: width * scale,
|
|
34
|
+
stageHeight: roomHeight > 0 ? roomHeight : 0,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const BREAKPOINT_LABELS = {
|
|
38
|
+
desktop: 'toolbar.breakpoint.desktop',
|
|
39
|
+
tablet: 'toolbar.breakpoint.tablet',
|
|
40
|
+
mobile: 'toolbar.breakpoint.mobile',
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* The canvas iframe, its channel and its status screens. A "Reload canvas" button (or a fatal
|
|
44
|
+
* error) mounts a new frame with a new session; nothing is lost, because the store holds the
|
|
45
|
+
* state and the new canvas is initialized from it.
|
|
46
|
+
*/
|
|
47
|
+
export function CanvasFrame(props) {
|
|
48
|
+
const t = useT();
|
|
49
|
+
const store = useEditor();
|
|
50
|
+
const [attempt, setAttempt] = useState(0);
|
|
51
|
+
const session = useMemo(() => {
|
|
52
|
+
void attempt;
|
|
53
|
+
return createSession();
|
|
54
|
+
}, [attempt]);
|
|
55
|
+
const source = useMemo(() => canvasSource(props.canvasUrl, session), [props.canvasUrl, session]);
|
|
56
|
+
const iframe = useRef(null);
|
|
57
|
+
const area = useRef(null);
|
|
58
|
+
const [host, setHost] = useState(null);
|
|
59
|
+
const wrap = useRef(null);
|
|
60
|
+
const [room, setRoom] = useState({ width: 0, height: 0 });
|
|
61
|
+
const propsRef = useRef(props);
|
|
62
|
+
propsRef.current = props;
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
const frame = iframe.current;
|
|
65
|
+
if (frame === null)
|
|
66
|
+
return;
|
|
67
|
+
const current = propsRef.current;
|
|
68
|
+
// biome-ignore lint/style/useConst: assigned below, read by the transport's callback
|
|
69
|
+
let created;
|
|
70
|
+
const transport = createParentTransport({
|
|
71
|
+
iframe: frame,
|
|
72
|
+
canvasOrigin: source.origin,
|
|
73
|
+
session,
|
|
74
|
+
onReject: (rejection) => created?.handleReject(rejection),
|
|
75
|
+
});
|
|
76
|
+
created = createCanvasHost({
|
|
77
|
+
store,
|
|
78
|
+
transport,
|
|
79
|
+
manifestHash: current.manifestHash,
|
|
80
|
+
locales: current.locales,
|
|
81
|
+
breakpoints: current.breakpoints,
|
|
82
|
+
...(current.breakpoint !== undefined ? { breakpoint: current.breakpoint } : {}),
|
|
83
|
+
...(current.locale !== undefined ? { locale: current.locale } : {}),
|
|
84
|
+
...(current.contextRef !== undefined ? { contextRef: current.contextRef } : {}),
|
|
85
|
+
...(current.handshakeTimeoutMs !== undefined
|
|
86
|
+
? { handshakeTimeoutMs: current.handshakeTimeoutMs }
|
|
87
|
+
: {}),
|
|
88
|
+
onKeyDown: (event) => propsRef.current.callbacks?.onKeyDown?.(event),
|
|
89
|
+
onContextMenu: (event) => propsRef.current.callbacks?.onContextMenu?.(event),
|
|
90
|
+
onNodeDoubleClick: (event) => propsRef.current.callbacks?.onNodeDoubleClick?.(event),
|
|
91
|
+
onDropTarget: (event) => propsRef.current.callbacks?.onDropTarget?.(event),
|
|
92
|
+
onCommandError: (error) => propsRef.current.callbacks?.onCommandError?.(error),
|
|
93
|
+
});
|
|
94
|
+
setHost(created);
|
|
95
|
+
propsRef.current.onHost?.(created);
|
|
96
|
+
return () => {
|
|
97
|
+
created?.destroy();
|
|
98
|
+
propsRef.current.onHost?.(null);
|
|
99
|
+
setHost(null);
|
|
100
|
+
};
|
|
101
|
+
}, [store, session, source.origin]);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const element = wrap.current;
|
|
104
|
+
if (element === null)
|
|
105
|
+
return;
|
|
106
|
+
const measure = () => setRoom((prev) => prev.width === element.clientWidth && prev.height === element.clientHeight
|
|
107
|
+
? prev
|
|
108
|
+
: { width: element.clientWidth, height: element.clientHeight });
|
|
109
|
+
measure();
|
|
110
|
+
const Observer = globalThis.ResizeObserver;
|
|
111
|
+
if (Observer === undefined)
|
|
112
|
+
return;
|
|
113
|
+
const observer = new Observer(measure);
|
|
114
|
+
observer.observe(element);
|
|
115
|
+
return () => observer.disconnect();
|
|
116
|
+
}, []);
|
|
117
|
+
const hostState = useHostState(host);
|
|
118
|
+
const width = hostState?.width ?? props.breakpoints[0]?.width ?? 1280;
|
|
119
|
+
const zoom = hostState?.zoom ?? 'fit';
|
|
120
|
+
const metrics = stageMetrics({ width, room: room.width, roomHeight: room.height, zoom });
|
|
121
|
+
const { scale } = metrics;
|
|
122
|
+
const breakpointId = hostState?.breakpoint ?? props.breakpoint;
|
|
123
|
+
const breakpointKey = breakpointId === undefined ? undefined : BREAKPOINT_LABELS[breakpointId];
|
|
124
|
+
const widthLabel = t('editor.canvas.width')
|
|
125
|
+
.replace('{name}', breakpointKey !== undefined ? t(breakpointKey) : (breakpointId ?? ''))
|
|
126
|
+
.replace('{width}', String(width));
|
|
127
|
+
const status = hostState?.status ?? 'connecting';
|
|
128
|
+
const error = hostState?.error;
|
|
129
|
+
return (_jsxs("div", { className: "bd-canvas-host", ref: area, "data-status": status, children: [_jsx("p", { className: "bd-canvas-width", children: widthLabel }), _jsx("div", { className: "bd-canvas-stage-area", ref: wrap, children: _jsx("div", { className: "bd-canvas-stage", style: {
|
|
130
|
+
width: metrics.stageWidth,
|
|
131
|
+
...(metrics.stageHeight > 0 ? { height: metrics.stageHeight } : {}),
|
|
132
|
+
}, children: _jsx("iframe", { ref: iframe, className: "bd-canvas-frame", title: t('editor.canvas.frame'), src: source.src, "data-status": status, style: {
|
|
133
|
+
width,
|
|
134
|
+
...(metrics.frameHeight > 0 ? { height: metrics.frameHeight } : {}),
|
|
135
|
+
transform: `scale(${scale})`,
|
|
136
|
+
} }, session) }) }), status === 'connecting' ? (_jsxs("div", { className: "bd-canvas-card bd-canvas-status", role: "status", children: [_jsx(Icon, { name: "monitor-smartphone", size: "md" }), _jsx("p", { className: "bd-canvas-title", children: t('editor.canvas.connecting') })] })) : null, status === 'error' && error !== undefined ? (_jsxs("div", { className: "bd-canvas-card bd-canvas-error", role: "alert", children: [_jsx(Icon, { name: "triangle-alert", size: "md" }), _jsx("p", { className: "bd-canvas-title", children: t('editor.canvas.error.title') }), _jsx("p", { children: t(`editor.canvas.error.${error.kind}`) }), error.kind === 'canvas' ? _jsx("p", { className: "bd-canvas-detail", children: error.message }) : null, error.details !== undefined ? (_jsx("dl", { className: "bd-canvas-detail", children: Object.entries(error.details).map(([name, value]) => (_jsxs("div", { children: [_jsx("dt", { children: name }), _jsx("dd", { children: String(value) })] }, name))) })) : null, _jsx(Button, { onClick: () => setAttempt((n) => n + 1), children: t('editor.canvas.reload') })] })) : null] }));
|
|
137
|
+
}
|
|
138
|
+
function useHostState(host) {
|
|
139
|
+
const [, force] = useState(0);
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (host === null)
|
|
142
|
+
return;
|
|
143
|
+
return host.state.subscribe(() => force((n) => n + 1));
|
|
144
|
+
}, [host]);
|
|
145
|
+
return host?.state.getState();
|
|
146
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-frame.test.d.ts","sourceRoot":"","sources":["../../src/canvas-host/canvas-frame.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @vitest-environment jsdom
|
|
3
|
+
import { createRegistryMeta } from '@next-buildr/core';
|
|
4
|
+
import { act } from 'react';
|
|
5
|
+
import { createRoot } from 'react-dom/client';
|
|
6
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
7
|
+
import { axe } from 'vitest-axe';
|
|
8
|
+
import * as matchers from 'vitest-axe/matchers';
|
|
9
|
+
import { DEFAULT_BREAKPOINTS } from '../app/config.js';
|
|
10
|
+
import { MessagesProvider } from '../messages/index.js';
|
|
11
|
+
import { createEditorStore, EditorStoreProvider } from '../store/index.js';
|
|
12
|
+
import { CanvasFrame, canvasSource, createSession, stageMetrics } from './canvas-frame.js';
|
|
13
|
+
expect.extend(matchers);
|
|
14
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
document.body.innerHTML = '';
|
|
17
|
+
});
|
|
18
|
+
const locales = { locales: ['en'], default: 'en', fallback: true, intl: {} };
|
|
19
|
+
describe('session and URL', () => {
|
|
20
|
+
it('makes an unguessable, URL-safe nonce every time', () => {
|
|
21
|
+
const a = createSession();
|
|
22
|
+
expect(a).toMatch(/^[0-9a-f]{32}$/);
|
|
23
|
+
expect(createSession()).not.toBe(a);
|
|
24
|
+
});
|
|
25
|
+
it('puts the session in the canvas URL and takes the origin from it', () => {
|
|
26
|
+
const { src, origin } = canvasSource('https://canvas.example.com/__canvas?x=1', 'abc');
|
|
27
|
+
expect(origin).toBe('https://canvas.example.com');
|
|
28
|
+
expect(new URL(src).searchParams.get('session')).toBe('abc');
|
|
29
|
+
expect(new URL(src).searchParams.get('x')).toBe('1');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('stageMetrics', () => {
|
|
33
|
+
it('fit: scales down to the room and fills the visible height', () => {
|
|
34
|
+
const m = stageMetrics({ width: 1280, room: 640, roomHeight: 600, zoom: 'fit' });
|
|
35
|
+
expect(m.scale).toBe(0.5);
|
|
36
|
+
expect(m.frameHeight).toBe(1200);
|
|
37
|
+
expect(m.stageWidth).toBe(640);
|
|
38
|
+
expect(m.stageHeight).toBe(600);
|
|
39
|
+
expect(m.frameHeight * m.scale).toBe(m.stageHeight);
|
|
40
|
+
});
|
|
41
|
+
it('fit: never scales above 100%', () => {
|
|
42
|
+
const m = stageMetrics({ width: 390, room: 900, roomHeight: 500, zoom: 'fit' });
|
|
43
|
+
expect(m).toMatchObject({ scale: 1, frameHeight: 500, stageWidth: 390 });
|
|
44
|
+
});
|
|
45
|
+
it('a fixed zoom shows 1/zoom of the page height (twice at 50%)', () => {
|
|
46
|
+
const half = stageMetrics({ width: 820, room: 2000, roomHeight: 700, zoom: 0.5 });
|
|
47
|
+
expect(half).toMatchObject({ scale: 0.5, frameHeight: 1400, stageWidth: 410 });
|
|
48
|
+
const twice = stageMetrics({ width: 820, room: 2000, roomHeight: 700, zoom: 2 });
|
|
49
|
+
expect(twice).toMatchObject({ scale: 2, frameHeight: 350, stageWidth: 1640 });
|
|
50
|
+
});
|
|
51
|
+
it('falls back to filling the parent while nothing is measured', () => {
|
|
52
|
+
const m = stageMetrics({ width: 1280, room: 0, roomHeight: 0, zoom: 'fit' });
|
|
53
|
+
expect(m).toMatchObject({ scale: 1, frameHeight: 0, stageHeight: 0, stageWidth: 1280 });
|
|
54
|
+
expect(stageMetrics({ width: 100, room: 50, roomHeight: 10, zoom: 0 }).scale).toBe(1);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('CanvasFrame', () => {
|
|
58
|
+
it('shows the connecting state, then an error screen that reloads with a new session', async () => {
|
|
59
|
+
const store = createEditorStore({
|
|
60
|
+
doc: {
|
|
61
|
+
schemaVersion: 1,
|
|
62
|
+
root: 'root',
|
|
63
|
+
nodes: { root: { id: 'root', type: 'buildr/page' } },
|
|
64
|
+
components: {},
|
|
65
|
+
},
|
|
66
|
+
registry: createRegistryMeta({ components: [] }),
|
|
67
|
+
validationDelayMs: null,
|
|
68
|
+
});
|
|
69
|
+
const container = document.createElement('div');
|
|
70
|
+
document.body.append(container);
|
|
71
|
+
const root = createRoot(container);
|
|
72
|
+
await act(async () => root.render(_jsx(MessagesProvider, { locale: "en", children: _jsx(EditorStoreProvider, { store: store, children: _jsx(CanvasFrame, { canvasUrl: "https://canvas.example.com/__canvas", manifestHash: "hash", locales: locales, breakpoints: DEFAULT_BREAKPOINTS, handshakeTimeoutMs: 30 }) }) })));
|
|
73
|
+
const iframe = () => container.querySelector('iframe');
|
|
74
|
+
expect(container.querySelector('[role=status]')?.textContent).toContain('Connecting');
|
|
75
|
+
expect(iframe()?.getAttribute('title')).toBe('Page preview');
|
|
76
|
+
expect(container.querySelector('.bd-canvas-width')?.textContent).toBe('Desktop · 1280px');
|
|
77
|
+
const firstSrc = iframe()?.getAttribute('src');
|
|
78
|
+
expect(firstSrc).toContain('https://canvas.example.com/__canvas?session=');
|
|
79
|
+
await act(async () => {
|
|
80
|
+
await new Promise((resolve) => setTimeout(resolve, 80));
|
|
81
|
+
});
|
|
82
|
+
expect(container.querySelector('[role=alert]')?.textContent).toContain('did not answer');
|
|
83
|
+
expect(await axe(container.querySelector('[role=alert]'))).toHaveNoViolations();
|
|
84
|
+
const reload = [...container.querySelectorAll('button')].find((b) => b.textContent === 'Reload canvas');
|
|
85
|
+
await act(async () => reload?.click());
|
|
86
|
+
expect(iframe()?.getAttribute('src')).not.toBe(firstSrc);
|
|
87
|
+
expect(container.querySelector('[role=alert]')).toBeNull();
|
|
88
|
+
expect(container.querySelector('[role=status]')).not.toBeNull();
|
|
89
|
+
await act(async () => root.unmount());
|
|
90
|
+
});
|
|
91
|
+
});
|