@jxsuite/studio 0.23.2 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/studio.js +2311 -718
  2. package/dist/studio.js.map +121 -104
  3. package/package.json +8 -7
  4. package/src/browse/{browse-modal.js → browse-modal.ts} +9 -10
  5. package/src/browse/{browse.js → browse.ts} +109 -84
  6. package/src/canvas/{canvas-diff.js → canvas-diff.ts} +42 -35
  7. package/src/canvas/{canvas-helpers.js → canvas-helpers.ts} +25 -19
  8. package/src/canvas/{canvas-live-render.js → canvas-live-render.ts} +53 -63
  9. package/src/canvas/{canvas-render.js → canvas-render.ts} +110 -121
  10. package/src/canvas/{canvas-utils.js → canvas-utils.ts} +48 -44
  11. package/src/canvas/{nested-site-style.js → nested-site-style.ts} +3 -3
  12. package/src/editor/{component-inline-edit.js → component-inline-edit.ts} +45 -33
  13. package/src/editor/{content-inline-edit.js → content-inline-edit.ts} +27 -45
  14. package/src/editor/{context-menu.js → context-menu.ts} +38 -36
  15. package/src/editor/{convert-targets.js → convert-targets.ts} +15 -12
  16. package/src/editor/{convert-to-component.js → convert-to-component.ts} +25 -26
  17. package/src/editor/{convert-to-repeater.js → convert-to-repeater.ts} +60 -40
  18. package/src/editor/{inline-edit.js → inline-edit.ts} +91 -55
  19. package/src/editor/{inline-format.js → inline-format.ts} +46 -51
  20. package/src/editor/{insertion-helper.js → insertion-helper.ts} +47 -63
  21. package/src/editor/{shortcuts.js → shortcuts.ts} +45 -31
  22. package/src/editor/{slash-menu.js → slash-menu.ts} +34 -35
  23. package/src/files/{components.js → components.ts} +12 -15
  24. package/src/files/{file-ops.js → file-ops.ts} +36 -29
  25. package/src/files/{files.js → files.ts} +102 -84
  26. package/src/github/{github-auth.js → github-auth.ts} +3 -3
  27. package/src/github/{github-publish.js → github-publish.ts} +20 -18
  28. package/src/markdown/{md-allowlist.js → md-allowlist.ts} +5 -2
  29. package/src/markdown/{md-convert.js → md-convert.ts} +146 -169
  30. package/src/new-project/{new-project-modal.js → new-project-modal.ts} +16 -18
  31. package/src/panels/{activity-bar.js → activity-bar.ts} +26 -34
  32. package/src/panels/{ai-panel.js → ai-panel.ts} +30 -30
  33. package/src/panels/{block-action-bar.js → block-action-bar.ts} +64 -73
  34. package/src/panels/{canvas-dnd.js → canvas-dnd.ts} +44 -49
  35. package/src/panels/{data-explorer.js → data-explorer.ts} +21 -15
  36. package/src/panels/dnd.ts +417 -0
  37. package/src/panels/{editors.js → editors.ts} +43 -50
  38. package/src/panels/{elements-panel.js → elements-panel.ts} +30 -27
  39. package/src/panels/{events-panel.js → events-panel.ts} +33 -25
  40. package/src/panels/{git-panel.js → git-panel.ts} +97 -83
  41. package/src/panels/{head-panel.js → head-panel.ts} +117 -139
  42. package/src/panels/{imports-panel.js → imports-panel.ts} +69 -89
  43. package/src/panels/{layers-panel.js → layers-panel.ts} +61 -57
  44. package/src/panels/{left-panel.js → left-panel.ts} +56 -63
  45. package/src/panels/{overlays.js → overlays.ts} +28 -36
  46. package/src/panels/{panel-events.js → panel-events.ts} +53 -51
  47. package/src/panels/{preview-render.js → preview-render.ts} +20 -15
  48. package/src/panels/{properties-panel.js → properties-panel.ts} +212 -246
  49. package/src/panels/{pseudo-preview.js → pseudo-preview.ts} +9 -8
  50. package/src/panels/{quick-search.js → quick-search.ts} +16 -17
  51. package/src/panels/{right-panel.js → right-panel.ts} +41 -59
  52. package/src/panels/{shared.js → shared.ts} +8 -6
  53. package/src/panels/{signals-panel.js → signals-panel.ts} +322 -362
  54. package/src/panels/{statusbar.js → statusbar.ts} +14 -14
  55. package/src/panels/{style-inputs.js → style-inputs.ts} +66 -48
  56. package/src/panels/{style-panel.js → style-panel.ts} +235 -290
  57. package/src/panels/{style-utils.js → style-utils.ts} +32 -31
  58. package/src/panels/{stylebook-layers-panel.js → stylebook-layers-panel.ts} +22 -14
  59. package/src/panels/{stylebook-panel.js → stylebook-panel.ts} +127 -140
  60. package/src/panels/{tab-strip.js → tab-strip.ts} +12 -14
  61. package/src/panels/{toolbar.js → toolbar.ts} +68 -70
  62. package/src/panels/{welcome-screen.js → welcome-screen.ts} +14 -16
  63. package/src/{platform.js → platform.ts} +5 -3
  64. package/src/platforms/{devserver.js → devserver.ts} +53 -44
  65. package/src/{recent-projects.js → recent-projects.ts} +17 -12
  66. package/src/{resize-edges.js → resize-edges.ts} +18 -13
  67. package/src/services/{cem-export.js → cem-export.ts} +14 -7
  68. package/src/services/{code-services.js → code-services.ts} +29 -20
  69. package/src/services/{monaco-setup.js → monaco-setup.ts} +2 -3
  70. package/src/settings/{content-types-editor.js → content-types-editor.ts} +88 -67
  71. package/src/settings/{css-vars-editor.js → css-vars-editor.ts} +78 -51
  72. package/src/settings/{defs-editor.js → defs-editor.ts} +70 -56
  73. package/src/settings/{general-settings.js → general-settings.ts} +29 -28
  74. package/src/settings/{head-editor.js → head-editor.ts} +37 -35
  75. package/src/settings/{schema-field-ui.js → schema-field-ui.ts} +86 -76
  76. package/src/settings/{settings-modal.js → settings-modal.ts} +14 -16
  77. package/src/{site-context.js → site-context.ts} +35 -32
  78. package/src/{state.js → state.ts} +95 -78
  79. package/src/{store.js → store.ts} +60 -63
  80. package/src/{studio.js → studio.ts} +117 -119
  81. package/src/tabs/tab.ts +196 -0
  82. package/src/tabs/{transact.js → transact.ts} +107 -60
  83. package/src/types.ts +185 -0
  84. package/src/ui/{button-group.js → button-group.ts} +21 -21
  85. package/src/ui/{color-selector.js → color-selector.ts} +44 -37
  86. package/src/ui/{expression-editor.js → expression-editor.ts} +65 -40
  87. package/src/ui/{field-row.js → field-row.ts} +19 -2
  88. package/src/ui/{icons.js → icons.ts} +2 -2
  89. package/src/ui/{layers.js → layers.ts} +33 -24
  90. package/src/ui/{media-picker.js → media-picker.ts} +13 -9
  91. package/src/ui/{panel-resize.js → panel-resize.ts} +9 -4
  92. package/src/ui/{spectrum.js → spectrum.ts} +4 -4
  93. package/src/ui/{unit-selector.js → unit-selector.ts} +16 -19
  94. package/src/ui/{value-selector.js → value-selector.ts} +28 -28
  95. package/src/ui/{widgets.js → widgets.ts} +62 -15
  96. package/src/utils/{canvas-media.js → canvas-media.ts} +29 -14
  97. package/src/utils/edit-display.ts +298 -0
  98. package/src/utils/{google-fonts.js → google-fonts.ts} +14 -13
  99. package/src/utils/{inherited-style.js → inherited-style.ts} +15 -10
  100. package/src/utils/{studio-utils.js → studio-utils.ts} +35 -23
  101. package/src/{view.js → view.ts} +53 -55
  102. package/src/workspace/{workspace.js → workspace.ts} +44 -33
  103. package/src/panels/dnd.js +0 -426
  104. package/src/tabs/tab.js +0 -192
  105. package/src/utils/edit-display.js +0 -203
  106. /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 { leftPanel, updateSession } from "../store.js";
11
- import { effect, effectScope } from "../reactivity.js";
12
- import { activeTab } from "../workspace/workspace.js";
13
- import { view } from "../view.js";
14
- import { transact, mutateUpdateFrontmatter } from "../tabs/transact.js";
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.js";
17
- import { renderStylebookLayersTemplate } from "./stylebook-layers-panel.js";
18
- import { renderElementsTemplate } from "./elements-panel.js";
19
- import { selectStylebookTag, stylebookMeta } from "./stylebook-panel.js";
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
- /** @typedef {import("lit-html").TemplateResult} TemplateResult */
22
-
23
- /**
24
- * @typedef {{
25
- * getCanvasMode: () => string;
26
- * setCanvasMode: (mode: string) => void;
27
- * renderImportsTemplate: Function;
28
- * renderFilesTemplate: Function;
29
- * renderSignalsTemplate: Function;
30
- * renderDataExplorerTemplate: Function;
31
- * renderHeadTemplate: Function;
32
- * renderGitPanel: Function;
33
- * renderCanvas: () => void;
34
- * defCategory: (def: unknown) => string;
35
- * defBadgeLabel: (def: unknown) => string;
36
- * navigateToComponent: (path: string) => void;
37
- * webdata: object;
38
- * defaultDef: (tag: string) => object;
39
- * registerLayersDnD: () => void;
40
- * registerElementsDnD: () => void;
41
- * registerComponentsDnD: () => void;
42
- * setupTreeKeyboard: (tree: HTMLElement) => void;
43
- * registerFileTreeDnD: (ctx: { renderLeftPanel: () => void }) => void;
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
- /** @type {LeftPanelCtx | null} */
50
- let _ctx = null;
48
+ let _ctx: LeftPanelCtx | null = null;
51
49
 
52
- /** @type {import("@vue/reactivity").EffectScope | null} */
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 = /** @type {LeftPanelCtx} */ (_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 = /** @type {HTMLElement | null} */ (leftPanel.querySelector(".file-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
- /** @type {Parameters<typeof renderElementsTemplate>[0]} */ ({
167
- webdata: ctx.webdata,
168
- defaultDef: ctx.defaultDef,
169
- rerender: render,
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
- /** @type {Parameters<typeof renderStylebookLayersTemplate>[0]} */ ({
213
- selectStylebookTag,
214
- stylebookMeta,
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: (/** @type {(doc: object) => void} */ fn) => {
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
- ? (/** @type {(doc: object) => void} */ fn) => {
251
- const tab = activeTab.value;
252
- const fm = /** @type {Record<string, unknown>} */ (tab.doc.content?.frontmatter ?? {});
253
- const fmHead = /** @type {unknown[] | undefined} */ (fm.$head);
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", /** @type {JsonValue} */ (tmp.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
- : (/** @type {(doc: object) => void} */ fn) => {
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.js";
9
- import { effect, effectScope } from "../reactivity.js";
10
- import { activeTab } from "../workspace/workspace.js";
11
- import { view } from "../view.js";
12
- import { findCanvasElement, getActivePanel, effectiveZoom } from "../canvas/canvas-helpers.js";
13
- import { layoutElements } from "../canvas/canvas-live-render.js";
14
-
15
- /**
16
- * @typedef {{
17
- * cls: string;
18
- * top: string;
19
- * left: string;
20
- * width: string;
21
- * height: string;
22
- * border?: string;
23
- * isLayout?: boolean;
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
- * @typedef {{
29
- * getCanvasMode: () => string;
30
- * isEditing: () => boolean;
31
- * renderBlockActionBar: () => void;
32
- * }} OverlaysCtx
33
- */
26
+ interface OverlaysCtx {
27
+ getCanvasMode: () => string;
28
+ isEditing: () => boolean;
29
+ renderBlockActionBar: () => void;
30
+ }
34
31
 
35
- /** @type {OverlaysCtx | null} */
36
- let _ctx = null;
32
+ let _ctx: OverlaysCtx | null = null;
37
33
 
38
- /** @type {import("@vue/reactivity").EffectScope | null} */
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
- /** @type {OverlayBox[]} */
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
- /** @type {OverlayBox} */
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
- /** @type {OverlayBox} */
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.js";
16
- import { activeTab } from "../workspace/workspace.js";
17
- import { view } from "../view.js";
18
- import { stopEditing, isEditing, isEditableBlock } from "../editor/inline-edit.js";
19
- import { showContextMenu } from "../editor/context-menu.js";
20
- import * as insertionHelper from "../editor/insertion-helper.js";
21
- import { defaultDef } from "../panels/shared.js";
22
- import { bubbleInlinePath, findCanvasElement, effectiveZoom } from "../canvas/canvas-helpers.js";
23
- import { layoutElements, activeLayoutPath } from "../canvas/canvas-live-render.js";
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
- /** @type {PanelEventsCtx | null} */
26
- let _ctx = null;
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 = /** @type {PanelEventsCtx} */ (_ctx);
48
- const canvas = /** @type {HTMLElement} */ (panel.canvas);
49
- const overlayClk = /** @type {HTMLElement} */ (panel.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 {Function} fn */
56
- function withPanelPointerEvents(fn) {
57
- const els = /** @type {NodeListOf<HTMLElement>} */ (canvas.querySelectorAll("*"));
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
- (/** @type {MouseEvent} */ e) => {
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 = /** @type {Element[]} */ (
88
- withPanelPointerEvents(() => document.elementsFromPoint(e.clientX, e.clientY))
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 = /** @type {HTMLElement} */ (
110
- path === originalPath ? el : findCanvasElement(path, canvas) || el
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
- (/** @type {MouseEvent} */ e) => {
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 = /** @type {Element[]} */ (
160
- withPanelPointerEvents(() => document.elementsFromPoint(e.clientX, e.clientY))
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 = /** @type {HTMLElement} */ (
171
- path === originalPath ? el : findCanvasElement(path, canvas) || el
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
- (/** @type {MouseEvent} */ e) => {
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 = /** @type {Element[]} */ (
203
- withPanelPointerEvents(() => document.elementsFromPoint(e.clientX, e.clientY))
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
- (/** @type {MouseEvent} */ e) => {
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 = /** @type {Element | null} */ (
237
- withPanelPointerEvents(() => document.elementFromPoint(e.clientX, e.clientY))
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: /** @type {import("../editor/insertion-helper.js").CanvasPanel} */ (
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.js";
7
- import { activeTab } from "../workspace/workspace.js";
8
- import { applyCanvasStyle } from "../utils/canvas-media.js";
9
- import { resolveDefaultForCanvas } from "../panels/signals-panel.js";
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(node, path, parent, activeBreakpoints, featureToggles) {
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 = /** @type {Record<string, unknown>} */ (node.textContent);
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 = /** @type {string | null} */ (resolved);
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, /** @type {string} */ (resolved));
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
- /** @type {Record<string, unknown>} */ (node.children).$prototype === "Array"
86
+ (node.children as Record<string, unknown>).$prototype === "Array"
82
87
  ) {
83
- const childrenObj = /** @type {Record<string, unknown>} */ (node.children);
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");