@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
|
* Canvas render — extracted from studio.js (Phase 4o). Multi-mode canvas rendering orchestrator:
|
|
3
4
|
* dispatches to manage/settings/source/edit/design/preview rendering paths.
|
|
@@ -7,12 +8,12 @@ import { html, render as litRender, nothing } from "lit-html";
|
|
|
7
8
|
import { ref } from "lit-html/directives/ref.js";
|
|
8
9
|
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
|
|
9
10
|
|
|
10
|
-
import { canvasWrap, canvasPanels, updateCanvas } from "../store
|
|
11
|
-
import { activeTab } from "../workspace/workspace
|
|
12
|
-
import { view } from "../view
|
|
13
|
-
import { loadMarkdown } from "../files/file-ops
|
|
14
|
-
import { renderWelcome } from "../panels/welcome-screen
|
|
15
|
-
import { projectState } from "../state
|
|
11
|
+
import { canvasWrap, canvasPanels, updateCanvas } from "../store";
|
|
12
|
+
import { activeTab } from "../workspace/workspace";
|
|
13
|
+
import { view } from "../view";
|
|
14
|
+
import { loadMarkdown } from "../files/file-ops";
|
|
15
|
+
import { renderWelcome } from "../panels/welcome-screen";
|
|
16
|
+
import { projectState } from "../state";
|
|
16
17
|
import {
|
|
17
18
|
canvasPanelTemplate,
|
|
18
19
|
applyTransform,
|
|
@@ -20,61 +21,47 @@ import {
|
|
|
20
21
|
renderZoomIndicator,
|
|
21
22
|
resetZoomIndicator,
|
|
22
23
|
updateActivePanelHeaders,
|
|
23
|
-
} from "./canvas-utils
|
|
24
|
-
import { effectiveZoom, overlayBoxDescriptor } from "./canvas-helpers
|
|
24
|
+
} from "./canvas-utils";
|
|
25
|
+
import { effectiveZoom, overlayBoxDescriptor } from "./canvas-helpers";
|
|
25
26
|
import {
|
|
26
27
|
parseMediaEntries,
|
|
27
28
|
activeBreakpointsForWidth,
|
|
28
29
|
collectMediaOverrides,
|
|
29
30
|
applyOverridesToCanvas,
|
|
30
|
-
} from "../utils/canvas-media
|
|
31
|
-
import { getEffectiveMedia } from "../site-context
|
|
32
|
-
import { renderCanvasLive } from "./canvas-live-render
|
|
33
|
-
import { renderCanvasNode } from "../panels/preview-render
|
|
34
|
-
import { registerPanelDnD } from "../panels/canvas-dnd
|
|
35
|
-
import { registerPanelEvents } from "../panels/panel-events
|
|
36
|
-
import { computeDocumentDiff } from "./canvas-diff
|
|
37
|
-
import { updateForcedPseudoPreview } from "../panels/pseudo-preview
|
|
38
|
-
import { findCanvasElement } from "./canvas-helpers
|
|
39
|
-
import { enterComponentInlineEdit } from "../editor/component-inline-edit
|
|
40
|
-
import { renderStylebookMode, refreshStylebookStyles } from "../panels/stylebook-panel
|
|
41
|
-
import { dismissLinkPopover, dismissBlockActionBar } from "../panels/block-action-bar
|
|
42
|
-
import { dismissContextMenu } from "../editor/context-menu
|
|
43
|
-
import { dismissSlashMenu } from "../editor/slash-menu
|
|
44
|
-
import { renderFunctionEditor } from "../panels/editors
|
|
45
|
-
import { mediaDisplayName } from "../panels/shared
|
|
46
|
-
import { statusMessage } from "../panels/statusbar
|
|
47
|
-
import * as overlaysPanel from "../panels/overlays
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
*/
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @typedef {{
|
|
66
|
-
* getCanvasMode: () => string;
|
|
67
|
-
* setCanvasMode: (mode: string) => void;
|
|
68
|
-
* openFileFromTree: (path: string) => void;
|
|
69
|
-
* exportFile: () => void;
|
|
70
|
-
* closeFunctionEditor: () => void;
|
|
71
|
-
* gitDiffState: GitDiffState | null;
|
|
72
|
-
* setGitDiffState: (state: GitDiffState | null) => void;
|
|
73
|
-
* }} CanvasRenderCtx
|
|
74
|
-
*/
|
|
31
|
+
} from "../utils/canvas-media";
|
|
32
|
+
import { getEffectiveMedia } from "../site-context";
|
|
33
|
+
import { renderCanvasLive } from "./canvas-live-render";
|
|
34
|
+
import { renderCanvasNode } from "../panels/preview-render";
|
|
35
|
+
import { registerPanelDnD } from "../panels/canvas-dnd";
|
|
36
|
+
import { registerPanelEvents } from "../panels/panel-events";
|
|
37
|
+
import { computeDocumentDiff } from "./canvas-diff";
|
|
38
|
+
import { updateForcedPseudoPreview } from "../panels/pseudo-preview";
|
|
39
|
+
import { findCanvasElement } from "./canvas-helpers";
|
|
40
|
+
import { enterComponentInlineEdit } from "../editor/component-inline-edit";
|
|
41
|
+
import { renderStylebookMode, refreshStylebookStyles } from "../panels/stylebook-panel";
|
|
42
|
+
import { dismissLinkPopover, dismissBlockActionBar } from "../panels/block-action-bar";
|
|
43
|
+
import { dismissContextMenu } from "../editor/context-menu";
|
|
44
|
+
import { dismissSlashMenu } from "../editor/slash-menu";
|
|
45
|
+
import { renderFunctionEditor } from "../panels/editors";
|
|
46
|
+
import { mediaDisplayName } from "../panels/shared";
|
|
47
|
+
import { statusMessage } from "../panels/statusbar";
|
|
48
|
+
import * as overlaysPanel from "../panels/overlays";
|
|
49
|
+
|
|
50
|
+
import type { CanvasPanel } from "../panels/canvas-dnd";
|
|
51
|
+
import type { GitDiffState, InlineEditDef } from "../types";
|
|
52
|
+
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
53
|
+
|
|
54
|
+
interface CanvasRenderCtx {
|
|
55
|
+
getCanvasMode: () => string;
|
|
56
|
+
setCanvasMode: (mode: string) => void;
|
|
57
|
+
openFileFromTree: (path: string) => void;
|
|
58
|
+
exportFile: () => void;
|
|
59
|
+
closeFunctionEditor: () => void;
|
|
60
|
+
gitDiffState: GitDiffState | null;
|
|
61
|
+
setGitDiffState: (state: GitDiffState | null) => void;
|
|
62
|
+
}
|
|
75
63
|
|
|
76
|
-
|
|
77
|
-
let _ctx = null;
|
|
64
|
+
let _ctx: CanvasRenderCtx | null = null;
|
|
78
65
|
|
|
79
66
|
let _prevStylebookFilter = "";
|
|
80
67
|
let _prevStylebookCustomizedOnly = false;
|
|
@@ -84,7 +71,7 @@ let _prevStylebookCustomizedOnly = false;
|
|
|
84
71
|
*
|
|
85
72
|
* @param {CanvasRenderCtx} ctx
|
|
86
73
|
*/
|
|
87
|
-
export function initCanvasRender(ctx) {
|
|
74
|
+
export function initCanvasRender(ctx: CanvasRenderCtx) {
|
|
88
75
|
_ctx = ctx;
|
|
89
76
|
}
|
|
90
77
|
|
|
@@ -98,7 +85,7 @@ export function renderCanvas() {
|
|
|
98
85
|
}
|
|
99
86
|
return;
|
|
100
87
|
}
|
|
101
|
-
const ctx =
|
|
88
|
+
const ctx = _ctx as CanvasRenderCtx;
|
|
102
89
|
const S = { document: tab.doc.document, ui: tab.session.ui, mode: tab.doc.mode };
|
|
103
90
|
const canvasMode = ctx.getCanvasMode();
|
|
104
91
|
|
|
@@ -227,8 +214,7 @@ export function renderCanvas() {
|
|
|
227
214
|
if (canvasMode === "source") {
|
|
228
215
|
canvasWrap.style.padding = "0";
|
|
229
216
|
canvasWrap.style.display = "block";
|
|
230
|
-
|
|
231
|
-
let editorContainer = null;
|
|
217
|
+
let editorContainer: HTMLDivElement | null = null;
|
|
232
218
|
litRender(
|
|
233
219
|
html`<div class="source-wrap">
|
|
234
220
|
<div class="source-toolbar">
|
|
@@ -240,7 +226,7 @@ export function renderCanvas() {
|
|
|
240
226
|
<div
|
|
241
227
|
class="source-editor"
|
|
242
228
|
${ref((el) => {
|
|
243
|
-
if (el) editorContainer =
|
|
229
|
+
if (el) editorContainer = el as HTMLDivElement;
|
|
244
230
|
})}
|
|
245
231
|
></div>
|
|
246
232
|
</div>`,
|
|
@@ -253,25 +239,21 @@ export function renderCanvas() {
|
|
|
253
239
|
lang === "json" ? JSON.stringify(S.document, null, 2) : S.document?.toString?.() || "";
|
|
254
240
|
const modelUri = monaco.Uri.parse("file:///" + filePath);
|
|
255
241
|
const model = monaco.editor.createModel(content, lang, modelUri);
|
|
256
|
-
view.monacoEditor = monaco.editor.create(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
tabSize: 2,
|
|
269
|
-
},
|
|
270
|
-
);
|
|
242
|
+
view.monacoEditor = monaco.editor.create(editorContainer as unknown as HTMLElement, {
|
|
243
|
+
model,
|
|
244
|
+
theme: "vs-dark",
|
|
245
|
+
automaticLayout: true,
|
|
246
|
+
minimap: { enabled: false },
|
|
247
|
+
fontSize: 12,
|
|
248
|
+
fontFamily: "'SF Mono', 'Fira Code', 'Consolas', monospace",
|
|
249
|
+
lineNumbers: "on",
|
|
250
|
+
scrollBeyondLastLine: false,
|
|
251
|
+
wordWrap: "on",
|
|
252
|
+
tabSize: 2,
|
|
253
|
+
});
|
|
271
254
|
|
|
272
255
|
// Debounced sync back to state
|
|
273
|
-
|
|
274
|
-
let debounce;
|
|
256
|
+
let debounce: ReturnType<typeof setTimeout> | undefined;
|
|
275
257
|
view.monacoEditor.onDidChangeModelContent(() => {
|
|
276
258
|
const editor = view.monacoEditor;
|
|
277
259
|
if (!editor) return;
|
|
@@ -282,6 +264,7 @@ export function renderCanvas() {
|
|
|
282
264
|
clearTimeout(debounce);
|
|
283
265
|
debounce = setTimeout(() => {
|
|
284
266
|
const tab = activeTab.value;
|
|
267
|
+
if (!tab) return;
|
|
285
268
|
if (lang === "json") {
|
|
286
269
|
try {
|
|
287
270
|
tab.doc.document = JSON.parse(editor.getValue());
|
|
@@ -332,7 +315,7 @@ export function renderCanvas() {
|
|
|
332
315
|
class="panzoom-wrap"
|
|
333
316
|
style="transform-origin:0 0"
|
|
334
317
|
${ref((el) => {
|
|
335
|
-
if (el) view.panzoomWrap =
|
|
318
|
+
if (el) view.panzoomWrap = el as HTMLDivElement;
|
|
336
319
|
})}
|
|
337
320
|
>
|
|
338
321
|
${origTpl} ${currTpl}
|
|
@@ -341,11 +324,11 @@ export function renderCanvas() {
|
|
|
341
324
|
canvasWrap,
|
|
342
325
|
);
|
|
343
326
|
|
|
344
|
-
canvasPanels.push(
|
|
345
|
-
canvasPanels.push(
|
|
327
|
+
canvasPanels.push(origPanel as unknown as CanvasPanel);
|
|
328
|
+
canvasPanels.push(currPanel as unknown as CanvasPanel);
|
|
346
329
|
|
|
347
330
|
/** @param {string} content */
|
|
348
|
-
const parseContent = (content) => {
|
|
331
|
+
const parseContent = (content: string) => {
|
|
349
332
|
if (gitDiffState.isMarkdown) {
|
|
350
333
|
return loadMarkdown(content).then((r) => r.document);
|
|
351
334
|
}
|
|
@@ -364,15 +347,15 @@ export function renderCanvas() {
|
|
|
364
347
|
parseContent(gitDiffState.currentContent || ""),
|
|
365
348
|
]).then(([originalDoc, currentDoc]) => {
|
|
366
349
|
renderCanvasIntoPanel(
|
|
367
|
-
|
|
368
|
-
new Set(),
|
|
350
|
+
origPanel as unknown as CanvasPanel,
|
|
351
|
+
new Set<string>(),
|
|
369
352
|
featureToggles,
|
|
370
353
|
originalDoc,
|
|
371
354
|
gitDiffState,
|
|
372
355
|
);
|
|
373
356
|
renderCanvasIntoPanel(
|
|
374
|
-
|
|
375
|
-
new Set(),
|
|
357
|
+
currPanel as unknown as CanvasPanel,
|
|
358
|
+
new Set<string>(),
|
|
376
359
|
featureToggles,
|
|
377
360
|
currentDoc,
|
|
378
361
|
gitDiffState,
|
|
@@ -400,16 +383,16 @@ export function renderCanvas() {
|
|
|
400
383
|
const editTpl = html`
|
|
401
384
|
<div
|
|
402
385
|
class="content-edit-canvas"
|
|
403
|
-
${ref((el) => {
|
|
404
|
-
panel.scrollContainer =
|
|
386
|
+
${ref((el: Element | undefined) => {
|
|
387
|
+
panel.scrollContainer = (el as HTMLElement) || null;
|
|
405
388
|
})}
|
|
406
389
|
>
|
|
407
390
|
<div class="content-edit-column" style="max-width:${baseWidth}px">${panelTpl}</div>
|
|
408
391
|
</div>
|
|
409
392
|
`;
|
|
410
393
|
litRender(editTpl, canvasWrap);
|
|
411
|
-
canvasPanels.push(
|
|
412
|
-
renderCanvasIntoPanel(
|
|
394
|
+
canvasPanels.push(panel as unknown as CanvasPanel);
|
|
395
|
+
renderCanvasIntoPanel(panel as unknown as CanvasPanel, new Set<string>(), S.ui.featureToggles);
|
|
413
396
|
return;
|
|
414
397
|
}
|
|
415
398
|
|
|
@@ -445,7 +428,7 @@ export function renderCanvas() {
|
|
|
445
428
|
class="panzoom-wrap"
|
|
446
429
|
style="transform-origin:0 0"
|
|
447
430
|
${ref((el) => {
|
|
448
|
-
if (el) view.panzoomWrap =
|
|
431
|
+
if (el) view.panzoomWrap = el as HTMLDivElement;
|
|
449
432
|
})}
|
|
450
433
|
>
|
|
451
434
|
${panelTpl}
|
|
@@ -453,8 +436,8 @@ export function renderCanvas() {
|
|
|
453
436
|
`,
|
|
454
437
|
canvasWrap,
|
|
455
438
|
);
|
|
456
|
-
canvasPanels.push(
|
|
457
|
-
renderCanvasIntoPanel(
|
|
439
|
+
canvasPanels.push(panel as unknown as CanvasPanel);
|
|
440
|
+
renderCanvasIntoPanel(panel as unknown as CanvasPanel, new Set<string>(), featureToggles);
|
|
458
441
|
applyTransform();
|
|
459
442
|
if (modeChanged) {
|
|
460
443
|
observeCenterUntilStable();
|
|
@@ -494,7 +477,7 @@ export function renderCanvas() {
|
|
|
494
477
|
class="panzoom-wrap"
|
|
495
478
|
style="transform-origin:0 0"
|
|
496
479
|
${ref((el) => {
|
|
497
|
-
if (el) view.panzoomWrap =
|
|
480
|
+
if (el) view.panzoomWrap = el as HTMLDivElement;
|
|
498
481
|
})}
|
|
499
482
|
>
|
|
500
483
|
${panelEntries.map((e) => e.tpl)}
|
|
@@ -503,10 +486,15 @@ export function renderCanvas() {
|
|
|
503
486
|
canvasWrap,
|
|
504
487
|
);
|
|
505
488
|
|
|
506
|
-
for (
|
|
507
|
-
const
|
|
489
|
+
for (let i = 0; i < panelEntries.length; i++) {
|
|
490
|
+
const { panel, activeSet } = panelEntries[i];
|
|
491
|
+
const p = panel as CanvasPanel;
|
|
508
492
|
canvasPanels.push(p);
|
|
509
|
-
|
|
493
|
+
if (i === 0) {
|
|
494
|
+
renderCanvasIntoPanel(p, activeSet, featureToggles);
|
|
495
|
+
} else {
|
|
496
|
+
setTimeout(() => renderCanvasIntoPanel(p, activeSet, featureToggles), 0);
|
|
497
|
+
}
|
|
510
498
|
}
|
|
511
499
|
|
|
512
500
|
// Highlight active panel header
|
|
@@ -535,19 +523,19 @@ export function renderCanvas() {
|
|
|
535
523
|
* applies diff highlighting.
|
|
536
524
|
*/
|
|
537
525
|
function renderCanvasIntoPanel(
|
|
538
|
-
panel,
|
|
539
|
-
activeBreakpoints
|
|
540
|
-
featureToggles,
|
|
541
|
-
docOverride = null,
|
|
542
|
-
gitDiffState = null,
|
|
526
|
+
panel: CanvasPanel,
|
|
527
|
+
activeBreakpoints: Set<string>,
|
|
528
|
+
featureToggles: Record<string, boolean>,
|
|
529
|
+
docOverride: JxMutableNode | null = null,
|
|
530
|
+
gitDiffState: GitDiffState | null = null,
|
|
543
531
|
) {
|
|
544
532
|
const gen = view.renderGeneration;
|
|
545
533
|
const tab = activeTab.value;
|
|
546
|
-
const docToRender =
|
|
547
|
-
const canvas =
|
|
534
|
+
const docToRender = docOverride || (tab?.doc.document as JxMutableNode);
|
|
535
|
+
const canvas = panel.canvas as HTMLElement;
|
|
548
536
|
|
|
549
537
|
renderCanvasLive(gen, docToRender, canvas)
|
|
550
|
-
.then((
|
|
538
|
+
.then((scope: Record<string, unknown> | null) => {
|
|
551
539
|
// Skip post-render setup if a newer render has started
|
|
552
540
|
if (gen !== view.renderGeneration) return;
|
|
553
541
|
if (scope) {
|
|
@@ -578,20 +566,18 @@ function renderCanvasIntoPanel(
|
|
|
578
566
|
renderCanvasNode(docToRender, [], canvas, activeBreakpoints, featureToggles);
|
|
579
567
|
}
|
|
580
568
|
try {
|
|
581
|
-
registerPanelDnD(
|
|
582
|
-
} catch (
|
|
583
|
-
console.warn("registerPanelDnD failed:",
|
|
569
|
+
registerPanelDnD(panel as unknown as CanvasPanel);
|
|
570
|
+
} catch (e) {
|
|
571
|
+
console.warn("registerPanelDnD failed:", (e as Error).message);
|
|
584
572
|
}
|
|
585
|
-
registerPanelEvents(
|
|
573
|
+
registerPanelEvents(panel as unknown as CanvasPanel);
|
|
586
574
|
renderOverlays();
|
|
587
575
|
updateForcedPseudoPreview();
|
|
588
576
|
|
|
589
577
|
// Process pending inline edit when canvas becomes ready
|
|
590
578
|
const currentTab = activeTab.value;
|
|
591
579
|
if (currentTab?.session.ui?.pendingInlineEdit) {
|
|
592
|
-
const { path, mediaName: mn } =
|
|
593
|
-
currentTab.session.ui.pendingInlineEdit
|
|
594
|
-
);
|
|
580
|
+
const { path, mediaName: mn } = currentTab.session.ui.pendingInlineEdit as InlineEditDef;
|
|
595
581
|
currentTab.session.ui.pendingInlineEdit = null;
|
|
596
582
|
const targetPanel = canvasPanels.find((p) => p.mediaName === mn) || canvasPanels[0];
|
|
597
583
|
if (targetPanel) {
|
|
@@ -600,18 +586,18 @@ function renderCanvasIntoPanel(
|
|
|
600
586
|
}
|
|
601
587
|
}
|
|
602
588
|
})
|
|
603
|
-
.catch((
|
|
589
|
+
.catch((err: unknown) => {
|
|
604
590
|
if (gen !== view.renderGeneration) return;
|
|
605
591
|
console.warn("renderCanvasLive rejected:", err instanceof Error ? err.message : err);
|
|
606
592
|
updateCanvas({ status: "ready", scope: null, error: null });
|
|
607
593
|
canvas.innerHTML = "";
|
|
608
594
|
renderCanvasNode(docToRender, [], canvas, activeBreakpoints, featureToggles);
|
|
609
595
|
try {
|
|
610
|
-
registerPanelDnD(
|
|
611
|
-
} catch (
|
|
612
|
-
console.warn("registerPanelDnD failed:",
|
|
596
|
+
registerPanelDnD(panel as unknown as CanvasPanel);
|
|
597
|
+
} catch (e) {
|
|
598
|
+
console.warn("registerPanelDnD failed:", (e as Error).message);
|
|
613
599
|
}
|
|
614
|
-
registerPanelEvents(
|
|
600
|
+
registerPanelEvents(panel as unknown as CanvasPanel);
|
|
615
601
|
renderOverlays();
|
|
616
602
|
updateForcedPseudoPreview();
|
|
617
603
|
});
|
|
@@ -624,11 +610,14 @@ function renderCanvasIntoPanel(
|
|
|
624
610
|
* @param {HTMLElement} canvas
|
|
625
611
|
* @param {Map<string, "added" | "removed" | "modified">} diffMap
|
|
626
612
|
*/
|
|
627
|
-
function applyDiffHighlightToCanvas(
|
|
613
|
+
function applyDiffHighlightToCanvas(
|
|
614
|
+
canvas: HTMLElement,
|
|
615
|
+
diffMap: Map<string, "added" | "removed" | "modified">,
|
|
616
|
+
) {
|
|
628
617
|
if (!diffMap || diffMap.size === 0) return;
|
|
629
618
|
|
|
630
619
|
// Walk all elements in canvas and check their data attributes or other markers
|
|
631
|
-
const walkCanvas = (
|
|
620
|
+
const walkCanvas = (el: HTMLElement, /** @type {string} */ path = "") => {
|
|
632
621
|
const pathKey = path || "/";
|
|
633
622
|
|
|
634
623
|
if (diffMap.has(pathKey)) {
|
|
@@ -643,7 +632,7 @@ function applyDiffHighlightToCanvas(canvas, diffMap) {
|
|
|
643
632
|
for (const child of el.children) {
|
|
644
633
|
const childPath =
|
|
645
634
|
pathKey === "/" ? `children/${childIdx}` : `${pathKey}/children/${childIdx}`;
|
|
646
|
-
walkCanvas(
|
|
635
|
+
walkCanvas(child as HTMLElement, childPath);
|
|
647
636
|
childIdx++;
|
|
648
637
|
}
|
|
649
638
|
};
|
|
@@ -659,13 +648,13 @@ function applyDiffHighlightToCanvas(canvas, diffMap) {
|
|
|
659
648
|
* @param {Element} canvasEl
|
|
660
649
|
* @param {Set<string>} activeBreakpoints
|
|
661
650
|
*/
|
|
662
|
-
function applyCanvasMediaOverrides(canvasEl, activeBreakpoints) {
|
|
651
|
+
function applyCanvasMediaOverrides(canvasEl: Element, activeBreakpoints: Set<string>) {
|
|
663
652
|
if (!activeBreakpoints.size) return;
|
|
664
653
|
const tab = activeTab.value;
|
|
665
654
|
if (!tab) return;
|
|
666
655
|
const docMedia = getEffectiveMedia(tab.doc.document.$media || {});
|
|
667
656
|
// Build a set of CSS condition texts that match active breakpoints
|
|
668
|
-
const activeConditions = new Set();
|
|
657
|
+
const activeConditions = new Set<string>();
|
|
669
658
|
for (const name of activeBreakpoints) {
|
|
670
659
|
if (docMedia[name]) activeConditions.add(docMedia[name]);
|
|
671
660
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Canvas panel utilities — extracted from studio.js (Phase 4l). Panzoom infrastructure: panel DOM
|
|
3
4
|
* template creation, centering, transform application, zoom indicator, and fit-to-screen.
|
|
@@ -9,24 +10,20 @@ import { classMap } from "lit-html/directives/class-map.js";
|
|
|
9
10
|
import { styleMap } from "lit-html/directives/style-map.js";
|
|
10
11
|
import { ifDefined } from "lit-html/directives/if-defined.js";
|
|
11
12
|
|
|
12
|
-
import { renderOnly, updateUi, canvasWrap, canvasPanels } from "../store
|
|
13
|
-
import { activeTab } from "../workspace/workspace
|
|
14
|
-
import { view } from "../view
|
|
15
|
-
import { getLayerSlot } from "../ui/layers
|
|
16
|
-
import { getActivePanel, findCanvasElement } from "./canvas-helpers
|
|
13
|
+
import { renderOnly, updateUi, canvasWrap, canvasPanels } from "../store";
|
|
14
|
+
import { activeTab } from "../workspace/workspace";
|
|
15
|
+
import { view } from "../view";
|
|
16
|
+
import { getLayerSlot } from "../ui/layers";
|
|
17
|
+
import { getActivePanel, findCanvasElement } from "./canvas-helpers";
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
* }}
|
|
25
|
-
*/
|
|
26
|
-
let _ctx;
|
|
19
|
+
let _ctx: {
|
|
20
|
+
getCanvasMode: () => string;
|
|
21
|
+
getZoom: () => number;
|
|
22
|
+
setZoomDirect: (zoom: number) => void;
|
|
23
|
+
renderStylebookOverlays: () => void;
|
|
24
|
+
};
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
let _zoomIndicatorEl = null;
|
|
26
|
+
let _zoomIndicatorEl: HTMLElement | null = null;
|
|
30
27
|
|
|
31
28
|
/**
|
|
32
29
|
* Initialize the canvas utils module.
|
|
@@ -38,7 +35,12 @@ let _zoomIndicatorEl = null;
|
|
|
38
35
|
* renderStylebookOverlays: () => void;
|
|
39
36
|
* }} ctx
|
|
40
37
|
*/
|
|
41
|
-
export function initCanvasUtils(ctx
|
|
38
|
+
export function initCanvasUtils(ctx: {
|
|
39
|
+
getCanvasMode: () => string;
|
|
40
|
+
getZoom: () => number;
|
|
41
|
+
setZoomDirect: (zoom: number) => void;
|
|
42
|
+
renderStylebookOverlays: () => void;
|
|
43
|
+
}) {
|
|
42
44
|
_ctx = ctx;
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -50,21 +52,23 @@ export function initCanvasUtils(ctx) {
|
|
|
50
52
|
* @param {boolean} fullWidth
|
|
51
53
|
* @param {number | null} width
|
|
52
54
|
*/
|
|
53
|
-
export function canvasPanelTemplate(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
export function canvasPanelTemplate(
|
|
56
|
+
mediaName: string | null,
|
|
57
|
+
label: string | null,
|
|
58
|
+
fullWidth: boolean,
|
|
59
|
+
width: number | null = null,
|
|
60
|
+
) {
|
|
61
|
+
const panel: {
|
|
62
|
+
mediaName: string;
|
|
63
|
+
element: HTMLElement | null;
|
|
64
|
+
canvas: HTMLElement | null;
|
|
65
|
+
overlay: HTMLElement | null;
|
|
66
|
+
overlayClk: HTMLElement | null;
|
|
67
|
+
viewport: HTMLElement | null;
|
|
68
|
+
scrollContainer: HTMLElement | null;
|
|
69
|
+
dropLine: HTMLElement | null;
|
|
70
|
+
_width: number | null;
|
|
71
|
+
} = {
|
|
68
72
|
mediaName: mediaName || "",
|
|
69
73
|
element: null,
|
|
70
74
|
canvas: null,
|
|
@@ -80,7 +84,7 @@ export function canvasPanelTemplate(mediaName, label, fullWidth, width = null) {
|
|
|
80
84
|
class=${classMap({ "canvas-panel": true, "full-width": fullWidth })}
|
|
81
85
|
data-media=${ifDefined(mediaName !== null ? mediaName : undefined)}
|
|
82
86
|
${ref((el) => {
|
|
83
|
-
if (el) panel.element =
|
|
87
|
+
if (el) panel.element = el as HTMLElement;
|
|
84
88
|
})}
|
|
85
89
|
>
|
|
86
90
|
${label
|
|
@@ -99,34 +103,34 @@ export function canvasPanelTemplate(mediaName, label, fullWidth, width = null) {
|
|
|
99
103
|
class="canvas-panel-viewport"
|
|
100
104
|
style=${styleMap({ width: width && !fullWidth ? `${width}px` : "" })}
|
|
101
105
|
${ref((el) => {
|
|
102
|
-
if (el) panel.viewport =
|
|
106
|
+
if (el) panel.viewport = el as HTMLElement;
|
|
103
107
|
})}
|
|
104
108
|
>
|
|
105
109
|
<div
|
|
106
110
|
class="canvas-panel-canvas"
|
|
107
111
|
style=${styleMap({ width: width ? `${width}px` : "" })}
|
|
108
112
|
${ref((el) => {
|
|
109
|
-
if (el) panel.canvas =
|
|
113
|
+
if (el) panel.canvas = el as HTMLElement;
|
|
110
114
|
})}
|
|
111
115
|
></div>
|
|
112
116
|
<div
|
|
113
117
|
class="canvas-panel-overlay"
|
|
114
118
|
${ref((el) => {
|
|
115
|
-
if (el) panel.overlay =
|
|
119
|
+
if (el) panel.overlay = el as HTMLElement;
|
|
116
120
|
})}
|
|
117
121
|
>
|
|
118
122
|
<div
|
|
119
123
|
class="canvas-drop-indicator"
|
|
120
124
|
style="display:none"
|
|
121
125
|
${ref((el) => {
|
|
122
|
-
if (el) panel.dropLine =
|
|
126
|
+
if (el) panel.dropLine = el as HTMLElement;
|
|
123
127
|
})}
|
|
124
128
|
></div>
|
|
125
129
|
</div>
|
|
126
130
|
<div
|
|
127
131
|
class="canvas-panel-click"
|
|
128
132
|
${ref((el) => {
|
|
129
|
-
if (el) panel.overlayClk =
|
|
133
|
+
if (el) panel.overlayClk = el as HTMLElement;
|
|
130
134
|
})}
|
|
131
135
|
></div>
|
|
132
136
|
</div>
|
|
@@ -231,7 +235,7 @@ export function resetZoomIndicator() {
|
|
|
231
235
|
* @param {HTMLElement} el
|
|
232
236
|
* @param {{ scrollContainer?: HTMLElement | null }} [panel]
|
|
233
237
|
*/
|
|
234
|
-
function _panToEl(el, panel) {
|
|
238
|
+
function _panToEl(el: HTMLElement, panel?: { scrollContainer?: HTMLElement | null }) {
|
|
235
239
|
const wrapRect = canvasWrap.getBoundingClientRect();
|
|
236
240
|
const elRect = el.getBoundingClientRect();
|
|
237
241
|
const elCenterY = elRect.top + elRect.height / 2 - wrapRect.top;
|
|
@@ -248,7 +252,7 @@ function _panToEl(el, panel) {
|
|
|
248
252
|
const targetY = startY + offsetY;
|
|
249
253
|
const start = performance.now();
|
|
250
254
|
const duration = 250;
|
|
251
|
-
function step(
|
|
255
|
+
function step(now: number) {
|
|
252
256
|
const t = Math.min((now - start) / duration, 1);
|
|
253
257
|
const ease = t * (2 - t);
|
|
254
258
|
view.panY = startY + (targetY - startY) * ease;
|
|
@@ -264,7 +268,7 @@ function _panToEl(el, panel) {
|
|
|
264
268
|
*
|
|
265
269
|
* @param {(string | number)[]} path
|
|
266
270
|
*/
|
|
267
|
-
export function panToElement(path) {
|
|
271
|
+
export function panToElement(path: (string | number)[]) {
|
|
268
272
|
const panel = getActivePanel();
|
|
269
273
|
if (!panel?.canvas) return;
|
|
270
274
|
const el = findCanvasElement(path, panel.canvas);
|
|
@@ -277,7 +281,7 @@ export function panToElement(path) {
|
|
|
277
281
|
*
|
|
278
282
|
* @param {HTMLElement} el
|
|
279
283
|
*/
|
|
280
|
-
export function panToCanvasEl(el) {
|
|
284
|
+
export function panToCanvasEl(el: HTMLElement) {
|
|
281
285
|
const panel = getActivePanel();
|
|
282
286
|
_panToEl(el, panel ?? undefined);
|
|
283
287
|
}
|
|
@@ -293,8 +297,8 @@ export function renderZoomIndicator() {
|
|
|
293
297
|
html`
|
|
294
298
|
<div
|
|
295
299
|
class="zoom-indicator"
|
|
296
|
-
${ref((el) => {
|
|
297
|
-
_zoomIndicatorEl =
|
|
300
|
+
${ref((el: Element | undefined) => {
|
|
301
|
+
_zoomIndicatorEl = (el as HTMLElement) || null;
|
|
298
302
|
})}
|
|
299
303
|
>
|
|
300
304
|
<span class="zoom-indicator-action" title="Reset to 100%" @click=${resetZoom}>
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
* @param {string} scope - The scoping selector (e.g. `[data-jx-site]`)
|
|
7
7
|
* @returns {string} Generated CSS text
|
|
8
8
|
*/
|
|
9
|
-
export function buildNestedSiteCSS(styleObj, scope) {
|
|
9
|
+
export function buildNestedSiteCSS(styleObj: Record<string, any>, scope: string) {
|
|
10
10
|
let css = "";
|
|
11
11
|
|
|
12
|
-
function emit(
|
|
12
|
+
function emit(parentSel: string, rules: Record<string, any>) {
|
|
13
13
|
const props = Object.entries(rules)
|
|
14
14
|
.filter(([, val]) => val === null || typeof val !== "object" || Array.isArray(val))
|
|
15
15
|
.map(([p, val]) => `${camelToKebab(p)}: ${val}`)
|
|
@@ -45,6 +45,6 @@ export function buildNestedSiteCSS(styleObj, scope) {
|
|
|
45
45
|
* @param {string} s
|
|
46
46
|
* @returns {string}
|
|
47
47
|
*/
|
|
48
|
-
function camelToKebab(s) {
|
|
48
|
+
function camelToKebab(s: string) {
|
|
49
49
|
return s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
50
50
|
}
|