@juo/orion-core 0.9.0 → 0.10.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.
@@ -542,15 +542,35 @@ class BlockWrapperEvent extends Event {
542
542
  this.callback = callback;
543
543
  }
544
544
  }
545
+ function isInEditorIframe() {
546
+ if (typeof window === "undefined")
547
+ return false;
548
+ const params = new URLSearchParams(window.location.search);
549
+ return params.get("editor") === "true";
550
+ }
545
551
  function withWrapper(fn) {
552
+ let wrapper = null;
546
553
  return (block) => {
554
+ var _a;
547
555
  let rendered = fn(block);
548
- const evt = new BlockWrapperEvent(block, (wrapper) => {
549
- wrapper.replaceChildren(fn(block));
550
- rendered = wrapper;
551
- });
552
- document.dispatchEvent(evt);
553
- return rendered;
556
+ if (wrapper === null) {
557
+ if (isInEditorIframe()) {
558
+ wrapper = document.createElement("juo-editor-block-wrapper");
559
+ wrapper.setAttribute("data-block-id", block.id);
560
+ (_a = wrapper.setBlock) == null ? void 0 : _a.call(wrapper, block);
561
+ wrapper.appendChild(rendered);
562
+ } else {
563
+ const evt = new BlockWrapperEvent(block, (evtWrapper) => {
564
+ wrapper = evtWrapper;
565
+ });
566
+ document.dispatchEvent(evt);
567
+ }
568
+ }
569
+ if (!wrapper) {
570
+ return rendered;
571
+ }
572
+ wrapper.replaceChildren(rendered);
573
+ return wrapper;
554
574
  };
555
575
  }
556
576
  function registerBlock(block) {
@@ -681,18 +701,10 @@ function createBlockInstanceFromObject(input) {
681
701
  function createBlockInstanceFromJSON(input) {
682
702
  return createBlockInstanceFromObject(JSON.parse(input));
683
703
  }
684
- function createPage() {
685
- const blocks = d([]);
686
- return {
687
- blocks
688
- };
689
- }
690
- const PageContext = createContext("page");
691
704
  export {
692
705
  BlockWrapperEvent as B,
693
706
  ContextRequestEvent as C,
694
707
  E,
695
- PageContext as P,
696
708
  SelectedBlockContext as S,
697
709
  createBlockInstance as a,
698
710
  createBlockInstanceFromJSON as b,
@@ -705,9 +717,9 @@ export {
705
717
  getDefinedBlocks as i,
706
718
  withWrapper as j,
707
719
  createSelectedBlock as k,
708
- createPage as l,
709
- ContextProvideEvent as m,
710
- injectContext as n,
720
+ ContextProvideEvent as l,
721
+ injectContext as m,
722
+ n,
711
723
  ContextRoot as o,
712
724
  provideContext as p,
713
725
  registerBlock as r,
package/dist/core.js CHANGED
@@ -4,8 +4,9 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import { c as createContext, d, w, E, u } from "./page-eBHITwro.js";
8
- import { B, m, C, P, S, a, b, e, f, l, k, g, h, i, n, p, r, s, j } from "./page-eBHITwro.js";
7
+ import { c as createContext, d, w, E, u } from "./block-CUUJl9_y.js";
8
+ import { B, l, C, S, a, b, e, f, k, g, h, i, m, p, r, s, n, j } from "./block-CUUJl9_y.js";
9
+ import { P, c } from "./page-DuW859eK.js";
9
10
  function createState() {
10
11
  const discountCode = d(null);
11
12
  const products = d([]);
@@ -87,7 +88,7 @@ const PARAMS = {
87
88
  function uuid() {
88
89
  return ("10000000-1000-4000-8000" + -1e11).replace(
89
90
  /[018]/g,
90
- (c) => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
91
+ (c2) => (c2 ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c2 / 4).toString(16)
91
92
  );
92
93
  }
93
94
  var define_import_meta_env_default = {};
@@ -834,7 +835,7 @@ export {
834
835
  AuthenticationError,
835
836
  AuthenticationErrorReason,
836
837
  B as BlockWrapperEvent,
837
- m as ContextProvideEvent,
838
+ l as ContextProvideEvent,
838
839
  C as ContextRequestEvent,
839
840
  LoginServiceContext,
840
841
  P as PageContext,
@@ -851,7 +852,7 @@ export {
851
852
  createContext,
852
853
  createMockProductAdapter,
853
854
  createMockSubscriptionAdapter,
854
- l as createPage,
855
+ c as createPage,
855
856
  createProductService,
856
857
  k as createSelectedBlock,
857
858
  createState,
@@ -860,11 +861,12 @@ export {
860
861
  h as defineBlockRuntime,
861
862
  E as effect,
862
863
  i as getDefinedBlocks,
863
- n as injectContext,
864
+ m as injectContext,
864
865
  loginService,
865
866
  p as provideContext,
866
867
  r as registerBlock,
867
868
  d as signal,
868
869
  s as subscribeContext,
870
+ n as untracked,
869
871
  j as withWrapper
870
872
  };
@@ -0,0 +1,6 @@
1
+ import { EditorMessage, IframeMessage } from './messages';
2
+ export interface EditorBridge {
3
+ sendMessage: (message: IframeMessage) => void;
4
+ onMessage: (handler: (message: EditorMessage) => void) => void;
5
+ }
6
+ export declare function createEditorBridge(): EditorBridge;
@@ -0,0 +1,23 @@
1
+ import { BlockInstance } from '../block';
2
+ export declare class BlockWrapper extends HTMLElement {
3
+ private block;
4
+ private editorBridge;
5
+ private nameElement;
6
+ static get observedAttributes(): string[];
7
+ constructor();
8
+ private setupStyles;
9
+ private setupTemplate;
10
+ connectedCallback(): void;
11
+ setBlock(block: BlockInstance): void;
12
+ private updateActiveState;
13
+ /**
14
+ * Traverses up the DOM tree to find the parent element, crossing shadow root boundaries
15
+ */
16
+ private getParentElement;
17
+ private handleRemoveBlock;
18
+ }
19
+ declare global {
20
+ interface HTMLElementTagNameMap {
21
+ "juo-editor-block-wrapper": BlockWrapper;
22
+ }
23
+ }
@@ -0,0 +1,10 @@
1
+ import { EditorMessage } from './messages';
2
+ import { PageContext } from '../page';
3
+ import { ContextType } from '../context';
4
+ export interface EditorHandlerOptions {
5
+ page: ContextType<typeof PageContext>;
6
+ onBlockSelection?: (blockId: string | null) => void;
7
+ }
8
+ export declare function createEditorHandler(options: EditorHandlerOptions): {
9
+ handleMessage: (message: EditorMessage) => void;
10
+ };
@@ -0,0 +1,13 @@
1
+ import { ContextType, PageContext, BlockDefinition } from '../main.ts';
2
+ export * from './messages';
3
+ export * from './bridge';
4
+ export * from './handler';
5
+ export * from './components';
6
+ /**
7
+ * Sets up editor mode integration for the theme.
8
+ * Should be called when a page context is available and editor mode is detected.
9
+ */
10
+ export declare function setupEditorMode(page: ContextType<typeof PageContext>, blocks: Record<string, BlockDefinition>, routes: Record<string, {
11
+ name: string;
12
+ pageComponent: string;
13
+ }>): Promise<void>;
@@ -0,0 +1,102 @@
1
+ import { Block } from '../block';
2
+ export type MessageType = "SYNC_PAGE_STATE" | "SELECT_BLOCK" | "UPDATE_BLOCK_PROPS" | "ADD_BLOCK" | "REMOVE_BLOCK" | "MOVE_BLOCK" | "IFRAME_READY" | "REGISTER_BLOCKS" | "REGISTER_ROUTES";
3
+ export interface BaseMessage {
4
+ type: MessageType;
5
+ timestamp: number;
6
+ }
7
+ export interface SyncPageStateMessage extends BaseMessage {
8
+ type: "SYNC_PAGE_STATE";
9
+ payload: {
10
+ blocks: Block[];
11
+ };
12
+ }
13
+ export interface SelectBlockMessage extends BaseMessage {
14
+ type: "SELECT_BLOCK";
15
+ payload: {
16
+ blockId: string | null;
17
+ };
18
+ blockId?: string;
19
+ }
20
+ export interface UpdateBlockPropsMessage extends BaseMessage {
21
+ type: "UPDATE_BLOCK_PROPS";
22
+ payload: {
23
+ blockId: string;
24
+ props: unknown;
25
+ };
26
+ blockId: string;
27
+ }
28
+ export interface AddBlockMessage extends BaseMessage {
29
+ type: "ADD_BLOCK";
30
+ payload: {
31
+ block: Block;
32
+ location: {
33
+ type: "before" | "after";
34
+ targetId: string;
35
+ } | {
36
+ type: "append";
37
+ slot: string;
38
+ parentId: string;
39
+ };
40
+ };
41
+ blockId: string;
42
+ }
43
+ export interface RemoveBlockMessage extends BaseMessage {
44
+ type: "REMOVE_BLOCK";
45
+ payload: {
46
+ blockId: string;
47
+ location: {
48
+ slot: string;
49
+ parentId: string;
50
+ };
51
+ };
52
+ blockId: string;
53
+ }
54
+ export interface MoveBlockMessage extends BaseMessage {
55
+ type: "MOVE_BLOCK";
56
+ payload: {
57
+ blockId: string;
58
+ location: {
59
+ index: number;
60
+ slot: string;
61
+ parentId: string;
62
+ };
63
+ };
64
+ blockId: string;
65
+ }
66
+ export interface IframeReadyMessage extends BaseMessage {
67
+ type: "IFRAME_READY";
68
+ payload: {};
69
+ }
70
+ export interface RegisterBlocksMessage extends BaseMessage {
71
+ type: "REGISTER_BLOCKS";
72
+ payload: {
73
+ blocks: Array<{
74
+ name: string;
75
+ group: string;
76
+ schema: unknown;
77
+ initialValue: unknown;
78
+ }>;
79
+ };
80
+ }
81
+ export interface RegisterRoutesMessage extends BaseMessage {
82
+ type: "REGISTER_ROUTES";
83
+ payload: {
84
+ routes: Record<string, {
85
+ name: string;
86
+ pageComponent: string;
87
+ }>;
88
+ };
89
+ }
90
+ export type EditorMessage = SyncPageStateMessage | SelectBlockMessage | UpdateBlockPropsMessage | AddBlockMessage | RemoveBlockMessage | MoveBlockMessage;
91
+ export type IframeMessage = SelectBlockMessage | IframeReadyMessage | RegisterBlocksMessage | RegisterRoutesMessage | RemoveBlockMessage | UpdateBlockPropsMessage;
92
+ export type AnyMessage = EditorMessage | IframeMessage;
93
+ export declare function isEditorMessage(message: AnyMessage): message is EditorMessage;
94
+ export declare function isIframeMessage(message: AnyMessage): message is IframeMessage;
95
+ export declare function createSyncPageStateMessage(payload: SyncPageStateMessage["payload"]): SyncPageStateMessage;
96
+ export declare function createSelectBlockMessage(payload: SelectBlockMessage["payload"], blockId?: string): SelectBlockMessage;
97
+ export declare function createUpdateBlockPropsMessage(payload: UpdateBlockPropsMessage["payload"], blockId: string): UpdateBlockPropsMessage;
98
+ export declare function createAddBlockMessage(payload: AddBlockMessage["payload"], blockId: string): AddBlockMessage;
99
+ export declare function createRemoveBlockMessage(payload: RemoveBlockMessage["payload"], blockId: string): RemoveBlockMessage;
100
+ export declare function createMoveBlockMessage(payload: MoveBlockMessage["payload"], blockId: string): MoveBlockMessage;
101
+ export declare function createRegisterBlocksMessage(payload: RegisterBlocksMessage["payload"]): RegisterBlocksMessage;
102
+ export declare function createRegisterRoutesMessage(payload: RegisterRoutesMessage["payload"]): RegisterRoutesMessage;
package/dist/editor.js ADDED
@@ -0,0 +1,646 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import { e as createBlockInstanceFromObject } from "./block-CUUJl9_y.js";
8
+ function isEditorMessage(message) {
9
+ return message.type === "SYNC_PAGE_STATE" || message.type === "SELECT_BLOCK" || message.type === "UPDATE_BLOCK_PROPS" || message.type === "ADD_BLOCK" || message.type === "REMOVE_BLOCK" || message.type === "MOVE_BLOCK";
10
+ }
11
+ function isIframeMessage(message) {
12
+ return message.type === "SELECT_BLOCK" || message.type === "IFRAME_READY" || message.type === "REGISTER_BLOCKS" || message.type === "REGISTER_ROUTES" || message.type === "REMOVE_BLOCK" || message.type === "UPDATE_BLOCK_PROPS";
13
+ }
14
+ function createSyncPageStateMessage(payload) {
15
+ return {
16
+ type: "SYNC_PAGE_STATE",
17
+ payload,
18
+ timestamp: Date.now()
19
+ };
20
+ }
21
+ function createSelectBlockMessage(payload, blockId) {
22
+ return {
23
+ type: "SELECT_BLOCK",
24
+ payload,
25
+ blockId,
26
+ timestamp: Date.now()
27
+ };
28
+ }
29
+ function createUpdateBlockPropsMessage(payload, blockId) {
30
+ return {
31
+ type: "UPDATE_BLOCK_PROPS",
32
+ payload,
33
+ blockId,
34
+ timestamp: Date.now()
35
+ };
36
+ }
37
+ function createAddBlockMessage(payload, blockId) {
38
+ return {
39
+ type: "ADD_BLOCK",
40
+ payload,
41
+ blockId,
42
+ timestamp: Date.now()
43
+ };
44
+ }
45
+ function createRemoveBlockMessage(payload, blockId) {
46
+ return {
47
+ type: "REMOVE_BLOCK",
48
+ payload,
49
+ blockId,
50
+ timestamp: Date.now()
51
+ };
52
+ }
53
+ function createMoveBlockMessage(payload, blockId) {
54
+ return {
55
+ type: "MOVE_BLOCK",
56
+ payload,
57
+ blockId,
58
+ timestamp: Date.now()
59
+ };
60
+ }
61
+ function createRegisterBlocksMessage(payload) {
62
+ const serializedBlocks = payload.blocks.map((block) => ({
63
+ name: block.name,
64
+ group: block.group,
65
+ schema: block.schema == null ? block.schema : JSON.parse(JSON.stringify(block.schema)),
66
+ initialValue: block.initialValue == null ? block.initialValue : JSON.parse(JSON.stringify(block.initialValue))
67
+ }));
68
+ return {
69
+ type: "REGISTER_BLOCKS",
70
+ payload: {
71
+ blocks: serializedBlocks
72
+ },
73
+ timestamp: Date.now()
74
+ };
75
+ }
76
+ function createRegisterRoutesMessage(payload) {
77
+ return {
78
+ type: "REGISTER_ROUTES",
79
+ payload,
80
+ timestamp: Date.now()
81
+ };
82
+ }
83
+ let bridgeInstance = null;
84
+ function createEditorBridge() {
85
+ if (bridgeInstance !== null) {
86
+ return bridgeInstance;
87
+ }
88
+ const messageHandlers = [];
89
+ const selectedBlockId = { value: null };
90
+ let parentOrigin = "*";
91
+ const frame = window.parent || window;
92
+ if (window.parent !== window) {
93
+ try {
94
+ parentOrigin = window.parent.location.origin;
95
+ } catch {
96
+ parentOrigin = "*";
97
+ }
98
+ }
99
+ function sendMessage(message) {
100
+ frame.postMessage(message, parentOrigin);
101
+ }
102
+ function onMessage(handler) {
103
+ messageHandlers.push(handler);
104
+ }
105
+ function updateBlockSelection(blockId) {
106
+ selectedBlockId.value = blockId;
107
+ }
108
+ function handleGlobalClick(event) {
109
+ const path = event.composedPath();
110
+ if (!path.some(
111
+ (node) => node instanceof HTMLElement && node.tagName !== "HTML"
112
+ )) {
113
+ return;
114
+ }
115
+ const isOverlay = path.some((node) => {
116
+ if (!(node instanceof HTMLElement))
117
+ return false;
118
+ let current = node;
119
+ while (current) {
120
+ const computedStyle = window.getComputedStyle(current);
121
+ const zIndex = parseInt(computedStyle.zIndex, 10);
122
+ if (!isNaN(zIndex) && zIndex >= 50 || ["listbox", "menu", "dialog"].includes(
123
+ current.getAttribute("role") || ""
124
+ )) {
125
+ return true;
126
+ }
127
+ current = current.parentElement;
128
+ }
129
+ return false;
130
+ });
131
+ const isEditorUI = path.some((node) => {
132
+ if (!(node instanceof HTMLElement))
133
+ return false;
134
+ let current = node;
135
+ const root = node.getRootNode();
136
+ while (current && current !== root) {
137
+ const classList = current.classList;
138
+ if (classList.contains("block-wrapper__name") || classList.contains("block-wrapper__actions") || classList.contains("block-wrapper__icon") || classList.contains("block-wrapper__remove-icon") || current.hasAttribute("data-block-editor")) {
139
+ return true;
140
+ }
141
+ current = current.parentElement;
142
+ }
143
+ return false;
144
+ });
145
+ if (isOverlay) {
146
+ return;
147
+ }
148
+ let blockWrapper = null;
149
+ for (const node of path) {
150
+ if (node instanceof HTMLElement && node.tagName === "JUO-EDITOR-BLOCK-WRAPPER") {
151
+ blockWrapper = node;
152
+ break;
153
+ }
154
+ }
155
+ if (!blockWrapper && isEditorUI) {
156
+ return;
157
+ }
158
+ const clickedBlockId = (blockWrapper == null ? void 0 : blockWrapper.getAttribute("data-block-id")) || null;
159
+ if (clickedBlockId && clickedBlockId === selectedBlockId.value) {
160
+ return;
161
+ }
162
+ const newBlockId = clickedBlockId || null;
163
+ if (newBlockId !== selectedBlockId.value) {
164
+ const message = createSelectBlockMessage(
165
+ { blockId: newBlockId },
166
+ newBlockId || void 0
167
+ );
168
+ updateBlockSelection(newBlockId);
169
+ messageHandlers.forEach((handler) => handler(message));
170
+ sendMessage(message);
171
+ }
172
+ }
173
+ document.addEventListener("click", handleGlobalClick, true);
174
+ window.addEventListener("message", (event) => {
175
+ if (parentOrigin !== "*" && event.origin !== parentOrigin) {
176
+ return;
177
+ }
178
+ const { data } = event;
179
+ if (isEditorMessage(data)) {
180
+ if (data.type === "SELECT_BLOCK") {
181
+ updateBlockSelection(data.payload.blockId);
182
+ }
183
+ messageHandlers.forEach((handler) => handler(data));
184
+ }
185
+ });
186
+ if (document.readyState === "complete") {
187
+ sendMessage({
188
+ type: "IFRAME_READY",
189
+ payload: {},
190
+ timestamp: Date.now()
191
+ });
192
+ } else {
193
+ window.addEventListener("load", () => {
194
+ sendMessage({
195
+ type: "IFRAME_READY",
196
+ payload: {},
197
+ timestamp: Date.now()
198
+ });
199
+ });
200
+ }
201
+ bridgeInstance = {
202
+ sendMessage,
203
+ onMessage
204
+ };
205
+ return bridgeInstance;
206
+ }
207
+ function createEditorHandler(options) {
208
+ const { page, onBlockSelection } = options;
209
+ function handleMessage(message) {
210
+ var _a;
211
+ if (message.type === "SYNC_PAGE_STATE") {
212
+ const blocks = message.payload.blocks.map(
213
+ (block) => createBlockInstanceFromObject(block)
214
+ ) || [];
215
+ page.blocks.value = blocks;
216
+ } else if (message.type === "SELECT_BLOCK") {
217
+ const blockId = message.payload.blockId;
218
+ if (onBlockSelection) {
219
+ onBlockSelection(blockId);
220
+ }
221
+ } else if (message.type === "UPDATE_BLOCK_PROPS") {
222
+ let findAndUpdateBlock = function(blocks, blockId, props) {
223
+ for (const block of blocks) {
224
+ if (block.id === blockId) {
225
+ block.props = { ...block.props, ...props };
226
+ return true;
227
+ }
228
+ for (const slotBlocks of Object.values(block.slots || {})) {
229
+ const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
230
+ for (const child of slotArray) {
231
+ if (typeof child !== "string" && (child == null ? void 0 : child.id)) {
232
+ if (findAndUpdateBlock([child], blockId, props)) {
233
+ return true;
234
+ }
235
+ }
236
+ }
237
+ }
238
+ }
239
+ return false;
240
+ };
241
+ findAndUpdateBlock(
242
+ page.blocks.value,
243
+ message.payload.blockId,
244
+ message.payload.props
245
+ );
246
+ page.blocks.value = [...page.blocks.value];
247
+ } else if (message.type === "ADD_BLOCK") {
248
+ const { block: blockData, location } = message.payload;
249
+ const newBlock = createBlockInstanceFromObject(blockData);
250
+ if (location.type === "before" || location.type === "after") {
251
+ let findAndInsertBlock = function(blocks, targetId, newBlock2, position) {
252
+ var _a2;
253
+ for (let i = 0; i < blocks.length; i++) {
254
+ if (blocks[i].id === targetId) {
255
+ if (position === "before") {
256
+ blocks.splice(i, 0, newBlock2);
257
+ } else {
258
+ blocks.splice(i + 1, 0, newBlock2);
259
+ }
260
+ return true;
261
+ }
262
+ for (const slotKey of Object.keys(blocks[i].slots || {})) {
263
+ const slotBlocks = blocks[i].slots[slotKey];
264
+ const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
265
+ for (let j = 0; j < slotArray.length; j++) {
266
+ if (typeof slotArray[j] !== "string" && ((_a2 = slotArray[j]) == null ? void 0 : _a2.id) === targetId) {
267
+ if (position === "before") {
268
+ slotArray.splice(j, 0, newBlock2);
269
+ } else {
270
+ slotArray.splice(j + 1, 0, newBlock2);
271
+ }
272
+ blocks[i].slots[slotKey] = slotArray;
273
+ return true;
274
+ }
275
+ }
276
+ }
277
+ }
278
+ return false;
279
+ };
280
+ findAndInsertBlock(
281
+ page.blocks.value,
282
+ location.targetId,
283
+ newBlock,
284
+ location.type
285
+ );
286
+ } else if (location.type === "append") {
287
+ let findAndAppendBlock = function(blocks, parentId, slot, newBlock2) {
288
+ for (const block of blocks) {
289
+ if (block.id === parentId) {
290
+ if (!block.slots[slot]) {
291
+ block.slots[slot] = [];
292
+ }
293
+ if (Array.isArray(block.slots[slot])) {
294
+ block.slots[slot].push(newBlock2);
295
+ } else {
296
+ block.slots[slot] = [block.slots[slot], newBlock2];
297
+ }
298
+ return true;
299
+ }
300
+ for (const slotKey of Object.keys(block.slots || {})) {
301
+ const slotBlocks = block.slots[slotKey];
302
+ const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
303
+ for (const child of slotArray) {
304
+ if (typeof child !== "string" && (child == null ? void 0 : child.id)) {
305
+ if (findAndAppendBlock([child], parentId, slot, newBlock2)) {
306
+ return true;
307
+ }
308
+ }
309
+ }
310
+ }
311
+ }
312
+ return false;
313
+ };
314
+ findAndAppendBlock(
315
+ page.blocks.value,
316
+ location.parentId,
317
+ location.slot,
318
+ newBlock
319
+ );
320
+ }
321
+ page.blocks.value = [...page.blocks.value];
322
+ } else if (message.type === "REMOVE_BLOCK") {
323
+ let findAndRemoveBlock = function(blocks, blockId, slot, parentId) {
324
+ var _a2;
325
+ for (let i = 0; i < blocks.length; i++) {
326
+ if (blocks[i].id === parentId && ((_a2 = blocks[i].slots) == null ? void 0 : _a2[slot])) {
327
+ const slotBlocks = blocks[i].slots[slot];
328
+ const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
329
+ const index = slotArray.findIndex(
330
+ (b) => typeof b !== "string" && (b == null ? void 0 : b.id) === blockId
331
+ );
332
+ if (index !== -1) {
333
+ slotArray.splice(index, 1);
334
+ blocks[i].slots[slot] = slotArray;
335
+ return true;
336
+ }
337
+ }
338
+ for (const slotKey of Object.keys(blocks[i].slots || {})) {
339
+ const slotBlocks = blocks[i].slots[slotKey];
340
+ const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
341
+ for (const child of slotArray) {
342
+ if (typeof child !== "string" && (child == null ? void 0 : child.id)) {
343
+ if (findAndRemoveBlock([child], blockId, slot, parentId)) {
344
+ return true;
345
+ }
346
+ }
347
+ }
348
+ }
349
+ }
350
+ return false;
351
+ };
352
+ let resolvedParentId = message.payload.location.parentId;
353
+ if (resolvedParentId === "root") {
354
+ resolvedParentId = ((_a = page.blocks.value[0]) == null ? void 0 : _a.id) ?? "root";
355
+ }
356
+ findAndRemoveBlock(
357
+ page.blocks.value,
358
+ message.payload.blockId,
359
+ message.payload.location.slot,
360
+ resolvedParentId
361
+ );
362
+ page.blocks.value = [...page.blocks.value];
363
+ } else if (message.type === "MOVE_BLOCK") {
364
+ let findAndMoveBlock = function(blocks, blockId, slot, parentId, newIndex) {
365
+ var _a2;
366
+ for (const block of blocks) {
367
+ if (block.id === parentId && ((_a2 = block.slots) == null ? void 0 : _a2[slot])) {
368
+ const slotBlocks = block.slots[slot];
369
+ const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
370
+ const oldIndex = slotArray.findIndex(
371
+ (b) => typeof b !== "string" && (b == null ? void 0 : b.id) === blockId
372
+ );
373
+ if (oldIndex !== -1) {
374
+ const [moved] = slotArray.splice(oldIndex, 1);
375
+ slotArray.splice(newIndex, 0, moved);
376
+ block.slots[slot] = slotArray;
377
+ return true;
378
+ }
379
+ }
380
+ for (const slotKey of Object.keys(block.slots || {})) {
381
+ const slotBlocks = block.slots[slotKey];
382
+ const slotArray = Array.isArray(slotBlocks) ? slotBlocks : [slotBlocks];
383
+ for (const child of slotArray) {
384
+ if (typeof child !== "string" && (child == null ? void 0 : child.id)) {
385
+ if (findAndMoveBlock([child], blockId, slot, parentId, newIndex)) {
386
+ return true;
387
+ }
388
+ }
389
+ }
390
+ }
391
+ }
392
+ return false;
393
+ };
394
+ findAndMoveBlock(
395
+ page.blocks.value,
396
+ message.payload.blockId,
397
+ message.payload.location.slot,
398
+ message.payload.location.parentId,
399
+ message.payload.location.index
400
+ );
401
+ page.blocks.value = [...page.blocks.value];
402
+ }
403
+ }
404
+ return {
405
+ handleMessage
406
+ };
407
+ }
408
+ const styles = `
409
+ <style>
410
+ .block-wrapper {
411
+ margin: 1rem 0;
412
+ position: relative;
413
+ padding: 12px;
414
+ background-color: white;
415
+ border: 1px solid #B5B5B5;
416
+ border-radius: 8px;
417
+ }
418
+
419
+ .block-wrapper:hover,
420
+ .block-wrapper.active {
421
+ border-color: #2400FF;
422
+ }
423
+
424
+ .block-wrapper__name {
425
+ display: flex;
426
+ justify-content: space-between;
427
+ align-items: center;
428
+ gap: 6.82px;
429
+ margin-bottom: 12px;
430
+ font-size: 10px;
431
+ font-weight: 500;
432
+ color: #8A8A8A;
433
+ }
434
+
435
+ .block-wrapper__actions {
436
+ display: flex;
437
+ align-items: center;
438
+ justify-content: flex-end;
439
+ flex-grow: 1;
440
+ }
441
+
442
+ .block-wrapper__actions button {
443
+ display: flex;
444
+ align-items: center;
445
+ justify-content: center;
446
+ appearance: none;
447
+ border: none;
448
+ text-inherit: inherit;
449
+ padding: 0;
450
+ background: none;
451
+ cursor: pointer;
452
+ }
453
+
454
+ .block-wrapper__icon {
455
+ width: 17px;
456
+ height: 15px;
457
+ }
458
+
459
+ .block-wrapper__remove-icon {
460
+ width: 10px;
461
+ height: 3px;
462
+ }
463
+ </style>
464
+ `;
465
+ const blockIconSvg = `
466
+ <svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg">
467
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M1.41064 10.7254H2.5477V11.8625C2.5477 12.4905 3.05678 12.9996 3.68476 12.9996H4.82181V14.1366H3.68476C2.4288 14.1366 1.41064 13.1185 1.41064 11.8625V10.7254ZM1.41064 3.90311H2.5477V2.76606C2.5477 2.13808 3.05678 1.629 3.68476 1.629H4.82181V0.491943H3.68476C2.4288 0.491943 1.41064 1.5101 1.41064 2.76606V3.90311ZM11.6441 0.491943V1.629H12.7812C13.4092 1.629 13.9183 2.13808 13.9183 2.76606V3.90311H15.0553V2.76606C15.0553 1.5101 14.0372 0.491943 12.7812 0.491943H11.6441ZM15.0553 10.7254H13.9183V11.8625C13.9183 12.4905 13.4092 12.9996 12.7812 12.9996H11.6441V14.1366H12.7812C14.0372 14.1366 15.0553 13.1185 15.0553 11.8625V10.7254Z" fill="#8A8A8A"/>
468
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M15.0554 6.17734H1.41074V8.45145H15.0554V6.17734ZM1.41074 5.04028C0.782759 5.04028 0.273682 5.54936 0.273682 6.17734V8.45145C0.273682 9.07943 0.782759 9.58851 1.41074 9.58851H15.0554C15.6834 9.58851 16.1925 9.07943 16.1925 8.45145V6.17734C16.1925 5.54936 15.6834 5.04028 15.0554 5.04028H1.41074Z" fill="#8A8A8A"/>
469
+ <rect x="6.52747" y="0.491943" width="3.41117" height="1.13706" fill="#8A8A8A"/>
470
+ <rect x="6.52747" y="12.9998" width="3.41117" height="1.13706" fill="#8A8A8A"/>
471
+ </svg>
472
+ `;
473
+ const removeIconSvg = `
474
+ <svg width="10" height="3" viewBox="0 0 10 3" fill="none" xmlns="http://www.w3.org/2000/svg">
475
+ <path d="M1.4001 2.11865C0.925912 2.11865 0.541504 1.74162 0.541504 1.27652C0.541504 0.811427 0.925912 0.434393 1.4001 0.434393C1.87429 0.434393 2.2587 0.811427 2.2587 1.27652C2.2587 1.74162 1.87429 2.11865 1.4001 2.11865Z" fill="black"/>
476
+ <path d="M4.8345 2.11865C4.36031 2.11865 3.9759 1.74162 3.9759 1.27652C3.9759 0.811427 4.36031 0.434393 4.8345 0.434393C5.30869 0.434393 5.69309 0.811427 5.69309 1.27652C5.69309 1.74162 5.30869 2.11865 4.8345 2.11865Z" fill="black"/>
477
+ <path d="M8.26915 2.11865C7.79496 2.11865 7.41055 1.74162 7.41055 1.27652C7.41055 0.811427 7.79496 0.434393 8.26915 0.434393C8.74334 0.434393 9.12774 0.811427 9.12774 1.27652C9.12774 1.74162 8.74334 2.11865 8.26915 2.11865Z" fill="black"/>
478
+ </svg>
479
+ `;
480
+ class BlockWrapper extends HTMLElement {
481
+ constructor() {
482
+ super();
483
+ __publicField(this, "block", null);
484
+ __publicField(this, "editorBridge", createEditorBridge());
485
+ __publicField(this, "nameElement", null);
486
+ this.attachShadow({ mode: "open" });
487
+ this.setupStyles();
488
+ this.setupTemplate();
489
+ }
490
+ static get observedAttributes() {
491
+ return ["data-block-id"];
492
+ }
493
+ setupStyles() {
494
+ const styleElement = document.createElement("style");
495
+ styleElement.textContent = styles.replace(/<style>|<\/style>/g, "").trim();
496
+ this.shadowRoot.appendChild(styleElement);
497
+ }
498
+ setupTemplate() {
499
+ const wrapper = document.createElement("div");
500
+ wrapper.className = "block-wrapper";
501
+ const nameDiv = document.createElement("div");
502
+ nameDiv.className = "block-wrapper__name";
503
+ const iconContainer = document.createElement("div");
504
+ iconContainer.className = "block-wrapper__icon";
505
+ iconContainer.innerHTML = blockIconSvg;
506
+ const nameSpan = document.createElement("span");
507
+ nameSpan.textContent = "";
508
+ const actionsDiv = document.createElement("div");
509
+ actionsDiv.className = "block-wrapper__actions";
510
+ const removeBtn = document.createElement("button");
511
+ removeBtn.type = "button";
512
+ removeBtn.innerHTML = removeIconSvg;
513
+ removeBtn.addEventListener("click", (e) => {
514
+ e.stopPropagation();
515
+ this.handleRemoveBlock();
516
+ });
517
+ actionsDiv.appendChild(removeBtn);
518
+ nameDiv.appendChild(iconContainer);
519
+ nameDiv.appendChild(nameSpan);
520
+ nameDiv.appendChild(actionsDiv);
521
+ wrapper.appendChild(nameDiv);
522
+ const slot = document.createElement("slot");
523
+ wrapper.appendChild(slot);
524
+ this.shadowRoot.appendChild(wrapper);
525
+ this.nameElement = nameSpan;
526
+ this.editorBridge.onMessage((message) => {
527
+ var _a;
528
+ if (message.type === "SELECT_BLOCK") {
529
+ this.updateActiveState(message.payload.blockId === ((_a = this.block) == null ? void 0 : _a.id));
530
+ }
531
+ });
532
+ }
533
+ connectedCallback() {
534
+ this.getAttribute("data-block-id");
535
+ this.setAttribute("draggable", "true");
536
+ }
537
+ setBlock(block) {
538
+ this.block = block;
539
+ this.setAttribute("data-block-id", block.id);
540
+ if (this.nameElement) {
541
+ this.nameElement.textContent = block.definition.name;
542
+ }
543
+ }
544
+ updateActiveState(isActive) {
545
+ const wrapper = this.shadowRoot.querySelector(
546
+ ".block-wrapper"
547
+ );
548
+ if (!wrapper)
549
+ return;
550
+ if (isActive) {
551
+ wrapper.classList.add("active");
552
+ } else {
553
+ wrapper.classList.remove("active");
554
+ }
555
+ }
556
+ /**
557
+ * Traverses up the DOM tree to find the parent element, crossing shadow root boundaries
558
+ */
559
+ getParentElement(element) {
560
+ const root = element.getRootNode();
561
+ if (root instanceof ShadowRoot) {
562
+ return root.host;
563
+ }
564
+ return element.parentElement;
565
+ }
566
+ handleRemoveBlock() {
567
+ if (!this.block)
568
+ return;
569
+ const extensionRoot = this.closest("juo-extension-root");
570
+ const slotName = (extensionRoot == null ? void 0 : extensionRoot.getAttribute("name")) || "default";
571
+ let parentId = "root";
572
+ let current = this;
573
+ while (current) {
574
+ const parent = this.getParentElement(current);
575
+ if (!parent) {
576
+ break;
577
+ }
578
+ if (parent !== this && parent.tagName === "JUO-EDITOR-BLOCK-WRAPPER") {
579
+ const parentBlockId = parent.getAttribute("data-block-id");
580
+ if (parentBlockId) {
581
+ parentId = parentBlockId;
582
+ break;
583
+ }
584
+ }
585
+ current = parent;
586
+ }
587
+ const location = {
588
+ slot: slotName,
589
+ parentId
590
+ };
591
+ const message = createRemoveBlockMessage(
592
+ {
593
+ blockId: this.block.id,
594
+ location
595
+ },
596
+ this.block.id
597
+ );
598
+ this.editorBridge.sendMessage(message);
599
+ }
600
+ }
601
+ if (customElements.get("juo-editor-block-wrapper") == null) {
602
+ customElements.define("juo-editor-block-wrapper", BlockWrapper);
603
+ }
604
+ async function setupEditorMode(page, blocks, routes) {
605
+ const editor = createEditorBridge();
606
+ const handler = createEditorHandler({
607
+ page
608
+ });
609
+ editor.onMessage((message) => {
610
+ handler.handleMessage(message);
611
+ });
612
+ const blocksArray = Object.values(blocks).map((block) => {
613
+ let initialValue = block.initialValue;
614
+ if (typeof initialValue === "function") {
615
+ try {
616
+ initialValue = initialValue();
617
+ } catch {
618
+ initialValue = void 0;
619
+ }
620
+ }
621
+ return {
622
+ name: block.name,
623
+ group: block.group,
624
+ schema: block.schema,
625
+ initialValue
626
+ };
627
+ });
628
+ editor.sendMessage(createRegisterBlocksMessage({ blocks: blocksArray }));
629
+ editor.sendMessage(createRegisterRoutesMessage({ routes }));
630
+ }
631
+ export {
632
+ BlockWrapper,
633
+ createAddBlockMessage,
634
+ createEditorBridge,
635
+ createEditorHandler,
636
+ createMoveBlockMessage,
637
+ createRegisterBlocksMessage,
638
+ createRegisterRoutesMessage,
639
+ createRemoveBlockMessage,
640
+ createSelectBlockMessage,
641
+ createSyncPageStateMessage,
642
+ createUpdateBlockPropsMessage,
643
+ isEditorMessage,
644
+ isIframeMessage,
645
+ setupEditorMode
646
+ };
package/dist/main.d.ts CHANGED
@@ -5,4 +5,4 @@ export { ContextRequestEvent, ContextProvideEvent, type ContextCallback, createC
5
5
  export { StateContext, createState } from './state';
6
6
  export * from './utils';
7
7
  export * from './services';
8
- export { Signal, signal, effect, computed } from '@preact/signals-core';
8
+ export { Signal, signal, effect, computed, untracked } from '@preact/signals-core';
@@ -0,0 +1,12 @@
1
+ import { c as createContext, d } from "./block-CUUJl9_y.js";
2
+ function createPage() {
3
+ const blocks = d([]);
4
+ return {
5
+ blocks
6
+ };
7
+ }
8
+ const PageContext = createContext("page");
9
+ export {
10
+ PageContext as P,
11
+ createPage as c
12
+ };
package/dist/state.d.ts CHANGED
@@ -47,6 +47,7 @@ export declare function createState(): {
47
47
  addItemToUpcomingOrder(item: Omit<Item, "price">): void;
48
48
  addSubscription(subscription: Subscription): void;
49
49
  };
50
+ /** @deprecated Use sepcialized services instead */
50
51
  export declare const StateContext: {
51
52
  __context__: {
52
53
  discountCode: import('@preact/signals-core').Signal<string | null>;
@@ -4,6 +4,8 @@ export default class ExtensionRoot extends HTMLElement {
4
4
  private disposeEffect?;
5
5
  static get observedAttributes(): string[];
6
6
  constructor();
7
+ private wrapperCache;
8
+ private withWrapper;
7
9
  connectedCallback(): void;
8
10
  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
9
11
  disconnectedCallback(): void;
@@ -4,8 +4,9 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
- import { a as createBlockInstance, P as PageContext, j as withWrapper, o as ContextRoot } from "./page-eBHITwro.js";
8
- import { signal, effect, subscribeContext } from "@juo/orion-core";
7
+ import { a as createBlockInstance, j as withWrapper, o as ContextRoot } from "./block-CUUJl9_y.js";
8
+ import { signal, effect, subscribeContext, untracked } from "@juo/orion-core";
9
+ import { P as PageContext } from "./page-DuW859eK.js";
9
10
  class Block extends HTMLElement {
10
11
  constructor() {
11
12
  super();
@@ -57,10 +58,18 @@ class ExtensionRoot extends HTMLElement {
57
58
  __publicField(this, "state", signal(null));
58
59
  __publicField(this, "unsubscribeContext");
59
60
  __publicField(this, "disposeEffect");
61
+ __publicField(this, "wrapperCache", /* @__PURE__ */ new WeakMap());
60
62
  }
61
63
  static get observedAttributes() {
62
64
  return ["name"];
63
65
  }
66
+ withWrapper(block) {
67
+ if (!this.wrapperCache.has(block)) {
68
+ const wrapper = withWrapper((block2) => block2.definition.render(block2));
69
+ this.wrapperCache.set(block, wrapper);
70
+ }
71
+ return this.wrapperCache.get(block)(block);
72
+ }
64
73
  connectedCallback() {
65
74
  this.state.value = null;
66
75
  this.unsubscribeContext = subscribeContext(
@@ -71,7 +80,6 @@ class ExtensionRoot extends HTMLElement {
71
80
  }
72
81
  );
73
82
  this.disposeEffect = effect(() => {
74
- var _a;
75
83
  const state = this.state.value;
76
84
  if (state == null) {
77
85
  this.replaceChildren();
@@ -83,17 +91,20 @@ class ExtensionRoot extends HTMLElement {
83
91
  this.replaceChildren();
84
92
  return;
85
93
  }
86
- try {
87
- const extensionBlocks = (((_a = state == null ? void 0 : state.blocks.value.at(0)) == null ? void 0 : _a.slots) ?? {})[name] ?? [];
88
- const children = extensionBlocks.map(
89
- (block) => withWrapper((block2) => block2.definition.render(block2))(block)
90
- ) ?? [];
91
- console.log("extension-root:host", this);
92
- this.replaceChildren(...children);
93
- } catch (error) {
94
- console.error(error);
95
- this.replaceChildren();
96
- }
94
+ const blocks = state.blocks.value;
95
+ untracked(() => {
96
+ var _a;
97
+ try {
98
+ const extensionBlocks = (((_a = blocks.at(0)) == null ? void 0 : _a.slots) ?? {})[name] ?? [];
99
+ const children = extensionBlocks.map(
100
+ (block) => this.withWrapper(block)
101
+ ) ?? [];
102
+ this.replaceChildren(...children);
103
+ } catch (error) {
104
+ console.error(error);
105
+ this.replaceChildren();
106
+ }
107
+ });
97
108
  });
98
109
  }
99
110
  attributeChangedCallback(name, oldValue, newValue) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@juo/orion-core",
3
3
  "private": false,
4
- "version": "0.9.0",
4
+ "version": "0.10.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -22,24 +22,28 @@
22
22
  },
23
23
  "exports": {
24
24
  ".": {
25
- "node": "./dist/core.js",
26
- "types": "./dist/main.d.ts"
25
+ "types": "./dist/main.d.ts",
26
+ "default": "./dist/core.js"
27
27
  },
28
28
  "./vue": {
29
- "node": "./dist/vue.js",
30
- "types": "./dist/vue/main.d.ts"
29
+ "types": "./dist/vue/main.d.ts",
30
+ "default": "./dist/vue.js"
31
31
  },
32
32
  "./react": {
33
- "node": "./dist/react.js",
34
- "types": "./dist/react/main.d.ts"
33
+ "types": "./dist/react/main.d.ts",
34
+ "default": "./dist/react.js"
35
35
  },
36
36
  "./preact": {
37
- "node": "./dist/preact.js",
38
- "types": "./dist/preact/main.d.ts"
37
+ "types": "./dist/preact/main.d.ts",
38
+ "default": "./dist/preact.js"
39
+ },
40
+ "./editor": {
41
+ "types": "./dist/editor/main.d.ts",
42
+ "default": "./dist/editor.js"
39
43
  },
40
44
  "./web-components": {
41
- "node": "./dist/webComponents.js",
42
- "types": "./dist/web-components/main.d.ts"
45
+ "types": "./dist/web-components/main.d.ts",
46
+ "node": "./dist/web-components.js"
43
47
  }
44
48
  },
45
49
  "dependencies": {