@jxsuite/studio 0.28.2 → 0.28.4
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 +86144 -83971
- package/dist/studio.js.map +229 -219
- package/package.json +5 -5
- package/src/browse/browse-modal.ts +9 -3
- package/src/browse/browse.ts +139 -82
- package/src/canvas/canvas-diff.ts +35 -18
- package/src/canvas/canvas-helpers.ts +55 -21
- package/src/canvas/canvas-live-render.ts +140 -89
- package/src/canvas/canvas-render.ts +127 -82
- package/src/canvas/canvas-utils.ts +68 -42
- package/src/canvas/nested-site-style.ts +15 -7
- package/src/editor/component-inline-edit.ts +90 -51
- package/src/editor/content-inline-edit.ts +75 -72
- package/src/editor/context-menu.ts +125 -71
- package/src/editor/convert-targets.ts +17 -13
- package/src/editor/convert-to-component.ts +51 -28
- package/src/editor/convert-to-repeater.ts +44 -19
- package/src/editor/inline-edit.ts +107 -52
- package/src/editor/inline-format.ts +128 -60
- package/src/editor/insertion-helper.ts +26 -14
- package/src/editor/shortcuts.ts +89 -43
- package/src/editor/slash-menu.ts +41 -26
- package/src/files/components.ts +9 -7
- package/src/files/file-ops.ts +53 -33
- package/src/files/files.ts +246 -143
- package/src/format/constraints.ts +25 -15
- package/src/format/format-host.ts +33 -10
- package/src/github/github-auth.ts +24 -14
- package/src/github/github-publish.ts +20 -14
- package/src/new-project/new-project-modal.ts +27 -18
- package/src/panels/activity-bar.ts +27 -26
- package/src/panels/ai-panel.ts +100 -44
- package/src/panels/block-action-bar.ts +84 -52
- package/src/panels/canvas-dnd.ts +47 -28
- package/src/panels/data-explorer.ts +24 -11
- package/src/panels/dnd.ts +148 -100
- package/src/panels/editors.ts +54 -37
- package/src/panels/elements-panel.ts +23 -13
- package/src/panels/events-panel.ts +48 -38
- package/src/panels/git-panel.ts +95 -60
- package/src/panels/head-panel.ts +138 -84
- package/src/panels/imports-panel.ts +66 -29
- package/src/panels/layers-panel.ts +80 -36
- package/src/panels/left-panel.ts +86 -53
- package/src/panels/overlays.ts +36 -19
- package/src/panels/panel-events.ts +48 -27
- package/src/panels/panel-scheduler.ts +41 -23
- package/src/panels/preview-render.ts +26 -26
- package/src/panels/properties-panel.ts +155 -118
- package/src/panels/pseudo-preview.ts +31 -15
- package/src/panels/quick-search.ts +28 -13
- package/src/panels/right-panel.ts +35 -24
- package/src/panels/shared.ts +46 -29
- package/src/panels/signals-panel.ts +303 -186
- package/src/panels/statusbar.ts +27 -12
- package/src/panels/style-inputs.ts +30 -24
- package/src/panels/style-panel.ts +130 -90
- package/src/panels/style-utils.ts +63 -23
- package/src/panels/stylebook-layers-panel.ts +27 -30
- package/src/panels/stylebook-panel.ts +140 -72
- package/src/panels/tab-strip.ts +21 -10
- package/src/panels/toolbar.ts +52 -40
- package/src/panels/welcome-screen.ts +1 -1
- package/src/platform.ts +2 -1
- package/src/platforms/devserver.ts +221 -105
- package/src/recent-projects.ts +15 -7
- package/src/resize-edges.ts +7 -5
- package/src/services/cem-export.ts +73 -57
- package/src/services/code-services.ts +52 -25
- package/src/services/monaco-setup.ts +5 -5
- package/src/settings/content-types-editor.ts +133 -62
- package/src/settings/css-vars-editor.ts +31 -14
- package/src/settings/defs-editor.ts +125 -63
- package/src/settings/general-settings.ts +11 -6
- package/src/settings/head-editor.ts +30 -15
- package/src/settings/schema-field-ui.ts +75 -35
- package/src/settings/settings-modal.ts +35 -17
- package/src/site-context.ts +80 -47
- package/src/state.ts +98 -65
- package/src/store.ts +42 -23
- package/src/studio.ts +165 -144
- package/src/tabs/tab.ts +51 -45
- package/src/tabs/transact.ts +230 -109
- package/src/types.ts +60 -51
- package/src/ui/button-group.ts +3 -2
- package/src/ui/color-selector.ts +33 -15
- package/src/ui/expression-editor.ts +139 -86
- package/src/ui/field-input.ts +35 -18
- package/src/ui/field-row.ts +1 -1
- package/src/ui/icons.ts +5 -6
- package/src/ui/layers.ts +33 -26
- package/src/ui/media-picker.ts +13 -7
- package/src/ui/panel-resize.ts +39 -20
- package/src/ui/spectrum.ts +4 -2
- package/src/ui/unit-selector.ts +20 -11
- package/src/ui/value-selector.ts +13 -7
- package/src/ui/widgets.ts +34 -18
- package/src/utils/canvas-media.ts +66 -33
- package/src/utils/edit-display.ts +43 -44
- package/src/utils/google-fonts.ts +10 -6
- package/src/utils/inherited-style.ts +22 -8
- package/src/utils/studio-utils.ts +88 -45
- package/src/view.ts +9 -5
- package/src/workspace/workspace.ts +49 -29
|
@@ -46,14 +46,22 @@ function componentSpecifier(comp: ComponentEntry) {
|
|
|
46
46
|
* @returns {boolean}
|
|
47
47
|
*/
|
|
48
48
|
function isComponentEnabled(comp: ComponentEntry, elements: ElementsEntry[]) {
|
|
49
|
-
if (!elements?.length)
|
|
49
|
+
if (!elements?.length) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
50
52
|
const specifier = componentSpecifier(comp);
|
|
51
53
|
for (const entry of elements) {
|
|
52
|
-
if (typeof entry !== "string")
|
|
54
|
+
if (typeof entry !== "string") {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
53
57
|
// Cherry-picked subpath match
|
|
54
|
-
if (entry === specifier)
|
|
58
|
+
if (entry === specifier) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
55
61
|
// Legacy full-package match
|
|
56
|
-
if (entry === comp.package)
|
|
62
|
+
if (entry === comp.package) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
57
65
|
}
|
|
58
66
|
return false;
|
|
59
67
|
}
|
|
@@ -64,10 +72,14 @@ function isComponentEnabled(comp: ComponentEntry, elements: ElementsEntry[]) {
|
|
|
64
72
|
* @returns {Map<string, ComponentEntry[]>}
|
|
65
73
|
*/
|
|
66
74
|
function groupByPackage() {
|
|
67
|
-
const groups
|
|
75
|
+
const groups = new Map<string, ComponentEntry[]>();
|
|
68
76
|
for (const comp of componentRegistry) {
|
|
69
|
-
if (comp.source !== "npm" || !comp.package || !comp.modulePath)
|
|
70
|
-
|
|
77
|
+
if (comp.source !== "npm" || !comp.package || !comp.modulePath) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (!groups.has(comp.package)) {
|
|
81
|
+
groups.set(comp.package, []);
|
|
82
|
+
}
|
|
71
83
|
groups.get(comp.package)?.push(comp);
|
|
72
84
|
}
|
|
73
85
|
return groups;
|
|
@@ -90,10 +102,10 @@ export function renderImportsTemplate({
|
|
|
90
102
|
}
|
|
91
103
|
|
|
92
104
|
return renderDocumentLevelImports({
|
|
93
|
-
renderLeftPanel,
|
|
94
|
-
documentPath,
|
|
95
|
-
documentElements,
|
|
96
105
|
applyMutation,
|
|
106
|
+
documentElements,
|
|
107
|
+
documentPath,
|
|
108
|
+
renderLeftPanel,
|
|
97
109
|
});
|
|
98
110
|
}
|
|
99
111
|
|
|
@@ -155,7 +167,9 @@ function renderSiteLevelImports(renderLeftPanel: () => void) {
|
|
|
155
167
|
const pathField = form?.querySelector(".import-add-path") as HTMLInputElement;
|
|
156
168
|
const name = nameField?.value?.trim();
|
|
157
169
|
const path = pathField?.value?.trim();
|
|
158
|
-
if (!name || !path)
|
|
170
|
+
if (!name || !path) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
159
173
|
nameField.value = "";
|
|
160
174
|
pathField.value = "";
|
|
161
175
|
const updated = { ...siteImports, [name]: path };
|
|
@@ -183,13 +197,15 @@ function renderSiteLevelImports(renderLeftPanel: () => void) {
|
|
|
183
197
|
confirmLabel: "Remove",
|
|
184
198
|
destructive: true,
|
|
185
199
|
});
|
|
186
|
-
if (!confirmed)
|
|
200
|
+
if (!confirmed) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
187
203
|
try {
|
|
188
204
|
const platform = getPlatform();
|
|
189
205
|
await platform.removePackage(pkg);
|
|
190
206
|
// Also remove all cherry-picked elements for this package
|
|
191
207
|
const updatedElements = siteElements.filter(
|
|
192
|
-
(e: ElementsEntry) => typeof e !== "string" || !e.startsWith(pkg
|
|
208
|
+
(e: ElementsEntry) => typeof e !== "string" || !e.startsWith(`${pkg}/`),
|
|
193
209
|
);
|
|
194
210
|
const { loadComponentRegistry } = await import("../files/components.js");
|
|
195
211
|
await loadComponentRegistry();
|
|
@@ -197,8 +213,8 @@ function renderSiteLevelImports(renderLeftPanel: () => void) {
|
|
|
197
213
|
$elements: updatedElements as (string | JxElement)[],
|
|
198
214
|
});
|
|
199
215
|
renderLeftPanel();
|
|
200
|
-
} catch (
|
|
201
|
-
console.error("Failed to remove package:",
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.error("Failed to remove package:", error);
|
|
202
218
|
}
|
|
203
219
|
}}
|
|
204
220
|
>
|
|
@@ -219,7 +235,9 @@ function renderSiteLevelImports(renderLeftPanel: () => void) {
|
|
|
219
235
|
// Remove legacy full-package import if present
|
|
220
236
|
updated = updated.filter((el: ElementsEntry) => el !== pkg);
|
|
221
237
|
if ((e.target as HTMLInputElement).checked) {
|
|
222
|
-
if (!updated.includes(specifier))
|
|
238
|
+
if (!updated.includes(specifier)) {
|
|
239
|
+
updated.push(specifier);
|
|
240
|
+
}
|
|
223
241
|
} else {
|
|
224
242
|
updated = updated.filter((el: ElementsEntry) => el !== specifier);
|
|
225
243
|
}
|
|
@@ -250,9 +268,13 @@ function renderSiteLevelImports(renderLeftPanel: () => void) {
|
|
|
250
268
|
size="s"
|
|
251
269
|
style="flex:1"
|
|
252
270
|
@keydown=${async (e: KeyboardEvent) => {
|
|
253
|
-
if (e.key !== "Enter")
|
|
271
|
+
if (e.key !== "Enter") {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
254
274
|
const name = (e.target as HTMLInputElement).value?.trim();
|
|
255
|
-
if (!name)
|
|
275
|
+
if (!name) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
256
278
|
(e.target as HTMLInputElement).value = "";
|
|
257
279
|
try {
|
|
258
280
|
const platform = getPlatform();
|
|
@@ -260,8 +282,8 @@ function renderSiteLevelImports(renderLeftPanel: () => void) {
|
|
|
260
282
|
const { loadComponentRegistry } = await import("../files/components.js");
|
|
261
283
|
await loadComponentRegistry();
|
|
262
284
|
renderLeftPanel();
|
|
263
|
-
} catch (
|
|
264
|
-
console.error("Failed to add package:",
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error("Failed to add package:", error);
|
|
265
287
|
}
|
|
266
288
|
}}
|
|
267
289
|
></sp-textfield>
|
|
@@ -274,7 +296,9 @@ function renderSiteLevelImports(renderLeftPanel: () => void) {
|
|
|
274
296
|
.closest(".import-add-form")
|
|
275
297
|
?.querySelector("sp-textfield");
|
|
276
298
|
const name = (input as HTMLInputElement | null)?.value?.trim();
|
|
277
|
-
if (!name)
|
|
299
|
+
if (!name) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
278
302
|
(input as HTMLInputElement).value = "";
|
|
279
303
|
try {
|
|
280
304
|
const platform = getPlatform();
|
|
@@ -282,8 +306,8 @@ function renderSiteLevelImports(renderLeftPanel: () => void) {
|
|
|
282
306
|
const { loadComponentRegistry } = await import("../files/components.js");
|
|
283
307
|
await loadComponentRegistry();
|
|
284
308
|
renderLeftPanel();
|
|
285
|
-
} catch (
|
|
286
|
-
console.error("Failed to add package:",
|
|
309
|
+
} catch (error) {
|
|
310
|
+
console.error("Failed to add package:", error);
|
|
287
311
|
}
|
|
288
312
|
}}
|
|
289
313
|
>
|
|
@@ -313,7 +337,10 @@ function renderDocumentLevelImports({
|
|
|
313
337
|
const importedRefs = new Set(refEntries.map((e: ElementsEntry) => (e as { $ref: string }).$ref));
|
|
314
338
|
const availableComponents = componentRegistry.filter(
|
|
315
339
|
(c: ComponentEntry) =>
|
|
316
|
-
c.source !== "npm" &&
|
|
340
|
+
c.source !== "npm" &&
|
|
341
|
+
c.path != null &&
|
|
342
|
+
!importedRefs.has(`./${c.path}`) &&
|
|
343
|
+
!importedRefs.has(c.path),
|
|
317
344
|
);
|
|
318
345
|
|
|
319
346
|
const packageGroups = groupByPackage();
|
|
@@ -368,13 +395,19 @@ function renderDocumentLevelImports({
|
|
|
368
395
|
class="import-picker"
|
|
369
396
|
@change=${(e: Event) => {
|
|
370
397
|
const tag = (e.target as HTMLInputElement).value;
|
|
371
|
-
if (!tag)
|
|
398
|
+
if (!tag) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
372
401
|
(e.target as HTMLInputElement).value = "";
|
|
373
402
|
const comp = componentRegistry.find((c: ComponentEntry) => c.tagName === tag);
|
|
374
|
-
if (!comp)
|
|
403
|
+
if (!comp?.path) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
375
406
|
const relPath = computeRelativePath(documentPath, comp.path);
|
|
376
407
|
applyMutation((doc: JxMutableNode) => {
|
|
377
|
-
if (!doc.$elements)
|
|
408
|
+
if (!doc.$elements) {
|
|
409
|
+
doc.$elements = [];
|
|
410
|
+
}
|
|
378
411
|
doc.$elements.push({ $ref: relPath });
|
|
379
412
|
});
|
|
380
413
|
renderLeftPanel();
|
|
@@ -408,11 +441,15 @@ function renderDocumentLevelImports({
|
|
|
408
441
|
.checked=${enabled}
|
|
409
442
|
@change=${(e: Event) => {
|
|
410
443
|
applyMutation((doc: JxMutableNode) => {
|
|
411
|
-
if (!doc.$elements)
|
|
444
|
+
if (!doc.$elements) {
|
|
445
|
+
doc.$elements = [];
|
|
446
|
+
}
|
|
412
447
|
// Remove legacy full-package import if present
|
|
413
448
|
doc.$elements = doc.$elements.filter((el: ElementsEntry) => el !== pkg);
|
|
414
449
|
if ((e.target as HTMLInputElement).checked) {
|
|
415
|
-
if (!doc.$elements.includes(specifier))
|
|
450
|
+
if (!doc.$elements.includes(specifier)) {
|
|
451
|
+
doc.$elements.push(specifier);
|
|
452
|
+
}
|
|
416
453
|
} else {
|
|
417
454
|
doc.$elements = doc.$elements.filter(
|
|
418
455
|
(el: ElementsEntry) => el !== specifier,
|
|
@@ -8,28 +8,30 @@ import { html, nothing } from "lit-html";
|
|
|
8
8
|
import { classMap } from "lit-html/directives/class-map.js";
|
|
9
9
|
import { ifDefined } from "lit-html/directives/if-defined.js";
|
|
10
10
|
import {
|
|
11
|
+
VOID_ELEMENTS,
|
|
12
|
+
childIndex,
|
|
13
|
+
childList,
|
|
11
14
|
flattenTree,
|
|
12
15
|
getNodeAtPath,
|
|
16
|
+
nodeLabel,
|
|
17
|
+
parentElementPath,
|
|
13
18
|
pathKey,
|
|
14
19
|
pathsEqual,
|
|
15
|
-
parentElementPath,
|
|
16
|
-
childIndex,
|
|
17
|
-
nodeLabel,
|
|
18
|
-
VOID_ELEMENTS,
|
|
19
20
|
} from "../store";
|
|
20
21
|
import { activeTab } from "../workspace/workspace";
|
|
21
22
|
import type { JxPath } from "../state";
|
|
22
23
|
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
23
24
|
import {
|
|
24
|
-
transactDoc,
|
|
25
25
|
mutateMoveNode,
|
|
26
26
|
mutateRemoveNode,
|
|
27
27
|
mutateUpdateProperty,
|
|
28
|
+
transactDoc,
|
|
28
29
|
} from "../tabs/transact";
|
|
29
30
|
import { view } from "../view";
|
|
30
31
|
import { isInlineElement } from "../editor/inline-edit";
|
|
31
32
|
import { showContextMenu } from "../editor/context-menu";
|
|
32
33
|
import { panToElement } from "../canvas/canvas-utils";
|
|
34
|
+
import type { TemplateResult } from "lit-html";
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
37
|
* Start inline title editing on a layer row.
|
|
@@ -40,14 +42,22 @@ import { panToElement } from "../canvas/canvas-utils";
|
|
|
40
42
|
export function startLayerTitleEdit(path: JxPath, rerender: () => void) {
|
|
41
43
|
const key = pathKey(path);
|
|
42
44
|
const row = document.querySelector(`.layer-row[data-path="${key}"]`);
|
|
43
|
-
if (!row)
|
|
45
|
+
if (!row) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
44
48
|
const label = row.querySelector(".layer-label") as HTMLElement | null;
|
|
45
|
-
if (!label)
|
|
49
|
+
if (!label) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
46
52
|
|
|
47
53
|
const tab = activeTab.value;
|
|
48
|
-
if (!tab)
|
|
54
|
+
if (!tab) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
49
57
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
50
|
-
if (!node)
|
|
58
|
+
if (!node) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
51
61
|
|
|
52
62
|
label.style.display = "none";
|
|
53
63
|
const input = document.createElement("input");
|
|
@@ -65,7 +75,9 @@ export function startLayerTitleEdit(path: JxPath, rerender: () => void) {
|
|
|
65
75
|
label.style.display = "";
|
|
66
76
|
};
|
|
67
77
|
const commit = () => {
|
|
68
|
-
if (committed)
|
|
78
|
+
if (committed) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
69
81
|
committed = true;
|
|
70
82
|
cleanup();
|
|
71
83
|
const val = input.value.trim();
|
|
@@ -73,7 +85,9 @@ export function startLayerTitleEdit(path: JxPath, rerender: () => void) {
|
|
|
73
85
|
rerender();
|
|
74
86
|
};
|
|
75
87
|
const cancel = () => {
|
|
76
|
-
if (committed)
|
|
88
|
+
if (committed) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
77
91
|
committed = true;
|
|
78
92
|
cleanup();
|
|
79
93
|
rerender();
|
|
@@ -101,13 +115,15 @@ export function renderLayersTemplate(ctx: {
|
|
|
101
115
|
}) {
|
|
102
116
|
const tab = activeTab.value;
|
|
103
117
|
|
|
104
|
-
for (const fn of view.dndCleanups)
|
|
118
|
+
for (const fn of view.dndCleanups) {
|
|
119
|
+
fn();
|
|
120
|
+
}
|
|
105
121
|
view.dndCleanups = [];
|
|
106
122
|
|
|
107
123
|
const rows = flattenTree(tab!.doc.document);
|
|
108
|
-
const collapsed =
|
|
124
|
+
const collapsed = (view._layersCollapsed ||= new Set());
|
|
109
125
|
|
|
110
|
-
const layerRows:
|
|
126
|
+
const layerRows: TemplateResult[] = [];
|
|
111
127
|
for (const { node, path, depth, nodeType } of rows) {
|
|
112
128
|
let hidden = false;
|
|
113
129
|
for (let d = 1; d <= path.length; d++) {
|
|
@@ -117,12 +133,16 @@ export function renderLayersTemplate(ctx: {
|
|
|
117
133
|
break;
|
|
118
134
|
}
|
|
119
135
|
}
|
|
120
|
-
if (hidden)
|
|
136
|
+
if (hidden) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
121
139
|
|
|
122
|
-
if (tab?.doc.mode === "content" && path.length === 0)
|
|
140
|
+
if (tab?.doc.mode === "content" && path.length === 0) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
123
143
|
|
|
124
144
|
if (nodeType === "text") {
|
|
125
|
-
const textPreview = String(node).length > 40 ? String(node).slice(0, 40)
|
|
145
|
+
const textPreview = String(node).length > 40 ? `${String(node).slice(0, 40)}…` : String(node);
|
|
126
146
|
layerRows.push(html`
|
|
127
147
|
<div
|
|
128
148
|
class="layer-row"
|
|
@@ -136,13 +156,17 @@ export function renderLayersTemplate(ctx: {
|
|
|
136
156
|
}
|
|
137
157
|
|
|
138
158
|
// After text-node skip, node is guaranteed to be JxMutableNode (not a primitive)
|
|
139
|
-
if (typeof node !== "object" || node === null)
|
|
159
|
+
if (typeof node !== "object" || node === null) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
140
162
|
const jxNode: JxMutableNode = node as JxMutableNode;
|
|
141
163
|
|
|
142
164
|
if (path.length >= 2 && nodeType === "element") {
|
|
143
165
|
const pPath = parentElementPath(path);
|
|
144
166
|
const parentNode = pPath ? getNodeAtPath(tab!.doc.document, pPath) : null;
|
|
145
|
-
if (parentNode && isInlineElement(jxNode, parentNode))
|
|
167
|
+
if (parentNode && isInlineElement(jxNode, parentNode)) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
146
170
|
}
|
|
147
171
|
|
|
148
172
|
const key = pathKey(path);
|
|
@@ -173,8 +197,8 @@ export function renderLayersTemplate(ctx: {
|
|
|
173
197
|
badgeTitle = "Repeater (mapped array)";
|
|
174
198
|
} else if (nodeType === "case" || nodeType === "case-ref") {
|
|
175
199
|
badgeClass = "layer-tag case-tag";
|
|
176
|
-
badgeText = path
|
|
177
|
-
badgeTitle = `$switch case: ${path
|
|
200
|
+
badgeText = path.at(-1);
|
|
201
|
+
badgeTitle = `$switch case: ${path.at(-1)}`;
|
|
178
202
|
} else if (jxNode.$switch) {
|
|
179
203
|
badgeClass = "layer-tag switch-tag";
|
|
180
204
|
badgeText = "⇄";
|
|
@@ -202,22 +226,33 @@ export function renderLayersTemplate(ctx: {
|
|
|
202
226
|
const idx = isElement ? (childIndex(path) as number) : 0;
|
|
203
227
|
const parentPath = isElement && !isRoot ? (parentElementPath(path) as JxPath) : null;
|
|
204
228
|
const parentNode = parentPath ? getNodeAtPath(tab!.doc.document, parentPath) : null;
|
|
205
|
-
const siblingCount = parentNode
|
|
229
|
+
const siblingCount = childList(parentNode).length;
|
|
206
230
|
const canMoveUp = isElement && !isRoot && idx > 0;
|
|
207
231
|
const canMoveDown = isElement && !isRoot && idx < siblingCount - 1;
|
|
208
|
-
const prevSibling = canMoveUp && parentNode ? parentNode
|
|
232
|
+
const prevSibling = canMoveUp && parentNode ? childList(parentNode)[idx - 1] : null;
|
|
209
233
|
const prevIsContainer = (() => {
|
|
210
|
-
if (!prevSibling || typeof prevSibling !== "object")
|
|
211
|
-
|
|
234
|
+
if (!prevSibling || typeof prevSibling !== "object") {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
if (VOID_ELEMENTS.has((prevSibling.tagName || "div").toLowerCase())) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
212
240
|
const ch = prevSibling.children;
|
|
213
|
-
if (!ch)
|
|
241
|
+
if (!ch) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
214
244
|
if (
|
|
215
245
|
typeof ch === "object" &&
|
|
216
246
|
(ch as unknown as Record<string, unknown>).$prototype === "Array"
|
|
217
|
-
)
|
|
247
|
+
) {
|
|
218
248
|
return true;
|
|
219
|
-
|
|
220
|
-
if (ch
|
|
249
|
+
}
|
|
250
|
+
if (!Array.isArray(ch)) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
if (ch.length === 0) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
221
256
|
return ch.some(
|
|
222
257
|
(c) => typeof c === "object" && c !== null && !isInlineElement(c, prevSibling),
|
|
223
258
|
);
|
|
@@ -227,7 +262,7 @@ export function renderLayersTemplate(ctx: {
|
|
|
227
262
|
isElement && parentPath && parentPath.length >= 2
|
|
228
263
|
? (parentElementPath(parentPath) as JxPath)
|
|
229
264
|
: null;
|
|
230
|
-
const canMoveOut = isElement && !isRoot &&
|
|
265
|
+
const canMoveOut = isElement && !isRoot && Boolean(grandparentPath);
|
|
231
266
|
|
|
232
267
|
layerRows.push(html`
|
|
233
268
|
<div
|
|
@@ -314,7 +349,7 @@ export function renderLayersTemplate(ctx: {
|
|
|
314
349
|
const pp = parentPath as JxPath;
|
|
315
350
|
const prevPath = [...pp, idx - 1];
|
|
316
351
|
const prev = getNodeAtPath(activeTab.value!.doc.document, prevPath);
|
|
317
|
-
const len = prev
|
|
352
|
+
const len = childList(prev).length;
|
|
318
353
|
transactDoc(activeTab.value!, (t) =>
|
|
319
354
|
mutateMoveNode(t, path, prevPath, len),
|
|
320
355
|
);
|
|
@@ -366,14 +401,23 @@ export function renderLayersTemplate(ctx: {
|
|
|
366
401
|
class="layers-tree"
|
|
367
402
|
@click=${(e: MouseEvent) => {
|
|
368
403
|
const toggle = (e.target as HTMLElement).closest(".layer-toggle");
|
|
369
|
-
if (!toggle)
|
|
404
|
+
if (!toggle) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
370
407
|
e.stopPropagation();
|
|
371
408
|
const row = toggle.closest(".layer-row");
|
|
372
|
-
if (!row)
|
|
409
|
+
if (!row) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
373
412
|
const key = (row as HTMLElement).dataset.path;
|
|
374
|
-
if (!key)
|
|
375
|
-
|
|
376
|
-
|
|
413
|
+
if (!key) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (collapsed.has(key)) {
|
|
417
|
+
collapsed.delete(key);
|
|
418
|
+
} else {
|
|
419
|
+
collapsed.add(key);
|
|
420
|
+
}
|
|
377
421
|
ctx.rerender();
|
|
378
422
|
}}
|
|
379
423
|
>
|