@juo/blocks 1.13.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/dist/ExtensionRoot-CRJx0Dtr.js +378 -0
  2. package/dist/block.d.ts.map +1 -1
  3. package/dist/{bridge-w5KQ-czl.js → bridge-D838SWmN.js} +146 -32
  4. package/dist/context.d.ts.map +1 -1
  5. package/dist/core.js +775 -35
  6. package/dist/{juo-workflow-BlG9CcAG.js → css-runtime-DWytAzZ5.js} +466 -611
  7. package/dist/editor/bridge.d.ts +8 -0
  8. package/dist/editor/bridge.d.ts.map +1 -1
  9. package/dist/editor/canvas-mode-signal.d.ts +22 -0
  10. package/dist/editor/canvas-mode-signal.d.ts.map +1 -0
  11. package/dist/editor/canvas-mode.d.ts +15 -0
  12. package/dist/editor/canvas-mode.d.ts.map +1 -0
  13. package/dist/editor/canvas-mode.test.d.ts +2 -0
  14. package/dist/editor/canvas-mode.test.d.ts.map +1 -0
  15. package/dist/editor/components.d.ts +113 -0
  16. package/dist/editor/components.d.ts.map +1 -1
  17. package/dist/editor/components.test.d.ts.map +1 -1
  18. package/dist/editor/handler.d.ts.map +1 -1
  19. package/dist/editor/handler.test.d.ts +2 -0
  20. package/dist/editor/handler.test.d.ts.map +1 -0
  21. package/dist/editor/layout-command-emitter.d.ts +31 -0
  22. package/dist/editor/layout-command-emitter.d.ts.map +1 -0
  23. package/dist/editor/layout-command-emitter.test.d.ts +2 -0
  24. package/dist/editor/layout-command-emitter.test.d.ts.map +1 -0
  25. package/dist/editor/layout-system-signal.d.ts +21 -0
  26. package/dist/editor/layout-system-signal.d.ts.map +1 -0
  27. package/dist/editor/main.d.ts +1 -0
  28. package/dist/editor/main.d.ts.map +1 -1
  29. package/dist/editor/messages.d.ts +90 -3
  30. package/dist/editor/messages.d.ts.map +1 -1
  31. package/dist/editor/messages.test.d.ts +2 -0
  32. package/dist/editor/messages.test.d.ts.map +1 -0
  33. package/dist/editor/surface-context.d.ts +7 -0
  34. package/dist/editor/surface-context.d.ts.map +1 -0
  35. package/dist/editor/surface-context.test.d.ts +2 -0
  36. package/dist/editor/surface-context.test.d.ts.map +1 -0
  37. package/dist/editor/wrapper-shared.d.ts +31 -0
  38. package/dist/editor/wrapper-shared.d.ts.map +1 -0
  39. package/dist/editor.js +863 -45
  40. package/dist/gridstack-adapter-DreG3XnB.js +5490 -0
  41. package/dist/layout/css-runtime.d.ts +41 -0
  42. package/dist/layout/css-runtime.d.ts.map +1 -0
  43. package/dist/layout/css-runtime.test.d.ts +2 -0
  44. package/dist/layout/css-runtime.test.d.ts.map +1 -0
  45. package/dist/layout/derive.d.ts +4 -0
  46. package/dist/layout/derive.d.ts.map +1 -0
  47. package/dist/layout/derive.test.d.ts +2 -0
  48. package/dist/layout/derive.test.d.ts.map +1 -0
  49. package/dist/layout/dividers.d.ts +34 -0
  50. package/dist/layout/dividers.d.ts.map +1 -0
  51. package/dist/layout/dividers.test.d.ts +2 -0
  52. package/dist/layout/dividers.test.d.ts.map +1 -0
  53. package/dist/layout/engine.d.ts +3 -0
  54. package/dist/layout/engine.d.ts.map +1 -0
  55. package/dist/layout/engine.test.d.ts +2 -0
  56. package/dist/layout/engine.test.d.ts.map +1 -0
  57. package/dist/layout/grid-utils.d.ts +57 -0
  58. package/dist/layout/grid-utils.d.ts.map +1 -0
  59. package/dist/layout/grid-utils.test.d.ts +2 -0
  60. package/dist/layout/grid-utils.test.d.ts.map +1 -0
  61. package/dist/layout/index.d.ts +12 -0
  62. package/dist/layout/index.d.ts.map +1 -0
  63. package/dist/layout/index.test.d.ts +2 -0
  64. package/dist/layout/index.test.d.ts.map +1 -0
  65. package/dist/layout/insert.d.ts +31 -0
  66. package/dist/layout/insert.d.ts.map +1 -0
  67. package/dist/layout/insert.test.d.ts +2 -0
  68. package/dist/layout/insert.test.d.ts.map +1 -0
  69. package/dist/layout/project-css.d.ts +6 -0
  70. package/dist/layout/project-css.d.ts.map +1 -0
  71. package/dist/layout/project-css.test.d.ts +2 -0
  72. package/dist/layout/project-css.test.d.ts.map +1 -0
  73. package/dist/layout/project-gridstack.d.ts +50 -0
  74. package/dist/layout/project-gridstack.d.ts.map +1 -0
  75. package/dist/layout/project-gridstack.test.d.ts +2 -0
  76. package/dist/layout/project-gridstack.test.d.ts.map +1 -0
  77. package/dist/layout/reconcile.d.ts +22 -0
  78. package/dist/layout/reconcile.d.ts.map +1 -0
  79. package/dist/layout/reconcile.test.d.ts +2 -0
  80. package/dist/layout/reconcile.test.d.ts.map +1 -0
  81. package/dist/layout/types.d.ts +118 -0
  82. package/dist/layout/types.d.ts.map +1 -0
  83. package/dist/layout-mode-adapter-BBd4JRQd.js +21 -0
  84. package/dist/main.d.ts +7 -1
  85. package/dist/main.d.ts.map +1 -1
  86. package/dist/morph-Dj-xvrwt.js +182 -0
  87. package/dist/preact.js +1 -1
  88. package/dist/project-gridstack-DYLMKSH1.js +52 -0
  89. package/dist/react.js +1 -1
  90. package/dist/theme-state.d.ts +16 -0
  91. package/dist/theme-state.d.ts.map +1 -1
  92. package/dist/theme-state.layout.test.d.ts +2 -0
  93. package/dist/theme-state.layout.test.d.ts.map +1 -0
  94. package/dist/theme-state.test.d.ts +2 -0
  95. package/dist/theme-state.test.d.ts.map +1 -0
  96. package/dist/vue.js +1 -1
  97. package/dist/web-components/ExtensionRoot.d.ts +50 -2
  98. package/dist/web-components/ExtensionRoot.d.ts.map +1 -1
  99. package/dist/web-components/editor/ExtensionRoot.d.ts +11 -0
  100. package/dist/web-components/editor/ExtensionRoot.d.ts.map +1 -0
  101. package/dist/web-components/editor/ExtensionRoot.test.d.ts +2 -0
  102. package/dist/web-components/editor/ExtensionRoot.test.d.ts.map +1 -0
  103. package/dist/web-components/editor/InlineText.d.ts +1 -0
  104. package/dist/web-components/editor/InlineText.d.ts.map +1 -1
  105. package/dist/web-components/editor/editor-layout-controller.d.ts +28 -0
  106. package/dist/web-components/editor/editor-layout-controller.d.ts.map +1 -0
  107. package/dist/web-components/editor/gridstack-adapter.d.ts +3 -0
  108. package/dist/web-components/editor/gridstack-adapter.d.ts.map +1 -0
  109. package/dist/web-components/editor/gridstack-adapter.test.d.ts +2 -0
  110. package/dist/web-components/editor/gridstack-adapter.test.d.ts.map +1 -0
  111. package/dist/web-components/editor/morph.d.ts +32 -0
  112. package/dist/web-components/editor/morph.d.ts.map +1 -0
  113. package/dist/web-components/editor/morph.test.d.ts +2 -0
  114. package/dist/web-components/editor/morph.test.d.ts.map +1 -0
  115. package/dist/web-components/layout/layout-controller.d.ts +55 -0
  116. package/dist/web-components/layout/layout-controller.d.ts.map +1 -0
  117. package/dist/web-components/layout/view-layout-controller.d.ts +17 -0
  118. package/dist/web-components/layout/view-layout-controller.d.ts.map +1 -0
  119. package/dist/web-components/layout/view-layout-controller.test.d.ts +2 -0
  120. package/dist/web-components/layout/view-layout-controller.test.d.ts.map +1 -0
  121. package/dist/web-components/layout-grid.d.ts +47 -0
  122. package/dist/web-components/layout-grid.d.ts.map +1 -0
  123. package/dist/web-components/layout-grid.test.d.ts +2 -0
  124. package/dist/web-components/layout-grid.test.d.ts.map +1 -0
  125. package/dist/web-components/layout-mode-adapter.d.ts +51 -0
  126. package/dist/web-components/layout-mode-adapter.d.ts.map +1 -0
  127. package/dist/web-components/layout-mode-adapter.test.d.ts +2 -0
  128. package/dist/web-components/layout-mode-adapter.test.d.ts.map +1 -0
  129. package/dist/web-components-editor.js +125 -17
  130. package/dist/web-components-runtime.js +4 -3
  131. package/package.json +3 -2
  132. package/dist/ExtensionRoot-2xTGTu3K.js +0 -219
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-layout-controller.test.d.ts","sourceRoot":"","sources":["../../../src/web-components/layout/view-layout-controller.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ export type GridLayoutItem = {
2
+ blockId: string;
3
+ element: HTMLElement;
4
+ };
5
+ /** Per-item boolean-attribute tags derived from the runtime layout. */
6
+ export type GridLayoutTags = {
7
+ /**
8
+ * Leader block ids (leftmost block of each divider row). Tagged with
9
+ * `data-juo-divider` so the surface stylesheet draws the full-width divider
10
+ * line above them.
11
+ */
12
+ dividerBlockIds?: ReadonlySet<string>;
13
+ /**
14
+ * Every block on a divider row. Tagged with `data-juo-divider-row` so the
15
+ * surface stylesheet adds the extra divider-row spacing (top margin) — only
16
+ * boundaries that actually show a divider grow; others keep the base row-gap.
17
+ */
18
+ dividerRowBlockIds?: ReadonlySet<string>;
19
+ /**
20
+ * Blocks currently spanning the full row width. Tagged with
21
+ * `data-juo-grid-full-width` so the block wrapper chrome can show the "fill"
22
+ * toggle as active.
23
+ */
24
+ fullWidthBlockIds?: ReadonlySet<string>;
25
+ };
26
+ export type GridLayoutInputs = GridLayoutTags & {
27
+ scopeId: string;
28
+ css: string;
29
+ items: GridLayoutItem[];
30
+ };
31
+ /**
32
+ * Assemble a CSS-Grid layout inside `host`:
33
+ * - host becomes the container-query container (container-type: inline-size)
34
+ * - a <style> child carries the scoped stylesheet
35
+ * - an inner [data-juo-layout] grid element holds the block items
36
+ * - each item element is tagged with data-block-id so projectToCss's
37
+ * `${scope} > [data-block-id]` rules match
38
+ *
39
+ * Replaces the host's children with [styleEl, gridEl]. The host/grid split is
40
+ * required because an element cannot be matched by its own @container query:
41
+ * the host hosts the container-query context; the inner grid (a descendant)
42
+ * is what the @container rules target.
43
+ */
44
+ export declare function applyGridLayout(host: HTMLElement, inputs: GridLayoutInputs): void;
45
+ /** Revert the container-query containment applied by applyGridLayout. */
46
+ export declare function clearGridLayout(host: HTMLElement): void;
47
+ //# sourceMappingURL=layout-grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-grid.d.ts","sourceRoot":"","sources":["../../src/web-components/layout-grid.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAEvE,uEAAuE;AACvE,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;OAIG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB,CAAC;AAqBF;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAgBjF;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAEvD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=layout-grid.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-grid.test.d.ts","sourceRoot":"","sources":["../../src/web-components/layout-grid.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ import { GridRect, LayoutDocument } from '../layout';
2
+ /**
3
+ * Bubbling, composed DOM CustomEvents an adapter fires on its host while the
4
+ * user is actively manipulating the layout (drag/resize). The morph controller
5
+ * listens for these to drive the idle-settle timer that morphs back to view
6
+ * mode. They are interaction-lifecycle signals only — NOT commit events
7
+ * (commits flow through `onChange`). Programmatic updates must NOT emit them.
8
+ */
9
+ export declare const LAYOUT_INTERACTION_START = "juo-layout-interaction-start";
10
+ export declare const LAYOUT_INTERACTION_END = "juo-layout-interaction-end";
11
+ /**
12
+ * Class the morph controller toggles on a `.grid-stack-item` to play a one-shot
13
+ * "pop toward the operator" animation when layout mode is entered from that
14
+ * block. The keyframes live in the adapter's injected stylesheet (same DOM root
15
+ * as the grid), so the class is shared between the two modules here.
16
+ */
17
+ export declare const LAYOUT_POP_CLASS = "juo-layout-pop";
18
+ /**
19
+ * Final rects emitted by a LayoutModeAdapter at gesture commit (drop /
20
+ * resize-stop). Commit-time ingestion only — no streaming positions.
21
+ */
22
+ export type LayoutModeRectsChange = {
23
+ rects: Record<string, GridRect>;
24
+ };
25
+ export type LayoutModeMountInputs = {
26
+ layout: LayoutDocument;
27
+ /** Render-ordered block ids that the host currently governs. */
28
+ blockIds: string[];
29
+ /**
30
+ * For each blockId, the HTMLElement ExtensionRoot already created for
31
+ * that block (in render order). Adapters MAY reuse / wrap / replace
32
+ * these. The spike GridStack adapter replaces them with simplified
33
+ * placeholder widgets and ignores these elements.
34
+ */
35
+ blockElements: Record<string, HTMLElement>;
36
+ /** Stable scope id for the host (same value Phase 3 uses for the CSS-grid scope). */
37
+ scopeId: string;
38
+ /** Called by the adapter on gesture completion. */
39
+ onChange: (event: LayoutModeRectsChange) => void;
40
+ };
41
+ export interface LayoutModeAdapter {
42
+ readonly id: string;
43
+ mount(host: HTMLElement, inputs: LayoutModeMountInputs): void;
44
+ unmount(host: HTMLElement): void;
45
+ /** Optional in-place update when the adapter is already mounted on `host`. */
46
+ update?(host: HTMLElement, inputs: LayoutModeMountInputs): void;
47
+ }
48
+ export declare function registerLayoutModeAdapter(adapter: LayoutModeAdapter): void;
49
+ export declare function getLayoutModeAdapter(): LayoutModeAdapter | null;
50
+ export declare function clearLayoutModeAdapter(): void;
51
+ //# sourceMappingURL=layout-mode-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-mode-adapter.d.ts","sourceRoot":"","sources":["../../src/web-components/layout-mode-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,iCAAiC,CAAC;AACvE,eAAO,MAAM,sBAAsB,+BAA+B,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,mBAAmB,CAAC;AAEjD;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,cAAc,CAAC;IACvB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,qFAAqF;IACrF,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,QAAQ,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAClD,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC9D,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,8EAA8E;IAC9E,MAAM,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACjE;AAID,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAE1E;AAED,wBAAgB,oBAAoB,IAAI,iBAAiB,GAAG,IAAI,CAE/D;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=layout-mode-adapter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-mode-adapter.test.d.ts","sourceRoot":"","sources":["../../src/web-components/layout-mode-adapter.test.ts"],"names":[],"mappings":""}
@@ -1,9 +1,98 @@
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 { z as injectContext, E, b as TranslationContext, M as ContextRoot } from "./juo-workflow-BlG9CcAG.js";
5
- import { E as ExtensionRoot, B as Block } from "./ExtensionRoot-2xTGTu3K.js";
6
- import { a as createEditorBridge, b as createFocusInlineTextMessage, d as createUpdateBlockTranslationMessage } from "./bridge-w5KQ-czl.js";
4
+ import { Q as injectContext, m as TranslationContext, a6 as ContextRoot } from "./css-runtime-DWytAzZ5.js";
5
+ import { V as ViewLayoutController, E as ExtensionRoot, B as Block } from "./ExtensionRoot-CRJx0Dtr.js";
6
+ import { canvasMode, getActiveSurfaceContext, emitLayoutSetRects, effect } from "@juo/blocks";
7
+ import { getLayoutModeAdapter } from "./layout-mode-adapter-BBd4JRQd.js";
8
+ import { c as createEditorBridge, d as createFocusInlineTextMessage, e as createUpdateBlockTranslationMessage } from "./bridge-D838SWmN.js";
9
+ import { i as initMorphController } from "./morph-Dj-xvrwt.js";
10
+ class EditorLayoutController {
11
+ constructor() {
12
+ __publicField(this, "currentAdapter", null);
13
+ __publicField(this, "view", new ViewLayoutController());
14
+ __publicField(this, "changeHandler", null);
15
+ }
16
+ readReactiveState() {
17
+ return { mode: canvasMode.value };
18
+ }
19
+ apply(host, inputs) {
20
+ const { extensionBlocks, children, layoutDoc, scopeId, reactive } = inputs;
21
+ const adapter = getLayoutModeAdapter();
22
+ const wantsAdapter = inputs.layoutEngineEnabled && host.hasAttribute("grid-layout") && layoutDoc != null && reactive.mode && adapter != null;
23
+ if (this.currentAdapter && this.currentAdapter !== adapter) {
24
+ this.unmountAdapter(host);
25
+ }
26
+ if (wantsAdapter) {
27
+ this.view.teardown(host);
28
+ const blockIds = extensionBlocks.map((block) => block.id);
29
+ const blockElements = {};
30
+ extensionBlocks.forEach((block, index) => {
31
+ blockElements[block.id] = children[index];
32
+ });
33
+ const adapterInputs = {
34
+ layout: layoutDoc,
35
+ blockIds,
36
+ blockElements,
37
+ scopeId,
38
+ onChange: this.handlerFor(host)
39
+ };
40
+ if (this.currentAdapter === adapter && adapter.update) {
41
+ adapter.update(host, adapterInputs);
42
+ } else {
43
+ this.unmountAdapter(host);
44
+ adapter.mount(host, adapterInputs);
45
+ this.currentAdapter = adapter;
46
+ }
47
+ return;
48
+ }
49
+ this.unmountAdapter(host);
50
+ this.view.apply(host, inputs);
51
+ }
52
+ teardown(host) {
53
+ this.unmountAdapter(host);
54
+ this.view.teardown(host);
55
+ }
56
+ /**
57
+ * Idempotently unmount the currently-mounted LayoutModeAdapter. Swallows
58
+ * secondary teardown errors so a broken adapter can't wedge rendering.
59
+ */
60
+ unmountAdapter(host) {
61
+ if (this.currentAdapter == null) return;
62
+ try {
63
+ this.currentAdapter.unmount(host);
64
+ } catch {
65
+ }
66
+ this.currentAdapter = null;
67
+ }
68
+ /**
69
+ * Stable commit-time rects handler bound to `host`'s surface. Cached so the
70
+ * adapter always receives the same callback reference (created once per
71
+ * controller/host, mirroring the previous per-element handler).
72
+ */
73
+ handlerFor(host) {
74
+ if (this.changeHandler == null) {
75
+ this.changeHandler = (event) => {
76
+ const surface = this.surfaceOf(host);
77
+ const ctx = getActiveSurfaceContext(surface);
78
+ if (ctx == null) {
79
+ return;
80
+ }
81
+ emitLayoutSetRects({ surface, id: ctx.id, rects: event.rects });
82
+ };
83
+ }
84
+ return this.changeHandler;
85
+ }
86
+ surfaceOf(host) {
87
+ return host.getAttribute("surface") === "overlay" ? "overlay" : "page";
88
+ }
89
+ }
90
+ class EditorExtensionRoot extends ExtensionRoot {
91
+ constructor() {
92
+ super();
93
+ this.layout = new EditorLayoutController();
94
+ }
95
+ }
7
96
  const _InlineText = class _InlineText extends HTMLElement {
8
97
  constructor() {
9
98
  super();
@@ -17,6 +106,10 @@ const _InlineText = class _InlineText extends HTMLElement {
17
106
  __publicField(this, "boundHandleClick", this.handleClick.bind(this));
18
107
  __publicField(this, "lastValue", null);
19
108
  __publicField(this, "dispose");
109
+ // One-time DOM/style setup guard — see initializeEditorMode. Persists across
110
+ // DOM moves so reconnecting (e.g. exiting layout mode) skips redundant,
111
+ // recalc-forcing style writes.
112
+ __publicField(this, "domInitialized", false);
20
113
  }
21
114
  static get observedAttributes() {
22
115
  return ["prop", "readonly"];
@@ -60,18 +153,21 @@ const _InlineText = class _InlineText extends HTMLElement {
60
153
  }
61
154
  initializeEditorMode() {
62
155
  this.editorBridge = createEditorBridge();
63
- this.contentEditable = "false";
64
- if (!this.isReadonly) {
65
- this.style.cursor = "text";
66
- this.style.borderRadius = "2px";
67
- this.style.outline = "0.5px solid transparent";
68
- this.style.outlineOffset = "2px";
69
- }
70
- if (!this.style.width) this.style.width = "100%";
71
- if (!this.style.overflowWrap) this.style.overflowWrap = "anywhere";
72
- if (!this.style.whiteSpace) this.style.whiteSpace = "pre-wrap";
73
- if (!this.isReadonly) {
74
- this.injectStyles();
156
+ if (!this.domInitialized) {
157
+ this.domInitialized = true;
158
+ this.contentEditable = "false";
159
+ if (!this.isReadonly) {
160
+ this.style.cursor = "text";
161
+ this.style.borderRadius = "2px";
162
+ this.style.outline = "0.5px solid transparent";
163
+ this.style.outlineOffset = "2px";
164
+ }
165
+ if (!this.style.width) this.style.width = "100%";
166
+ if (!this.style.overflowWrap) this.style.overflowWrap = "anywhere";
167
+ if (!this.style.whiteSpace) this.style.whiteSpace = "pre-wrap";
168
+ if (!this.isReadonly) {
169
+ this.injectStyles();
170
+ }
75
171
  }
76
172
  this.addEventListener("blur", this.boundHandleBlur);
77
173
  this.addEventListener("pointerdown", this.boundHandlePointerDown);
@@ -80,7 +176,7 @@ const _InlineText = class _InlineText extends HTMLElement {
80
176
  if (this.translationService && this.propName && this.blockType && this.blockId) {
81
177
  const key = this.propName;
82
178
  const fallbackText = this.textContent ?? "";
83
- this.dispose = E(() => {
179
+ this.dispose = effect(() => {
84
180
  const service = this.translationService;
85
181
  if (!service) return;
86
182
  void service.locale.value;
@@ -185,7 +281,7 @@ if (customElements.get("juo-context-root") == null) {
185
281
  customElements.define("juo-context-root", ContextRoot);
186
282
  }
187
283
  if (customElements.get("juo-extension-root") == null) {
188
- customElements.define("juo-extension-root", ExtensionRoot);
284
+ customElements.define("juo-extension-root", EditorExtensionRoot);
189
285
  }
190
286
  if (customElements.get("juo-block") == null) {
191
287
  customElements.define("juo-block", Block);
@@ -193,3 +289,15 @@ if (customElements.get("juo-block") == null) {
193
289
  if (customElements.get("juo-text") == null) {
194
290
  customElements.define("juo-text", InlineText);
195
291
  }
292
+ initMorphController();
293
+ void (async () => {
294
+ try {
295
+ const [{ createGridStackAdapter }, { registerLayoutModeAdapter }] = await Promise.all([
296
+ import("./gridstack-adapter-DreG3XnB.js"),
297
+ import("./layout-mode-adapter-BBd4JRQd.js")
298
+ ]);
299
+ registerLayoutModeAdapter(createGridStackAdapter());
300
+ } catch (error) {
301
+ console.error("[blocks] failed to register GridStack adapter:", error);
302
+ }
303
+ })();
@@ -1,8 +1,9 @@
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 { z as injectContext, b as TranslationContext, E, M as ContextRoot } from "./juo-workflow-BlG9CcAG.js";
5
- import { E as ExtensionRoot, B as Block } from "./ExtensionRoot-2xTGTu3K.js";
4
+ import { Q as injectContext, m as TranslationContext, a6 as ContextRoot } from "./css-runtime-DWytAzZ5.js";
5
+ import { E as ExtensionRoot, B as Block } from "./ExtensionRoot-CRJx0Dtr.js";
6
+ import { effect } from "@juo/blocks";
6
7
  class InlineText extends HTMLElement {
7
8
  constructor() {
8
9
  super(...arguments);
@@ -24,7 +25,7 @@ class InlineText extends HTMLElement {
24
25
  const blockId = (blockEl == null ? void 0 : blockEl.getAttribute("data-block-id")) ?? null;
25
26
  const service = injectContext(this, TranslationContext);
26
27
  const fallbackText = this.textContent ?? "";
27
- this.dispose = E(() => {
28
+ this.dispose = effect(() => {
28
29
  void service.locale.value;
29
30
  const resolved = service.resolve(blockType, blockId, key);
30
31
  const isMissing = resolved === key || this.hasAttribute("fallback-on-empty") && resolved.trim() === "";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@juo/blocks",
3
3
  "private": false,
4
- "version": "1.13.0",
4
+ "version": "1.14.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -18,7 +18,8 @@
18
18
  "vite": "5.4.21",
19
19
  "vite-plugin-dts": "4.5.4",
20
20
  "vitest": "3.2.4",
21
- "vue": "3.5.13"
21
+ "vue": "3.5.13",
22
+ "gridstack": "^11.5.1"
22
23
  },
23
24
  "exports": {
24
25
  ".": {
@@ -1,219 +0,0 @@
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) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { signal, effect, createBlockInstance } from "@juo/blocks";
5
- import { reportBlockWarning, reportBlockError } from "./observability.js";
6
- import { d, J as subscribeContext, T as ThemeStateContext, E, L as withWrapper, K as n, f as backfillInstanceDefaults, F as isStubDefinition, G as onRegisterBlock } from "./juo-workflow-BlG9CcAG.js";
7
- class Block extends HTMLElement {
8
- constructor() {
9
- super();
10
- /** @description The block name to render */
11
- __publicField(this, "name", signal(null));
12
- __publicField(this, "disposeEffect");
13
- }
14
- static get observedAttributes() {
15
- return ["name"];
16
- }
17
- connectedCallback() {
18
- this.name.value = this.getAttribute("name") ?? null;
19
- this.disposeEffect = effect(() => {
20
- this.renderBlock(this.name.value);
21
- });
22
- }
23
- attributeChangedCallback(name, oldValue, newValue) {
24
- if (name === "name" && oldValue !== newValue) {
25
- this.name.value = newValue ?? null;
26
- }
27
- }
28
- disconnectedCallback() {
29
- if (this.disposeEffect) {
30
- this.disposeEffect();
31
- this.disposeEffect = void 0;
32
- }
33
- }
34
- renderBlock(name) {
35
- if (name == null) {
36
- reportBlockWarning("'name' attribute is required on <juo-block>", {
37
- site: "web-components.Block.renderBlock"
38
- });
39
- this.replaceChildren();
40
- return;
41
- }
42
- const props = Object.fromEntries(
43
- Array.from(this.attributes).map((attr) => [attr.name, attr.value])
44
- );
45
- try {
46
- const block = createBlockInstance(name, { props });
47
- this.replaceChildren(block.definition.render(block));
48
- } catch (error) {
49
- reportBlockError(error, {
50
- site: "web-components.Block.renderBlock",
51
- block: { id: "(none)", type: name },
52
- keys: { props: Object.keys(props) }
53
- });
54
- this.replaceChildren();
55
- }
56
- }
57
- }
58
- class ExtensionRoot extends HTMLElement {
59
- constructor() {
60
- super();
61
- __publicField(this, "state", d(null));
62
- __publicField(this, "themeState", null);
63
- __publicField(this, "unsubscribeThemeContext");
64
- __publicField(this, "disposeEffect");
65
- __publicField(this, "__vueInstance", null);
66
- /**
67
- * Names of top-level slot children that resolved to a stub on the last
68
- * render pass — i.e. blocks whose definition hasn't been registered yet.
69
- * Rebuilt on each render and consulted from the registration listener so
70
- * we only retrigger when a block we're actually waiting on lands.
71
- *
72
- * Only top-level children are tracked — nested stubs inside a registered
73
- * parent's renderer aren't currently handled (rare in practice; revisit
74
- * if it shows up).
75
- */
76
- __publicField(this, "unresolvedNames", /* @__PURE__ */ new Set());
77
- __publicField(this, "unregisterListener");
78
- /**
79
- * Optional function to wrap each rendered block element.
80
- * Called with the rendered block HTMLElement, must return an HTMLElement.
81
- * When set, the wrapper sits between the editor wrapper (outer) and the actual block (inner).
82
- * Must be set before blocks are first rendered; changing it afterwards has no effect
83
- * on already-cached block wrappers.
84
- */
85
- __publicField(this, "blockWrapper", null);
86
- __publicField(this, "wrapperCache", /* @__PURE__ */ new WeakMap());
87
- }
88
- static get observedAttributes() {
89
- return ["name", "surface"];
90
- }
91
- withWrapper(block) {
92
- if (!this.wrapperCache.has(block)) {
93
- const blockWrapper = this.blockWrapper;
94
- const wrapper = withWrapper((block2) => {
95
- const rendered = block2.definition.render({ ...block2, __vueInstance: this.__vueInstance });
96
- return blockWrapper ? blockWrapper(rendered) : rendered;
97
- });
98
- this.wrapperCache.set(block, wrapper);
99
- }
100
- return this.wrapperCache.get(block)(block);
101
- }
102
- getSurface() {
103
- return this.getAttribute("surface") === "overlay" ? "overlay" : "page";
104
- }
105
- setStateFromThemeState(themeState) {
106
- const surface = this.getSurface();
107
- this.state.value = surface === "overlay" ? themeState.overlay : themeState.page;
108
- }
109
- connectedCallback() {
110
- this.state.value = null;
111
- this.themeState = null;
112
- this.style.display = "flex";
113
- this.style.flexDirection = "column";
114
- this.style.maxWidth = "100%";
115
- this.unsubscribeThemeContext = subscribeContext(
116
- this,
117
- ThemeStateContext,
118
- (contextValue) => {
119
- this.themeState = contextValue;
120
- this.setStateFromThemeState(contextValue);
121
- }
122
- );
123
- this.disposeEffect = E(() => {
124
- const state = this.state.value;
125
- if (state == null) {
126
- this.replaceChildren();
127
- return;
128
- }
129
- const name = this.getAttribute("name");
130
- if (name == null) {
131
- console.error("'name' attribute is required");
132
- this.replaceChildren();
133
- return;
134
- }
135
- const blocks = state.blocks.value;
136
- n(() => {
137
- var _a;
138
- let extensionBlocks = [];
139
- try {
140
- extensionBlocks = (((_a = blocks.at(0)) == null ? void 0 : _a.slots) ?? {})[name] ?? [];
141
- for (const block of extensionBlocks) {
142
- if (block != null && typeof block === "object") {
143
- backfillInstanceDefaults(block);
144
- }
145
- }
146
- const children = extensionBlocks.map(
147
- (block) => this.withWrapper(block)
148
- );
149
- this.replaceChildren(...children);
150
- } catch (error) {
151
- reportBlockError(error, {
152
- site: "web-components.ExtensionRoot.effect",
153
- extra: {
154
- surface: this.getSurface(),
155
- name: this.getAttribute("name") ?? "(none)"
156
- }
157
- });
158
- this.replaceChildren();
159
- extensionBlocks = [];
160
- }
161
- this.unresolvedNames.clear();
162
- for (const block of extensionBlocks) {
163
- if (block != null && typeof block === "object" && isStubDefinition(block.definition)) {
164
- this.unresolvedNames.add(block.type);
165
- }
166
- }
167
- if (this.unresolvedNames.size > 0 && !this.unregisterListener) {
168
- this.unregisterListener = onRegisterBlock((name2) => {
169
- var _a2;
170
- if (!this.unresolvedNames.has(name2)) return;
171
- const stateRef = this.state.value;
172
- if (stateRef == null) return;
173
- const surfaceBlocks = stateRef.blocks.value;
174
- const slotName = this.getAttribute("name");
175
- if (slotName != null) {
176
- const children = (((_a2 = surfaceBlocks.at(0)) == null ? void 0 : _a2.slots) ?? {})[slotName] ?? [];
177
- for (const child of children) {
178
- if (child != null && typeof child === "object" && child.type === name2) {
179
- backfillInstanceDefaults(child);
180
- }
181
- }
182
- }
183
- this.state.value = { ...stateRef };
184
- });
185
- }
186
- });
187
- });
188
- }
189
- attributeChangedCallback(name, oldValue, newValue) {
190
- if ((name === "name" || name === "surface") && oldValue !== newValue && this.state.value) {
191
- if (name === "surface") {
192
- if (this.themeState) {
193
- this.setStateFromThemeState(this.themeState);
194
- return;
195
- }
196
- }
197
- this.state.value = { ...this.state.value };
198
- }
199
- }
200
- disconnectedCallback() {
201
- if (this.unsubscribeThemeContext) {
202
- this.unsubscribeThemeContext();
203
- this.unsubscribeThemeContext = void 0;
204
- }
205
- if (this.disposeEffect) {
206
- this.disposeEffect();
207
- this.disposeEffect = void 0;
208
- }
209
- if (this.unregisterListener) {
210
- this.unregisterListener();
211
- this.unregisterListener = void 0;
212
- }
213
- this.unresolvedNames.clear();
214
- }
215
- }
216
- export {
217
- Block as B,
218
- ExtensionRoot as E
219
- };