@jxsuite/studio 0.11.0 → 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/dist/studio.js +4248 -3412
- package/dist/studio.js.map +49 -43
- package/package.json +5 -3
- package/src/canvas/canvas-diff.js +184 -0
- package/src/canvas/canvas-helpers.js +10 -14
- package/src/canvas/canvas-live-render.js +3 -2
- package/src/canvas/canvas-render.js +152 -20
- 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/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 +91 -41
- package/src/panels/panel-events.js +9 -12
- package/src/panels/properties-panel.js +179 -104
- 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 +11 -15
- 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 +56 -7
- package/src/settings/defs-editor.js +56 -7
- package/src/settings/schema-field-ui.js +60 -25
- package/src/state.js +0 -456
- package/src/store.js +97 -124
- package/src/studio.js +112 -121
- package/src/tabs/tab.js +153 -0
- package/src/tabs/transact.js +406 -0
- package/src/workspace/workspace.js +89 -0
package/src/panels/overlays.js
CHANGED
|
@@ -4,42 +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
|
-
findCanvasElement,
|
|
11
|
-
getActivePanel,
|
|
12
|
-
overlayBoxDescriptor,
|
|
13
|
-
} from "../canvas/canvas-helpers.js";
|
|
11
|
+
import { findCanvasElement, getActivePanel, effectiveZoom } from "../canvas/canvas-helpers.js";
|
|
14
12
|
import { layoutElements } from "../canvas/canvas-live-render.js";
|
|
15
13
|
|
|
16
|
-
/**
|
|
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} */
|
|
17
35
|
let _ctx = null;
|
|
18
36
|
|
|
19
|
-
/** @type {(
|
|
20
|
-
let
|
|
37
|
+
/** @type {import("@vue/reactivity").EffectScope | null} */
|
|
38
|
+
let _scope = null;
|
|
39
|
+
|
|
40
|
+
let _scheduled = false;
|
|
21
41
|
|
|
22
42
|
/**
|
|
23
43
|
* Mount the overlays panel.
|
|
24
44
|
*
|
|
25
|
-
* @param {
|
|
45
|
+
* @param {OverlaysCtx} ctx
|
|
26
46
|
*/
|
|
27
47
|
export function mount(ctx) {
|
|
28
48
|
_ctx = ctx;
|
|
29
|
-
|
|
30
|
-
|
|
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
|
+
});
|
|
31
60
|
});
|
|
32
61
|
}
|
|
33
62
|
|
|
34
63
|
export function unmount() {
|
|
35
|
-
|
|
36
|
-
|
|
64
|
+
_scope?.stop();
|
|
65
|
+
_scope = null;
|
|
37
66
|
_ctx = null;
|
|
38
67
|
}
|
|
39
68
|
|
|
40
69
|
export function render() {
|
|
41
70
|
if (!_ctx) return;
|
|
42
|
-
|
|
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;
|
|
43
84
|
const canvasMode = _ctx.getCanvasMode();
|
|
44
85
|
|
|
45
86
|
if (canvasMode !== "design" && canvasMode !== "edit" && canvasMode !== "settings") {
|
|
@@ -55,7 +96,7 @@ export function render() {
|
|
|
55
96
|
}
|
|
56
97
|
|
|
57
98
|
if (canvasMode === "settings") {
|
|
58
|
-
const enable =
|
|
99
|
+
const enable = stylebookTab === "elements";
|
|
59
100
|
for (const p of canvasPanels) {
|
|
60
101
|
p.overlayClk.style.pointerEvents = enable ? "" : "none";
|
|
61
102
|
}
|
|
@@ -72,33 +113,46 @@ export function render() {
|
|
|
72
113
|
}
|
|
73
114
|
|
|
74
115
|
for (const p of canvasPanels) {
|
|
75
|
-
/**
|
|
76
|
-
* @type {{
|
|
77
|
-
* cls: string;
|
|
78
|
-
* top: string;
|
|
79
|
-
* left: string;
|
|
80
|
-
* width: string;
|
|
81
|
-
* height: string;
|
|
82
|
-
* border?: string;
|
|
83
|
-
* }[]}
|
|
84
|
-
*/
|
|
116
|
+
/** @type {OverlayBox[]} */
|
|
85
117
|
const boxes = [];
|
|
86
118
|
|
|
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);
|
|
89
127
|
if (el) {
|
|
90
|
-
const
|
|
91
|
-
|
|
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;
|
|
92
138
|
boxes.push(desc);
|
|
93
139
|
}
|
|
94
140
|
}
|
|
95
141
|
|
|
96
|
-
if (
|
|
97
|
-
const el = findCanvasElement(
|
|
142
|
+
if (selection && p === getActivePanel()) {
|
|
143
|
+
const el = findCanvasElement(selection, p.canvas);
|
|
98
144
|
if (el) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
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;
|
|
102
156
|
boxes.push(desc);
|
|
103
157
|
}
|
|
104
158
|
}
|
|
@@ -109,16 +163,12 @@ export function render() {
|
|
|
109
163
|
${boxes.map(
|
|
110
164
|
(b) => html`
|
|
111
165
|
<div
|
|
112
|
-
class="${b.cls}${
|
|
166
|
+
class="${b.cls}${b.isLayout ? " overlay-layout" : ""}"
|
|
113
167
|
style="top:${b.top};left:${b.left};width:${b.width};height:${b.height}${b.border
|
|
114
168
|
? `;border:${b.border}`
|
|
115
169
|
: ""}"
|
|
116
170
|
>
|
|
117
|
-
${
|
|
118
|
-
/** @type {any} */ (b).isLayout
|
|
119
|
-
? html`<span class="overlay-layout-badge">Layout</span>`
|
|
120
|
-
: nothing
|
|
121
|
-
}
|
|
171
|
+
${b.isLayout ? html`<span class="overlay-layout-badge">Layout</span>` : nothing}
|
|
122
172
|
</div>
|
|
123
173
|
`,
|
|
124
174
|
)}
|
|
@@ -5,18 +5,16 @@
|
|
|
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";
|
|
@@ -91,7 +89,7 @@ export function registerPanelEvents(panel) {
|
|
|
91
89
|
// Layout element clicked — show layout info instead of selecting in page doc
|
|
92
90
|
if (layoutElements.has(el)) {
|
|
93
91
|
view.layoutSelection = { el, layoutPath: activeLayoutPath };
|
|
94
|
-
|
|
92
|
+
activeTab.value.session.selection = null;
|
|
95
93
|
renderOnly("rightPanel");
|
|
96
94
|
return;
|
|
97
95
|
}
|
|
@@ -117,16 +115,18 @@ export function registerPanelEvents(panel) {
|
|
|
117
115
|
|
|
118
116
|
if (canvasMode === "design" && S.mode !== "content") {
|
|
119
117
|
updateUi("pendingInlineEdit", { path, mediaName });
|
|
120
|
-
|
|
118
|
+
activeTab.value.session.ui.activeMedia = newMedia;
|
|
119
|
+
activeTab.value.session.selection = path;
|
|
121
120
|
return;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
activeTab.value.session.ui.activeMedia = newMedia;
|
|
124
|
+
activeTab.value.session.selection = path;
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
|
|
129
|
+
activeTab.value.session.selection = null;
|
|
130
130
|
},
|
|
131
131
|
opts,
|
|
132
132
|
);
|
|
@@ -161,8 +161,8 @@ export function registerPanelEvents(panel) {
|
|
|
161
161
|
const resolvedEl = path === originalPath ? el : findCanvasElement(path, canvas) || el;
|
|
162
162
|
if (isEditableBlock(resolvedEl)) {
|
|
163
163
|
const newMedia = mediaName === "base" ? null : (mediaName ?? null);
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
activeTab.value.session.ui.activeMedia = newMedia;
|
|
165
|
+
activeTab.value.session.selection = path;
|
|
166
166
|
_ctx.enterInlineEdit(resolvedEl, path);
|
|
167
167
|
return;
|
|
168
168
|
}
|
|
@@ -253,13 +253,10 @@ export function registerPanelEvents(panel) {
|
|
|
253
253
|
|
|
254
254
|
insertionHelper.mount({
|
|
255
255
|
getState: _ctx.getState,
|
|
256
|
-
update,
|
|
257
256
|
getCanvasMode: _ctx.getCanvasMode,
|
|
258
257
|
withPanelPointerEvents,
|
|
259
258
|
effectiveZoom: effectiveZoom,
|
|
260
259
|
defaultDef,
|
|
261
|
-
insertNode,
|
|
262
|
-
selectNode,
|
|
263
260
|
parentElementPath,
|
|
264
261
|
childIndex,
|
|
265
262
|
getNodeAtPath,
|