@jxsuite/studio 0.23.1 → 0.24.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 +2231 -715
- package/dist/studio.js.map +121 -104
- package/package.json +8 -7
- package/src/browse/{browse-modal.js → browse-modal.ts} +9 -10
- package/src/browse/{browse.js → browse.ts} +110 -85
- package/src/canvas/{canvas-diff.js → canvas-diff.ts} +42 -35
- package/src/canvas/{canvas-helpers.js → canvas-helpers.ts} +25 -19
- package/src/canvas/{canvas-live-render.js → canvas-live-render.ts} +53 -63
- package/src/canvas/{canvas-render.js → canvas-render.ts} +110 -121
- package/src/canvas/{canvas-utils.js → canvas-utils.ts} +48 -44
- package/src/canvas/{nested-site-style.js → nested-site-style.ts} +3 -3
- package/src/editor/{component-inline-edit.js → component-inline-edit.ts} +45 -33
- package/src/editor/{content-inline-edit.js → content-inline-edit.ts} +27 -45
- package/src/editor/{context-menu.js → context-menu.ts} +38 -36
- package/src/editor/{convert-targets.js → convert-targets.ts} +15 -12
- package/src/editor/{convert-to-component.js → convert-to-component.ts} +25 -26
- package/src/editor/{convert-to-repeater.js → convert-to-repeater.ts} +60 -40
- package/src/editor/{inline-edit.js → inline-edit.ts} +91 -55
- package/src/editor/{inline-format.js → inline-format.ts} +46 -51
- package/src/editor/{insertion-helper.js → insertion-helper.ts} +47 -63
- package/src/editor/{shortcuts.js → shortcuts.ts} +45 -31
- package/src/editor/{slash-menu.js → slash-menu.ts} +34 -35
- package/src/files/{components.js → components.ts} +12 -15
- package/src/files/{file-ops.js → file-ops.ts} +36 -29
- package/src/files/{files.js → files.ts} +102 -84
- package/src/github/{github-auth.js → github-auth.ts} +3 -3
- package/src/github/{github-publish.js → github-publish.ts} +20 -18
- package/src/markdown/{md-allowlist.js → md-allowlist.ts} +5 -2
- package/src/markdown/{md-convert.js → md-convert.ts} +146 -169
- package/src/new-project/{new-project-modal.js → new-project-modal.ts} +16 -18
- package/src/panels/{activity-bar.js → activity-bar.ts} +26 -34
- package/src/panels/{ai-panel.js → ai-panel.ts} +30 -30
- package/src/panels/{block-action-bar.js → block-action-bar.ts} +64 -73
- package/src/panels/{canvas-dnd.js → canvas-dnd.ts} +44 -49
- package/src/panels/{data-explorer.js → data-explorer.ts} +21 -15
- package/src/panels/dnd.ts +417 -0
- package/src/panels/{editors.js → editors.ts} +43 -50
- package/src/panels/{elements-panel.js → elements-panel.ts} +30 -27
- package/src/panels/{events-panel.js → events-panel.ts} +33 -25
- package/src/panels/{git-panel.js → git-panel.ts} +97 -83
- package/src/panels/{head-panel.js → head-panel.ts} +117 -139
- package/src/panels/{imports-panel.js → imports-panel.ts} +69 -89
- package/src/panels/{layers-panel.js → layers-panel.ts} +61 -57
- package/src/panels/{left-panel.js → left-panel.ts} +56 -63
- package/src/panels/{overlays.js → overlays.ts} +28 -36
- package/src/panels/{panel-events.js → panel-events.ts} +53 -51
- package/src/panels/{preview-render.js → preview-render.ts} +20 -15
- package/src/panels/{properties-panel.js → properties-panel.ts} +212 -246
- package/src/panels/{pseudo-preview.js → pseudo-preview.ts} +9 -8
- package/src/panels/{quick-search.js → quick-search.ts} +16 -17
- package/src/panels/{right-panel.js → right-panel.ts} +41 -59
- package/src/panels/{shared.js → shared.ts} +7 -5
- package/src/panels/{signals-panel.js → signals-panel.ts} +322 -362
- package/src/panels/{statusbar.js → statusbar.ts} +14 -14
- package/src/panels/{style-inputs.js → style-inputs.ts} +66 -48
- package/src/panels/{style-panel.js → style-panel.ts} +235 -290
- package/src/panels/{style-utils.js → style-utils.ts} +32 -31
- package/src/panels/{stylebook-layers-panel.js → stylebook-layers-panel.ts} +22 -14
- package/src/panels/{stylebook-panel.js → stylebook-panel.ts} +127 -140
- package/src/panels/{tab-strip.js → tab-strip.ts} +12 -14
- package/src/panels/{toolbar.js → toolbar.ts} +68 -70
- package/src/panels/{welcome-screen.js → welcome-screen.ts} +14 -16
- package/src/{platform.js → platform.ts} +5 -3
- package/src/platforms/{devserver.js → devserver.ts} +53 -44
- package/src/{recent-projects.js → recent-projects.ts} +17 -12
- package/src/{resize-edges.js → resize-edges.ts} +18 -13
- package/src/services/{cem-export.js → cem-export.ts} +14 -7
- package/src/services/{code-services.js → code-services.ts} +29 -20
- package/src/services/{monaco-setup.js → monaco-setup.ts} +2 -3
- package/src/settings/{content-types-editor.js → content-types-editor.ts} +88 -67
- package/src/settings/{css-vars-editor.js → css-vars-editor.ts} +78 -51
- package/src/settings/{defs-editor.js → defs-editor.ts} +70 -56
- package/src/settings/{general-settings.js → general-settings.ts} +29 -28
- package/src/settings/{head-editor.js → head-editor.ts} +37 -35
- package/src/settings/{schema-field-ui.js → schema-field-ui.ts} +86 -76
- package/src/settings/{settings-modal.js → settings-modal.ts} +14 -16
- package/src/{site-context.js → site-context.ts} +35 -32
- package/src/{state.js → state.ts} +95 -78
- package/src/{store.js → store.ts} +60 -63
- package/src/{studio.js → studio.ts} +117 -119
- package/src/tabs/tab.ts +196 -0
- package/src/tabs/{transact.js → transact.ts} +107 -60
- package/src/types.ts +185 -0
- package/src/ui/{button-group.js → button-group.ts} +21 -21
- package/src/ui/{color-selector.js → color-selector.ts} +44 -37
- package/src/ui/{expression-editor.js → expression-editor.ts} +65 -40
- package/src/ui/{field-row.js → field-row.ts} +19 -2
- package/src/ui/{icons.js → icons.ts} +2 -2
- package/src/ui/{layers.js → layers.ts} +33 -24
- package/src/ui/{media-picker.js → media-picker.ts} +13 -9
- package/src/ui/{panel-resize.js → panel-resize.ts} +9 -4
- package/src/ui/{spectrum.js → spectrum.ts} +4 -4
- package/src/ui/{unit-selector.js → unit-selector.ts} +16 -19
- package/src/ui/{value-selector.js → value-selector.ts} +28 -28
- package/src/ui/{widgets.js → widgets.ts} +62 -15
- package/src/utils/{canvas-media.js → canvas-media.ts} +29 -14
- package/src/utils/{edit-display.js → edit-display.ts} +23 -20
- package/src/utils/{google-fonts.js → google-fonts.ts} +14 -13
- package/src/utils/{inherited-style.js → inherited-style.ts} +15 -10
- package/src/utils/{studio-utils.js → studio-utils.ts} +38 -26
- package/src/{view.js → view.ts} +53 -55
- package/src/workspace/{workspace.js → workspace.ts} +44 -33
- package/src/panels/dnd.js +0 -426
- package/src/tabs/tab.js +0 -192
- /package/src/{reactivity.js → reactivity.ts} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Left panel — orchestrator that delegates to per-tab render functions.
|
|
3
4
|
*
|
|
@@ -7,50 +8,46 @@
|
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import { html, render as litRender, nothing } from "lit-html";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
11
|
+
import type { TemplateResult } from "lit-html";
|
|
12
|
+
import { leftPanel, updateSession } from "../store";
|
|
13
|
+
import { effect, effectScope } from "../reactivity";
|
|
14
|
+
import { activeTab } from "../workspace/workspace";
|
|
15
|
+
import { view } from "../view";
|
|
16
|
+
import { transact, mutateUpdateFrontmatter } from "../tabs/transact";
|
|
17
|
+
import type { GitDiffState, JsonValue } from "../types";
|
|
15
18
|
|
|
16
|
-
import { renderLayersTemplate } from "./layers-panel
|
|
17
|
-
import { renderStylebookLayersTemplate } from "./stylebook-layers-panel
|
|
18
|
-
import { renderElementsTemplate } from "./elements-panel
|
|
19
|
-
import { selectStylebookTag, stylebookMeta } from "./stylebook-panel
|
|
19
|
+
import { renderLayersTemplate } from "./layers-panel";
|
|
20
|
+
import { renderStylebookLayersTemplate } from "./stylebook-layers-panel";
|
|
21
|
+
import { renderElementsTemplate } from "./elements-panel";
|
|
22
|
+
import { selectStylebookTag, stylebookMeta } from "./stylebook-panel";
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
* setGitDiffState: (state: import("../canvas/canvas-render.js").GitDiffState | null) => void;
|
|
45
|
-
* cloneRepository?: () => void;
|
|
46
|
-
* }} LeftPanelCtx
|
|
47
|
-
*/
|
|
24
|
+
interface LeftPanelCtx {
|
|
25
|
+
getCanvasMode: () => string;
|
|
26
|
+
setCanvasMode: (mode: string) => void;
|
|
27
|
+
renderImportsTemplate: (...args: any[]) => TemplateResult;
|
|
28
|
+
renderFilesTemplate: (...args: any[]) => TemplateResult;
|
|
29
|
+
renderSignalsTemplate: (...args: any[]) => TemplateResult;
|
|
30
|
+
renderDataExplorerTemplate: (...args: any[]) => TemplateResult;
|
|
31
|
+
renderHeadTemplate: (...args: any[]) => TemplateResult;
|
|
32
|
+
renderGitPanel: (...args: any[]) => TemplateResult;
|
|
33
|
+
renderCanvas: () => void;
|
|
34
|
+
defCategory: (def: unknown) => string;
|
|
35
|
+
defBadgeLabel: (def: unknown) => string;
|
|
36
|
+
navigateToComponent: (path: string) => void;
|
|
37
|
+
webdata: Record<string, unknown>;
|
|
38
|
+
defaultDef: (tag: string) => Record<string, unknown>;
|
|
39
|
+
registerLayersDnD: () => void;
|
|
40
|
+
registerElementsDnD: () => void;
|
|
41
|
+
registerComponentsDnD: () => void;
|
|
42
|
+
setupTreeKeyboard: (tree: HTMLElement) => void;
|
|
43
|
+
registerFileTreeDnD: (ctx: { renderLeftPanel: () => void }) => void;
|
|
44
|
+
setGitDiffState: (state: GitDiffState | null) => void;
|
|
45
|
+
cloneRepository?: () => void;
|
|
46
|
+
}
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
let _ctx = null;
|
|
48
|
+
let _ctx: LeftPanelCtx | null = null;
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
let _scope = null;
|
|
50
|
+
let _scope: import("@vue/reactivity").EffectScope | null = null;
|
|
54
51
|
|
|
55
52
|
let _rendering = false;
|
|
56
53
|
let _scheduled = false;
|
|
@@ -70,7 +67,7 @@ function _onFocusOut() {
|
|
|
70
67
|
*
|
|
71
68
|
* @param {LeftPanelCtx} ctx
|
|
72
69
|
*/
|
|
73
|
-
export function mount(ctx) {
|
|
70
|
+
export function mount(ctx: LeftPanelCtx) {
|
|
74
71
|
_ctx = ctx;
|
|
75
72
|
leftPanel.addEventListener("focusin", _onFocusIn);
|
|
76
73
|
leftPanel.addEventListener("focusout", _onFocusOut);
|
|
@@ -141,14 +138,14 @@ function _flush() {
|
|
|
141
138
|
}
|
|
142
139
|
|
|
143
140
|
function _render() {
|
|
144
|
-
const ctx =
|
|
141
|
+
const ctx = _ctx as LeftPanelCtx;
|
|
145
142
|
const tab = view.leftTab;
|
|
146
143
|
|
|
147
144
|
// ── Project-level panels: render based on projectState, independent of active tab ──
|
|
148
145
|
|
|
149
146
|
if (tab === "files") {
|
|
150
147
|
litRender(html`<div class="panel-body">${ctx.renderFilesTemplate()}</div>`, leftPanel);
|
|
151
|
-
const tree =
|
|
148
|
+
const tree = leftPanel.querySelector(".file-tree") as HTMLElement | null;
|
|
152
149
|
if (tree) ctx.setupTreeKeyboard(tree);
|
|
153
150
|
ctx.registerFileTreeDnD({ renderLeftPanel: render });
|
|
154
151
|
return;
|
|
@@ -162,13 +159,11 @@ function _render() {
|
|
|
162
159
|
}
|
|
163
160
|
|
|
164
161
|
if (tab === "blocks") {
|
|
165
|
-
const content = renderElementsTemplate(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}),
|
|
171
|
-
);
|
|
162
|
+
const content = renderElementsTemplate({
|
|
163
|
+
webdata: ctx.webdata,
|
|
164
|
+
defaultDef: ctx.defaultDef,
|
|
165
|
+
rerender: render,
|
|
166
|
+
} as Parameters<typeof renderElementsTemplate>[0]);
|
|
172
167
|
litRender(html`<div class="panel-body">${content}</div>`, leftPanel);
|
|
173
168
|
ctx.registerElementsDnD();
|
|
174
169
|
ctx.registerComponentsDnD();
|
|
@@ -208,12 +203,10 @@ function _render() {
|
|
|
208
203
|
if (tab === "layers")
|
|
209
204
|
content =
|
|
210
205
|
ctx.getCanvasMode() === "stylebook"
|
|
211
|
-
? renderStylebookLayersTemplate(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}),
|
|
216
|
-
)
|
|
206
|
+
? renderStylebookLayersTemplate({
|
|
207
|
+
selectStylebookTag,
|
|
208
|
+
stylebookMeta,
|
|
209
|
+
} as Parameters<typeof renderStylebookLayersTemplate>[0])
|
|
217
210
|
: renderLayersTemplate({
|
|
218
211
|
navigateToComponent: ctx.navigateToComponent,
|
|
219
212
|
rerender: render,
|
|
@@ -223,7 +216,7 @@ function _render() {
|
|
|
223
216
|
renderLeftPanel: render,
|
|
224
217
|
documentPath: S.documentPath,
|
|
225
218
|
documentElements: S.document.$elements || [],
|
|
226
|
-
applyMutation: (
|
|
219
|
+
applyMutation: (fn: (doc: object) => void) => {
|
|
227
220
|
transact(activeTab.value, fn);
|
|
228
221
|
},
|
|
229
222
|
});
|
|
@@ -247,19 +240,19 @@ function _render() {
|
|
|
247
240
|
content = ctx.renderHeadTemplate({
|
|
248
241
|
document: headDoc,
|
|
249
242
|
applyMutation: isContent
|
|
250
|
-
? (
|
|
251
|
-
const tab = activeTab.value
|
|
252
|
-
const fm =
|
|
253
|
-
const fmHead =
|
|
243
|
+
? (fn: (doc: object) => void) => {
|
|
244
|
+
const tab = activeTab.value!;
|
|
245
|
+
const fm = (tab.doc.content?.frontmatter ?? {}) as Record<string, unknown>;
|
|
246
|
+
const fmHead = fm.$head as unknown[] | undefined;
|
|
254
247
|
const tmp = { title: fm.title, $head: fmHead ? [...fmHead] : undefined };
|
|
255
248
|
fn(tmp);
|
|
256
249
|
if (tmp.title !== fm.title)
|
|
257
|
-
mutateUpdateFrontmatter(tab, "title",
|
|
250
|
+
mutateUpdateFrontmatter(tab, "title", tmp.title as JsonValue);
|
|
258
251
|
const newHead = tmp.$head && tmp.$head.length > 0 ? tmp.$head : undefined;
|
|
259
252
|
mutateUpdateFrontmatter(tab, "$head", /** @type {JsonValue} */ (newHead));
|
|
260
253
|
render();
|
|
261
254
|
}
|
|
262
|
-
: (
|
|
255
|
+
: (fn: (doc: object) => void) => {
|
|
263
256
|
transact(activeTab.value, fn);
|
|
264
257
|
},
|
|
265
258
|
renderLeftPanel: render,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Overlays panel — renders hover/selection overlay boxes on canvas panels. Delegates block action
|
|
3
4
|
* bar rendering to studio.js via ctx callback.
|
|
@@ -5,38 +6,32 @@
|
|
|
5
6
|
|
|
6
7
|
import { html, render as litRender, nothing } from "lit-html";
|
|
7
8
|
import { styleMap } from "lit-html/directives/style-map.js";
|
|
8
|
-
import { canvasPanels, pathsEqual } from "../store
|
|
9
|
-
import { effect, effectScope } from "../reactivity
|
|
10
|
-
import { activeTab } from "../workspace/workspace
|
|
11
|
-
import { view } from "../view
|
|
12
|
-
import { findCanvasElement, getActivePanel, effectiveZoom } from "../canvas/canvas-helpers
|
|
13
|
-
import { layoutElements } from "../canvas/canvas-live-render
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
* }} OverlayBox
|
|
25
|
-
*/
|
|
9
|
+
import { canvasPanels, pathsEqual } from "../store";
|
|
10
|
+
import { effect, effectScope } from "../reactivity";
|
|
11
|
+
import { activeTab } from "../workspace/workspace";
|
|
12
|
+
import { view } from "../view";
|
|
13
|
+
import { findCanvasElement, getActivePanel, effectiveZoom } from "../canvas/canvas-helpers";
|
|
14
|
+
import { layoutElements } from "../canvas/canvas-live-render";
|
|
15
|
+
|
|
16
|
+
interface OverlayBox {
|
|
17
|
+
cls: string;
|
|
18
|
+
top: string;
|
|
19
|
+
left: string;
|
|
20
|
+
width: string;
|
|
21
|
+
height: string;
|
|
22
|
+
border?: string;
|
|
23
|
+
isLayout?: boolean;
|
|
24
|
+
}
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* }} OverlaysCtx
|
|
33
|
-
*/
|
|
26
|
+
interface OverlaysCtx {
|
|
27
|
+
getCanvasMode: () => string;
|
|
28
|
+
isEditing: () => boolean;
|
|
29
|
+
renderBlockActionBar: () => void;
|
|
30
|
+
}
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
let _ctx = null;
|
|
32
|
+
let _ctx: OverlaysCtx | null = null;
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
let _scope = null;
|
|
34
|
+
let _scope: import("@vue/reactivity").EffectScope | null = null;
|
|
40
35
|
|
|
41
36
|
let _scheduled = false;
|
|
42
37
|
|
|
@@ -45,7 +40,7 @@ let _scheduled = false;
|
|
|
45
40
|
*
|
|
46
41
|
* @param {OverlaysCtx} ctx
|
|
47
42
|
*/
|
|
48
|
-
export function mount(ctx) {
|
|
43
|
+
export function mount(ctx: OverlaysCtx) {
|
|
49
44
|
_ctx = ctx;
|
|
50
45
|
_scope = effectScope();
|
|
51
46
|
_scope.run(() => {
|
|
@@ -114,8 +109,7 @@ function _flush() {
|
|
|
114
109
|
}
|
|
115
110
|
|
|
116
111
|
for (const p of canvasPanels) {
|
|
117
|
-
|
|
118
|
-
const boxes = [];
|
|
112
|
+
const boxes: OverlayBox[] = [];
|
|
119
113
|
|
|
120
114
|
// Batch layout reads: read viewport geometry once per panel
|
|
121
115
|
if (!p.viewport) continue;
|
|
@@ -128,8 +122,7 @@ function _flush() {
|
|
|
128
122
|
const el = findCanvasElement(hover, p.canvas);
|
|
129
123
|
if (el) {
|
|
130
124
|
const elRect = el.getBoundingClientRect();
|
|
131
|
-
|
|
132
|
-
const desc = {
|
|
125
|
+
const desc: OverlayBox = {
|
|
133
126
|
cls: "overlay-box overlay-hover",
|
|
134
127
|
top: `${(elRect.top - vpRect.top + scrollTop) / scale}px`,
|
|
135
128
|
left: `${(elRect.left - vpRect.left + scrollLeft) / scale}px`,
|
|
@@ -145,8 +138,7 @@ function _flush() {
|
|
|
145
138
|
const el = findCanvasElement(selection, p.canvas);
|
|
146
139
|
if (el) {
|
|
147
140
|
const elRect = el.getBoundingClientRect();
|
|
148
|
-
|
|
149
|
-
const desc = {
|
|
141
|
+
const desc: OverlayBox = {
|
|
150
142
|
cls: "overlay-box overlay-selection",
|
|
151
143
|
top: `${(elRect.top - vpRect.top + scrollTop) / scale}px`,
|
|
152
144
|
left: `${(elRect.left - vpRect.left + scrollLeft) / scale}px`,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Panel events — extracted from studio.js (Phase 4m). Unified event handler system for canvas
|
|
3
4
|
* panels: click-to-select, double-click inline edit, context menu, hover tracking, insertion
|
|
@@ -12,49 +13,48 @@ import {
|
|
|
12
13
|
childIndex,
|
|
13
14
|
getNodeAtPath,
|
|
14
15
|
renderOnly,
|
|
15
|
-
} from "../store
|
|
16
|
-
import { activeTab } from "../workspace/workspace
|
|
17
|
-
import { view } from "../view
|
|
18
|
-
import { stopEditing, isEditing, isEditableBlock } from "../editor/inline-edit
|
|
19
|
-
import { showContextMenu } from "../editor/context-menu
|
|
20
|
-
import * as insertionHelper from "../editor/insertion-helper
|
|
21
|
-
import { defaultDef } from "../panels/shared
|
|
22
|
-
import { bubbleInlinePath, findCanvasElement, effectiveZoom } from "../canvas/canvas-helpers
|
|
23
|
-
import { layoutElements, activeLayoutPath } from "../canvas/canvas-live-render
|
|
16
|
+
} from "../store";
|
|
17
|
+
import { activeTab } from "../workspace/workspace";
|
|
18
|
+
import { view } from "../view";
|
|
19
|
+
import { stopEditing, isEditing, isEditableBlock } from "../editor/inline-edit";
|
|
20
|
+
import { showContextMenu } from "../editor/context-menu";
|
|
21
|
+
import * as insertionHelper from "../editor/insertion-helper";
|
|
22
|
+
import { defaultDef } from "../panels/shared";
|
|
23
|
+
import { bubbleInlinePath, findCanvasElement, effectiveZoom } from "../canvas/canvas-helpers";
|
|
24
|
+
import { layoutElements, activeLayoutPath } from "../canvas/canvas-live-render";
|
|
25
|
+
import type { CanvasPanel } from "./canvas-dnd";
|
|
26
|
+
import type { JxPath } from "../state";
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
interface PanelEventsCtx {
|
|
29
|
+
getCanvasMode: () => string;
|
|
30
|
+
enterInlineEdit: (el: HTMLElement, path: JxPath) => void;
|
|
31
|
+
navigateToComponent: (path: string) => void;
|
|
32
|
+
}
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
* @typedef {{
|
|
30
|
-
* getCanvasMode: () => string;
|
|
31
|
-
* enterInlineEdit: (el: HTMLElement, path: JxPath) => void;
|
|
32
|
-
* navigateToComponent: (path: string) => void;
|
|
33
|
-
* }} PanelEventsCtx
|
|
34
|
-
*/
|
|
34
|
+
let _ctx: PanelEventsCtx | null = null;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Initialize the panel events module.
|
|
38
38
|
*
|
|
39
39
|
* @param {PanelEventsCtx} ctx
|
|
40
40
|
*/
|
|
41
|
-
export function initPanelEvents(ctx) {
|
|
41
|
+
export function initPanelEvents(ctx: PanelEventsCtx) {
|
|
42
42
|
_ctx = ctx;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/** @param {import("../canvas/canvas-render.js").CanvasPanel} panel */
|
|
46
|
-
export function registerPanelEvents(panel) {
|
|
47
|
-
const ctx =
|
|
48
|
-
const canvas =
|
|
49
|
-
const overlayClk =
|
|
46
|
+
export function registerPanelEvents(panel: CanvasPanel) {
|
|
47
|
+
const ctx = _ctx as PanelEventsCtx;
|
|
48
|
+
const canvas = panel.canvas as HTMLElement;
|
|
49
|
+
const overlayClk = panel.overlayClk as HTMLElement;
|
|
50
50
|
const { mediaName } = panel;
|
|
51
51
|
const ac = new AbortController();
|
|
52
52
|
const opts = { signal: ac.signal };
|
|
53
53
|
view.canvasEventCleanups.push(() => ac.abort());
|
|
54
54
|
|
|
55
|
-
/** @param {
|
|
56
|
-
function withPanelPointerEvents(fn) {
|
|
57
|
-
const els =
|
|
55
|
+
/** @param {() => unknown} fn */
|
|
56
|
+
function withPanelPointerEvents(fn: () => unknown) {
|
|
57
|
+
const els = canvas.querySelectorAll("*") as NodeListOf<HTMLElement>;
|
|
58
58
|
for (const el of els) el.style.pointerEvents = "auto";
|
|
59
59
|
overlayClk.style.display = "none";
|
|
60
60
|
const result = fn();
|
|
@@ -65,7 +65,7 @@ export function registerPanelEvents(panel) {
|
|
|
65
65
|
|
|
66
66
|
overlayClk.addEventListener(
|
|
67
67
|
"click",
|
|
68
|
-
(
|
|
68
|
+
(e: MouseEvent) => {
|
|
69
69
|
const barInner = view.blockActionBarEl?.firstElementChild;
|
|
70
70
|
if (barInner) {
|
|
71
71
|
const r = barInner.getBoundingClientRect();
|
|
@@ -84,9 +84,9 @@ export function registerPanelEvents(panel) {
|
|
|
84
84
|
const tab = activeTab.value;
|
|
85
85
|
const canvasMode = ctx.getCanvasMode();
|
|
86
86
|
|
|
87
|
-
const elements =
|
|
88
|
-
|
|
89
|
-
);
|
|
87
|
+
const elements = withPanelPointerEvents(() =>
|
|
88
|
+
document.elementsFromPoint(e.clientX, e.clientY),
|
|
89
|
+
) as Element[];
|
|
90
90
|
|
|
91
91
|
if (!tab) return;
|
|
92
92
|
|
|
@@ -106,9 +106,11 @@ export function registerPanelEvents(panel) {
|
|
|
106
106
|
let path = bubbleInlinePath(tab.doc.document, originalPath);
|
|
107
107
|
const newMedia = mediaName === "base" ? null : (mediaName ?? null);
|
|
108
108
|
|
|
109
|
-
const resolvedEl =
|
|
110
|
-
path === originalPath
|
|
111
|
-
|
|
109
|
+
const resolvedEl = (
|
|
110
|
+
path === originalPath
|
|
111
|
+
? el
|
|
112
|
+
: (findCanvasElement(path, canvas) as HTMLElement | null) || el
|
|
113
|
+
) as HTMLElement;
|
|
112
114
|
|
|
113
115
|
if (
|
|
114
116
|
pathsEqual(path, tab.session.selection) &&
|
|
@@ -140,7 +142,7 @@ export function registerPanelEvents(panel) {
|
|
|
140
142
|
|
|
141
143
|
overlayClk.addEventListener(
|
|
142
144
|
"dblclick",
|
|
143
|
-
(
|
|
145
|
+
(e: MouseEvent) => {
|
|
144
146
|
const barInner = view.blockActionBarEl?.firstElementChild;
|
|
145
147
|
if (barInner) {
|
|
146
148
|
const r = barInner.getBoundingClientRect();
|
|
@@ -156,9 +158,9 @@ export function registerPanelEvents(panel) {
|
|
|
156
158
|
if (canvasMode !== "edit" && canvasMode !== "design") return;
|
|
157
159
|
|
|
158
160
|
const tab = activeTab.value;
|
|
159
|
-
const elements =
|
|
160
|
-
|
|
161
|
-
);
|
|
161
|
+
const elements = withPanelPointerEvents(() =>
|
|
162
|
+
document.elementsFromPoint(e.clientX, e.clientY),
|
|
163
|
+
) as Element[];
|
|
162
164
|
|
|
163
165
|
if (!tab) return;
|
|
164
166
|
|
|
@@ -167,9 +169,11 @@ export function registerPanelEvents(panel) {
|
|
|
167
169
|
const originalPath = elToPath.get(el);
|
|
168
170
|
if (originalPath) {
|
|
169
171
|
const path = bubbleInlinePath(tab.doc.document, originalPath);
|
|
170
|
-
const resolvedEl =
|
|
171
|
-
path === originalPath
|
|
172
|
-
|
|
172
|
+
const resolvedEl = (
|
|
173
|
+
path === originalPath
|
|
174
|
+
? el
|
|
175
|
+
: (findCanvasElement(path, canvas) as HTMLElement | null) || el
|
|
176
|
+
) as HTMLElement;
|
|
173
177
|
if (isEditableBlock(resolvedEl)) {
|
|
174
178
|
const newMedia = mediaName === "base" ? null : (mediaName ?? null);
|
|
175
179
|
tab.session.ui.activeMedia = newMedia;
|
|
@@ -186,7 +190,7 @@ export function registerPanelEvents(panel) {
|
|
|
186
190
|
|
|
187
191
|
overlayClk.addEventListener(
|
|
188
192
|
"contextmenu",
|
|
189
|
-
(
|
|
193
|
+
(e: MouseEvent) => {
|
|
190
194
|
const barInner = view.blockActionBarEl?.firstElementChild;
|
|
191
195
|
if (barInner) {
|
|
192
196
|
const r = barInner.getBoundingClientRect();
|
|
@@ -199,9 +203,9 @@ export function registerPanelEvents(panel) {
|
|
|
199
203
|
return;
|
|
200
204
|
}
|
|
201
205
|
const tab = activeTab.value;
|
|
202
|
-
const elements =
|
|
203
|
-
|
|
204
|
-
);
|
|
206
|
+
const elements = withPanelPointerEvents(() =>
|
|
207
|
+
document.elementsFromPoint(e.clientX, e.clientY),
|
|
208
|
+
) as Element[];
|
|
205
209
|
for (const el of elements) {
|
|
206
210
|
if (canvas.contains(el) && el !== canvas) {
|
|
207
211
|
let path = elToPath.get(el);
|
|
@@ -219,7 +223,7 @@ export function registerPanelEvents(panel) {
|
|
|
219
223
|
|
|
220
224
|
overlayClk.addEventListener(
|
|
221
225
|
"mousemove",
|
|
222
|
-
(
|
|
226
|
+
(e: MouseEvent) => {
|
|
223
227
|
const barInner = view.blockActionBarEl?.firstElementChild;
|
|
224
228
|
if (barInner) {
|
|
225
229
|
const r = barInner.getBoundingClientRect();
|
|
@@ -233,9 +237,9 @@ export function registerPanelEvents(panel) {
|
|
|
233
237
|
}
|
|
234
238
|
const tab = activeTab.value;
|
|
235
239
|
if (!tab) return;
|
|
236
|
-
const el =
|
|
237
|
-
|
|
238
|
-
);
|
|
240
|
+
const el = withPanelPointerEvents(() =>
|
|
241
|
+
document.elementFromPoint(e.clientX, e.clientY),
|
|
242
|
+
) as Element | null;
|
|
239
243
|
if (el && canvas.contains(el) && el !== canvas) {
|
|
240
244
|
let path = elToPath.get(el);
|
|
241
245
|
if (path) {
|
|
@@ -273,9 +277,7 @@ export function registerPanelEvents(panel) {
|
|
|
273
277
|
childIndex,
|
|
274
278
|
getNodeAtPath,
|
|
275
279
|
elToPath,
|
|
276
|
-
panel:
|
|
277
|
-
/** @type {unknown} */ (panel)
|
|
278
|
-
),
|
|
280
|
+
panel: panel as unknown as Parameters<typeof insertionHelper.mount>[0]["panel"],
|
|
279
281
|
});
|
|
280
282
|
view.canvasEventCleanups.push(() => insertionHelper.unmount());
|
|
281
283
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Preview render — extracted from studio.js (Phase 4m). Structural preview renderer that creates
|
|
3
4
|
* DOM from Jx node trees as a fallback when runtime rendering fails.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
import { elToPath } from "../store
|
|
7
|
-
import { activeTab } from "../workspace/workspace
|
|
8
|
-
import { applyCanvasStyle } from "../utils/canvas-media
|
|
9
|
-
import { resolveDefaultForCanvas } from "../panels/signals-panel
|
|
7
|
+
import { elToPath } from "../store";
|
|
8
|
+
import { activeTab } from "../workspace/workspace";
|
|
9
|
+
import { applyCanvasStyle } from "../utils/canvas-media";
|
|
10
|
+
import { resolveDefaultForCanvas } from "../panels/signals-panel";
|
|
11
|
+
import type { JxPath } from "../state";
|
|
12
|
+
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* Recursively render a Jx node to the canvas DOM. Media-aware: applies base styles + active
|
|
@@ -18,7 +21,13 @@ import { resolveDefaultForCanvas } from "../panels/signals-panel.js";
|
|
|
18
21
|
* @param {Set<string>} activeBreakpoints
|
|
19
22
|
* @param {Record<string, boolean>} featureToggles
|
|
20
23
|
*/
|
|
21
|
-
export function renderCanvasNode(
|
|
24
|
+
export function renderCanvasNode(
|
|
25
|
+
node: JxMutableNode | string | number | boolean | null | undefined,
|
|
26
|
+
path: JxPath,
|
|
27
|
+
parent: HTMLElement,
|
|
28
|
+
activeBreakpoints: Set<string>,
|
|
29
|
+
featureToggles: Record<string, boolean>,
|
|
30
|
+
) {
|
|
22
31
|
if (typeof node === "string" || typeof node === "number" || typeof node === "boolean") {
|
|
23
32
|
parent.appendChild(document.createTextNode(String(node)));
|
|
24
33
|
return;
|
|
@@ -33,10 +42,10 @@ export function renderCanvasNode(node, path, parent, activeBreakpoints, featureT
|
|
|
33
42
|
if (typeof node.textContent === "string") {
|
|
34
43
|
el.textContent = node.textContent;
|
|
35
44
|
} else if (typeof node.textContent === "object" && node.textContent !== null) {
|
|
36
|
-
const tc =
|
|
45
|
+
const tc = node.textContent as Record<string, unknown>;
|
|
37
46
|
if (tc.$ref) {
|
|
38
47
|
const resolved = resolveDefaultForCanvas(tc, activeTab.value?.doc.document?.state);
|
|
39
|
-
el.textContent =
|
|
48
|
+
el.textContent = resolved as string | null;
|
|
40
49
|
el.style.opacity = "0.7";
|
|
41
50
|
el.style.fontStyle = "italic";
|
|
42
51
|
el.title = `Bound: ${tc.$ref}`;
|
|
@@ -51,13 +60,9 @@ export function renderCanvasNode(node, path, parent, activeBreakpoints, featureT
|
|
|
51
60
|
if (node.attributes && typeof node.attributes === "object") {
|
|
52
61
|
for (const [attr, val] of Object.entries(node.attributes)) {
|
|
53
62
|
try {
|
|
54
|
-
if (
|
|
55
|
-
typeof val === "object" &&
|
|
56
|
-
val !== null &&
|
|
57
|
-
/** @type {Record<string, unknown>} */ (val).$ref
|
|
58
|
-
) {
|
|
63
|
+
if (typeof val === "object" && val !== null && (val as Record<string, unknown>).$ref) {
|
|
59
64
|
const resolved = resolveDefaultForCanvas(val, activeTab.value?.doc.document?.state);
|
|
60
|
-
el.setAttribute(attr,
|
|
65
|
+
el.setAttribute(attr, resolved as string);
|
|
61
66
|
} else {
|
|
62
67
|
el.setAttribute(attr, val);
|
|
63
68
|
}
|
|
@@ -78,9 +83,9 @@ export function renderCanvasNode(node, path, parent, activeBreakpoints, featureT
|
|
|
78
83
|
} else if (
|
|
79
84
|
node.children &&
|
|
80
85
|
typeof node.children === "object" &&
|
|
81
|
-
|
|
86
|
+
(node.children as Record<string, unknown>).$prototype === "Array"
|
|
82
87
|
) {
|
|
83
|
-
const childrenObj =
|
|
88
|
+
const childrenObj = node.children as Record<string, unknown>;
|
|
84
89
|
const template = childrenObj.map;
|
|
85
90
|
if (template && typeof template === "object") {
|
|
86
91
|
const wrapper = document.createElement("div");
|