@juo/blocks 1.13.0 → 1.15.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.
Files changed (157) hide show
  1. package/dist/ExtensionRoot-C3lVJEBl.js +385 -0
  2. package/dist/block.d.ts.map +1 -1
  3. package/dist/block.devtools.test.d.ts +2 -0
  4. package/dist/block.devtools.test.d.ts.map +1 -0
  5. package/dist/{bridge-w5KQ-czl.js → bridge-xiKEzCGR.js} +146 -32
  6. package/dist/context.d.ts.map +1 -1
  7. package/dist/context.devtools.test.d.ts +2 -0
  8. package/dist/context.devtools.test.d.ts.map +1 -0
  9. package/dist/core.js +786 -37
  10. package/dist/{juo-workflow-BlG9CcAG.js → css-runtime-ClH0MEYr.js} +511 -618
  11. package/dist/devtools/env.d.ts +3 -0
  12. package/dist/devtools/env.d.ts.map +1 -0
  13. package/dist/devtools/hook.d.ts +40 -0
  14. package/dist/devtools/hook.d.ts.map +1 -0
  15. package/dist/devtools/index.d.ts +5 -0
  16. package/dist/devtools/index.d.ts.map +1 -0
  17. package/dist/devtools/instrumentation.d.ts +47 -0
  18. package/dist/devtools/instrumentation.d.ts.map +1 -0
  19. package/dist/devtools/protocol.d.ts +77 -0
  20. package/dist/devtools/protocol.d.ts.map +1 -0
  21. package/dist/devtools.js +11 -0
  22. package/dist/editor/bridge.d.ts +8 -0
  23. package/dist/editor/bridge.d.ts.map +1 -1
  24. package/dist/editor/canvas-mode-signal.d.ts +22 -0
  25. package/dist/editor/canvas-mode-signal.d.ts.map +1 -0
  26. package/dist/editor/canvas-mode.d.ts +15 -0
  27. package/dist/editor/canvas-mode.d.ts.map +1 -0
  28. package/dist/editor/canvas-mode.test.d.ts +2 -0
  29. package/dist/editor/canvas-mode.test.d.ts.map +1 -0
  30. package/dist/editor/components.d.ts +113 -0
  31. package/dist/editor/components.d.ts.map +1 -1
  32. package/dist/editor/components.test.d.ts.map +1 -1
  33. package/dist/editor/handler.d.ts.map +1 -1
  34. package/dist/editor/handler.test.d.ts +2 -0
  35. package/dist/editor/handler.test.d.ts.map +1 -0
  36. package/dist/editor/layout-command-emitter.d.ts +37 -0
  37. package/dist/editor/layout-command-emitter.d.ts.map +1 -0
  38. package/dist/editor/layout-command-emitter.test.d.ts +2 -0
  39. package/dist/editor/layout-command-emitter.test.d.ts.map +1 -0
  40. package/dist/editor/layout-system-signal.d.ts +21 -0
  41. package/dist/editor/layout-system-signal.d.ts.map +1 -0
  42. package/dist/editor/main.d.ts +1 -0
  43. package/dist/editor/main.d.ts.map +1 -1
  44. package/dist/editor/messages.d.ts +96 -3
  45. package/dist/editor/messages.d.ts.map +1 -1
  46. package/dist/editor/messages.test.d.ts +2 -0
  47. package/dist/editor/messages.test.d.ts.map +1 -0
  48. package/dist/editor/surface-context.d.ts +7 -0
  49. package/dist/editor/surface-context.d.ts.map +1 -0
  50. package/dist/editor/surface-context.test.d.ts +2 -0
  51. package/dist/editor/surface-context.test.d.ts.map +1 -0
  52. package/dist/editor/wrapper-shared.d.ts +31 -0
  53. package/dist/editor/wrapper-shared.d.ts.map +1 -0
  54. package/dist/editor.js +882 -57
  55. package/dist/gridstack-adapter-CDWbSpbt.js +5489 -0
  56. package/dist/index-JSv6UH_o.js +169 -0
  57. package/dist/layout/css-runtime.d.ts +41 -0
  58. package/dist/layout/css-runtime.d.ts.map +1 -0
  59. package/dist/layout/css-runtime.test.d.ts +2 -0
  60. package/dist/layout/css-runtime.test.d.ts.map +1 -0
  61. package/dist/layout/derive.d.ts +4 -0
  62. package/dist/layout/derive.d.ts.map +1 -0
  63. package/dist/layout/derive.test.d.ts +2 -0
  64. package/dist/layout/derive.test.d.ts.map +1 -0
  65. package/dist/layout/dividers.d.ts +34 -0
  66. package/dist/layout/dividers.d.ts.map +1 -0
  67. package/dist/layout/dividers.test.d.ts +2 -0
  68. package/dist/layout/dividers.test.d.ts.map +1 -0
  69. package/dist/layout/engine.d.ts +3 -0
  70. package/dist/layout/engine.d.ts.map +1 -0
  71. package/dist/layout/engine.test.d.ts +2 -0
  72. package/dist/layout/engine.test.d.ts.map +1 -0
  73. package/dist/layout/grid-utils.d.ts +57 -0
  74. package/dist/layout/grid-utils.d.ts.map +1 -0
  75. package/dist/layout/grid-utils.test.d.ts +2 -0
  76. package/dist/layout/grid-utils.test.d.ts.map +1 -0
  77. package/dist/layout/index.d.ts +13 -0
  78. package/dist/layout/index.d.ts.map +1 -0
  79. package/dist/layout/index.test.d.ts +2 -0
  80. package/dist/layout/index.test.d.ts.map +1 -0
  81. package/dist/layout/insert.d.ts +34 -0
  82. package/dist/layout/insert.d.ts.map +1 -0
  83. package/dist/layout/insert.test.d.ts +2 -0
  84. package/dist/layout/insert.test.d.ts.map +1 -0
  85. package/dist/layout/override.d.ts +10 -0
  86. package/dist/layout/override.d.ts.map +1 -0
  87. package/dist/layout/override.test.d.ts +2 -0
  88. package/dist/layout/override.test.d.ts.map +1 -0
  89. package/dist/layout/project-css.d.ts +6 -0
  90. package/dist/layout/project-css.d.ts.map +1 -0
  91. package/dist/layout/project-css.test.d.ts +2 -0
  92. package/dist/layout/project-css.test.d.ts.map +1 -0
  93. package/dist/layout/project-gridstack.d.ts +50 -0
  94. package/dist/layout/project-gridstack.d.ts.map +1 -0
  95. package/dist/layout/project-gridstack.test.d.ts +2 -0
  96. package/dist/layout/project-gridstack.test.d.ts.map +1 -0
  97. package/dist/layout/reconcile.d.ts +23 -0
  98. package/dist/layout/reconcile.d.ts.map +1 -0
  99. package/dist/layout/reconcile.test.d.ts +2 -0
  100. package/dist/layout/reconcile.test.d.ts.map +1 -0
  101. package/dist/layout/types.d.ts +118 -0
  102. package/dist/layout/types.d.ts.map +1 -0
  103. package/dist/layout-mode-adapter-BBd4JRQd.js +21 -0
  104. package/dist/main.d.ts +7 -1
  105. package/dist/main.d.ts.map +1 -1
  106. package/dist/morph-n4LMxOYo.js +182 -0
  107. package/dist/preact/block.d.ts.map +1 -1
  108. package/dist/preact.js +14 -10
  109. package/dist/project-gridstack-CM783oKI.js +52 -0
  110. package/dist/react/block.d.ts.map +1 -1
  111. package/dist/react.js +13 -9
  112. package/dist/registry.devtools.test.d.ts +2 -0
  113. package/dist/registry.devtools.test.d.ts.map +1 -0
  114. package/dist/theme-state.d.ts +16 -0
  115. package/dist/theme-state.d.ts.map +1 -1
  116. package/dist/theme-state.layout.test.d.ts +2 -0
  117. package/dist/theme-state.layout.test.d.ts.map +1 -0
  118. package/dist/theme-state.test.d.ts +2 -0
  119. package/dist/theme-state.test.d.ts.map +1 -0
  120. package/dist/vue/block.d.ts.map +1 -1
  121. package/dist/vue.js +22 -4
  122. package/dist/web-components/ExtensionRoot.d.ts +50 -2
  123. package/dist/web-components/ExtensionRoot.d.ts.map +1 -1
  124. package/dist/web-components/editor/ExtensionRoot.d.ts +11 -0
  125. package/dist/web-components/editor/ExtensionRoot.d.ts.map +1 -0
  126. package/dist/web-components/editor/ExtensionRoot.test.d.ts +2 -0
  127. package/dist/web-components/editor/ExtensionRoot.test.d.ts.map +1 -0
  128. package/dist/web-components/editor/InlineText.d.ts +1 -0
  129. package/dist/web-components/editor/InlineText.d.ts.map +1 -1
  130. package/dist/web-components/editor/editor-layout-controller.d.ts +28 -0
  131. package/dist/web-components/editor/editor-layout-controller.d.ts.map +1 -0
  132. package/dist/web-components/editor/gridstack-adapter.d.ts +3 -0
  133. package/dist/web-components/editor/gridstack-adapter.d.ts.map +1 -0
  134. package/dist/web-components/editor/gridstack-adapter.test.d.ts +2 -0
  135. package/dist/web-components/editor/gridstack-adapter.test.d.ts.map +1 -0
  136. package/dist/web-components/editor/morph.d.ts +32 -0
  137. package/dist/web-components/editor/morph.d.ts.map +1 -0
  138. package/dist/web-components/editor/morph.test.d.ts +2 -0
  139. package/dist/web-components/editor/morph.test.d.ts.map +1 -0
  140. package/dist/web-components/layout/layout-controller.d.ts +55 -0
  141. package/dist/web-components/layout/layout-controller.d.ts.map +1 -0
  142. package/dist/web-components/layout/view-layout-controller.d.ts +17 -0
  143. package/dist/web-components/layout/view-layout-controller.d.ts.map +1 -0
  144. package/dist/web-components/layout/view-layout-controller.test.d.ts +2 -0
  145. package/dist/web-components/layout/view-layout-controller.test.d.ts.map +1 -0
  146. package/dist/web-components/layout-grid.d.ts +47 -0
  147. package/dist/web-components/layout-grid.d.ts.map +1 -0
  148. package/dist/web-components/layout-grid.test.d.ts +2 -0
  149. package/dist/web-components/layout-grid.test.d.ts.map +1 -0
  150. package/dist/web-components/layout-mode-adapter.d.ts +57 -0
  151. package/dist/web-components/layout-mode-adapter.d.ts.map +1 -0
  152. package/dist/web-components/layout-mode-adapter.test.d.ts +2 -0
  153. package/dist/web-components/layout-mode-adapter.test.d.ts.map +1 -0
  154. package/dist/web-components-editor.js +130 -17
  155. package/dist/web-components-runtime.js +4 -3
  156. package/package.json +7 -2
  157. package/dist/ExtensionRoot-2xTGTu3K.js +0 -219
@@ -1,8 +1,8 @@
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 { g as getInstrumentation, _ as __setDefinedBlocksReader } from "./index-JSv6UH_o.js";
4
5
  import { reportBlockError, reportBlockWarning } from "./observability.js";
5
- import { a as createEditorBridge, e as createSelectBlockMessage } from "./bridge-w5KQ-czl.js";
6
6
  const createContext = (key) => key;
7
7
  class ContextRequestEvent extends Event {
8
8
  constructor(context, callback, subscribe) {
@@ -21,13 +21,13 @@ class ContextProvideEvent extends Event {
21
21
  }
22
22
  }
23
23
  function provideContext(target, context, init) {
24
- console.log("context:provide", context, target);
24
+ getInstrumentation().onContextProvided(context);
25
25
  const ev = new ContextProvideEvent(context, init);
26
26
  target.dispatchEvent(ev);
27
27
  }
28
28
  function injectContext(target, context) {
29
29
  let value = void 0;
30
- console.log("context:inject", context, target);
30
+ getInstrumentation().onContextRequested(context);
31
31
  const ev = new ContextRequestEvent(context, (received) => {
32
32
  value = received;
33
33
  });
@@ -39,7 +39,7 @@ function injectContext(target, context) {
39
39
  }
40
40
  function subscribeContext(target, context, callback) {
41
41
  let unsubscribeFunction = null;
42
- console.log("context:subscribe", context, target);
42
+ getInstrumentation().onContextRequested(context);
43
43
  const protocolCallback = (value, unsubscribe) => {
44
44
  if (unsubscribe) {
45
45
  unsubscribeFunction = unsubscribe;
@@ -63,10 +63,8 @@ class ContextRoot extends HTMLElement {
63
63
  connectedCallback() {
64
64
  this.addEventListener("context-provide", (ev) => {
65
65
  ev.stopPropagation();
66
- console.log("context-root:provide", ev.context, ev.value);
67
66
  this.store.set(ev.context, ev.value);
68
67
  const registeredCallbacks = this.callbacks.get(ev.context) ?? [];
69
- console.log("callbacks", registeredCallbacks);
70
68
  registeredCallbacks.forEach((cb) => {
71
69
  const unsubscribe = () => {
72
70
  const callbacks = this.callbacks.get(ev.context);
@@ -76,14 +74,12 @@ class ContextRoot extends HTMLElement {
76
74
  callbacks.splice(cbIndex, 1);
77
75
  }
78
76
  }
79
- console.log("context-root:unsubscribed", ev.context);
80
77
  };
81
78
  cb(ev.value, unsubscribe);
82
79
  });
83
80
  });
84
81
  this.addEventListener("context-request", (ev) => {
85
82
  ev.stopPropagation();
86
- console.log("context-root:request", ev.context, ev);
87
83
  const storedValue = this.store.get(ev.context);
88
84
  if (ev.subscribe) {
89
85
  let callbacks = this.callbacks.get(ev.context);
@@ -99,7 +95,6 @@ class ContextRoot extends HTMLElement {
99
95
  currentCallbacks.splice(index, 1);
100
96
  }
101
97
  }
102
- console.log("context-root:unsubscribed", ev.context);
103
98
  };
104
99
  callbacks.push(ev.callback);
105
100
  if (storedValue !== void 0) {
@@ -113,7 +108,6 @@ class ContextRoot extends HTMLElement {
113
108
  }
114
109
  }
115
110
  });
116
- console.log("context-root:ready");
117
111
  }
118
112
  }
119
113
  var i = Symbol.for("preact-signals");
@@ -121,22 +115,22 @@ function t() {
121
115
  if (!(s > 1)) {
122
116
  var i2, t2 = false;
123
117
  while (void 0 !== h) {
124
- var r = h;
118
+ var r2 = h;
125
119
  h = void 0;
126
120
  f++;
127
- while (void 0 !== r) {
128
- var o2 = r.o;
129
- r.o = void 0;
130
- r.f &= -3;
131
- if (!(8 & r.f) && c(r)) try {
132
- r.c();
133
- } catch (r2) {
121
+ while (void 0 !== r2) {
122
+ var o2 = r2.o;
123
+ r2.o = void 0;
124
+ r2.f &= -3;
125
+ if (!(8 & r2.f) && c(r2)) try {
126
+ r2.c();
127
+ } catch (r3) {
134
128
  if (!t2) {
135
- i2 = r2;
129
+ i2 = r3;
136
130
  t2 = true;
137
131
  }
138
132
  }
139
- r = o2;
133
+ r2 = o2;
140
134
  }
141
135
  }
142
136
  f = 0;
@@ -144,6 +138,15 @@ function t() {
144
138
  if (t2) throw i2;
145
139
  } else s--;
146
140
  }
141
+ function r(i2) {
142
+ if (s > 0) return i2();
143
+ s++;
144
+ try {
145
+ return i2();
146
+ } finally {
147
+ t();
148
+ }
149
+ }
147
150
  var o = void 0;
148
151
  function n(i2) {
149
152
  var t2 = o;
@@ -192,11 +195,11 @@ u.prototype.h = function() {
192
195
  return true;
193
196
  };
194
197
  u.prototype.S = function(i2) {
195
- var t2 = this, r = this.t;
196
- if (r !== i2 && void 0 === i2.e) {
197
- i2.x = r;
198
+ var t2 = this, r2 = this.t;
199
+ if (r2 !== i2 && void 0 === i2.e) {
200
+ i2.x = r2;
198
201
  this.t = i2;
199
- if (void 0 !== r) r.e = i2;
202
+ if (void 0 !== r2) r2.e = i2;
200
203
  else n(function() {
201
204
  var i3;
202
205
  null == (i3 = t2.W) || i3.call(t2);
@@ -206,13 +209,13 @@ u.prototype.S = function(i2) {
206
209
  u.prototype.U = function(i2) {
207
210
  var t2 = this;
208
211
  if (void 0 !== this.t) {
209
- var r = i2.e, o2 = i2.x;
210
- if (void 0 !== r) {
211
- r.x = o2;
212
+ var r2 = i2.e, o2 = i2.x;
213
+ if (void 0 !== r2) {
214
+ r2.x = o2;
212
215
  i2.e = void 0;
213
216
  }
214
217
  if (void 0 !== o2) {
215
- o2.e = r;
218
+ o2.e = r2;
216
219
  i2.x = void 0;
217
220
  }
218
221
  if (i2 === this.t) {
@@ -227,10 +230,10 @@ u.prototype.U = function(i2) {
227
230
  u.prototype.subscribe = function(i2) {
228
231
  var t2 = this;
229
232
  return E(function() {
230
- var r = t2.value, n2 = o;
233
+ var r2 = t2.value, n2 = o;
231
234
  o = void 0;
232
235
  try {
233
- i2(r);
236
+ i2(r2);
234
237
  } finally {
235
238
  o = n2;
236
239
  }
@@ -266,7 +269,7 @@ Object.defineProperty(u.prototype, "value", { get: function() {
266
269
  v++;
267
270
  s++;
268
271
  try {
269
- for (var r = this.t; void 0 !== r; r = r.x) r.t.N();
272
+ for (var r2 = this.t; void 0 !== r2; r2 = r2.x) r2.t.N();
270
273
  } finally {
271
274
  t();
272
275
  }
@@ -281,8 +284,8 @@ function c(i2) {
281
284
  }
282
285
  function a(i2) {
283
286
  for (var t2 = i2.s; void 0 !== t2; t2 = t2.n) {
284
- var r = t2.S.n;
285
- if (void 0 !== r) t2.r = r;
287
+ var r2 = t2.S.n;
288
+ if (void 0 !== r2) t2.r = r2;
286
289
  t2.S.n = t2;
287
290
  t2.i = -1;
288
291
  if (void 0 === t2.n) {
@@ -292,19 +295,19 @@ function a(i2) {
292
295
  }
293
296
  }
294
297
  function l(i2) {
295
- var t2 = i2.s, r = void 0;
298
+ var t2 = i2.s, r2 = void 0;
296
299
  while (void 0 !== t2) {
297
300
  var o2 = t2.p;
298
301
  if (-1 === t2.i) {
299
302
  t2.S.U(t2);
300
303
  if (void 0 !== o2) o2.n = t2.n;
301
304
  if (void 0 !== t2.n) t2.n.p = o2;
302
- } else r = t2;
305
+ } else r2 = t2;
303
306
  t2.S.n = t2.r;
304
307
  if (void 0 !== t2.r) t2.r = void 0;
305
308
  t2 = o2;
306
309
  }
307
- i2.s = r;
310
+ i2.s = r2;
308
311
  }
309
312
  function y(i2, t2) {
310
313
  u.call(this, void 0);
@@ -382,14 +385,14 @@ function w(i2, t2) {
382
385
  return new y(i2, t2);
383
386
  }
384
387
  function _(i2) {
385
- var r = i2.u;
388
+ var r2 = i2.u;
386
389
  i2.u = void 0;
387
- if ("function" == typeof r) {
390
+ if ("function" == typeof r2) {
388
391
  s++;
389
392
  var n2 = o;
390
393
  o = void 0;
391
394
  try {
392
- r();
395
+ r2();
393
396
  } catch (t2) {
394
397
  i2.f &= -2;
395
398
  i2.f |= 8;
@@ -466,14 +469,19 @@ function E(i2) {
466
469
  t2.d();
467
470
  throw i3;
468
471
  }
469
- var r = t2.d.bind(t2);
470
- r[Symbol.dispose] = r;
471
- return r;
472
+ var r2 = t2.d.bind(t2);
473
+ r2[Symbol.dispose] = r2;
474
+ return r2;
472
475
  }
473
476
  function isEditorPreview() {
474
477
  if (typeof window === "undefined") return false;
475
478
  return new URLSearchParams(window.location.search).get("editor") === "true";
476
479
  }
480
+ const layoutSystemEnabled = d(false);
481
+ function setLayoutSystemEnabled(enabled) {
482
+ if (layoutSystemEnabled.peek() === enabled) return;
483
+ layoutSystemEnabled.value = enabled;
484
+ }
477
485
  function hasRenderedContent(scope) {
478
486
  var _a;
479
487
  for (const child of scope.children) {
@@ -579,9 +587,12 @@ function withWrapper(fn) {
579
587
  });
580
588
  rendered = createStubDefinition(block.type).render(block);
581
589
  }
590
+ getInstrumentation().onBlockRendered(block, rendered);
582
591
  if (wrapper === null) {
583
592
  if (isEditorPreview()) {
584
- wrapper = document.createElement("juo-editor-block-wrapper");
593
+ wrapper = document.createElement(
594
+ layoutSystemEnabled.value ? "juo-editor-layout-block-wrapper" : "juo-editor-block-wrapper"
595
+ );
585
596
  wrapper.setAttribute("data-block-id", block.id);
586
597
  (_a = wrapper.setBlock) == null ? void 0 : _a.call(wrapper, block);
587
598
  wrapper.appendChild(rendered);
@@ -604,6 +615,7 @@ function registerBlock(block) {
604
615
  blockDefinitions.set(block.name, block);
605
616
  stubDefinitionCache.delete(block.name);
606
617
  registerBlockListeners.forEach((cb) => cb(block.name, block));
618
+ getInstrumentation().onBlockRegistered(block);
607
619
  }
608
620
  function onRegisterBlock(cb) {
609
621
  registerBlockListeners.push(cb);
@@ -641,6 +653,7 @@ function defineBlockRuntime(name, opts) {
641
653
  function getDefinedBlocks() {
642
654
  return [...blockDefinitions.values()];
643
655
  }
656
+ __setDefinedBlocksReader(getDefinedBlocks);
644
657
  function createCeRenderer(name) {
645
658
  function renderSlots(slots, block) {
646
659
  if (!slots) {
@@ -688,9 +701,11 @@ function createCeRenderer(name) {
688
701
  const el = document.createElement(name);
689
702
  el.setAttribute("data-block-id", block.id);
690
703
  el.setAttribute("data-block-type", block.type);
691
- Object.entries(block.props).forEach(([key, value]) => {
692
- el[key] = value;
693
- });
704
+ Object.entries(getInstrumentation().resolveProps(block)).forEach(
705
+ ([key, value]) => {
706
+ el[key] = value;
707
+ }
708
+ );
694
709
  el.replaceChildren(...renderSlots(block.slots, block));
695
710
  attachEmptyTracking(el);
696
711
  return el;
@@ -895,8 +910,14 @@ function indexOverrides(overrides) {
895
910
  function createThemeState(deps) {
896
911
  var _a;
897
912
  const surfaces = {
898
- page: { blocks: d([]) },
899
- overlay: { blocks: d([]) }
913
+ page: {
914
+ blocks: d([]),
915
+ layout: d(null)
916
+ },
917
+ overlay: {
918
+ blocks: d([]),
919
+ layout: d(null)
920
+ }
900
921
  };
901
922
  const locale = d("en");
902
923
  const catalogs = d(null);
@@ -906,6 +927,9 @@ function createThemeState(deps) {
906
927
  function setGlobalStyles(styles) {
907
928
  globalStyles.value = styles;
908
929
  }
930
+ E(() => {
931
+ setLayoutSystemEnabled(globalStyles.value.layoutEngine === "grid-v1");
932
+ });
909
933
  async function collectBlockDefaults(loc) {
910
934
  const nextDefaults = {};
911
935
  const nextModes = {};
@@ -949,10 +973,13 @@ function createThemeState(deps) {
949
973
  }
950
974
  async function resolve(surface, path) {
951
975
  var _a2, _b, _c, _d;
952
- surfaces[surface].blocks.value = [];
976
+ r(() => {
977
+ surfaces[surface].blocks.value = [];
978
+ surfaces[surface].layout.value = null;
979
+ });
953
980
  const stored = await deps.resolve(surface, path);
954
981
  if (stored != null) {
955
- surfaces[surface].blocks.value = stored.blocks.flatMap((block) => {
982
+ const hydratedBlocks = stored.blocks.flatMap((block) => {
956
983
  try {
957
984
  return [createBlockInstanceFromObject(block)];
958
985
  } catch (error) {
@@ -967,6 +994,10 @@ function createThemeState(deps) {
967
994
  return [];
968
995
  }
969
996
  });
997
+ r(() => {
998
+ surfaces[surface].blocks.value = hydratedBlocks;
999
+ surfaces[surface].layout.value = stored.layout ?? null;
1000
+ });
970
1001
  return stored;
971
1002
  }
972
1003
  const blockToUse = surface === "page" ? (_b = (_a2 = deps.routerService) == null ? void 0 : _a2.getPages().find((p2) => p2.path === path)) == null ? void 0 : _b.block : (_c = getDefinedBlocks().find((b2) => b2.name === path)) == null ? void 0 : _c.name;
@@ -1068,610 +1099,472 @@ function createTranslationService(locales, options = {}) {
1068
1099
  }
1069
1100
  };
1070
1101
  }
1071
- function getDefaultBlockForAction(actionType, actionConfig, blockId) {
1072
- const blockName = `action:${actionType}`;
1073
- const definedBlocks = getDefinedBlocks();
1074
- const exists = definedBlocks.some((b2) => b2.name === blockName);
1075
- if (!exists) {
1076
- throw new Error(
1077
- `No default block registered for action type "${actionType}". Expected a block named "${blockName}" to be registered in blocks-extensions.`
1078
- );
1079
- }
1080
- return createBlockInstance(blockName, { props: actionConfig, id: blockId });
1102
+ const GRID_V1_ENGINE_ID = "grid-v1";
1103
+ const PAGE_ROOT_SLOT = "content";
1104
+ const DEFAULT_GRID = { cols: 12, gap: 16, rowUnit: 40 };
1105
+ const MAX_BLOCKS_PER_ROW = 3;
1106
+ const DEFAULT_BREAKPOINTS = [
1107
+ { id: "desktop", cols: 12 },
1108
+ { id: "mobile", cols: 1, query: { maxWidth: 600 } }
1109
+ ];
1110
+ function sharesRowBand$1(a2, b2) {
1111
+ return a2.r < b2.r + b2.h && a2.r + a2.h > b2.r;
1081
1112
  }
1082
- function hasDefaultBlockForAction(actionType) {
1083
- const blockName = `action:${actionType}`;
1084
- return getDefinedBlocks().some((b2) => b2.name === blockName);
1113
+ function minFillCols(cols) {
1114
+ return Math.max(1, Math.ceil(Math.max(1, cols) / MAX_BLOCKS_PER_ROW));
1085
1115
  }
1086
- const WorkflowServiceContext = createContext("services/workflow");
1087
- const RUN_SCOPED_RESET = {
1088
- firstPollReason: null,
1089
- feedbackCollected: false
1090
- };
1091
- function createWorkflowApiAdapter(sdk) {
1092
- return {
1093
- async start(flowType, context, workflowId, dryRun) {
1094
- const { data } = await sdk.post("/customer/v1/workflows/start", {
1095
- flowType,
1096
- context,
1097
- ...workflowId ? { workflowId } : {},
1098
- ...dryRun ? { dryRun: true } : {}
1099
- });
1100
- return data;
1101
- },
1102
- async respond(runId, interactionId, responseType, responseData, expectedRunVersion, eventId) {
1103
- const { data } = await sdk.post(
1104
- "/customer/v1/workflows/{runId}/respond",
1105
- {
1106
- runId,
1107
- interactionId,
1108
- responseType,
1109
- responseData,
1110
- expectedRunVersion,
1111
- eventId
1112
- }
1113
- );
1114
- return data;
1115
- },
1116
- async getState(runId) {
1117
- const { data } = await sdk.get("/customer/v1/workflows/{runId}", {
1118
- runId
1119
- });
1120
- return data;
1121
- },
1122
- async cancel(runId) {
1123
- const { data } = await sdk.post("/customer/v1/workflows/{runId}/cancel", {
1124
- runId
1125
- });
1126
- return data;
1127
- }
1128
- };
1116
+ function clampRect(rect, cols) {
1117
+ const w2 = Math.max(1, Math.min(rect.w, cols));
1118
+ const c2 = Math.max(0, Math.min(rect.c, cols - w2));
1119
+ const h2 = Math.max(1, rect.h);
1120
+ const r2 = Math.max(0, rect.r);
1121
+ return { ...rect, c: c2, r: r2, w: w2, h: h2 };
1129
1122
  }
1130
- function createWorkflowService(deps) {
1131
- const { api } = deps;
1132
- const editor = createEditorBridge();
1133
- const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
1134
- const previewWorkflowTrigger = (urlParams == null ? void 0 : urlParams.get("trigger")) ?? null;
1135
- const previewStepId = (urlParams == null ? void 0 : urlParams.get("step-id")) ?? null;
1136
- const previewWorkflowId = (urlParams == null ? void 0 : urlParams.get("workflow-id")) ?? null;
1137
- const isEditorMode = editor.isEditorMode || previewWorkflowTrigger !== null;
1138
- const _state = d({
1139
- status: "idle",
1140
- flowType: null,
1141
- workflowId: null,
1142
- workflowVersion: null,
1143
- runId: null,
1144
- runVersion: null,
1145
- currentStepId: null,
1146
- currentInteraction: null,
1147
- error: null,
1148
- result: null,
1149
- flowParams: null,
1150
- invalidatedResources: [],
1151
- outcome: null,
1152
- completionData: null,
1153
- dryRun: null,
1154
- ...RUN_SCOPED_RESET
1155
- });
1156
- const _backendInteractionId = d(null);
1157
- const _registeredRootBlocks = /* @__PURE__ */ new Set();
1158
- const isActive = w(() => _state.value.status === "active");
1159
- const isLoading = w(() => _state.value.status === "loading");
1160
- const isCompleted = w(() => _state.value.status === "completed");
1161
- const hasError = w(() => _state.value.status === "error");
1162
- const currentInteraction = w(() => _state.value.currentInteraction);
1163
- const canRespond = w(() => {
1164
- const interaction = _state.value.currentInteraction;
1165
- const backendId = _backendInteractionId.value;
1166
- if (!interaction || !backendId) return false;
1167
- return interaction.interactionId === backendId;
1168
- });
1169
- const currentStepInfo = w(() => {
1170
- const interaction = _state.value.currentInteraction;
1171
- if (!interaction) return null;
1172
- const actionConfig = deps.shopCurrencyCode ? { ...interaction.actionConfig, currency: deps.shopCurrencyCode } : interaction.actionConfig;
1173
- return {
1174
- interactionId: interaction.interactionId,
1175
- stepId: interaction.stepId,
1176
- actionType: interaction.actionType,
1177
- actionConfig,
1178
- availableResponses: interaction.availableResponses
1179
- };
1123
+ function rectsOverlap(a2, b2) {
1124
+ return a2.c < b2.c + b2.w && a2.c + a2.w > b2.c && a2.r < b2.r + b2.h && a2.r + a2.h > b2.r;
1125
+ }
1126
+ function readingOrder(items) {
1127
+ return Object.keys(items).sort((idA, idB) => {
1128
+ const a2 = items[idA];
1129
+ const b2 = items[idB];
1130
+ if (a2.r !== b2.r) return a2.r - b2.r;
1131
+ return a2.c - b2.c;
1180
1132
  });
1181
- function updateState(updates) {
1182
- _state.value = { ..._state.value, ...updates };
1183
- }
1184
- function hashString(value) {
1185
- let hash = 2166136261;
1186
- for (let index = 0; index < value.length; index += 1) {
1187
- hash ^= value.charCodeAt(index);
1188
- hash = Math.imul(hash, 16777619);
1133
+ }
1134
+ function compactItems(items, cols) {
1135
+ const columnBottoms = new Array(Math.max(1, cols)).fill(0);
1136
+ const compacted = {};
1137
+ for (const id of readingOrder(items)) {
1138
+ const rect = clampRect(items[id], cols);
1139
+ let top = 0;
1140
+ for (let c2 = rect.c; c2 < rect.c + rect.w; c2++) {
1141
+ top = Math.max(top, columnBottoms[c2] ?? 0);
1142
+ }
1143
+ compacted[id] = { ...rect, r: top };
1144
+ for (let c2 = rect.c; c2 < rect.c + rect.w; c2++) {
1145
+ columnBottoms[c2] = top + rect.h;
1189
1146
  }
1190
- return (hash >>> 0).toString(36);
1191
- }
1192
- function shortenId(value, slugLength = 6) {
1193
- const compact = value.toLowerCase().replace(/[^a-z0-9]/g, "");
1194
- const slug = (compact || "id").slice(0, slugLength);
1195
- return `${slug}-${hashString(value)}`;
1196
1147
  }
1197
- function createStableStepBlockId(workflowId, stepId) {
1198
- return `wf-${shortenId(workflowId)}-${shortenId(stepId)}`;
1148
+ return compacted;
1149
+ }
1150
+ function rowBandBounds(items, target, cols, excludeId) {
1151
+ let left = 0;
1152
+ let right = Math.max(1, cols);
1153
+ for (const [id, rect] of Object.entries(items)) {
1154
+ if (id === excludeId) continue;
1155
+ const sharesRow = rect.r < target.r + target.h && rect.r + rect.h > target.r;
1156
+ if (!sharesRow) continue;
1157
+ const rectRight = rect.c + rect.w;
1158
+ if (rectRight <= target.c) {
1159
+ left = Math.max(left, rectRight);
1160
+ } else if (rect.c >= target.c + target.w) {
1161
+ right = Math.min(right, rect.c);
1162
+ }
1199
1163
  }
1200
- function handleFlowResponse(data) {
1201
- var _a, _b, _c, _d, _e, _f, _g;
1202
- const mergedInvalidated = [
1203
- ..._state.value.invalidatedResources,
1204
- ...data.invalidatedResources ?? []
1205
- ];
1206
- if (data.status === "waiting_interaction") {
1207
- const currentStepId = ((_a = data.pendingInteraction) == null ? void 0 : _a.stepId) ?? (isEditorMode ? (_c = (_b = data.interactiveSteps) == null ? void 0 : _b[0]) == null ? void 0 : _c.stepId : null);
1208
- _backendInteractionId.value = ((_d = data.pendingInteraction) == null ? void 0 : _d.interactionId) ?? null;
1209
- const isInitialResponse = _state.value.runId == null;
1210
- updateState({
1211
- status: "active",
1212
- workflowId: data.workflowId,
1213
- workflowVersion: data.workflowVersion,
1214
- runId: data.runId,
1215
- runVersion: data.runVersion,
1216
- currentStepId,
1217
- currentInteraction: data.pendingInteraction,
1218
- invalidatedResources: mergedInvalidated,
1219
- outcome: null
1220
- });
1221
- if (editor.isEditorMode) {
1222
- const displayStepId = isInitialResponse && previewStepId && ((_e = data.interactiveSteps) == null ? void 0 : _e.some((s2) => s2.stepId === previewStepId)) ? previewStepId : currentStepId;
1223
- const overlayBlocks = deps.themeState.overlay.blocks.value;
1224
- const rootBlock = overlayBlocks[0];
1225
- const stepSlot = displayStepId ? (_f = rootBlock == null ? void 0 : rootBlock.slots) == null ? void 0 : _f[displayStepId] : null;
1226
- const stepBlock = Array.isArray(stepSlot) ? stepSlot[0] : null;
1227
- const blockId = stepBlock && typeof stepBlock === "object" && "id" in stepBlock ? stepBlock.id : null;
1228
- if (blockId) {
1229
- editor.sendMessage(
1230
- createSelectBlockMessage({ blockId }, blockId)
1231
- );
1232
- }
1233
- }
1234
- } else if (data.status === "completed") {
1235
- _backendInteractionId.value = null;
1236
- updateState({
1237
- status: "completed",
1238
- currentStepId: null,
1239
- currentInteraction: null,
1240
- runVersion: data.runVersion,
1241
- result: data.result || null,
1242
- invalidatedResources: mergedInvalidated,
1243
- outcome: data.outcome || null,
1244
- completionData: data.completionData || null
1245
- });
1246
- } else if (data.status === "failed") {
1247
- _backendInteractionId.value = null;
1248
- handleError(new Error(((_g = data.error) == null ? void 0 : _g.message) || "Flow failed"));
1249
- } else if (data.status === "cancelled") {
1250
- _backendInteractionId.value = null;
1251
- updateState({
1252
- status: "idle",
1253
- flowType: null,
1254
- workflowId: null,
1255
- workflowVersion: null,
1256
- runId: null,
1257
- runVersion: null,
1258
- currentStepId: null,
1259
- currentInteraction: null,
1260
- error: null,
1261
- result: null,
1262
- invalidatedResources: [],
1263
- outcome: null,
1264
- completionData: null,
1265
- ...RUN_SCOPED_RESET
1266
- });
1164
+ return { left, right };
1165
+ }
1166
+ function fillSegmentBounds(target, nonFill, cols) {
1167
+ let left = 0;
1168
+ let right = Math.max(1, cols);
1169
+ for (const rect of nonFill) {
1170
+ if (!sharesRowBand$1(rect, target)) continue;
1171
+ const rectRight = rect.c + rect.w;
1172
+ if (rectRight <= target.c) {
1173
+ left = Math.max(left, rectRight);
1174
+ } else if (rect.c >= target.c) {
1175
+ right = Math.min(right, rect.c);
1176
+ } else {
1177
+ left = Math.max(left, rectRight);
1267
1178
  }
1268
1179
  }
1269
- function handleError(error) {
1270
- const message = error instanceof Error ? error.message : "Unknown error";
1271
- updateState({
1272
- status: "error",
1273
- error: message
1274
- });
1180
+ return { left, right: Math.max(left, right) };
1181
+ }
1182
+ function applyFillExpansion(items, cols) {
1183
+ const next = {};
1184
+ for (const id of readingOrder(items)) {
1185
+ next[id] = items[id];
1275
1186
  }
1276
- function maybeApplyPreviewStep(flowType, data) {
1277
- var _a;
1278
- if (!previewWorkflowTrigger) return;
1279
- if (flowType !== previewWorkflowTrigger) return;
1280
- if (data.status !== "waiting_interaction") return;
1281
- const step = (_a = data.interactiveSteps) == null ? void 0 : _a.find(
1282
- (interactiveStep) => interactiveStep.stepId === previewStepId
1187
+ const fillIds = readingOrder(next).filter((id) => next[id].fill === true);
1188
+ if (fillIds.length === 0) return next;
1189
+ const nonFill = Object.values(next).filter((rect) => rect.fill !== true);
1190
+ const groups = [];
1191
+ for (const id of fillIds) {
1192
+ const rect = next[id];
1193
+ const seg = fillSegmentBounds(rect, nonFill, cols);
1194
+ const group = groups.find(
1195
+ (g2) => g2.left === seg.left && g2.right === seg.right && g2.members.some((memberId) => sharesRowBand$1(next[memberId], rect))
1283
1196
  );
1284
- if (!step) return;
1285
- updateState({
1286
- currentStepId: step.stepId,
1287
- currentInteraction: {
1288
- interactionId: `preview-${data.runId}-${step.stepId}`,
1289
- stepId: step.stepId,
1290
- actionType: step.actionType,
1291
- actionBehavior: "input",
1292
- actionConfig: step.actionConfig,
1293
- availableResponses: step.availableResponses,
1294
- presentedAt: /* @__PURE__ */ new Date()
1295
- }
1296
- });
1197
+ if (group) group.members.push(id);
1198
+ else groups.push({ left: seg.left, right: seg.right, members: [id] });
1297
1199
  }
1298
- function initWorkflowRootBlock(data) {
1299
- if (_registeredRootBlocks.has(data.workflowId)) {
1300
- return;
1200
+ const minCols = minFillCols(cols);
1201
+ const overflow = [];
1202
+ for (const group of groups) {
1203
+ const span = Math.max(1, group.right - group.left);
1204
+ const fit = Math.min(group.members.length, Math.floor(span / minCols));
1205
+ if (fit <= 0) {
1206
+ overflow.push(...group.members);
1207
+ continue;
1301
1208
  }
1302
- const allSteps = data.interactiveSteps ?? (data.pendingInteraction ? [
1303
- {
1304
- stepId: data.pendingInteraction.stepId,
1305
- actionType: data.pendingInteraction.actionType,
1306
- actionConfig: data.pendingInteraction.actionConfig,
1307
- availableResponses: data.pendingInteraction.availableResponses
1209
+ const staying = group.members.slice(0, fit);
1210
+ overflow.push(...group.members.slice(fit));
1211
+ const base = Math.floor(span / fit);
1212
+ const remainder = span - base * fit;
1213
+ let pos = group.left;
1214
+ staying.forEach((id, index) => {
1215
+ const w2 = base + (index < remainder ? 1 : 0);
1216
+ next[id] = { ...next[id], c: pos, w: Math.max(1, w2) };
1217
+ pos += w2;
1218
+ });
1219
+ }
1220
+ if (overflow.length === 0) return next;
1221
+ for (const id of overflow) {
1222
+ const rect = next[id];
1223
+ let bandBottom = rect.r;
1224
+ for (const [otherId, other] of Object.entries(next)) {
1225
+ if (otherId === id || overflow.includes(otherId)) continue;
1226
+ if (sharesRowBand$1(other, rect)) {
1227
+ bandBottom = Math.max(bandBottom, other.r + other.h);
1308
1228
  }
1309
- ] : []);
1310
- const slotProperties = {};
1311
- for (const step of allSteps) {
1312
- slotProperties[step.stepId] = {};
1313
1229
  }
1314
- const presets = {};
1315
- const baseLabelFor = (step) => {
1316
- var _a;
1317
- return ((_a = getDefinedBlocks().find((b2) => b2.name === `action:${step.actionType}`)) == null ? void 0 : _a.displayName) ?? step.stepId;
1318
- };
1319
- const totalCounts = /* @__PURE__ */ new Map();
1320
- for (const step of allSteps) {
1321
- const baseLabel = baseLabelFor(step);
1322
- totalCounts.set(baseLabel, (totalCounts.get(baseLabel) ?? 0) + 1);
1230
+ next[id] = { ...next[id], c: 0, r: bandBottom, w: cols };
1231
+ }
1232
+ return compactItems(next, cols);
1233
+ }
1234
+ function findFreeRect(items, size, cols) {
1235
+ const w2 = Math.max(1, Math.min(size.w, cols));
1236
+ const h2 = Math.max(1, size.h);
1237
+ const existing = Object.values(items);
1238
+ for (let r2 = 0; ; r2++) {
1239
+ for (let c2 = 0; c2 <= cols - w2; c2++) {
1240
+ const candidate = { c: c2, r: r2, w: w2, h: h2 };
1241
+ if (!existing.some((rect) => rectsOverlap(candidate, rect))) {
1242
+ return candidate;
1243
+ }
1323
1244
  }
1324
- const seenCounts = /* @__PURE__ */ new Map();
1325
- for (const step of allSteps) {
1326
- const baseLabel = baseLabelFor(step);
1327
- const occurrence = (seenCounts.get(baseLabel) ?? 0) + 1;
1328
- seenCounts.set(baseLabel, occurrence);
1329
- const isDuplicated = (totalCounts.get(baseLabel) ?? 0) > 1;
1330
- const label = isDuplicated ? `${baseLabel} (${occurrence})` : baseLabel;
1331
- presets[step.stepId] = {
1332
- label,
1333
- description: step.actionType,
1334
- state: step.stepId,
1335
- // @ts-expect-error Untyped
1336
- context: step
1337
- };
1245
+ }
1246
+ }
1247
+ function deriveLayout(base, target) {
1248
+ const cols = target.cols;
1249
+ const items = {};
1250
+ let r2 = 0;
1251
+ for (const id of readingOrder(base.items)) {
1252
+ const h2 = Math.max(1, base.items[id].h);
1253
+ items[id] = clampRect({ c: 0, r: r2, w: cols, h: h2 }, cols);
1254
+ r2 += h2;
1255
+ }
1256
+ return { grid: { ...base.grid, cols }, items };
1257
+ }
1258
+ function resolveLayout(doc, breakpointId) {
1259
+ var _a;
1260
+ const present = doc.layouts[breakpointId];
1261
+ if (present) return present;
1262
+ const baseId = (_a = doc.breakpoints[0]) == null ? void 0 : _a.id;
1263
+ const baseLayout = baseId ? doc.layouts[baseId] : void 0;
1264
+ const target = doc.breakpoints.find((b2) => b2.id === breakpointId);
1265
+ if (!baseLayout || !target) {
1266
+ return { grid: { ...DEFAULT_GRID, cols: (target == null ? void 0 : target.cols) ?? 1 }, items: {} };
1267
+ }
1268
+ return deriveLayout(baseLayout, target);
1269
+ }
1270
+ function classifyRowDividers(items, blockIds) {
1271
+ const leaderBlockIds = /* @__PURE__ */ new Set();
1272
+ const rowBlockIds = /* @__PURE__ */ new Set();
1273
+ const placed = blockIds.filter((id) => items[id] != null);
1274
+ if (placed.length === 0) return { leaderBlockIds, rowBlockIds };
1275
+ const rects = placed.map((id) => items[id]);
1276
+ const minRow = Math.min(...rects.map((rect) => rect.r));
1277
+ const boundaryIsCrossed = (boundary) => rects.some((rect) => rect.r < boundary && rect.r + rect.h > boundary);
1278
+ const ordered = [...placed].sort((a2, b2) => {
1279
+ const ra = items[a2];
1280
+ const rb = items[b2];
1281
+ return ra.r - rb.r || ra.c - rb.c;
1282
+ });
1283
+ let lastLeaderRow = null;
1284
+ for (const id of ordered) {
1285
+ const { r: r2 } = items[id];
1286
+ if (r2 <= minRow || boundaryIsCrossed(r2)) continue;
1287
+ rowBlockIds.add(id);
1288
+ if (r2 !== lastLeaderRow) {
1289
+ leaderBlockIds.add(id);
1290
+ lastLeaderRow = r2;
1338
1291
  }
1339
- registerBlock(
1340
- defineBlock(`workflow:${data.workflowId}`, {
1341
- group: "workflow",
1342
- schema: {
1343
- type: "object",
1344
- properties: {
1345
- props: { type: "object" },
1346
- slots: {
1347
- type: "object",
1348
- properties: slotProperties
1349
- }
1350
- },
1351
- required: ["props", "slots"],
1352
- additionalProperties: true
1353
- },
1354
- initialValue: () => ({
1355
- props: {},
1356
- slots: Object.fromEntries(
1357
- allSteps.map((step) => [
1358
- step.stepId,
1359
- [
1360
- getDefaultBlockForAction(
1361
- step.actionType,
1362
- step.actionConfig,
1363
- createStableStepBlockId(data.workflowId, step.stepId)
1364
- )
1365
- ]
1366
- ])
1367
- )
1368
- }),
1369
- presets,
1370
- renderer() {
1371
- return null;
1372
- }
1292
+ }
1293
+ return { leaderBlockIds, rowBlockIds };
1294
+ }
1295
+ function containerRule(scope, grid) {
1296
+ return `${scope}{display:grid;grid-template-columns:repeat(${grid.cols},minmax(0,1fr));--juo-layout-cols:${grid.cols};--juo-layout-gap:var(--juo-layout-spacing,${grid.gap}px);column-gap:var(--juo-layout-gap);row-gap:0;margin-block-end:calc(-1 * var(--juo-layout-gap));}`;
1297
+ }
1298
+ function baseSpacingRule(scope) {
1299
+ return `${scope} > [data-block-id]{margin-block-end:var(--juo-layout-gap);}`;
1300
+ }
1301
+ function collapseRule(scope) {
1302
+ return `${scope} > [data-empty],${scope} > :has(> [data-empty]){margin-block-end:0;}`;
1303
+ }
1304
+ function itemRule(scope, blockId, rect, divider) {
1305
+ return `${scope} > [data-block-id="${blockId}"]{grid-column:${rect.c + 1}/span ${rect.w};grid-row:${rect.r + 1}/span ${rect.h};--juo-layout-c:${rect.c};--juo-divider-row:${divider.row ? 1 : 0};--juo-divider-line:${divider.line ? 1 : 0};}`;
1306
+ }
1307
+ function breakpointCss(scope, layout, domOrder) {
1308
+ const { leaderBlockIds, rowBlockIds } = classifyRowDividers(
1309
+ layout.items,
1310
+ domOrder
1311
+ );
1312
+ const rules = [containerRule(scope, layout.grid)];
1313
+ for (const blockId of Object.keys(layout.items)) {
1314
+ rules.push(
1315
+ itemRule(scope, blockId, layout.items[blockId], {
1316
+ row: rowBlockIds.has(blockId),
1317
+ line: leaderBlockIds.has(blockId)
1373
1318
  })
1374
1319
  );
1375
- _registeredRootBlocks.add(data.workflowId);
1376
1320
  }
1377
- async function initWorkflowState(data) {
1378
- const { blocks } = await deps.themeState.resolve(
1379
- "overlay",
1380
- `workflow:${data.workflowId}`
1381
- );
1382
- if (blocks.length === 0) return;
1383
- editor.onBlockPresetChange(blocks[0].id, (preset) => {
1384
- if (!preset) {
1385
- return;
1386
- }
1387
- updateState({
1388
- // @ts-expect-error Untyped
1389
- currentStepId: preset.state,
1390
- // @ts-expect-error Untyped
1391
- currentInteraction: { ...preset == null ? void 0 : preset.context }
1392
- });
1393
- });
1321
+ return rules.join("");
1322
+ }
1323
+ function sharesRowBand(a2, b2) {
1324
+ return a2.r < b2.r + b2.h && a2.r + a2.h > b2.r;
1325
+ }
1326
+ function nonEmptySubsets(ids) {
1327
+ const out = [];
1328
+ for (let mask = 1; mask < 1 << ids.length; mask++) {
1329
+ const subset = [];
1330
+ for (let i2 = 0; i2 < ids.length; i2++) {
1331
+ if (mask & 1 << i2) subset.push(ids[i2]);
1332
+ }
1333
+ out.push(subset);
1394
1334
  }
1395
- const service = {
1396
- // State signals (readonly)
1397
- state: _state,
1398
- /** True when the portal is running inside the Blocks Editor (editorMode dep
1399
- * or ?trigger=... URL param). Consumers use this to suppress auto-start. */
1400
- isPreviewMode: isEditorMode,
1401
- // Computed signals
1402
- isActive,
1403
- isLoading,
1404
- isCompleted,
1405
- hasError,
1406
- canRespond,
1407
- currentInteraction,
1408
- currentStepInfo,
1409
- // Methods
1410
- async startFlow(flowType, context, workflowId) {
1411
- const isDryRun = isEditorMode;
1412
- updateState({
1413
- status: "loading",
1414
- error: null,
1415
- flowParams: context,
1416
- flowType,
1417
- dryRun: isDryRun,
1418
- ...RUN_SCOPED_RESET
1419
- });
1420
- try {
1421
- const data = await api.start(
1422
- flowType,
1423
- context,
1424
- workflowId,
1425
- isDryRun || void 0
1426
- );
1427
- if (data.status === "no_workflow") {
1428
- service.reset();
1429
- return;
1430
- }
1431
- if (data.status === "completed_silently") {
1432
- updateState({
1433
- status: "completed",
1434
- currentStepId: null,
1435
- currentInteraction: null,
1436
- result: null,
1437
- invalidatedResources: data.invalidatedResources ?? [],
1438
- outcome: data.outcome || null,
1439
- completionData: data.completionData || null
1440
- });
1441
- return;
1442
- }
1443
- initWorkflowRootBlock(data);
1444
- await initWorkflowState(data);
1445
- handleFlowResponse(data);
1446
- maybeApplyPreviewStep(flowType, data);
1447
- } catch (error) {
1448
- handleError(error);
1449
- }
1450
- },
1451
- async respond(responseType, responseData) {
1452
- const { runId, runVersion, currentInteraction: currentInteraction2 } = _state.value;
1453
- if (!runId || !currentInteraction2) {
1454
- throw new Error("No active interaction to respond to");
1455
- }
1456
- updateState({ status: "loading" });
1457
- try {
1458
- const data = await api.respond(
1459
- runId,
1460
- currentInteraction2.interactionId,
1461
- responseType,
1462
- responseData,
1463
- runVersion ?? void 0
1464
- );
1465
- if (_state.value.firstPollReason == null && currentInteraction2.actionType === "poll") {
1466
- const reason = responseData == null ? void 0 : responseData.reason;
1467
- if (typeof reason === "string" && reason.length > 0) {
1468
- updateState({ firstPollReason: reason });
1469
- }
1470
- }
1471
- if (!_state.value.feedbackCollected && currentInteraction2.actionType === "collect_feedback" && responseType === "submitted") {
1472
- const feedback = responseData == null ? void 0 : responseData.feedback;
1473
- if (typeof feedback === "string" && feedback.trim().length > 0) {
1474
- updateState({ feedbackCollected: true });
1475
- }
1476
- }
1477
- handleFlowResponse(data);
1478
- } catch (error) {
1479
- handleError(error);
1480
- }
1481
- },
1482
- async cancel() {
1483
- const { runId, status } = _state.value;
1484
- const isTerminal = status === "completed" || status === "error";
1485
- if (runId && !isTerminal) {
1486
- try {
1487
- const data = await api.cancel(runId);
1488
- if (data.outcome) {
1489
- updateState({
1490
- status: "completed",
1491
- flowType: null,
1492
- workflowId: null,
1493
- workflowVersion: null,
1494
- runId: null,
1495
- runVersion: null,
1496
- currentStepId: null,
1497
- currentInteraction: null,
1498
- error: null,
1499
- result: null,
1500
- flowParams: null,
1501
- invalidatedResources: data.invalidatedResources ?? [],
1502
- outcome: data.outcome || null,
1503
- dryRun: null
1504
- });
1505
- return;
1506
- }
1507
- } catch {
1508
- }
1509
- }
1510
- service.reset();
1511
- },
1512
- reset() {
1513
- _backendInteractionId.value = null;
1514
- updateState({
1515
- status: "idle",
1516
- flowType: null,
1517
- workflowId: null,
1518
- workflowVersion: null,
1519
- runId: null,
1520
- runVersion: null,
1521
- currentStepId: null,
1522
- currentInteraction: null,
1523
- error: null,
1524
- result: null,
1525
- flowParams: null,
1526
- invalidatedResources: [],
1527
- outcome: null,
1528
- completionData: null,
1529
- ...RUN_SCOPED_RESET
1530
- });
1531
- },
1532
- async refresh() {
1533
- const { runId } = _state.value;
1534
- if (!runId) return;
1535
- try {
1536
- const data = await api.getState(runId);
1537
- handleFlowResponse(data);
1538
- } catch (error) {
1539
- handleError(error);
1335
+ return out;
1336
+ }
1337
+ function reclaimSelector(scope, fillId, emptyMates, domIndex) {
1338
+ const fillIdx = domIndex.get(fillId) ?? 0;
1339
+ const byDom = (a2, b2) => (domIndex.get(a2) ?? 0) - (domIndex.get(b2) ?? 0);
1340
+ const before = emptyMates.filter((id) => (domIndex.get(id) ?? 0) < fillIdx).sort(byDom);
1341
+ const after = emptyMates.filter((id) => (domIndex.get(id) ?? 0) > fillIdx).sort(byDom);
1342
+ const emptyBefore = (id) => `[data-block-id="${id}"]:is([data-empty],:has(> [data-empty]))`;
1343
+ const emptyAfterHas = (id) => `~ [data-block-id="${id}"][data-empty],~ [data-block-id="${id}"] > [data-empty]`;
1344
+ let sel = "";
1345
+ for (const id of before) sel += `${emptyBefore(id)} ~ `;
1346
+ sel += `[data-block-id="${fillId}"]`;
1347
+ for (const id of after) sel += `:has(${emptyAfterHas(id)})`;
1348
+ return `${scope} > ${sel}`;
1349
+ }
1350
+ function reclaimCss(scope, layout, domOrder) {
1351
+ const items = layout.items;
1352
+ const cols = layout.grid.cols;
1353
+ const domIndex = new Map(domOrder.map((id, index) => [id, index]));
1354
+ const rules = [];
1355
+ for (const [fillId, fillRect] of Object.entries(items)) {
1356
+ if (fillRect.fill !== true) continue;
1357
+ const mateIds = Object.entries(items).filter(([id, rect]) => id !== fillId && sharesRowBand(rect, fillRect)).map(([id]) => id);
1358
+ if (mateIds.length === 0 || mateIds.length > 4) continue;
1359
+ for (const emptyMates of nonEmptySubsets(mateIds)) {
1360
+ const remaining = {};
1361
+ for (const [id, rect] of Object.entries(items)) {
1362
+ if (id === fillId || emptyMates.includes(id)) continue;
1363
+ remaining[id] = rect;
1540
1364
  }
1365
+ const { left, right } = rowBandBounds(remaining, fillRect, cols);
1366
+ if (left >= fillRect.c && right <= fillRect.c + fillRect.w) continue;
1367
+ const selector = reclaimSelector(scope, fillId, emptyMates, domIndex);
1368
+ rules.push(
1369
+ `${selector}{grid-column:${left + 1}/span ${Math.max(1, right - left)};--juo-layout-c:${left};}`
1370
+ );
1541
1371
  }
1542
- };
1543
- if (previewWorkflowTrigger) {
1544
- void service.startFlow(
1545
- previewWorkflowTrigger,
1546
- {},
1547
- previewWorkflowId ?? void 0
1548
- );
1549
1372
  }
1550
- return service;
1373
+ return rules.join("");
1551
1374
  }
1552
- class JuoWorkflowElement extends HTMLElement {
1553
- constructor() {
1554
- super(...arguments);
1555
- __publicField(this, "workflowService", null);
1556
- __publicField(this, "unsubscribeContext", null);
1557
- __publicField(this, "unsubscribeEffect", null);
1558
- /** Tracks which step is currently mounted to avoid unnecessary DOM teardown. */
1559
- __publicField(this, "renderedStepId", null);
1560
- /**
1561
- * Optional function to wrap rendered content (step blocks).
1562
- * Must be set before workflow becomes active for correct behavior.
1563
- */
1564
- __publicField(this, "blockWrapper", null);
1565
- }
1566
- connectedCallback() {
1567
- this.style.display = "contents";
1568
- this.unsubscribeContext = subscribeContext(
1569
- this,
1570
- WorkflowServiceContext,
1571
- (service) => {
1572
- this.workflowService = service;
1573
- this.setupSubscription();
1574
- }
1375
+ function projectToCss(doc, opts) {
1376
+ const base = doc.breakpoints[0];
1377
+ if (!base) return "";
1378
+ const baseLayout = resolveLayout(doc, base.id);
1379
+ const domOrder = opts.domOrder ?? Object.keys(baseLayout.items);
1380
+ const parts = [
1381
+ breakpointCss(opts.scope, baseLayout, domOrder),
1382
+ baseSpacingRule(opts.scope),
1383
+ collapseRule(opts.scope),
1384
+ reclaimCss(opts.scope, baseLayout, domOrder)
1385
+ ];
1386
+ for (const bp of doc.breakpoints.slice(1)) {
1387
+ if (!bp.query) continue;
1388
+ parts.push(
1389
+ `@container (max-width:${bp.query.maxWidth}px){` + breakpointCss(opts.scope, resolveLayout(doc, bp.id), domOrder) + `}`
1575
1390
  );
1576
1391
  }
1577
- disconnectedCallback() {
1578
- var _a, _b;
1579
- (_a = this.unsubscribeContext) == null ? void 0 : _a.call(this);
1580
- (_b = this.unsubscribeEffect) == null ? void 0 : _b.call(this);
1581
- this.unsubscribeContext = null;
1582
- this.unsubscribeEffect = null;
1583
- this.renderedStepId = null;
1584
- }
1585
- setupSubscription() {
1586
- var _a;
1587
- if (!this.workflowService) return;
1588
- (_a = this.unsubscribeEffect) == null ? void 0 : _a.call(this);
1589
- this.unsubscribeEffect = E(() => {
1590
- var _a2, _b;
1591
- const status = ((_a2 = this.workflowService) == null ? void 0 : _a2.state.value.status) ?? "idle";
1592
- const stepInfo = (_b = this.workflowService) == null ? void 0 : _b.currentStepInfo.value;
1593
- const stepId = (stepInfo == null ? void 0 : stepInfo.stepId) ?? null;
1594
- queueMicrotask(() => {
1595
- if (this.isConnected) {
1596
- this.render(status, stepId);
1597
- }
1598
- });
1599
- });
1392
+ return parts.join("");
1393
+ }
1394
+ function createDefaultLayoutDocument(blockIds) {
1395
+ const items = {};
1396
+ blockIds.forEach((id, index) => {
1397
+ items[id] = { c: 0, r: index, w: DEFAULT_GRID.cols, h: 1 };
1398
+ });
1399
+ return {
1400
+ version: 1,
1401
+ engine: GRID_V1_ENGINE_ID,
1402
+ breakpoints: structuredClone([...DEFAULT_BREAKPOINTS]),
1403
+ layouts: {
1404
+ [DEFAULT_BREAKPOINTS[0].id]: { grid: { ...DEFAULT_GRID }, items }
1405
+ }
1406
+ };
1407
+ }
1408
+ function colsForBreakpoint(doc, breakpointId, layout) {
1409
+ var _a;
1410
+ return ((_a = doc.breakpoints.find((b2) => b2.id === breakpointId)) == null ? void 0 : _a.cols) ?? layout.grid.cols;
1411
+ }
1412
+ function reconcileBreakpointLayout(layout, blockIds, cols) {
1413
+ const known = new Set(blockIds);
1414
+ for (const id of Object.keys(layout.items)) {
1415
+ if (!known.has(id)) delete layout.items[id];
1600
1416
  }
1601
- render(status, stepId) {
1602
- var _a;
1603
- if ((status === "active" || status === "loading") && stepId) {
1604
- if (this.renderedStepId !== stepId) {
1605
- this.innerHTML = "";
1606
- this.renderedStepId = stepId;
1607
- const extensionRoot = document.createElement(
1608
- "juo-extension-root"
1609
- );
1610
- extensionRoot.setAttribute("surface", "overlay");
1611
- extensionRoot.setAttribute("name", stepId);
1612
- extensionRoot.blockWrapper = this.blockWrapper;
1613
- this.appendChild(extensionRoot);
1614
- }
1615
- return;
1417
+ for (const id of blockIds) {
1418
+ if (!layout.items[id]) {
1419
+ layout.items[id] = findFreeRect(layout.items, { w: cols, h: 1 }, cols);
1616
1420
  }
1617
- this.innerHTML = "";
1618
- this.renderedStepId = null;
1619
- if (status === "error") {
1620
- const error = ((_a = this.workflowService) == null ? void 0 : _a.state.value.error) ?? "Unknown error";
1621
- this.dispatchEvent(
1622
- new CustomEvent("juo-workflow-error", {
1623
- bubbles: true,
1624
- composed: true,
1625
- detail: { error }
1626
- })
1627
- );
1421
+ }
1422
+ }
1423
+ function reconcileLayout(doc, blockIds) {
1424
+ var _a;
1425
+ if (!doc) return createDefaultLayoutDocument(blockIds);
1426
+ const next = structuredClone(doc);
1427
+ const baseId = (_a = next.breakpoints[0]) == null ? void 0 : _a.id;
1428
+ if (!baseId) return createDefaultLayoutDocument(blockIds);
1429
+ for (const def of DEFAULT_BREAKPOINTS) {
1430
+ if (!next.breakpoints.some((b2) => b2.id === def.id)) {
1431
+ next.breakpoints.push(structuredClone(def));
1628
1432
  }
1629
1433
  }
1434
+ next.layouts[baseId] = next.layouts[baseId] ?? {
1435
+ grid: { ...DEFAULT_GRID },
1436
+ items: {}
1437
+ };
1438
+ for (const breakpointId of Object.keys(next.layouts)) {
1439
+ const layout = next.layouts[breakpointId];
1440
+ if (!layout) continue;
1441
+ reconcileBreakpointLayout(
1442
+ layout,
1443
+ blockIds,
1444
+ colsForBreakpoint(next, breakpointId, layout)
1445
+ );
1446
+ }
1447
+ return next;
1630
1448
  }
1631
- if (typeof customElements !== "undefined" && !customElements.get("juo-workflow")) {
1632
- customElements.define("juo-workflow", JuoWorkflowElement);
1449
+ function compactLayoutDocument(doc) {
1450
+ if (!doc) return doc;
1451
+ const next = structuredClone(doc);
1452
+ for (const breakpointId of Object.keys(next.layouts)) {
1453
+ const layout = next.layouts[breakpointId];
1454
+ if (!layout) continue;
1455
+ layout.items = compactItems(
1456
+ layout.items,
1457
+ colsForBreakpoint(next, breakpointId, layout)
1458
+ );
1459
+ }
1460
+ return next;
1461
+ }
1462
+ function expandFillLayoutDocument(doc) {
1463
+ if (!doc) return doc;
1464
+ const next = structuredClone(doc);
1465
+ for (const breakpointId of Object.keys(next.layouts)) {
1466
+ const layout = next.layouts[breakpointId];
1467
+ if (!layout) continue;
1468
+ layout.items = applyFillExpansion(
1469
+ layout.items,
1470
+ colsForBreakpoint(next, breakpointId, layout)
1471
+ );
1472
+ }
1473
+ return next;
1474
+ }
1475
+ const LAYOUT_SCOPE_ATTR = "data-juo-layout";
1476
+ function layoutScopeSelector(scopeId) {
1477
+ return `[${LAYOUT_SCOPE_ATTR}="${scopeId}"]`;
1478
+ }
1479
+ function buildLayoutCss(layout, blockIds, scopeId) {
1480
+ const reconciled = reconcileLayout(layout, blockIds);
1481
+ return projectToCss(reconciled, {
1482
+ scope: layoutScopeSelector(scopeId),
1483
+ domOrder: blockIds
1484
+ });
1485
+ }
1486
+ function buildGridLayout(layout, blockIds, scopeId) {
1487
+ var _a, _b;
1488
+ const scope = layoutScopeSelector(scopeId);
1489
+ const reconciled = reconcileLayout(layout, blockIds);
1490
+ const baseId = (_a = reconciled.breakpoints[0]) == null ? void 0 : _a.id;
1491
+ const layoutItems = (baseId != null ? (_b = reconciled.layouts[baseId]) == null ? void 0 : _b.items : null) ?? {};
1492
+ const { leaderBlockIds, rowBlockIds } = classifyRowDividers(
1493
+ layoutItems,
1494
+ blockIds
1495
+ );
1496
+ const fullWidthBlockIds = /* @__PURE__ */ new Set();
1497
+ for (const [id, rect] of Object.entries(layoutItems)) {
1498
+ if (rect.fill === true) fullWidthBlockIds.add(id);
1499
+ }
1500
+ return {
1501
+ css: projectToCss(reconciled, { scope, domOrder: blockIds }),
1502
+ dividerBlockIds: leaderBlockIds,
1503
+ dividerRowBlockIds: rowBlockIds,
1504
+ fullWidthBlockIds
1505
+ };
1633
1506
  }
1634
1507
  export {
1635
- isEditorPreview as A,
1508
+ layoutScopeSelector as $,
1509
+ attachEmptyTracking as A,
1636
1510
  BlockWrapperEvent as B,
1637
- ContextProvideEvent as C,
1638
- DEFAULT_GLOBAL_STYLES as D,
1511
+ ContextRoot as C,
1512
+ DEFAULT_GRID as D,
1639
1513
  E,
1640
- isStubDefinition as F,
1641
- onRegisterBlock as G,
1642
- provideContext as H,
1643
- serializeBlocks as I,
1644
- subscribeContext as J,
1645
- n as K,
1646
- withWrapper as L,
1647
- ContextRoot as M,
1514
+ buildLayoutCss as F,
1515
+ GRID_V1_ENGINE_ID as G,
1516
+ classifyRowDividers as H,
1517
+ compactLayoutDocument as I,
1518
+ createBlockInstanceFromJSON as J,
1519
+ createBlockInstanceFromObject as K,
1520
+ LAYOUT_SCOPE_ATTR as L,
1521
+ MAX_BLOCKS_PER_ROW as M,
1522
+ createCeRenderer as N,
1523
+ createDefaultLayoutDocument as O,
1524
+ PAGE_ROOT_SLOT as P,
1525
+ createSelectedBlock as Q,
1526
+ createThemeState as R,
1648
1527
  SelectedBlockContext as S,
1649
- ThemeStateContext as T,
1650
- WorkflowServiceContext as W,
1651
- ContextRequestEvent as a,
1652
- TranslationContext as b,
1653
- createContext as c,
1654
- d,
1655
- attachEmptyTracking as e,
1656
- backfillInstanceDefaults as f,
1657
- createBlockInstance as g,
1658
- createBlockInstanceFromJSON as h,
1659
- createBlockInstanceFromObject as i,
1660
- createCeRenderer as j,
1661
- createSelectedBlock as k,
1662
- createThemeState as l,
1663
- createTranslationService as m,
1664
- createWorkflowApiAdapter as n,
1665
- createWorkflowService as o,
1666
- defineBlock as p,
1667
- defineBlockRuntime as q,
1668
- registerBlock as r,
1669
- getDefaultBlockForAction as s,
1670
- getDefinedBlocks as t,
1528
+ TranslationContext as T,
1529
+ createTranslationService as U,
1530
+ defineBlockRuntime as V,
1531
+ deriveLayout as W,
1532
+ expandFillLayoutDocument as X,
1533
+ hasRenderedContent as Y,
1534
+ indexOverrides as Z,
1535
+ isEditorPreview as _,
1536
+ isStubDefinition as a,
1537
+ layoutSystemEnabled as a0,
1538
+ projectToCss as a1,
1539
+ provideContext as a2,
1540
+ readingOrder as a3,
1541
+ rectsOverlap as a4,
1542
+ serializeBlocks as a5,
1543
+ setLayoutSystemEnabled as a6,
1544
+ n as a7,
1545
+ buildGridLayout as b,
1546
+ ThemeStateContext as c,
1547
+ backfillInstanceDefaults as d,
1548
+ reconcileLayout as e,
1549
+ createContext as f,
1550
+ d as g,
1551
+ w as h,
1552
+ injectContext as i,
1553
+ registerBlock as j,
1554
+ getDefinedBlocks as k,
1555
+ createBlockInstance as l,
1556
+ defineBlock as m,
1557
+ clampRect as n,
1558
+ onRegisterBlock as o,
1559
+ applyFillExpansion as p,
1560
+ compactItems as q,
1561
+ resolveLayout as r,
1562
+ subscribeContext as s,
1563
+ findFreeRect as t,
1671
1564
  u,
1672
- hasDefaultBlockForAction as v,
1673
- w,
1674
- hasRenderedContent as x,
1675
- indexOverrides as y,
1676
- injectContext as z
1565
+ ContextProvideEvent as v,
1566
+ withWrapper as w,
1567
+ ContextRequestEvent as x,
1568
+ DEFAULT_BREAKPOINTS as y,
1569
+ DEFAULT_GLOBAL_STYLES as z
1677
1570
  };