@jxsuite/studio 0.10.2 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -0
- package/dist/studio.js +5114 -3424
- package/dist/studio.js.map +65 -49
- package/package.json +6 -3
- package/src/browse/browse.js +27 -3
- package/src/canvas/canvas-diff.js +184 -0
- package/src/canvas/canvas-helpers.js +10 -14
- package/src/canvas/canvas-live-render.js +136 -17
- package/src/canvas/canvas-render.js +154 -21
- package/src/canvas/canvas-utils.js +21 -23
- package/src/editor/component-inline-edit.js +54 -41
- package/src/editor/content-inline-edit.js +46 -47
- package/src/editor/context-menu.js +63 -39
- package/src/editor/convert-to-component.js +11 -14
- package/src/editor/insertion-helper.js +8 -10
- package/src/editor/shortcuts.js +69 -39
- package/src/files/components.js +15 -4
- package/src/files/files.js +72 -24
- package/src/panels/activity-bar.js +29 -7
- package/src/panels/block-action-bar.js +104 -80
- package/src/panels/canvas-dnd.js +132 -50
- package/src/panels/dnd.js +32 -28
- package/src/panels/editors.js +7 -14
- package/src/panels/elements-panel.js +9 -3
- package/src/panels/events-panel.js +44 -39
- package/src/panels/git-panel.js +45 -3
- package/src/panels/layers-panel.js +16 -11
- package/src/panels/left-panel.js +108 -43
- package/src/panels/overlays.js +97 -35
- package/src/panels/panel-events.js +18 -11
- package/src/panels/properties-panel.js +467 -98
- package/src/panels/right-panel.js +85 -37
- package/src/panels/shared.js +0 -22
- package/src/panels/signals-panel.js +125 -54
- package/src/panels/statusbar.js +23 -8
- package/src/panels/style-inputs.js +4 -2
- package/src/panels/style-panel.js +128 -105
- package/src/panels/stylebook-panel.js +42 -17
- package/src/panels/tab-strip.js +124 -0
- package/src/panels/toolbar.js +39 -9
- package/src/reactivity.js +28 -0
- package/src/settings/content-types-editor.js +78 -8
- package/src/settings/defs-editor.js +56 -7
- package/src/settings/schema-field-ui.js +99 -11
- package/src/site-context.js +105 -0
- package/src/state.js +0 -456
- package/src/store.js +105 -124
- package/src/studio.js +112 -121
- package/src/tabs/tab.js +153 -0
- package/src/tabs/transact.js +406 -0
- package/src/ui/spectrum.js +2 -0
- package/src/view.js +3 -0
- package/src/workspace/workspace.js +89 -0
package/src/panels/left-panel.js
CHANGED
|
@@ -7,40 +7,94 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { html, render as litRender, nothing } from "lit-html";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
applyMutation,
|
|
16
|
-
updateFrontmatter,
|
|
17
|
-
} from "../store.js";
|
|
18
|
-
import { ensureLitState } from "./shared.js";
|
|
10
|
+
import { leftPanel, updateSession } from "../store.js";
|
|
11
|
+
import { effect, effectScope } from "../reactivity.js";
|
|
12
|
+
import { activeTab } from "../workspace/workspace.js";
|
|
13
|
+
import { transact, mutateUpdateFrontmatter } from "../tabs/transact.js";
|
|
14
|
+
|
|
19
15
|
import { renderLayersTemplate } from "./layers-panel.js";
|
|
20
16
|
import { renderStylebookLayersTemplate } from "./stylebook-layers-panel.js";
|
|
21
17
|
import { renderElementsTemplate } from "./elements-panel.js";
|
|
22
18
|
import { selectStylebookTag, stylebookMeta } from "./stylebook-panel.js";
|
|
23
19
|
|
|
24
|
-
/** @
|
|
20
|
+
/** @typedef {import("lit-html").TemplateResult} TemplateResult */
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {{
|
|
24
|
+
* getCanvasMode: () => string;
|
|
25
|
+
* setCanvasMode: (mode: string) => void;
|
|
26
|
+
* renderImportsTemplate: (...args: any[]) => TemplateResult;
|
|
27
|
+
* renderFilesTemplate: () => TemplateResult;
|
|
28
|
+
* renderSignalsTemplate: (...args: any[]) => TemplateResult;
|
|
29
|
+
* renderDataExplorerTemplate: (...args: any[]) => TemplateResult;
|
|
30
|
+
* renderHeadTemplate: (...args: any[]) => TemplateResult;
|
|
31
|
+
* renderGitPanel: (...args: any[]) => TemplateResult;
|
|
32
|
+
* renderCanvas: () => void;
|
|
33
|
+
* defCategory: (tag: string) => string;
|
|
34
|
+
* defBadgeLabel: (tag: string) => string;
|
|
35
|
+
* navigateToComponent: (path: string) => void;
|
|
36
|
+
* webdata: object;
|
|
37
|
+
* defaultDef: (tag: string) => object;
|
|
38
|
+
* registerLayersDnD: () => void;
|
|
39
|
+
* registerElementsDnD: () => void;
|
|
40
|
+
* registerComponentsDnD: () => void;
|
|
41
|
+
* setupTreeKeyboard: (tree: HTMLElement) => void;
|
|
42
|
+
* }} LeftPanelCtx
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/** @type {LeftPanelCtx | null} */
|
|
25
46
|
let _ctx = null;
|
|
26
47
|
|
|
48
|
+
/** @type {import("@vue/reactivity").EffectScope | null} */
|
|
49
|
+
let _scope = null;
|
|
50
|
+
|
|
51
|
+
let _rendering = false;
|
|
52
|
+
let _scheduled = false;
|
|
53
|
+
|
|
27
54
|
/**
|
|
28
55
|
* Mount the left panel orchestrator.
|
|
29
56
|
*
|
|
30
|
-
* @param {
|
|
57
|
+
* @param {LeftPanelCtx} ctx
|
|
31
58
|
*/
|
|
32
59
|
export function mount(ctx) {
|
|
33
60
|
_ctx = ctx;
|
|
61
|
+
_scope = effectScope();
|
|
62
|
+
_scope.run(() => {
|
|
63
|
+
effect(() => {
|
|
64
|
+
const tab = activeTab.value;
|
|
65
|
+
if (!tab) return;
|
|
66
|
+
// Track properties the left panel reads
|
|
67
|
+
void tab.doc.document;
|
|
68
|
+
void tab.doc.mode;
|
|
69
|
+
void tab.session.selection;
|
|
70
|
+
void tab.session.ui.leftTab;
|
|
71
|
+
void tab.session.ui.settingsTab;
|
|
72
|
+
render();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
34
75
|
}
|
|
35
76
|
|
|
36
77
|
export function unmount() {
|
|
78
|
+
_scope?.stop();
|
|
79
|
+
_scope = null;
|
|
37
80
|
_ctx = null;
|
|
38
81
|
}
|
|
39
82
|
|
|
40
83
|
export function render() {
|
|
41
84
|
if (!_ctx) return;
|
|
85
|
+
if (_rendering) return;
|
|
86
|
+
if (!_scheduled) {
|
|
87
|
+
_scheduled = true;
|
|
88
|
+
queueMicrotask(_flush);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function _flush() {
|
|
93
|
+
_scheduled = false;
|
|
94
|
+
if (!_ctx) return;
|
|
95
|
+
if (_rendering) return;
|
|
96
|
+
_rendering = true;
|
|
42
97
|
try {
|
|
43
|
-
ensureLitState(leftPanel);
|
|
44
98
|
_render();
|
|
45
99
|
} catch (e) {
|
|
46
100
|
console.error("left-panel render error:", e);
|
|
@@ -52,90 +106,101 @@ export function render() {
|
|
|
52
106
|
} catch (e2) {
|
|
53
107
|
console.error("left-panel retry failed:", e2);
|
|
54
108
|
}
|
|
109
|
+
} finally {
|
|
110
|
+
_rendering = false;
|
|
55
111
|
}
|
|
56
112
|
}
|
|
57
113
|
|
|
58
114
|
function _render() {
|
|
59
|
-
const
|
|
115
|
+
const ctx = /** @type {LeftPanelCtx} */ (_ctx);
|
|
116
|
+
const aTab = activeTab.value;
|
|
117
|
+
if (!aTab) return;
|
|
118
|
+
const S = /** @type {any} */ ({
|
|
119
|
+
ui: aTab.session.ui,
|
|
120
|
+
document: aTab.doc.document,
|
|
121
|
+
mode: aTab.doc.mode,
|
|
122
|
+
selection: aTab.session.selection,
|
|
123
|
+
});
|
|
60
124
|
const tab = S.ui.leftTab;
|
|
61
125
|
|
|
62
|
-
/** @type {
|
|
126
|
+
/** @type {TemplateResult | typeof nothing} */
|
|
63
127
|
let content;
|
|
64
128
|
if (tab === "layers")
|
|
65
129
|
content =
|
|
66
|
-
|
|
130
|
+
ctx.getCanvasMode() === "settings"
|
|
67
131
|
? renderStylebookLayersTemplate({
|
|
68
132
|
selectStylebookTag,
|
|
69
133
|
stylebookMeta,
|
|
70
134
|
})
|
|
71
135
|
: renderLayersTemplate({
|
|
72
|
-
navigateToComponent:
|
|
136
|
+
navigateToComponent: ctx.navigateToComponent,
|
|
73
137
|
rerender: render,
|
|
74
138
|
});
|
|
75
139
|
else if (tab === "imports")
|
|
76
|
-
content =
|
|
140
|
+
content = ctx.renderImportsTemplate({
|
|
77
141
|
renderLeftPanel: render,
|
|
78
142
|
documentPath: S.documentPath,
|
|
79
143
|
documentElements: S.document.$elements || [],
|
|
80
|
-
applyMutation: (/** @type {
|
|
81
|
-
|
|
144
|
+
applyMutation: (/** @type {(doc: object) => void} */ fn) => {
|
|
145
|
+
transact(activeTab.value, fn);
|
|
82
146
|
},
|
|
83
147
|
});
|
|
84
|
-
else if (tab === "files") content =
|
|
148
|
+
else if (tab === "files") content = ctx.renderFilesTemplate();
|
|
85
149
|
else if (tab === "blocks")
|
|
86
150
|
content = renderElementsTemplate({
|
|
87
|
-
webdata:
|
|
88
|
-
defaultDef:
|
|
151
|
+
webdata: ctx.webdata,
|
|
152
|
+
defaultDef: ctx.defaultDef,
|
|
89
153
|
rerender: render,
|
|
90
154
|
});
|
|
91
155
|
else if (tab === "state")
|
|
92
|
-
content =
|
|
156
|
+
content = ctx.renderSignalsTemplate(S, {
|
|
93
157
|
renderLeftPanel: render,
|
|
94
|
-
renderCanvas:
|
|
158
|
+
renderCanvas: ctx.renderCanvas,
|
|
95
159
|
updateSession,
|
|
96
160
|
});
|
|
97
161
|
else if (tab === "data")
|
|
98
|
-
content =
|
|
99
|
-
renderCanvas:
|
|
162
|
+
content = ctx.renderDataExplorerTemplate(S.document.state, S.canvas?.scope ?? null, {
|
|
163
|
+
renderCanvas: ctx.renderCanvas,
|
|
100
164
|
renderLeftPanel: render,
|
|
101
|
-
defCategory:
|
|
102
|
-
defBadgeLabel:
|
|
165
|
+
defCategory: ctx.defCategory,
|
|
166
|
+
defBadgeLabel: ctx.defBadgeLabel,
|
|
103
167
|
});
|
|
104
168
|
else if (tab === "head") {
|
|
105
169
|
const isContent = S.mode === "content";
|
|
106
170
|
const fm = S.content?.frontmatter ?? {};
|
|
107
171
|
const headDoc = isContent ? { ...S.document, title: fm.title, $head: fm.$head } : S.document;
|
|
108
|
-
content =
|
|
172
|
+
content = ctx.renderHeadTemplate({
|
|
109
173
|
document: headDoc,
|
|
110
174
|
applyMutation: isContent
|
|
111
|
-
? (/** @type {
|
|
175
|
+
? (/** @type {(doc: object) => void} */ fn) => {
|
|
176
|
+
const tab = activeTab.value;
|
|
177
|
+
const fm = /** @type {Record<string, any>} */ (tab.doc.content?.frontmatter ?? {});
|
|
112
178
|
const tmp = { title: fm.title, $head: fm.$head ? [...fm.$head] : undefined };
|
|
113
179
|
fn(tmp);
|
|
114
|
-
|
|
115
|
-
|
|
180
|
+
if (tmp.title !== fm.title)
|
|
181
|
+
mutateUpdateFrontmatter(tab, "title", /** @type {any} */ (tmp.title));
|
|
116
182
|
const newHead = tmp.$head && tmp.$head.length > 0 ? tmp.$head : undefined;
|
|
117
|
-
|
|
118
|
-
update(s);
|
|
183
|
+
mutateUpdateFrontmatter(tab, "$head", newHead);
|
|
119
184
|
}
|
|
120
|
-
: (/** @type {
|
|
121
|
-
|
|
185
|
+
: (/** @type {(doc: object) => void} */ fn) => {
|
|
186
|
+
transact(activeTab.value, fn);
|
|
122
187
|
},
|
|
123
188
|
renderLeftPanel: render,
|
|
124
189
|
});
|
|
125
|
-
} else if (tab === "git") content =
|
|
190
|
+
} else if (tab === "git") content = ctx.renderGitPanel(S, ctx);
|
|
126
191
|
else content = nothing;
|
|
127
192
|
|
|
128
|
-
litRender(html`<div class="panel-body">${content}</div>`,
|
|
193
|
+
litRender(html`<div class="panel-body">${content}</div>`, leftPanel);
|
|
129
194
|
|
|
130
195
|
// Post-render side effects
|
|
131
|
-
if (tab === "layers" &&
|
|
196
|
+
if (tab === "layers" && ctx.getCanvasMode() !== "settings") ctx.registerLayersDnD();
|
|
132
197
|
else if (tab === "imports") {
|
|
133
198
|
/* no post-render DnD needed */
|
|
134
199
|
} else if (tab === "blocks") {
|
|
135
|
-
|
|
136
|
-
|
|
200
|
+
ctx.registerElementsDnD();
|
|
201
|
+
ctx.registerComponentsDnD();
|
|
137
202
|
} else if (tab === "files") {
|
|
138
|
-
const tree = /** @type {
|
|
139
|
-
if (tree)
|
|
203
|
+
const tree = /** @type {HTMLElement | null} */ (leftPanel.querySelector(".file-tree"));
|
|
204
|
+
if (tree) ctx.setupTreeKeyboard(tree);
|
|
140
205
|
}
|
|
141
206
|
}
|
package/src/panels/overlays.js
CHANGED
|
@@ -4,41 +4,83 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { html, render as litRender, nothing } from "lit-html";
|
|
7
|
-
import {
|
|
7
|
+
import { canvasPanels, pathsEqual } from "../store.js";
|
|
8
|
+
import { effect, effectScope } from "../reactivity.js";
|
|
9
|
+
import { activeTab } from "../workspace/workspace.js";
|
|
8
10
|
import { view } from "../view.js";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
getActivePanel,
|
|
12
|
-
overlayBoxDescriptor,
|
|
13
|
-
} from "../canvas/canvas-helpers.js";
|
|
11
|
+
import { findCanvasElement, getActivePanel, effectiveZoom } from "../canvas/canvas-helpers.js";
|
|
12
|
+
import { layoutElements } from "../canvas/canvas-live-render.js";
|
|
14
13
|
|
|
15
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {{
|
|
16
|
+
* cls: string;
|
|
17
|
+
* top: string;
|
|
18
|
+
* left: string;
|
|
19
|
+
* width: string;
|
|
20
|
+
* height: string;
|
|
21
|
+
* border?: string;
|
|
22
|
+
* isLayout?: boolean;
|
|
23
|
+
* }} OverlayBox
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {{
|
|
28
|
+
* getCanvasMode: () => string;
|
|
29
|
+
* isEditing: () => boolean;
|
|
30
|
+
* renderBlockActionBar: () => void;
|
|
31
|
+
* }} OverlaysCtx
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/** @type {OverlaysCtx | null} */
|
|
16
35
|
let _ctx = null;
|
|
17
36
|
|
|
18
|
-
/** @type {(
|
|
19
|
-
let
|
|
37
|
+
/** @type {import("@vue/reactivity").EffectScope | null} */
|
|
38
|
+
let _scope = null;
|
|
39
|
+
|
|
40
|
+
let _scheduled = false;
|
|
20
41
|
|
|
21
42
|
/**
|
|
22
43
|
* Mount the overlays panel.
|
|
23
44
|
*
|
|
24
|
-
* @param {
|
|
45
|
+
* @param {OverlaysCtx} ctx
|
|
25
46
|
*/
|
|
26
47
|
export function mount(ctx) {
|
|
27
48
|
_ctx = ctx;
|
|
28
|
-
|
|
29
|
-
|
|
49
|
+
_scope = effectScope();
|
|
50
|
+
_scope.run(() => {
|
|
51
|
+
effect(() => {
|
|
52
|
+
const tab = activeTab.value;
|
|
53
|
+
if (!tab) return;
|
|
54
|
+
// Track selection, hover, and mode
|
|
55
|
+
void tab.session.selection;
|
|
56
|
+
void tab.session.hover;
|
|
57
|
+
void tab.doc.mode;
|
|
58
|
+
render();
|
|
59
|
+
});
|
|
30
60
|
});
|
|
31
61
|
}
|
|
32
62
|
|
|
33
63
|
export function unmount() {
|
|
34
|
-
|
|
35
|
-
|
|
64
|
+
_scope?.stop();
|
|
65
|
+
_scope = null;
|
|
36
66
|
_ctx = null;
|
|
37
67
|
}
|
|
38
68
|
|
|
39
69
|
export function render() {
|
|
40
70
|
if (!_ctx) return;
|
|
41
|
-
|
|
71
|
+
if (!_scheduled) {
|
|
72
|
+
_scheduled = true;
|
|
73
|
+
queueMicrotask(_flush);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function _flush() {
|
|
78
|
+
_scheduled = false;
|
|
79
|
+
if (!_ctx) return;
|
|
80
|
+
const tab = activeTab.value;
|
|
81
|
+
if (!tab) return;
|
|
82
|
+
const { selection, hover } = tab.session;
|
|
83
|
+
const { stylebookTab } = tab.session.ui;
|
|
42
84
|
const canvasMode = _ctx.getCanvasMode();
|
|
43
85
|
|
|
44
86
|
if (canvasMode !== "design" && canvasMode !== "edit" && canvasMode !== "settings") {
|
|
@@ -54,7 +96,7 @@ export function render() {
|
|
|
54
96
|
}
|
|
55
97
|
|
|
56
98
|
if (canvasMode === "settings") {
|
|
57
|
-
const enable =
|
|
99
|
+
const enable = stylebookTab === "elements";
|
|
58
100
|
for (const p of canvasPanels) {
|
|
59
101
|
p.overlayClk.style.pointerEvents = enable ? "" : "none";
|
|
60
102
|
}
|
|
@@ -71,28 +113,46 @@ export function render() {
|
|
|
71
113
|
}
|
|
72
114
|
|
|
73
115
|
for (const p of canvasPanels) {
|
|
74
|
-
/**
|
|
75
|
-
* @type {{
|
|
76
|
-
* cls: string;
|
|
77
|
-
* top: string;
|
|
78
|
-
* left: string;
|
|
79
|
-
* width: string;
|
|
80
|
-
* height: string;
|
|
81
|
-
* border?: string;
|
|
82
|
-
* }[]}
|
|
83
|
-
*/
|
|
116
|
+
/** @type {OverlayBox[]} */
|
|
84
117
|
const boxes = [];
|
|
85
118
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
119
|
+
// Batch layout reads: read viewport geometry once per panel
|
|
120
|
+
const vpRect = p.viewport.getBoundingClientRect();
|
|
121
|
+
const scrollTop = p.viewport.scrollTop;
|
|
122
|
+
const scrollLeft = p.viewport.scrollLeft;
|
|
123
|
+
const scale = effectiveZoom();
|
|
124
|
+
|
|
125
|
+
if (hover && !pathsEqual(hover, selection)) {
|
|
126
|
+
const el = findCanvasElement(hover, p.canvas);
|
|
127
|
+
if (el) {
|
|
128
|
+
const elRect = el.getBoundingClientRect();
|
|
129
|
+
/** @type {OverlayBox} */
|
|
130
|
+
const desc = {
|
|
131
|
+
cls: "overlay-box overlay-hover",
|
|
132
|
+
top: `${(elRect.top - vpRect.top + scrollTop) / scale}px`,
|
|
133
|
+
left: `${(elRect.left - vpRect.left + scrollLeft) / scale}px`,
|
|
134
|
+
width: `${elRect.width / scale}px`,
|
|
135
|
+
height: `${elRect.height / scale}px`,
|
|
136
|
+
};
|
|
137
|
+
if (layoutElements.has(el)) desc.isLayout = true;
|
|
138
|
+
boxes.push(desc);
|
|
139
|
+
}
|
|
89
140
|
}
|
|
90
141
|
|
|
91
|
-
if (
|
|
92
|
-
const el = findCanvasElement(
|
|
142
|
+
if (selection && p === getActivePanel()) {
|
|
143
|
+
const el = findCanvasElement(selection, p.canvas);
|
|
93
144
|
if (el) {
|
|
94
|
-
const
|
|
95
|
-
|
|
145
|
+
const elRect = el.getBoundingClientRect();
|
|
146
|
+
/** @type {OverlayBox} */
|
|
147
|
+
const desc = {
|
|
148
|
+
cls: "overlay-box overlay-selection",
|
|
149
|
+
top: `${(elRect.top - vpRect.top + scrollTop) / scale}px`,
|
|
150
|
+
left: `${(elRect.left - vpRect.left + scrollLeft) / scale}px`,
|
|
151
|
+
width: `${elRect.width / scale}px`,
|
|
152
|
+
height: `${elRect.height / scale}px`,
|
|
153
|
+
};
|
|
154
|
+
if (view.componentInlineEdit || _ctx.isEditing()) desc.border = "none";
|
|
155
|
+
if (layoutElements.has(el)) desc.isLayout = true;
|
|
96
156
|
boxes.push(desc);
|
|
97
157
|
}
|
|
98
158
|
}
|
|
@@ -103,11 +163,13 @@ export function render() {
|
|
|
103
163
|
${boxes.map(
|
|
104
164
|
(b) => html`
|
|
105
165
|
<div
|
|
106
|
-
class
|
|
166
|
+
class="${b.cls}${b.isLayout ? " overlay-layout" : ""}"
|
|
107
167
|
style="top:${b.top};left:${b.left};width:${b.width};height:${b.height}${b.border
|
|
108
168
|
? `;border:${b.border}`
|
|
109
169
|
: ""}"
|
|
110
|
-
|
|
170
|
+
>
|
|
171
|
+
${b.isLayout ? html`<span class="overlay-layout-badge">Layout</span>` : nothing}
|
|
172
|
+
</div>
|
|
111
173
|
`,
|
|
112
174
|
)}
|
|
113
175
|
`,
|
|
@@ -5,24 +5,23 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
|
-
update,
|
|
9
8
|
updateUi,
|
|
10
|
-
selectNode,
|
|
11
9
|
hoverNode,
|
|
12
10
|
elToPath,
|
|
13
11
|
pathsEqual,
|
|
14
|
-
insertNode,
|
|
15
12
|
parentElementPath,
|
|
16
13
|
childIndex,
|
|
17
14
|
getNodeAtPath,
|
|
18
15
|
renderOnly,
|
|
19
16
|
} from "../store.js";
|
|
17
|
+
import { activeTab } from "../workspace/workspace.js";
|
|
20
18
|
import { view } from "../view.js";
|
|
21
19
|
import { stopEditing, isEditing, isEditableBlock } from "../editor/inline-edit.js";
|
|
22
20
|
import { showContextMenu } from "../editor/context-menu.js";
|
|
23
21
|
import * as insertionHelper from "../editor/insertion-helper.js";
|
|
24
22
|
import { defaultDef } from "../panels/shared.js";
|
|
25
23
|
import { bubbleInlinePath, findCanvasElement, effectiveZoom } from "../canvas/canvas-helpers.js";
|
|
24
|
+
import { layoutElements, activeLayoutPath } from "../canvas/canvas-live-render.js";
|
|
26
25
|
|
|
27
26
|
/** @type {any} */
|
|
28
27
|
let _ctx = null;
|
|
@@ -87,6 +86,15 @@ export function registerPanelEvents(panel) {
|
|
|
87
86
|
|
|
88
87
|
for (const el of elements) {
|
|
89
88
|
if (canvas.contains(el) && el !== canvas) {
|
|
89
|
+
// Layout element clicked — show layout info instead of selecting in page doc
|
|
90
|
+
if (layoutElements.has(el)) {
|
|
91
|
+
view.layoutSelection = { el, layoutPath: activeLayoutPath };
|
|
92
|
+
activeTab.value.session.selection = null;
|
|
93
|
+
renderOnly("rightPanel");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
view.layoutSelection = null;
|
|
97
|
+
|
|
90
98
|
const originalPath = elToPath.get(el);
|
|
91
99
|
if (originalPath) {
|
|
92
100
|
let path = bubbleInlinePath(S.document, originalPath);
|
|
@@ -107,16 +115,18 @@ export function registerPanelEvents(panel) {
|
|
|
107
115
|
|
|
108
116
|
if (canvasMode === "design" && S.mode !== "content") {
|
|
109
117
|
updateUi("pendingInlineEdit", { path, mediaName });
|
|
110
|
-
|
|
118
|
+
activeTab.value.session.ui.activeMedia = newMedia;
|
|
119
|
+
activeTab.value.session.selection = path;
|
|
111
120
|
return;
|
|
112
121
|
}
|
|
113
122
|
|
|
114
|
-
|
|
123
|
+
activeTab.value.session.ui.activeMedia = newMedia;
|
|
124
|
+
activeTab.value.session.selection = path;
|
|
115
125
|
return;
|
|
116
126
|
}
|
|
117
127
|
}
|
|
118
128
|
}
|
|
119
|
-
|
|
129
|
+
activeTab.value.session.selection = null;
|
|
120
130
|
},
|
|
121
131
|
opts,
|
|
122
132
|
);
|
|
@@ -151,8 +161,8 @@ export function registerPanelEvents(panel) {
|
|
|
151
161
|
const resolvedEl = path === originalPath ? el : findCanvasElement(path, canvas) || el;
|
|
152
162
|
if (isEditableBlock(resolvedEl)) {
|
|
153
163
|
const newMedia = mediaName === "base" ? null : (mediaName ?? null);
|
|
154
|
-
|
|
155
|
-
|
|
164
|
+
activeTab.value.session.ui.activeMedia = newMedia;
|
|
165
|
+
activeTab.value.session.selection = path;
|
|
156
166
|
_ctx.enterInlineEdit(resolvedEl, path);
|
|
157
167
|
return;
|
|
158
168
|
}
|
|
@@ -243,13 +253,10 @@ export function registerPanelEvents(panel) {
|
|
|
243
253
|
|
|
244
254
|
insertionHelper.mount({
|
|
245
255
|
getState: _ctx.getState,
|
|
246
|
-
update,
|
|
247
256
|
getCanvasMode: _ctx.getCanvasMode,
|
|
248
257
|
withPanelPointerEvents,
|
|
249
258
|
effectiveZoom: effectiveZoom,
|
|
250
259
|
defaultDef,
|
|
251
|
-
insertNode,
|
|
252
|
-
selectNode,
|
|
253
260
|
parentElementPath,
|
|
254
261
|
childIndex,
|
|
255
262
|
getNodeAtPath,
|