@juo/blocks 1.13.0-alpha.2 → 1.14.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/dist/ExtensionRoot-CRJx0Dtr.js +378 -0
- package/dist/block.d.ts +0 -50
- package/dist/block.d.ts.map +1 -1
- package/dist/{bridge-r7Yk8fjY.js → bridge-D838SWmN.js} +147 -42
- package/dist/context.d.ts.map +1 -1
- package/dist/core.js +1120 -2157
- package/dist/css-runtime-DWytAzZ5.js +1532 -0
- package/dist/editor/bridge.d.ts +8 -7
- package/dist/editor/bridge.d.ts.map +1 -1
- package/dist/editor/canvas-mode-signal.d.ts +22 -0
- package/dist/editor/canvas-mode-signal.d.ts.map +1 -0
- package/dist/editor/canvas-mode.d.ts +15 -0
- package/dist/editor/canvas-mode.d.ts.map +1 -0
- package/dist/editor/canvas-mode.test.d.ts +2 -0
- package/dist/editor/canvas-mode.test.d.ts.map +1 -0
- package/dist/editor/components.d.ts +113 -0
- package/dist/editor/components.d.ts.map +1 -1
- package/dist/editor/components.test.d.ts.map +1 -1
- package/dist/editor/handler.d.ts.map +1 -1
- package/dist/editor/handler.test.d.ts +2 -0
- package/dist/editor/handler.test.d.ts.map +1 -0
- package/dist/editor/layout-command-emitter.d.ts +31 -0
- package/dist/editor/layout-command-emitter.d.ts.map +1 -0
- package/dist/editor/layout-command-emitter.test.d.ts +2 -0
- package/dist/editor/layout-command-emitter.test.d.ts.map +1 -0
- package/dist/editor/layout-system-signal.d.ts +21 -0
- package/dist/editor/layout-system-signal.d.ts.map +1 -0
- package/dist/editor/main.d.ts +2 -2
- package/dist/editor/main.d.ts.map +1 -1
- package/dist/editor/messages.d.ts +90 -14
- package/dist/editor/messages.d.ts.map +1 -1
- package/dist/editor/surface-context.d.ts +7 -0
- package/dist/editor/surface-context.d.ts.map +1 -0
- package/dist/editor/surface-context.test.d.ts +2 -0
- package/dist/editor/surface-context.test.d.ts.map +1 -0
- package/dist/editor/wrapper-shared.d.ts +31 -0
- package/dist/editor/wrapper-shared.d.ts.map +1 -0
- package/dist/editor.js +887 -88
- package/dist/flows/WorkflowService.d.ts +2 -0
- package/dist/flows/WorkflowService.d.ts.map +1 -1
- package/dist/gridstack-adapter-DreG3XnB.js +5490 -0
- package/dist/layout/css-runtime.d.ts +41 -0
- package/dist/layout/css-runtime.d.ts.map +1 -0
- package/dist/layout/css-runtime.test.d.ts +2 -0
- package/dist/layout/css-runtime.test.d.ts.map +1 -0
- package/dist/layout/derive.d.ts +4 -0
- package/dist/layout/derive.d.ts.map +1 -0
- package/dist/layout/derive.test.d.ts +2 -0
- package/dist/layout/derive.test.d.ts.map +1 -0
- package/dist/layout/dividers.d.ts +34 -0
- package/dist/layout/dividers.d.ts.map +1 -0
- package/dist/layout/dividers.test.d.ts +2 -0
- package/dist/layout/dividers.test.d.ts.map +1 -0
- package/dist/layout/engine.d.ts +3 -0
- package/dist/layout/engine.d.ts.map +1 -0
- package/dist/layout/engine.test.d.ts +2 -0
- package/dist/layout/engine.test.d.ts.map +1 -0
- package/dist/layout/grid-utils.d.ts +57 -0
- package/dist/layout/grid-utils.d.ts.map +1 -0
- package/dist/layout/grid-utils.test.d.ts +2 -0
- package/dist/layout/grid-utils.test.d.ts.map +1 -0
- package/dist/layout/index.d.ts +12 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.test.d.ts +2 -0
- package/dist/layout/index.test.d.ts.map +1 -0
- package/dist/layout/insert.d.ts +31 -0
- package/dist/layout/insert.d.ts.map +1 -0
- package/dist/layout/insert.test.d.ts +2 -0
- package/dist/layout/insert.test.d.ts.map +1 -0
- package/dist/layout/project-css.d.ts +6 -0
- package/dist/layout/project-css.d.ts.map +1 -0
- package/dist/layout/project-css.test.d.ts +2 -0
- package/dist/layout/project-css.test.d.ts.map +1 -0
- package/dist/layout/project-gridstack.d.ts +50 -0
- package/dist/layout/project-gridstack.d.ts.map +1 -0
- package/dist/layout/project-gridstack.test.d.ts +2 -0
- package/dist/layout/project-gridstack.test.d.ts.map +1 -0
- package/dist/layout/reconcile.d.ts +22 -0
- package/dist/layout/reconcile.d.ts.map +1 -0
- package/dist/layout/reconcile.test.d.ts +2 -0
- package/dist/layout/reconcile.test.d.ts.map +1 -0
- package/dist/layout/types.d.ts +118 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout-mode-adapter-BBd4JRQd.js +21 -0
- package/dist/main.d.ts +8 -4
- package/dist/main.d.ts.map +1 -1
- package/dist/morph-Dj-xvrwt.js +182 -0
- package/dist/preact.js +1 -1
- package/dist/project-gridstack-DYLMKSH1.js +52 -0
- package/dist/react.js +1 -1
- package/dist/services/customer/customerService.d.ts +2 -3
- package/dist/services/customer/customerService.d.ts.map +1 -1
- package/dist/services/customer/index.d.ts +0 -1
- package/dist/services/customer/index.d.ts.map +1 -1
- package/dist/services/customer/types.d.ts +1 -4
- package/dist/services/customer/types.d.ts.map +1 -1
- package/dist/services/index.d.ts +0 -3
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/login/index.d.ts +1 -3
- package/dist/services/login/index.d.ts.map +1 -1
- package/dist/services/login/loginService.d.ts +2 -6
- package/dist/services/login/loginService.d.ts.map +1 -1
- package/dist/services/orders/adapter.d.ts +0 -2
- package/dist/services/orders/adapter.d.ts.map +1 -1
- package/dist/services/orders/index.d.ts +1 -1
- package/dist/services/orders/index.d.ts.map +1 -1
- package/dist/services/product/adapter.d.ts +2 -27
- package/dist/services/product/adapter.d.ts.map +1 -1
- package/dist/services/product/index.d.ts +1 -1
- package/dist/services/product/index.d.ts.map +1 -1
- package/dist/services/product/productService.d.ts.map +1 -1
- package/dist/services/product/types.d.ts +0 -68
- package/dist/services/product/types.d.ts.map +1 -1
- package/dist/services/subscription/adapter.d.ts +2 -77
- package/dist/services/subscription/adapter.d.ts.map +1 -1
- package/dist/services/subscription/index.d.ts +1 -1
- package/dist/services/subscription/index.d.ts.map +1 -1
- package/dist/services/subscription/subscriptionService.d.ts +6 -1
- package/dist/services/subscription/subscriptionService.d.ts.map +1 -1
- package/dist/services/subscription/types.d.ts +9 -220
- package/dist/services/subscription/types.d.ts.map +1 -1
- package/dist/theme-state.d.ts +17 -2
- package/dist/theme-state.d.ts.map +1 -1
- package/dist/theme-state.layout.test.d.ts +2 -0
- package/dist/theme-state.layout.test.d.ts.map +1 -0
- package/dist/theme-state.test.d.ts +2 -0
- package/dist/theme-state.test.d.ts.map +1 -0
- package/dist/utils/index.d.ts +0 -6
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/vue/block.d.ts.map +1 -1
- package/dist/vue.js +4 -25
- package/dist/web-components/ExtensionRoot.d.ts +50 -3
- package/dist/web-components/ExtensionRoot.d.ts.map +1 -1
- package/dist/web-components/editor/ExtensionRoot.d.ts +11 -0
- package/dist/web-components/editor/ExtensionRoot.d.ts.map +1 -0
- package/dist/web-components/editor/ExtensionRoot.test.d.ts +2 -0
- package/dist/web-components/editor/ExtensionRoot.test.d.ts.map +1 -0
- package/dist/web-components/editor/InlineText.d.ts +1 -0
- package/dist/web-components/editor/InlineText.d.ts.map +1 -1
- package/dist/web-components/editor/editor-layout-controller.d.ts +28 -0
- package/dist/web-components/editor/editor-layout-controller.d.ts.map +1 -0
- package/dist/web-components/editor/gridstack-adapter.d.ts +3 -0
- package/dist/web-components/editor/gridstack-adapter.d.ts.map +1 -0
- package/dist/web-components/editor/gridstack-adapter.test.d.ts +2 -0
- package/dist/web-components/editor/gridstack-adapter.test.d.ts.map +1 -0
- package/dist/web-components/editor/morph.d.ts +32 -0
- package/dist/web-components/editor/morph.d.ts.map +1 -0
- package/dist/web-components/editor/morph.test.d.ts +2 -0
- package/dist/web-components/editor/morph.test.d.ts.map +1 -0
- package/dist/web-components/layout/layout-controller.d.ts +55 -0
- package/dist/web-components/layout/layout-controller.d.ts.map +1 -0
- package/dist/web-components/layout/view-layout-controller.d.ts +17 -0
- package/dist/web-components/layout/view-layout-controller.d.ts.map +1 -0
- package/dist/web-components/layout/view-layout-controller.test.d.ts +2 -0
- package/dist/web-components/layout/view-layout-controller.test.d.ts.map +1 -0
- package/dist/web-components/layout-grid.d.ts +47 -0
- package/dist/web-components/layout-grid.d.ts.map +1 -0
- package/dist/web-components/layout-grid.test.d.ts +2 -0
- package/dist/web-components/layout-grid.test.d.ts.map +1 -0
- package/dist/web-components/layout-mode-adapter.d.ts +51 -0
- package/dist/web-components/layout-mode-adapter.d.ts.map +1 -0
- package/dist/web-components/layout-mode-adapter.test.d.ts +2 -0
- package/dist/web-components/layout-mode-adapter.test.d.ts.map +1 -0
- package/dist/web-components-editor.js +125 -18
- package/dist/web-components-runtime.js +4 -4
- package/package.json +3 -2
- package/dist/ExtensionRoot-peABLAZZ.js +0 -231
- package/dist/block-B6s9jL7l.js +0 -966
- package/dist/block.devtools.test.d.ts +0 -2
- package/dist/block.devtools.test.d.ts.map +0 -1
- package/dist/context.devtools.test.d.ts +0 -2
- package/dist/context.devtools.test.d.ts.map +0 -1
- package/dist/devtools/env.d.ts +0 -3
- package/dist/devtools/env.d.ts.map +0 -1
- package/dist/devtools/hook.d.ts +0 -35
- package/dist/devtools/hook.d.ts.map +0 -1
- package/dist/devtools/index.d.ts +0 -4
- package/dist/devtools/index.d.ts.map +0 -1
- package/dist/devtools/protocol.d.ts +0 -91
- package/dist/devtools/protocol.d.ts.map +0 -1
- package/dist/devtools.js +0 -44
- package/dist/editor/overlays.d.ts +0 -14
- package/dist/editor/overlays.d.ts.map +0 -1
- package/dist/editor/overlays.test.d.ts +0 -2
- package/dist/editor/overlays.test.d.ts.map +0 -1
- package/dist/juo-workflow-DY4rd256.js +0 -868
- package/dist/overlay-wrapper.d.ts +0 -69
- package/dist/overlay-wrapper.d.ts.map +0 -1
- package/dist/overlay-wrapper.test.d.ts +0 -2
- package/dist/overlay-wrapper.test.d.ts.map +0 -1
- package/dist/overlays/OverlayService.d.ts +0 -34
- package/dist/overlays/OverlayService.d.ts.map +0 -1
- package/dist/overlays/OverlayService.test.d.ts +0 -2
- package/dist/overlays/OverlayService.test.d.ts.map +0 -1
- package/dist/registry.devtools.test.d.ts +0 -2
- package/dist/registry.devtools.test.d.ts.map +0 -1
- package/dist/services/customer/adapter.d.ts +0 -8
- package/dist/services/customer/adapter.d.ts.map +0 -1
- package/dist/services/login/adapter.d.ts +0 -32
- package/dist/services/login/adapter.d.ts.map +0 -1
- package/dist/services/order/adapter.d.ts +0 -9
- package/dist/services/order/adapter.d.ts.map +0 -1
- package/dist/services/order/index.d.ts +0 -5
- package/dist/services/order/index.d.ts.map +0 -1
- package/dist/services/order/orderService.d.ts +0 -7
- package/dist/services/order/orderService.d.ts.map +0 -1
- package/dist/services/order/types.d.ts +0 -21
- package/dist/services/order/types.d.ts.map +0 -1
- package/dist/services/product/adapter.test.d.ts +0 -2
- package/dist/services/product/adapter.test.d.ts.map +0 -1
- package/dist/services/schedules/adapter.d.ts +0 -71
- package/dist/services/schedules/adapter.d.ts.map +0 -1
- package/dist/services/schedules/adapter.test.d.ts +0 -2
- package/dist/services/schedules/adapter.test.d.ts.map +0 -1
- package/dist/services/schedules/index.d.ts +0 -5
- package/dist/services/schedules/index.d.ts.map +0 -1
- package/dist/services/schedules/schedulesService.d.ts +0 -11
- package/dist/services/schedules/schedulesService.d.ts.map +0 -1
- package/dist/services/schedules/schedulesService.test.d.ts +0 -2
- package/dist/services/schedules/schedulesService.test.d.ts.map +0 -1
- package/dist/services/schedules/types.d.ts +0 -226
- package/dist/services/schedules/types.d.ts.map +0 -1
- package/dist/services/settings/index.d.ts +0 -3
- package/dist/services/settings/index.d.ts.map +0 -1
- package/dist/services/settings/settingsService.d.ts +0 -7
- package/dist/services/settings/settingsService.d.ts.map +0 -1
- package/dist/services/settings/settingsService.test.d.ts +0 -2
- package/dist/services/settings/settingsService.test.d.ts.map +0 -1
- package/dist/services/settings/types.d.ts +0 -35
- package/dist/services/settings/types.d.ts.map +0 -1
- package/dist/services/shop/index.d.ts +0 -3
- package/dist/services/shop/index.d.ts.map +0 -1
- package/dist/services/shop/shopService.d.ts +0 -12
- package/dist/services/shop/shopService.d.ts.map +0 -1
- package/dist/services/shop/shopService.test.d.ts +0 -2
- package/dist/services/shop/shopService.test.d.ts.map +0 -1
- package/dist/services/shop/types.d.ts +0 -7
- package/dist/services/shop/types.d.ts.map +0 -1
- package/dist/services/subscription/adapter.test.d.ts +0 -2
- package/dist/services/subscription/adapter.test.d.ts.map +0 -1
- package/dist/services/subscription/types.test.d.ts +0 -2
- package/dist/services/subscription/types.test.d.ts.map +0 -1
- package/dist/theme-state.params.test.d.ts +0 -2
- package/dist/theme-state.params.test.d.ts.map +0 -1
- package/dist/theme-state.translations.test.d.ts +0 -2
- package/dist/theme-state.translations.test.d.ts.map +0 -1
package/dist/editor.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { createBlockInstanceFromObject, indexOverrides, DEFAULT_GLOBAL_STYLES, effect, onRegisterBlock, getDefinedBlocks } from "@juo/blocks";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { serializeBlocks, createBlockInstanceFromObject, setActiveSurfaceContext, indexOverrides, canvasMode, getActiveSurfaceContext, emitLayoutCommand, DEFAULT_GLOBAL_STYLES, effect, setLayoutCommandEmitter, setLayoutCommandDispatcher, onRegisterBlock, getDefinedBlocks, clearAllSurfaceContexts } from "@juo/blocks";
|
|
5
|
+
import { canvasMode as canvasMode2 } from "@juo/blocks";
|
|
6
|
+
import { L as LAYOUT_BLOCK_WRAPPER_TAG, c as createEditorBridge, f as createOpenAddBlockMenuMessage, g as createRemoveBlockMessage, i as isBlockWrapperTag, r as resolveOutlineTarget, h as getBlockLabel, j as createLayoutCommandMessage, k as createRegisterBlocksMessage, l as createRegisterRoutesMessage } from "./bridge-D838SWmN.js";
|
|
7
|
+
import { m, n, d, o, p, q, s, t, u, v, w, b, x, y, z, A, B, C, D, a, E, F, G, H, I, e, J, K, M, N } from "./bridge-D838SWmN.js";
|
|
8
|
+
import { s as setCanvasMode, e as enterLayout } from "./morph-Dj-xvrwt.js";
|
|
9
|
+
import { r } from "./morph-Dj-xvrwt.js";
|
|
7
10
|
function createEditorHandler(options) {
|
|
8
11
|
const { themeState, onBlockSelection } = options;
|
|
9
12
|
const blockSurfaceIndex = /* @__PURE__ */ new Map();
|
|
@@ -53,19 +56,23 @@ function createEditorHandler(options) {
|
|
|
53
56
|
return "page";
|
|
54
57
|
}
|
|
55
58
|
function handleMessage(message) {
|
|
56
|
-
var _a
|
|
59
|
+
var _a;
|
|
57
60
|
if (message.type === "SET_GLOBAL_STYLES") {
|
|
58
61
|
themeState.setGlobalStyles(message.payload.styles);
|
|
59
62
|
return;
|
|
60
63
|
}
|
|
61
64
|
if (message.type === "PROVIDE_THEME_STATE") {
|
|
62
65
|
const surface = message.payload.surface ?? "page";
|
|
63
|
-
const blocks = ((_a = message.payload.blocks) == null ? void 0 : _a.map(
|
|
64
|
-
(block) => createBlockInstanceFromObject(block)
|
|
65
|
-
)) || [];
|
|
66
66
|
const target = getBlocks(surface);
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
const incoming = message.payload.blocks ?? [];
|
|
68
|
+
const unchanged = JSON.stringify(serializeBlocks(target.value)) === JSON.stringify(incoming);
|
|
69
|
+
if (!unchanged) {
|
|
70
|
+
target.value = incoming.map(
|
|
71
|
+
(block) => createBlockInstanceFromObject(block)
|
|
72
|
+
);
|
|
73
|
+
indexSurface(surface, target.value);
|
|
74
|
+
}
|
|
75
|
+
setActiveSurfaceContext(surface, message.payload.id);
|
|
69
76
|
} else if (message.type === "SELECT_BLOCK") {
|
|
70
77
|
const blockId = message.payload.blockId;
|
|
71
78
|
if (onBlockSelection) {
|
|
@@ -126,26 +133,26 @@ function createEditorHandler(options) {
|
|
|
126
133
|
if (location.type === "before" || location.type === "after") {
|
|
127
134
|
let findAndInsertBlock = function(blocks, targetId, newBlock2, position) {
|
|
128
135
|
var _a2;
|
|
129
|
-
for (let
|
|
130
|
-
if (blocks[
|
|
136
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
137
|
+
if (blocks[i].id === targetId) {
|
|
131
138
|
if (position === "before") {
|
|
132
|
-
blocks.splice(
|
|
139
|
+
blocks.splice(i, 0, newBlock2);
|
|
133
140
|
} else {
|
|
134
|
-
blocks.splice(
|
|
141
|
+
blocks.splice(i + 1, 0, newBlock2);
|
|
135
142
|
}
|
|
136
143
|
return true;
|
|
137
144
|
}
|
|
138
|
-
for (const slotKey of Object.keys(blocks[
|
|
139
|
-
const slotBlocks = blocks[
|
|
145
|
+
for (const slotKey of Object.keys(blocks[i].slots || {})) {
|
|
146
|
+
const slotBlocks = blocks[i].slots[slotKey];
|
|
140
147
|
const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
|
|
141
|
-
for (let
|
|
142
|
-
if (typeof slotArray[
|
|
148
|
+
for (let j = 0; j < slotArray.length; j++) {
|
|
149
|
+
if (typeof slotArray[j] !== "string" && ((_a2 = slotArray[j]) == null ? void 0 : _a2.id) === targetId) {
|
|
143
150
|
if (position === "before") {
|
|
144
|
-
slotArray.splice(
|
|
151
|
+
slotArray.splice(j, 0, newBlock2);
|
|
145
152
|
} else {
|
|
146
|
-
slotArray.splice(
|
|
153
|
+
slotArray.splice(j + 1, 0, newBlock2);
|
|
147
154
|
}
|
|
148
|
-
blocks[
|
|
155
|
+
blocks[i].slots[slotKey] = slotArray;
|
|
149
156
|
return true;
|
|
150
157
|
}
|
|
151
158
|
}
|
|
@@ -199,21 +206,21 @@ function createEditorHandler(options) {
|
|
|
199
206
|
} else if (message.type === "REMOVE_BLOCK") {
|
|
200
207
|
let findAndRemoveBlock = function(blocks, blockId, slot, parentId) {
|
|
201
208
|
var _a2;
|
|
202
|
-
for (let
|
|
203
|
-
if (blocks[
|
|
204
|
-
const slotBlocks = blocks[
|
|
209
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
210
|
+
if (blocks[i].id === parentId && ((_a2 = blocks[i].slots) == null ? void 0 : _a2[slot])) {
|
|
211
|
+
const slotBlocks = blocks[i].slots[slot];
|
|
205
212
|
const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
|
|
206
213
|
const index = slotArray.findIndex(
|
|
207
214
|
(b2) => typeof b2 !== "string" && (b2 == null ? void 0 : b2.id) === blockId
|
|
208
215
|
);
|
|
209
216
|
if (index !== -1) {
|
|
210
217
|
slotArray.splice(index, 1);
|
|
211
|
-
blocks[
|
|
218
|
+
blocks[i].slots[slot] = slotArray;
|
|
212
219
|
return true;
|
|
213
220
|
}
|
|
214
221
|
}
|
|
215
|
-
for (const slotKey of Object.keys(blocks[
|
|
216
|
-
const slotBlocks = blocks[
|
|
222
|
+
for (const slotKey of Object.keys(blocks[i].slots || {})) {
|
|
223
|
+
const slotBlocks = blocks[i].slots[slotKey];
|
|
217
224
|
const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
|
|
218
225
|
for (const child of slotArray) {
|
|
219
226
|
if (typeof child !== "string" && (child == null ? void 0 : child.id)) {
|
|
@@ -230,7 +237,7 @@ function createEditorHandler(options) {
|
|
|
230
237
|
const target = getBlocks(surface);
|
|
231
238
|
let resolvedParentId = message.payload.location.parentId;
|
|
232
239
|
if (resolvedParentId === "root") {
|
|
233
|
-
resolvedParentId = ((
|
|
240
|
+
resolvedParentId = ((_a = target.value[0]) == null ? void 0 : _a.id) ?? "root";
|
|
234
241
|
}
|
|
235
242
|
findAndRemoveBlock(
|
|
236
243
|
target.value,
|
|
@@ -282,6 +289,17 @@ function createEditorHandler(options) {
|
|
|
282
289
|
);
|
|
283
290
|
target.value = [...target.value];
|
|
284
291
|
indexSurface(surface, target.value);
|
|
292
|
+
} else if (message.type === "SET_LAYOUTING_MODE") {
|
|
293
|
+
setCanvasMode(message.payload.enabled);
|
|
294
|
+
} else if (message.type === "PROVIDE_LAYOUT_DOCUMENT") {
|
|
295
|
+
const surface = message.payload.surface;
|
|
296
|
+
const target = surface === "overlay" ? themeState.overlay : themeState.page;
|
|
297
|
+
setActiveSurfaceContext(surface, message.payload.id);
|
|
298
|
+
const incoming = message.payload.layout;
|
|
299
|
+
const changed = JSON.stringify(target.layout.value) !== JSON.stringify(incoming);
|
|
300
|
+
if (changed) {
|
|
301
|
+
target.layout.value = incoming;
|
|
302
|
+
}
|
|
285
303
|
}
|
|
286
304
|
}
|
|
287
305
|
indexSurface("page", themeState.page.blocks.value);
|
|
@@ -789,14 +807,39 @@ const addBlockIconSvg = `
|
|
|
789
807
|
<path d="M7 4.77V9.23M4.77 7H9.23" stroke="white" stroke-width="1.14" stroke-linecap="round"/>
|
|
790
808
|
</svg>
|
|
791
809
|
`;
|
|
792
|
-
const
|
|
810
|
+
const layoutToggleSvg = `
|
|
793
811
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
794
|
-
<
|
|
795
|
-
<
|
|
796
|
-
<
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
812
|
+
<rect x="8.5" y="0.5" width="5" height="7" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
813
|
+
<rect x="8.5" y="9.5" width="5" height="4" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
814
|
+
<rect x="0.5" y="0.5" width="5" height="13" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
815
|
+
</svg>
|
|
816
|
+
`;
|
|
817
|
+
const dragGripSvg = `
|
|
818
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
819
|
+
<circle cx="5" cy="3.5" r="1" fill="currentColor"/>
|
|
820
|
+
<circle cx="9" cy="3.5" r="1" fill="currentColor"/>
|
|
821
|
+
<circle cx="5" cy="7" r="1" fill="currentColor"/>
|
|
822
|
+
<circle cx="9" cy="7" r="1" fill="currentColor"/>
|
|
823
|
+
<circle cx="5" cy="10.5" r="1" fill="currentColor"/>
|
|
824
|
+
<circle cx="9" cy="10.5" r="1" fill="currentColor"/>
|
|
825
|
+
</svg>
|
|
826
|
+
`;
|
|
827
|
+
const addCircleOutlineSvg = `
|
|
828
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
829
|
+
<rect x="0.5" y="0.5" width="13" height="13" rx="6.5" stroke="currentColor"/>
|
|
830
|
+
<path d="M4.17133 7.0003L9.82818 7.0003" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
831
|
+
<path d="M7.00006 9.82843L7.00006 4.17157" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
832
|
+
</svg>
|
|
833
|
+
`;
|
|
834
|
+
const fillHorizontalSvg = `
|
|
835
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
836
|
+
<path d="M4.50013 4.11285L1.50013 7.00174L4.50013 9.89062M1.50013 7.00174L12.3647 7.00174" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
837
|
+
<path d="M9.50024 4.11328L12.5002 7.00217L9.50024 9.89106" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
838
|
+
</svg>
|
|
839
|
+
`;
|
|
840
|
+
const trashIconSvg = `
|
|
841
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
842
|
+
<path d="M11.375 2.39649V11.5C11.375 12.6046 10.4796 13.5 9.375 13.5H4.375C3.27043 13.5 2.375 12.6046 2.375 11.5V2.39649H4.375M11.375 2.39649H9.375M11.375 2.39649H13.125M9.375 2.39649V0.5H4.375V2.39649M9.375 2.39649H4.375M4.375 2.39649H0.875M5 4.06653V11.0665M7 4.06653V11.0665M9 4.06653V11.0665" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
800
843
|
</svg>
|
|
801
844
|
`;
|
|
802
845
|
class BlockWrapper extends HTMLElement {
|
|
@@ -857,8 +900,8 @@ class BlockWrapper extends HTMLElement {
|
|
|
857
900
|
const moreBtn = document.createElement("button");
|
|
858
901
|
moreBtn.type = "button";
|
|
859
902
|
moreBtn.innerHTML = moreIconSvg;
|
|
860
|
-
moreBtn.addEventListener("click", (
|
|
861
|
-
|
|
903
|
+
moreBtn.addEventListener("click", (e2) => {
|
|
904
|
+
e2.stopPropagation();
|
|
862
905
|
this.toggleMenu();
|
|
863
906
|
});
|
|
864
907
|
const menuEl = document.createElement("div");
|
|
@@ -874,8 +917,8 @@ class BlockWrapper extends HTMLElement {
|
|
|
874
917
|
deleteBtn.className = "block-wrapper__menu-item block-wrapper__menu-item--danger";
|
|
875
918
|
deleteBtn.setAttribute("role", "menuitem");
|
|
876
919
|
deleteBtn.innerHTML = `${trashIconSvg}<span>Delete</span>`;
|
|
877
|
-
deleteBtn.addEventListener("click", (
|
|
878
|
-
|
|
920
|
+
deleteBtn.addEventListener("click", (e2) => {
|
|
921
|
+
e2.stopPropagation();
|
|
879
922
|
this.closeMenu();
|
|
880
923
|
this.handleRemoveBlock();
|
|
881
924
|
});
|
|
@@ -943,9 +986,9 @@ class BlockWrapper extends HTMLElement {
|
|
|
943
986
|
surface.appendChild(text);
|
|
944
987
|
inner.appendChild(surface);
|
|
945
988
|
btn.appendChild(inner);
|
|
946
|
-
btn.addEventListener("click", (
|
|
947
|
-
|
|
948
|
-
|
|
989
|
+
btn.addEventListener("click", (e2) => {
|
|
990
|
+
e2.stopPropagation();
|
|
991
|
+
e2.preventDefault();
|
|
949
992
|
this.handleAddBlock(position, btn);
|
|
950
993
|
});
|
|
951
994
|
return btn;
|
|
@@ -1006,11 +1049,6 @@ class BlockWrapper extends HTMLElement {
|
|
|
1006
1049
|
}
|
|
1007
1050
|
this.addEventListener("mouseenter", this.handleHoverEnter);
|
|
1008
1051
|
this.addEventListener("mouseleave", this.handleHoverLeave);
|
|
1009
|
-
if (this.block != null) {
|
|
1010
|
-
this.updateActiveState(
|
|
1011
|
-
this.editorBridge.getSelectedBlockId() === this.block.id
|
|
1012
|
-
);
|
|
1013
|
-
}
|
|
1014
1052
|
}
|
|
1015
1053
|
/**
|
|
1016
1054
|
* Resolve the slotted block's first painted descendant — the
|
|
@@ -1056,8 +1094,8 @@ class BlockWrapper extends HTMLElement {
|
|
|
1056
1094
|
if (!this.menuElement) return;
|
|
1057
1095
|
this.menuElement.classList.add("open");
|
|
1058
1096
|
this.isMenuOpen = true;
|
|
1059
|
-
this.closeMenuOnOutsideClick = (
|
|
1060
|
-
if (!this.shadowRoot.contains(
|
|
1097
|
+
this.closeMenuOnOutsideClick = (e2) => {
|
|
1098
|
+
if (!this.shadowRoot.contains(e2.composedPath()[0])) {
|
|
1061
1099
|
this.closeMenu();
|
|
1062
1100
|
}
|
|
1063
1101
|
};
|
|
@@ -1075,7 +1113,6 @@ class BlockWrapper extends HTMLElement {
|
|
|
1075
1113
|
setBlock(block) {
|
|
1076
1114
|
this.block = block;
|
|
1077
1115
|
this.setAttribute("data-block-id", block.id);
|
|
1078
|
-
this.setAttribute("data-block-type", block.type);
|
|
1079
1116
|
if (this.nameElement) {
|
|
1080
1117
|
this.nameElement.textContent = block.definition.displayName ?? block.definition.name;
|
|
1081
1118
|
}
|
|
@@ -1136,6 +1173,755 @@ class BlockWrapper extends HTMLElement {
|
|
|
1136
1173
|
if (customElements.get("juo-editor-block-wrapper") == null) {
|
|
1137
1174
|
customElements.define("juo-editor-block-wrapper", BlockWrapper);
|
|
1138
1175
|
}
|
|
1176
|
+
const layoutStyles = `
|
|
1177
|
+
<style>
|
|
1178
|
+
:host {
|
|
1179
|
+
display: block;
|
|
1180
|
+
box-sizing: border-box;
|
|
1181
|
+
/* Re-enable hit-testing (mirrors the legacy wrapper). */
|
|
1182
|
+
pointer-events: auto;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.layout-block-wrapper {
|
|
1186
|
+
position: relative;
|
|
1187
|
+
box-sizing: border-box;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
/*
|
|
1191
|
+
* Grid-cell fill chain. The GridStack adapter tags the host with
|
|
1192
|
+
* data-juo-grid-cell; that gates an unbroken height:100% chain from the cell
|
|
1193
|
+
* down to the slotted block root so short blocks fill the cell the merchant
|
|
1194
|
+
* sized instead of top-aligning. In grid mode the slotted content is hidden
|
|
1195
|
+
* and the hardcoded skeleton (below) fills the cell instead.
|
|
1196
|
+
*/
|
|
1197
|
+
:host([data-juo-grid-cell]),
|
|
1198
|
+
:host([data-juo-grid-cell]) .layout-block-wrapper,
|
|
1199
|
+
:host([data-juo-grid-cell]) .layout-block-wrapper__slot-host {
|
|
1200
|
+
height: 100%;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
:host([data-juo-grid-cell]) ::slotted([data-block-id]) {
|
|
1204
|
+
/* display:block so inline CE block hosts honour height:100% and fill the cell. */
|
|
1205
|
+
display: block;
|
|
1206
|
+
height: 100%;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/*
|
|
1210
|
+
* Bare row divider in the SETTLED grid view (mirrors the customer portal).
|
|
1211
|
+
* Paints a hairline centred in the gap above each row leader (data-juo-divider);
|
|
1212
|
+
* data-juo-divider-row adds the divider gap as top margin so only boundaries
|
|
1213
|
+
* that show a divider grow. Gated with :not([data-juo-grid-cell]) so stale
|
|
1214
|
+
* divider attributes don't keep painting while dragging in layout mode.
|
|
1215
|
+
*/
|
|
1216
|
+
:host([data-juo-divider-row]:not([data-juo-grid-cell])) {
|
|
1217
|
+
margin-top: var(--juo-layout-divider-gap, 0px);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
:host([data-juo-divider]:not([data-juo-grid-cell])) .layout-block-wrapper::before {
|
|
1221
|
+
content: "";
|
|
1222
|
+
position: absolute;
|
|
1223
|
+
top: calc(-0.5 * (var(--juo-layout-gap, var(--card-divider-margin, 20px)) + var(--juo-layout-divider-gap, 0px)) - var(--card-divider-height, 1px) / 2);
|
|
1224
|
+
left: calc(-1 * var(--juo-layout-c, 0) * (100cqw + var(--juo-layout-gap, 0px)) / var(--juo-layout-cols, 12));
|
|
1225
|
+
width: 100cqw;
|
|
1226
|
+
height: var(--card-divider-height, 1px);
|
|
1227
|
+
background: var(--card-divider-background, #e5e5e5);
|
|
1228
|
+
pointer-events: none;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
/*
|
|
1232
|
+
* Layout-mode skeleton. Hidden while the settled view shows real content; in
|
|
1233
|
+
* grid (drag) mode the slot host is hidden and this shimmer placeholder fills
|
|
1234
|
+
* the cell so the canvas stays uniform while the merchant arranges blocks. The
|
|
1235
|
+
* block name is retained so each cell stays identifiable.
|
|
1236
|
+
*/
|
|
1237
|
+
.layout-block-wrapper__skeleton {
|
|
1238
|
+
display: none;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
:host([data-juo-grid-cell]) .layout-block-wrapper__slot-host {
|
|
1242
|
+
display: none !important;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
:host([data-juo-grid-cell]) .layout-block-wrapper__skeleton {
|
|
1246
|
+
display: flex;
|
|
1247
|
+
flex-direction: column;
|
|
1248
|
+
gap: 14px;
|
|
1249
|
+
box-sizing: border-box;
|
|
1250
|
+
height: 100%;
|
|
1251
|
+
padding: 16px 18px;
|
|
1252
|
+
background: #ffffff;
|
|
1253
|
+
border: 1px solid #ececf1;
|
|
1254
|
+
border-radius: 10px;
|
|
1255
|
+
overflow: hidden;
|
|
1256
|
+
/* Ease the placeholder in when entering layout mode instead of snapping.
|
|
1257
|
+
* Long, gentle fade so the card doesn't appear aggressively. */
|
|
1258
|
+
animation: juo-skeleton-in 320ms cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
@keyframes juo-skeleton-in {
|
|
1262
|
+
from { opacity: 0; }
|
|
1263
|
+
to { opacity: 1; }
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
/* Opacity-only (no translate) so bars breathe in softly rather than jumping. */
|
|
1267
|
+
@keyframes juo-skeleton-bar-in {
|
|
1268
|
+
from { opacity: 0; }
|
|
1269
|
+
to { opacity: 1; }
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
.layout-block-wrapper__skeleton-head {
|
|
1273
|
+
display: flex;
|
|
1274
|
+
align-items: center;
|
|
1275
|
+
gap: 8px;
|
|
1276
|
+
flex-shrink: 0;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
.layout-block-wrapper__skeleton-icon {
|
|
1280
|
+
display: inline-flex;
|
|
1281
|
+
align-items: center;
|
|
1282
|
+
justify-content: center;
|
|
1283
|
+
color: #9a9aa6;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
.layout-block-wrapper__skeleton-title {
|
|
1287
|
+
font-family: inherit;
|
|
1288
|
+
font-size: 12px;
|
|
1289
|
+
font-weight: 600;
|
|
1290
|
+
letter-spacing: -0.04px;
|
|
1291
|
+
color: #6b6b76;
|
|
1292
|
+
white-space: nowrap;
|
|
1293
|
+
overflow: hidden;
|
|
1294
|
+
text-overflow: ellipsis;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
/*
|
|
1298
|
+
* Placeholder bars sit directly under the header with a fixed height and a
|
|
1299
|
+
* uniform gap, so every block's skeleton reads identically. The region grows
|
|
1300
|
+
* to the skeleton's padding box (flex: 1) but the bars stay top-aligned — the
|
|
1301
|
+
* count is intentionally sparse (recomputeSkeletonLines caps it) so the
|
|
1302
|
+
* skeleton reads as a light "block placeholder" rather than a wall of noise.
|
|
1303
|
+
* Per-bar widths are assigned in JS from a block-type-seeded sequence so
|
|
1304
|
+
* adjacent blocks don't share the same width rhythm.
|
|
1305
|
+
*/
|
|
1306
|
+
.layout-block-wrapper__skeleton-lines {
|
|
1307
|
+
display: flex;
|
|
1308
|
+
flex: 1 1 auto;
|
|
1309
|
+
min-height: 0;
|
|
1310
|
+
flex-direction: column;
|
|
1311
|
+
justify-content: flex-start;
|
|
1312
|
+
gap: 12px;
|
|
1313
|
+
overflow: hidden;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
/* Flat placeholder bars — no shimmer so the layout-mode skeleton reads as a
|
|
1317
|
+
static "block placeholder" rather than a loading state. Width is set in JS
|
|
1318
|
+
(block-type-seeded); the value here is only a pre-measurement default. */
|
|
1319
|
+
.layout-block-wrapper__skeleton-line {
|
|
1320
|
+
width: 82%;
|
|
1321
|
+
height: 12px;
|
|
1322
|
+
flex-shrink: 0;
|
|
1323
|
+
border-radius: 4px;
|
|
1324
|
+
background-color: #ededf2;
|
|
1325
|
+
/* Newly added bars (first measure / resize) fade in softly, lightly
|
|
1326
|
+
* staggered (see nth-child delays) so they don't all snap in together. */
|
|
1327
|
+
animation: juo-skeleton-bar-in 360ms cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
.layout-block-wrapper__skeleton-line:nth-child(2) { animation-delay: 60ms; }
|
|
1331
|
+
.layout-block-wrapper__skeleton-line:nth-child(3) { animation-delay: 120ms; }
|
|
1332
|
+
.layout-block-wrapper__skeleton-line:nth-child(4) { animation-delay: 180ms; }
|
|
1333
|
+
|
|
1334
|
+
/*
|
|
1335
|
+
* Center hover toolbar — the block's affordances: layout toggle (leading grip
|
|
1336
|
+
* = morph trigger), add-below, fill, and delete. Shown on hover in BOTH view
|
|
1337
|
+
* mode and grid/layout mode (data-juo-grid-cell). Its vertical position is set
|
|
1338
|
+
* by JS (positionToolbar) to the midpoint of the block's VISIBLE portion so it
|
|
1339
|
+
* stays reachable on tall / partially-scrolled blocks; top:50% is the
|
|
1340
|
+
* fully-on-screen default before JS runs.
|
|
1341
|
+
*/
|
|
1342
|
+
.layout-block-wrapper__toolbar {
|
|
1343
|
+
position: absolute;
|
|
1344
|
+
top: 50%;
|
|
1345
|
+
left: 50%;
|
|
1346
|
+
transform: translate(-50%, -50%);
|
|
1347
|
+
z-index: 104;
|
|
1348
|
+
display: none;
|
|
1349
|
+
align-items: center;
|
|
1350
|
+
gap: 6px;
|
|
1351
|
+
box-sizing: border-box;
|
|
1352
|
+
padding: 6px;
|
|
1353
|
+
border-radius: 10px;
|
|
1354
|
+
background: #f5f5f5;
|
|
1355
|
+
border: 1px solid #ffffff;
|
|
1356
|
+
box-shadow: 0 2px 3.5px rgba(0, 0, 0, 0.15);
|
|
1357
|
+
backdrop-filter: blur(17px);
|
|
1358
|
+
-webkit-backdrop-filter: blur(17px);
|
|
1359
|
+
opacity: 0;
|
|
1360
|
+
pointer-events: auto;
|
|
1361
|
+
transition: opacity 140ms ease;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
:host(:hover) .layout-block-wrapper__toolbar {
|
|
1365
|
+
display: inline-flex;
|
|
1366
|
+
opacity: 1;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/* While GridStack is actively dragging / resizing this block, hide the toolbar
|
|
1370
|
+
so it doesn't overlap or interfere with the block being moved. The grid
|
|
1371
|
+
adapter toggles data-juo-grid-interacting on the wrapper under interaction. */
|
|
1372
|
+
:host([data-juo-grid-interacting]) .layout-block-wrapper__toolbar {
|
|
1373
|
+
display: none !important;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
.layout-block-wrapper__tool-btn {
|
|
1377
|
+
display: inline-flex;
|
|
1378
|
+
align-items: center;
|
|
1379
|
+
justify-content: center;
|
|
1380
|
+
box-sizing: border-box;
|
|
1381
|
+
width: 24px;
|
|
1382
|
+
height: 24px;
|
|
1383
|
+
padding: 0;
|
|
1384
|
+
border: none;
|
|
1385
|
+
border-radius: 6px;
|
|
1386
|
+
background: transparent;
|
|
1387
|
+
color: #121212;
|
|
1388
|
+
cursor: pointer;
|
|
1389
|
+
transition: background 120ms ease;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
.layout-block-wrapper__tool-btn:hover {
|
|
1393
|
+
background: rgba(0, 0, 0, 0.06);
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
.layout-block-wrapper__tool-btn:disabled {
|
|
1397
|
+
opacity: 0.4;
|
|
1398
|
+
cursor: default;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
.layout-block-wrapper__tool-btn:disabled:hover {
|
|
1402
|
+
background: transparent;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
.layout-block-wrapper__tool-btn svg {
|
|
1406
|
+
display: block;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
/* Leading position swaps between two buttons: the layout toggle in preview
|
|
1410
|
+
mode and the drag grip in layout mode (host tagged data-juo-grid-cell by the
|
|
1411
|
+
GridStack adapter). They are mutually exclusive so only one shows at a time. */
|
|
1412
|
+
.layout-block-wrapper__tool-btn--toggle {
|
|
1413
|
+
display: inline-flex;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
:host([data-juo-grid-cell]) .layout-block-wrapper__tool-btn--toggle {
|
|
1417
|
+
display: none;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
.layout-block-wrapper__tool-btn--grip {
|
|
1421
|
+
display: none;
|
|
1422
|
+
cursor: grab;
|
|
1423
|
+
touch-action: none;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
.layout-block-wrapper__tool-btn--grip:active {
|
|
1427
|
+
cursor: grabbing;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
:host([data-juo-grid-cell]) .layout-block-wrapper__tool-btn--grip {
|
|
1431
|
+
display: inline-flex;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
/* The fill toggle only makes sense while arranging, so it is hidden in the
|
|
1435
|
+
settled view and revealed only in layout mode (host tagged data-juo-grid-cell
|
|
1436
|
+
by the GridStack adapter). Add / delete stay visible in both modes. */
|
|
1437
|
+
.layout-block-wrapper__tool-btn--fill-h {
|
|
1438
|
+
display: none;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
:host([data-juo-grid-cell]) .layout-block-wrapper__tool-btn--fill-h {
|
|
1442
|
+
display: inline-flex;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
/* Derived (non-base) breakpoints are display-only in layout mode: the grid is
|
|
1446
|
+
auto-generated and edits target the authored breakpoint, so hide the layout-
|
|
1447
|
+
position affordances (drag grip + fill). Add/delete (tree edits) remain. */
|
|
1448
|
+
:host([data-juo-grid-readonly]) .layout-block-wrapper__tool-btn--grip,
|
|
1449
|
+
:host([data-juo-grid-readonly]) .layout-block-wrapper__tool-btn--fill-h {
|
|
1450
|
+
display: none;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
/* Active (pressed) state for the fill toggle — shown while the block spans the
|
|
1454
|
+
full row (data-juo-grid-full-width set on the host by the layout runtime). */
|
|
1455
|
+
:host([data-juo-grid-full-width]) .layout-block-wrapper__tool-btn--fill-h {
|
|
1456
|
+
background: #121212;
|
|
1457
|
+
color: #ffffff;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
:host([data-juo-grid-full-width]) .layout-block-wrapper__tool-btn--fill-h:hover {
|
|
1461
|
+
background: #121212;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1465
|
+
.layout-block-wrapper__toolbar,
|
|
1466
|
+
.layout-block-wrapper__tool-btn {
|
|
1467
|
+
transition: none;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
.layout-block-wrapper__skeleton,
|
|
1471
|
+
.layout-block-wrapper__skeleton-line {
|
|
1472
|
+
animation: none;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
</style>
|
|
1476
|
+
`;
|
|
1477
|
+
const _LayoutBlockWrapper = class _LayoutBlockWrapper extends HTMLElement {
|
|
1478
|
+
constructor() {
|
|
1479
|
+
super();
|
|
1480
|
+
__publicField(this, "block", null);
|
|
1481
|
+
__publicField(this, "editorBridge", createEditorBridge());
|
|
1482
|
+
__publicField(this, "skeletonTitle", null);
|
|
1483
|
+
__publicField(this, "skeletonLines", null);
|
|
1484
|
+
__publicField(this, "skeletonResizeObserver", null);
|
|
1485
|
+
__publicField(this, "toolbar", null);
|
|
1486
|
+
__publicField(this, "toolbarRafId", 0);
|
|
1487
|
+
__publicField(this, "toolbarScrollListening", false);
|
|
1488
|
+
__publicField(this, "hoverOutlineTarget", null);
|
|
1489
|
+
__publicField(this, "selectionOutlineTarget", null);
|
|
1490
|
+
__publicField(this, "skeletonRafId", 0);
|
|
1491
|
+
__publicField(this, "scheduleSkeletonRecompute", () => {
|
|
1492
|
+
if (typeof requestAnimationFrame !== "function") {
|
|
1493
|
+
this.recomputeSkeletonLines();
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (this.skeletonRafId) return;
|
|
1497
|
+
this.skeletonRafId = requestAnimationFrame(() => {
|
|
1498
|
+
this.skeletonRafId = 0;
|
|
1499
|
+
this.recomputeSkeletonLines();
|
|
1500
|
+
});
|
|
1501
|
+
});
|
|
1502
|
+
/**
|
|
1503
|
+
* Pointerdown on the layout toggle grip.
|
|
1504
|
+
*
|
|
1505
|
+
* - View mode: "arm" layout mode — the canvas morphs into GridStack, after
|
|
1506
|
+
* which the merchant drags/resizes natively. Passing THIS element (not its
|
|
1507
|
+
* id) lets the morph controller scroll + pop the exact block grabbed.
|
|
1508
|
+
* stopPropagation keeps the bridge's global-click selection — and the morph
|
|
1509
|
+
* controller's click-away exit — from also firing.
|
|
1510
|
+
* - Layout mode: the grip IS GridStack's drag handle, so we do nothing here and
|
|
1511
|
+
* let the event fall through. GridStack starts the drag off `mousedown` (a
|
|
1512
|
+
* separate event from this `pointerdown`), so it is unaffected by the
|
|
1513
|
+
* toolbar's pointerdown stop; toggling back to view would abort the drag
|
|
1514
|
+
* before it begins.
|
|
1515
|
+
*/
|
|
1516
|
+
__publicField(this, "handleMorphGrab", (e2) => {
|
|
1517
|
+
if (e2.button !== 0) return;
|
|
1518
|
+
if (canvasMode.value) return;
|
|
1519
|
+
e2.stopPropagation();
|
|
1520
|
+
enterLayout(this);
|
|
1521
|
+
});
|
|
1522
|
+
__publicField(this, "handleHoverEnter", () => {
|
|
1523
|
+
this.startToolbarTracking();
|
|
1524
|
+
if (this.classList.contains("active")) return;
|
|
1525
|
+
if (this.hasAttribute("data-juo-grid-cell")) return;
|
|
1526
|
+
const target = this.paintTarget();
|
|
1527
|
+
if (!target) return;
|
|
1528
|
+
this.hoverOutlineTarget = target;
|
|
1529
|
+
target.style.outline = "1px solid #060606";
|
|
1530
|
+
target.style.outlineOffset = "0";
|
|
1531
|
+
});
|
|
1532
|
+
__publicField(this, "handleHoverLeave", () => {
|
|
1533
|
+
this.stopToolbarTracking();
|
|
1534
|
+
if (!this.hoverOutlineTarget) return;
|
|
1535
|
+
this.hoverOutlineTarget.style.outline = "";
|
|
1536
|
+
this.hoverOutlineTarget.style.outlineOffset = "";
|
|
1537
|
+
this.hoverOutlineTarget = null;
|
|
1538
|
+
});
|
|
1539
|
+
/**
|
|
1540
|
+
* Center the toolbar on the block's VISIBLE portion so it stays reachable when
|
|
1541
|
+
* the block is taller than / partially scrolled out of the viewport. When the
|
|
1542
|
+
* block is fully on screen this equals its geometric center.
|
|
1543
|
+
*/
|
|
1544
|
+
__publicField(this, "positionToolbar", () => {
|
|
1545
|
+
if (!this.toolbar) return;
|
|
1546
|
+
const rect = this.getBoundingClientRect();
|
|
1547
|
+
if (rect.height <= 0) return;
|
|
1548
|
+
const viewportH = typeof window !== "undefined" && window.innerHeight ? window.innerHeight : rect.bottom;
|
|
1549
|
+
const visibleTop = Math.max(rect.top, 0);
|
|
1550
|
+
const visibleBottom = Math.min(rect.bottom, viewportH);
|
|
1551
|
+
const midpoint = visibleBottom > visibleTop ? (visibleTop + visibleBottom) / 2 : rect.top + rect.height / 2;
|
|
1552
|
+
const relative = Math.min(Math.max(midpoint - rect.top, 0), rect.height);
|
|
1553
|
+
this.toolbar.style.top = `${relative}px`;
|
|
1554
|
+
});
|
|
1555
|
+
__publicField(this, "scheduleToolbarReposition", () => {
|
|
1556
|
+
if (typeof requestAnimationFrame !== "function") {
|
|
1557
|
+
this.positionToolbar();
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
if (this.toolbarRafId) return;
|
|
1561
|
+
this.toolbarRafId = requestAnimationFrame(() => {
|
|
1562
|
+
this.toolbarRafId = 0;
|
|
1563
|
+
this.positionToolbar();
|
|
1564
|
+
});
|
|
1565
|
+
});
|
|
1566
|
+
this.attachShadow({ mode: "open" });
|
|
1567
|
+
const styleElement = document.createElement("style");
|
|
1568
|
+
styleElement.textContent = layoutStyles.replace(/<style>|<\/style>/g, "").trim();
|
|
1569
|
+
this.shadowRoot.appendChild(styleElement);
|
|
1570
|
+
this.setupTemplate();
|
|
1571
|
+
}
|
|
1572
|
+
static get observedAttributes() {
|
|
1573
|
+
return ["data-block-id", "data-juo-grid-cell"];
|
|
1574
|
+
}
|
|
1575
|
+
attributeChangedCallback(name) {
|
|
1576
|
+
if (name === "data-juo-grid-cell") this.scheduleSkeletonRecompute();
|
|
1577
|
+
}
|
|
1578
|
+
setupTemplate() {
|
|
1579
|
+
const wrapper = document.createElement("div");
|
|
1580
|
+
wrapper.className = "layout-block-wrapper";
|
|
1581
|
+
const slotHost = document.createElement("div");
|
|
1582
|
+
slotHost.className = "layout-block-wrapper__slot-host";
|
|
1583
|
+
slotHost.appendChild(document.createElement("slot"));
|
|
1584
|
+
wrapper.appendChild(slotHost);
|
|
1585
|
+
const skeleton = document.createElement("div");
|
|
1586
|
+
skeleton.className = "layout-block-wrapper__skeleton";
|
|
1587
|
+
skeleton.setAttribute("aria-hidden", "true");
|
|
1588
|
+
const skeletonHead = document.createElement("div");
|
|
1589
|
+
skeletonHead.className = "layout-block-wrapper__skeleton-head";
|
|
1590
|
+
const skeletonIcon = document.createElement("span");
|
|
1591
|
+
skeletonIcon.className = "layout-block-wrapper__skeleton-icon";
|
|
1592
|
+
skeletonIcon.innerHTML = blockIconSvg;
|
|
1593
|
+
const skeletonTitle = document.createElement("span");
|
|
1594
|
+
skeletonTitle.className = "layout-block-wrapper__skeleton-title";
|
|
1595
|
+
skeletonHead.appendChild(skeletonIcon);
|
|
1596
|
+
skeletonHead.appendChild(skeletonTitle);
|
|
1597
|
+
const skeletonLines = document.createElement("div");
|
|
1598
|
+
skeletonLines.className = "layout-block-wrapper__skeleton-lines";
|
|
1599
|
+
for (let i = 0; i < 3; i++) {
|
|
1600
|
+
const line = document.createElement("span");
|
|
1601
|
+
line.className = "layout-block-wrapper__skeleton-line";
|
|
1602
|
+
skeletonLines.appendChild(line);
|
|
1603
|
+
}
|
|
1604
|
+
skeleton.appendChild(skeletonHead);
|
|
1605
|
+
skeleton.appendChild(skeletonLines);
|
|
1606
|
+
wrapper.appendChild(skeleton);
|
|
1607
|
+
this.skeletonTitle = skeletonTitle;
|
|
1608
|
+
this.skeletonLines = skeletonLines;
|
|
1609
|
+
const toolbar = this.buildToolbar();
|
|
1610
|
+
wrapper.appendChild(toolbar);
|
|
1611
|
+
this.toolbar = toolbar;
|
|
1612
|
+
this.shadowRoot.appendChild(wrapper);
|
|
1613
|
+
this.editorBridge.onMessage((message) => {
|
|
1614
|
+
var _a;
|
|
1615
|
+
if (message.type === "SELECT_BLOCK") {
|
|
1616
|
+
this.updateActiveState(message.payload.blockId === ((_a = this.block) == null ? void 0 : _a.id));
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
/**
|
|
1621
|
+
* Build the center hover toolbar. Buttons (left→right): layout toggle (grip,
|
|
1622
|
+
* leading), add-below, delete, fill-horizontal.
|
|
1623
|
+
* pointerdown/click are stopped at the container so selecting a tool never
|
|
1624
|
+
* bubbles to the bridge's global-click selection.
|
|
1625
|
+
*/
|
|
1626
|
+
buildToolbar() {
|
|
1627
|
+
const toolbar = document.createElement("div");
|
|
1628
|
+
toolbar.className = "layout-block-wrapper__toolbar";
|
|
1629
|
+
toolbar.setAttribute("role", "toolbar");
|
|
1630
|
+
toolbar.setAttribute("aria-label", "Block actions");
|
|
1631
|
+
toolbar.addEventListener("pointerdown", (e2) => e2.stopPropagation());
|
|
1632
|
+
toolbar.addEventListener("click", (e2) => e2.stopPropagation());
|
|
1633
|
+
const toggle = this.createToolButton(
|
|
1634
|
+
layoutToggleSvg,
|
|
1635
|
+
"Edit layout",
|
|
1636
|
+
"layout-block-wrapper__tool-btn--toggle"
|
|
1637
|
+
);
|
|
1638
|
+
toggle.addEventListener(
|
|
1639
|
+
"pointerdown",
|
|
1640
|
+
(e2) => this.handleMorphGrab(e2)
|
|
1641
|
+
);
|
|
1642
|
+
const grip = this.createToolButton(
|
|
1643
|
+
dragGripSvg,
|
|
1644
|
+
"Drag to reposition",
|
|
1645
|
+
"layout-block-wrapper__tool-btn--grip"
|
|
1646
|
+
);
|
|
1647
|
+
grip.addEventListener(
|
|
1648
|
+
"pointerdown",
|
|
1649
|
+
(e2) => this.handleMorphGrab(e2)
|
|
1650
|
+
);
|
|
1651
|
+
const addBtn = this.createToolButton(
|
|
1652
|
+
addCircleOutlineSvg,
|
|
1653
|
+
"Add block below",
|
|
1654
|
+
"layout-block-wrapper__tool-btn--add"
|
|
1655
|
+
);
|
|
1656
|
+
addBtn.addEventListener("click", (e2) => {
|
|
1657
|
+
e2.stopPropagation();
|
|
1658
|
+
this.handleAddBelow(addBtn);
|
|
1659
|
+
});
|
|
1660
|
+
const deleteBtn = this.createToolButton(trashIconSvg, "Delete block");
|
|
1661
|
+
deleteBtn.addEventListener("click", (e2) => {
|
|
1662
|
+
e2.stopPropagation();
|
|
1663
|
+
this.handleRemoveBlock();
|
|
1664
|
+
});
|
|
1665
|
+
const fillH = this.createToolButton(
|
|
1666
|
+
fillHorizontalSvg,
|
|
1667
|
+
"Fill horizontally",
|
|
1668
|
+
"layout-block-wrapper__tool-btn--fill-h"
|
|
1669
|
+
);
|
|
1670
|
+
fillH.addEventListener("click", (e2) => {
|
|
1671
|
+
e2.stopPropagation();
|
|
1672
|
+
this.handleFillWidth();
|
|
1673
|
+
});
|
|
1674
|
+
toolbar.append(toggle, grip, addBtn, fillH, deleteBtn);
|
|
1675
|
+
return toolbar;
|
|
1676
|
+
}
|
|
1677
|
+
createToolButton(svg, label, extraClass) {
|
|
1678
|
+
const btn = document.createElement("button");
|
|
1679
|
+
btn.type = "button";
|
|
1680
|
+
btn.className = "layout-block-wrapper__tool-btn";
|
|
1681
|
+
if (extraClass) btn.classList.add(extraClass);
|
|
1682
|
+
btn.setAttribute("aria-label", label);
|
|
1683
|
+
btn.setAttribute("title", label);
|
|
1684
|
+
btn.innerHTML = svg;
|
|
1685
|
+
return btn;
|
|
1686
|
+
}
|
|
1687
|
+
/** Open the add-block menu anchored to the toolbar button, inserting AFTER. */
|
|
1688
|
+
handleAddBelow(button) {
|
|
1689
|
+
if (!this.block) return;
|
|
1690
|
+
const rect = button.getBoundingClientRect();
|
|
1691
|
+
this.editorBridge.sendMessage(
|
|
1692
|
+
createOpenAddBlockMenuMessage({
|
|
1693
|
+
targetBlockId: this.block.id,
|
|
1694
|
+
position: "after",
|
|
1695
|
+
anchor: { x: rect.right, y: rect.top }
|
|
1696
|
+
})
|
|
1697
|
+
);
|
|
1698
|
+
}
|
|
1699
|
+
/**
|
|
1700
|
+
* Traverse up the DOM (crossing shadow-root boundaries) to resolve the
|
|
1701
|
+
* containing block wrapper's id, then send REMOVE_BLOCK. Mirrors the legacy
|
|
1702
|
+
* wrapper's removal, but recognizes either wrapper tag (grid nesting uses the
|
|
1703
|
+
* layout wrapper).
|
|
1704
|
+
*/
|
|
1705
|
+
handleRemoveBlock() {
|
|
1706
|
+
if (!this.block) return;
|
|
1707
|
+
const extensionRoot = this.closest("juo-extension-root");
|
|
1708
|
+
const slotName = (extensionRoot == null ? void 0 : extensionRoot.getAttribute("name")) || "default";
|
|
1709
|
+
let parentId = "root";
|
|
1710
|
+
let current = this;
|
|
1711
|
+
while (current) {
|
|
1712
|
+
const parent = this.getParentElement(current);
|
|
1713
|
+
if (!parent) break;
|
|
1714
|
+
if (parent !== this && isBlockWrapperTag(parent.tagName)) {
|
|
1715
|
+
const parentBlockId = parent.getAttribute("data-block-id");
|
|
1716
|
+
if (parentBlockId) {
|
|
1717
|
+
parentId = parentBlockId;
|
|
1718
|
+
break;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
current = parent;
|
|
1722
|
+
}
|
|
1723
|
+
this.editorBridge.sendMessage(
|
|
1724
|
+
createRemoveBlockMessage(
|
|
1725
|
+
{ blockId: this.block.id, location: { slot: slotName, parentId } },
|
|
1726
|
+
this.block.id
|
|
1727
|
+
)
|
|
1728
|
+
);
|
|
1729
|
+
}
|
|
1730
|
+
/** Resolve the parent element, crossing shadow-root boundaries. */
|
|
1731
|
+
getParentElement(element) {
|
|
1732
|
+
const root = element.getRootNode();
|
|
1733
|
+
if (root instanceof ShadowRoot) return root.host;
|
|
1734
|
+
return element.parentElement;
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Toggle the block's sticky fill flag. Emitted as a layout command; the parent
|
|
1738
|
+
* engine flips the flag, expands the block into its free row-band space, pushes
|
|
1739
|
+
* the change to history + re-syncs the iframe.
|
|
1740
|
+
*/
|
|
1741
|
+
handleFillWidth() {
|
|
1742
|
+
if (!this.block) return;
|
|
1743
|
+
const surface = this.closest(
|
|
1744
|
+
'juo-extension-root[surface="overlay"]'
|
|
1745
|
+
) ? "overlay" : "page";
|
|
1746
|
+
const ctx = getActiveSurfaceContext(surface);
|
|
1747
|
+
if (!ctx) return;
|
|
1748
|
+
emitLayoutCommand({
|
|
1749
|
+
surface,
|
|
1750
|
+
id: ctx.id,
|
|
1751
|
+
command: { kind: "fillWidth", blockId: this.block.id }
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
connectedCallback() {
|
|
1755
|
+
const isInOverlay = this.closest('juo-extension-root[surface="overlay"]') !== null;
|
|
1756
|
+
if (isInOverlay && this.toolbar) {
|
|
1757
|
+
this.toolbar.style.display = "none";
|
|
1758
|
+
}
|
|
1759
|
+
const isWorkflowPreview = (() => {
|
|
1760
|
+
try {
|
|
1761
|
+
const params = new URLSearchParams(window.location.search);
|
|
1762
|
+
return params.get("workflow-mode") === "true";
|
|
1763
|
+
} catch {
|
|
1764
|
+
return false;
|
|
1765
|
+
}
|
|
1766
|
+
})();
|
|
1767
|
+
if (isWorkflowPreview && !isInOverlay) {
|
|
1768
|
+
this.style.pointerEvents = "none";
|
|
1769
|
+
}
|
|
1770
|
+
this.addEventListener("mouseenter", this.handleHoverEnter);
|
|
1771
|
+
this.addEventListener("mouseleave", this.handleHoverLeave);
|
|
1772
|
+
if (typeof ResizeObserver !== "undefined" && this.skeletonLines) {
|
|
1773
|
+
this.skeletonResizeObserver = new ResizeObserver(
|
|
1774
|
+
this.scheduleSkeletonRecompute
|
|
1775
|
+
);
|
|
1776
|
+
this.skeletonResizeObserver.observe(this.skeletonLines);
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
disconnectedCallback() {
|
|
1780
|
+
var _a;
|
|
1781
|
+
this.stopToolbarTracking();
|
|
1782
|
+
(_a = this.skeletonResizeObserver) == null ? void 0 : _a.disconnect();
|
|
1783
|
+
this.skeletonResizeObserver = null;
|
|
1784
|
+
if (this.skeletonRafId) {
|
|
1785
|
+
cancelAnimationFrame(this.skeletonRafId);
|
|
1786
|
+
this.skeletonRafId = 0;
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
startToolbarTracking() {
|
|
1790
|
+
this.positionToolbar();
|
|
1791
|
+
if (this.toolbarScrollListening || typeof window === "undefined") return;
|
|
1792
|
+
this.toolbarScrollListening = true;
|
|
1793
|
+
window.addEventListener("scroll", this.scheduleToolbarReposition, true);
|
|
1794
|
+
window.addEventListener("resize", this.scheduleToolbarReposition);
|
|
1795
|
+
}
|
|
1796
|
+
stopToolbarTracking() {
|
|
1797
|
+
if (this.toolbarScrollListening && typeof window !== "undefined") {
|
|
1798
|
+
this.toolbarScrollListening = false;
|
|
1799
|
+
window.removeEventListener("scroll", this.scheduleToolbarReposition, true);
|
|
1800
|
+
window.removeEventListener("resize", this.scheduleToolbarReposition);
|
|
1801
|
+
}
|
|
1802
|
+
if (this.toolbarRafId) {
|
|
1803
|
+
cancelAnimationFrame(this.toolbarRafId);
|
|
1804
|
+
this.toolbarRafId = 0;
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
paintTarget() {
|
|
1808
|
+
const slotted = this.firstElementChild;
|
|
1809
|
+
if (!slotted || slotted.hasAttribute("data-empty")) return null;
|
|
1810
|
+
return resolveOutlineTarget(slotted);
|
|
1811
|
+
}
|
|
1812
|
+
updateActiveState(isActive) {
|
|
1813
|
+
if (isActive) {
|
|
1814
|
+
this.classList.add("active");
|
|
1815
|
+
this.handleHoverLeave();
|
|
1816
|
+
if (this.hasAttribute("data-juo-grid-cell")) return;
|
|
1817
|
+
const target = this.paintTarget();
|
|
1818
|
+
if (!target) return;
|
|
1819
|
+
this.selectionOutlineTarget = target;
|
|
1820
|
+
target.style.outline = "2px solid #060606";
|
|
1821
|
+
target.style.outlineOffset = "0";
|
|
1822
|
+
} else {
|
|
1823
|
+
this.classList.remove("active");
|
|
1824
|
+
if (this.selectionOutlineTarget) {
|
|
1825
|
+
this.selectionOutlineTarget.style.outline = "";
|
|
1826
|
+
this.selectionOutlineTarget.style.outlineOffset = "";
|
|
1827
|
+
this.selectionOutlineTarget = null;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
/**
|
|
1832
|
+
* Match the placeholder bars to the (dynamic) cell height. Bars are a fixed
|
|
1833
|
+
* height with a uniform gap and stay top-aligned under the header, so every
|
|
1834
|
+
* skeleton reads identically. The count scales gently with height but is
|
|
1835
|
+
* halved and capped so tall cells don't fill with noise; very short cells
|
|
1836
|
+
* (< 2 bars) drop the bars entirely and show just the header. Count depends
|
|
1837
|
+
* only on the cell height (not on the bars), so there is no measure→mutate
|
|
1838
|
+
* feedback loop.
|
|
1839
|
+
*/
|
|
1840
|
+
recomputeSkeletonLines() {
|
|
1841
|
+
var _a;
|
|
1842
|
+
if (!this.skeletonLines) return;
|
|
1843
|
+
if (!this.hasAttribute("data-juo-grid-cell")) return;
|
|
1844
|
+
const avail = this.skeletonLines.clientHeight;
|
|
1845
|
+
if (avail <= 0) return;
|
|
1846
|
+
const { SKELETON_LINE_H: LINE_H, SKELETON_GAP: GAP, SKELETON_MAX_BARS: MAX } = _LayoutBlockWrapper;
|
|
1847
|
+
const fit = Math.floor((avail + GAP) / (LINE_H + GAP));
|
|
1848
|
+
const count = fit < 2 ? 0 : Math.min(MAX, Math.max(2, Math.round(fit / 2)));
|
|
1849
|
+
const current = this.skeletonLines.childElementCount;
|
|
1850
|
+
if (count > current) {
|
|
1851
|
+
for (let i = current; i < count; i++) {
|
|
1852
|
+
const line = document.createElement("span");
|
|
1853
|
+
line.className = "layout-block-wrapper__skeleton-line";
|
|
1854
|
+
this.skeletonLines.appendChild(line);
|
|
1855
|
+
}
|
|
1856
|
+
} else if (count < current) {
|
|
1857
|
+
for (let i = current; i > count; i--) {
|
|
1858
|
+
(_a = this.skeletonLines.lastElementChild) == null ? void 0 : _a.remove();
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
this.applyBarWidths();
|
|
1862
|
+
}
|
|
1863
|
+
/**
|
|
1864
|
+
* Stable offset into {@link LayoutBlockWrapper.SKELETON_BAR_WIDTHS} derived
|
|
1865
|
+
* from the block type, so each block type has its own width rhythm and
|
|
1866
|
+
* adjacent (differently-typed) blocks don't line up.
|
|
1867
|
+
*/
|
|
1868
|
+
skeletonWidthOffset() {
|
|
1869
|
+
var _a;
|
|
1870
|
+
const key = ((_a = this.block) == null ? void 0 : _a.definition.name) ?? "";
|
|
1871
|
+
let hash = 0;
|
|
1872
|
+
for (let i = 0; i < key.length; i++) {
|
|
1873
|
+
hash = hash * 31 + key.charCodeAt(i) >>> 0;
|
|
1874
|
+
}
|
|
1875
|
+
return hash % _LayoutBlockWrapper.SKELETON_BAR_WIDTHS.length;
|
|
1876
|
+
}
|
|
1877
|
+
/** Assign each bar its width from the block-type-seeded sequence. */
|
|
1878
|
+
applyBarWidths() {
|
|
1879
|
+
if (!this.skeletonLines) return;
|
|
1880
|
+
const widths = _LayoutBlockWrapper.SKELETON_BAR_WIDTHS;
|
|
1881
|
+
const offset = this.skeletonWidthOffset();
|
|
1882
|
+
const bars = this.skeletonLines.children;
|
|
1883
|
+
for (let i = 0; i < bars.length; i++) {
|
|
1884
|
+
bars[i].style.width = `${widths[(offset + i) % widths.length]}%`;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
setBlock(block) {
|
|
1888
|
+
this.block = block;
|
|
1889
|
+
this.setAttribute("data-block-id", block.id);
|
|
1890
|
+
if (this.skeletonTitle) {
|
|
1891
|
+
this.skeletonTitle.textContent = getBlockLabel(block);
|
|
1892
|
+
}
|
|
1893
|
+
this.applyBarWidths();
|
|
1894
|
+
}
|
|
1895
|
+
};
|
|
1896
|
+
/**
|
|
1897
|
+
* Height-tiers for the placeholder bar count. Deliberately sparse: the bars
|
|
1898
|
+
* are a hint at "a block lives here", not a faithful line count, so we show
|
|
1899
|
+
* few and cap hard to avoid a noisy wall of identical bars on tall blocks.
|
|
1900
|
+
* Cells too short for >= 2 bars render header-only (no lonely single bar).
|
|
1901
|
+
*/
|
|
1902
|
+
__publicField(_LayoutBlockWrapper, "SKELETON_LINE_H", 12);
|
|
1903
|
+
__publicField(_LayoutBlockWrapper, "SKELETON_GAP", 12);
|
|
1904
|
+
__publicField(_LayoutBlockWrapper, "SKELETON_MAX_BARS", 4);
|
|
1905
|
+
/**
|
|
1906
|
+
* Per-block width sequence. Widths are read from this palette starting at a
|
|
1907
|
+
* block-type-seeded offset so neighbouring blocks of different types get a
|
|
1908
|
+
* different width rhythm (deterministic — the same block type always renders
|
|
1909
|
+
* the same sequence). Chosen to look like varied text lines, none too short.
|
|
1910
|
+
*/
|
|
1911
|
+
__publicField(_LayoutBlockWrapper, "SKELETON_BAR_WIDTHS", [
|
|
1912
|
+
92,
|
|
1913
|
+
68,
|
|
1914
|
+
84,
|
|
1915
|
+
58,
|
|
1916
|
+
96,
|
|
1917
|
+
74,
|
|
1918
|
+
88,
|
|
1919
|
+
62
|
|
1920
|
+
]);
|
|
1921
|
+
let LayoutBlockWrapper = _LayoutBlockWrapper;
|
|
1922
|
+
if (customElements.get(LAYOUT_BLOCK_WRAPPER_TAG) == null) {
|
|
1923
|
+
customElements.define(LAYOUT_BLOCK_WRAPPER_TAG, LayoutBlockWrapper);
|
|
1924
|
+
}
|
|
1139
1925
|
async function serializeBlock(block) {
|
|
1140
1926
|
let initialValue = block.initialValue;
|
|
1141
1927
|
if (typeof initialValue === "function") {
|
|
@@ -1163,7 +1949,7 @@ async function serializeBlock(block) {
|
|
|
1163
1949
|
}
|
|
1164
1950
|
})
|
|
1165
1951
|
);
|
|
1166
|
-
const loaded = entries.filter((
|
|
1952
|
+
const loaded = entries.filter((e2) => e2 !== null);
|
|
1167
1953
|
if (loaded.length > 0) {
|
|
1168
1954
|
locales = Object.fromEntries(loaded);
|
|
1169
1955
|
}
|
|
@@ -1188,7 +1974,7 @@ function buildEditorCanvasStyleContent(backgroundColor) {
|
|
|
1188
1974
|
}`;
|
|
1189
1975
|
}
|
|
1190
1976
|
async function setupEditorMode(deps) {
|
|
1191
|
-
const { routerService, themeState
|
|
1977
|
+
const { routerService, themeState } = deps;
|
|
1192
1978
|
const padStyle = document.createElement("style");
|
|
1193
1979
|
document.head.appendChild(padStyle);
|
|
1194
1980
|
const disposeCanvasStyles = effect(() => {
|
|
@@ -1200,6 +1986,18 @@ async function setupEditorMode(deps) {
|
|
|
1200
1986
|
const handler = createEditorHandler({
|
|
1201
1987
|
themeState
|
|
1202
1988
|
});
|
|
1989
|
+
setLayoutCommandEmitter(({ surface, id, rects }) => {
|
|
1990
|
+
editor.sendMessage(
|
|
1991
|
+
createLayoutCommandMessage({
|
|
1992
|
+
surface,
|
|
1993
|
+
id,
|
|
1994
|
+
command: { kind: "setRects", rects }
|
|
1995
|
+
})
|
|
1996
|
+
);
|
|
1997
|
+
});
|
|
1998
|
+
setLayoutCommandDispatcher(({ surface, id, command }) => {
|
|
1999
|
+
editor.sendMessage(createLayoutCommandMessage({ surface, id, command }));
|
|
2000
|
+
});
|
|
1203
2001
|
const { unsubscribe } = editor.onMessage((message) => {
|
|
1204
2002
|
handler.handleMessage(message);
|
|
1205
2003
|
});
|
|
@@ -1214,65 +2012,66 @@ async function setupEditorMode(deps) {
|
|
|
1214
2012
|
})
|
|
1215
2013
|
)
|
|
1216
2014
|
);
|
|
1217
|
-
if (typeof block.name === "string" && block.name.startsWith("overlay:")) {
|
|
1218
|
-
editor.sendMessage(
|
|
1219
|
-
createRegisterOverlaysMessage({
|
|
1220
|
-
overlays: overlayService.getEditableOverlays()
|
|
1221
|
-
})
|
|
1222
|
-
);
|
|
1223
|
-
}
|
|
1224
2015
|
});
|
|
1225
2016
|
const blocks = await Promise.all(getDefinedBlocks().map(serializeBlock));
|
|
1226
2017
|
editor.sendMessage(createRegisterBlocksMessage({ blocks }));
|
|
1227
2018
|
editor.sendMessage(createRegisterRoutesMessage({ routes }));
|
|
1228
|
-
editor.sendMessage(
|
|
1229
|
-
createRegisterOverlaysMessage({
|
|
1230
|
-
overlays: overlayService.getEditableOverlays()
|
|
1231
|
-
})
|
|
1232
|
-
);
|
|
1233
2019
|
return () => {
|
|
1234
2020
|
disposeCanvasStyles();
|
|
1235
2021
|
padStyle.remove();
|
|
1236
2022
|
unsubscribeRegister();
|
|
1237
2023
|
unsubscribe();
|
|
1238
2024
|
editor.destroy();
|
|
2025
|
+
setLayoutCommandEmitter(null);
|
|
2026
|
+
setLayoutCommandDispatcher(null);
|
|
2027
|
+
clearAllSurfaceContexts();
|
|
1239
2028
|
};
|
|
1240
2029
|
}
|
|
1241
2030
|
export {
|
|
1242
2031
|
BlockWrapper,
|
|
1243
2032
|
EDITOR_BODY_BOTTOM_PADDING_PX,
|
|
1244
2033
|
EDITOR_BODY_TOP_PADDING_PX,
|
|
2034
|
+
LayoutBlockWrapper,
|
|
1245
2035
|
buildEditorCanvasStyleContent,
|
|
1246
|
-
|
|
1247
|
-
|
|
2036
|
+
canvasMode2 as canvasMode,
|
|
2037
|
+
m as createAddBlockMenuClosedMessage,
|
|
2038
|
+
n as createAddBlockMessage,
|
|
1248
2039
|
createEditorBridge,
|
|
1249
2040
|
createEditorHandler,
|
|
1250
|
-
|
|
1251
|
-
|
|
2041
|
+
d as createFocusInlineTextMessage,
|
|
2042
|
+
createLayoutCommandMessage,
|
|
2043
|
+
o as createLayoutingModeChangedMessage,
|
|
2044
|
+
p as createMoveBlockMessage,
|
|
1252
2045
|
createOpenAddBlockMenuMessage,
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
2046
|
+
q as createProvideGlobalStylesMessage,
|
|
2047
|
+
s as createProvideInitialGlobalStylesMessage,
|
|
2048
|
+
t as createProvideLayoutDocumentMessage,
|
|
2049
|
+
u as createProvideLayoutMessage,
|
|
2050
|
+
v as createProvideThemeStateMessage,
|
|
2051
|
+
w as createProvideTranslationOverridesMessage,
|
|
2052
|
+
b as createRegisterBlockTranslationKeysMessage,
|
|
1258
2053
|
createRegisterBlocksMessage,
|
|
1259
|
-
createRegisterOverlaysMessage,
|
|
1260
2054
|
createRegisterRoutesMessage,
|
|
1261
2055
|
createRemoveBlockMessage,
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
2056
|
+
x as createReportBlockContentSizeMessage,
|
|
2057
|
+
y as createReportContentHeightMessage,
|
|
2058
|
+
z as createRequestCloseAddBlockMenuMessage,
|
|
2059
|
+
A as createRequestGlobalStylesMessage,
|
|
2060
|
+
B as createRequestThemeStateMessage,
|
|
2061
|
+
C as createRequestTranslationOverridesMessage,
|
|
2062
|
+
D as createScrollSyncMessage,
|
|
2063
|
+
a as createSelectBlockMessage,
|
|
2064
|
+
E as createSetBlockPresetMessage,
|
|
2065
|
+
F as createSetGlobalStylesMessage,
|
|
2066
|
+
G as createSetLayoutingModeMessage,
|
|
2067
|
+
H as createSetLocaleMessage,
|
|
2068
|
+
I as createUpdateBlockPropsMessage,
|
|
2069
|
+
e as createUpdateBlockTranslationMessage,
|
|
2070
|
+
J as createUpsertThemeStateMessage,
|
|
2071
|
+
K as getEditorBridge,
|
|
2072
|
+
M as isEditorMessage,
|
|
2073
|
+
N as isIframeMessage,
|
|
2074
|
+
r as resetCanvasMode,
|
|
2075
|
+
setCanvasMode,
|
|
1277
2076
|
setupEditorMode
|
|
1278
2077
|
};
|