@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.
- package/dist/studio.js +2311 -718
- 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} +109 -84
- 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} +8 -6
- 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.ts +298 -0
- 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} +35 -23
- 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/utils/edit-display.js +0 -203
- /package/src/{reactivity.js → reactivity.ts} +0 -0
|
@@ -1,39 +1,42 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Editor panels — extracted from studio.js (Phase 4g). Monaco-based function editor (JS mode) and
|
|
3
4
|
* completion provider for state scope variables.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
/** @typedef {import("../services/code-services.js").OxLintDiagnostic} OxLintDiagnostic */
|
|
7
|
-
|
|
8
7
|
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
|
|
9
8
|
import { html, render as litRender, nothing } from "lit-html";
|
|
10
9
|
import { ref } from "lit-html/directives/ref.js";
|
|
11
10
|
|
|
12
|
-
import { renderOnly, canvasWrap, canvasPanels, getNodeAtPath } from "../store
|
|
13
|
-
import { activeTab } from "../workspace/workspace
|
|
14
|
-
import { transactDoc, mutateUpdateDef, mutateUpdateProperty } from "../tabs/transact
|
|
15
|
-
import { view } from "../view
|
|
16
|
-
import { codeService, setLintMarkers, getFunctionArgs } from "../services/code-services
|
|
11
|
+
import { renderOnly, canvasWrap, canvasPanels, getNodeAtPath } from "../store";
|
|
12
|
+
import { activeTab } from "../workspace/workspace";
|
|
13
|
+
import { transactDoc, mutateUpdateDef, mutateUpdateProperty } from "../tabs/transact";
|
|
14
|
+
import { view } from "../view";
|
|
15
|
+
import { codeService, setLintMarkers, getFunctionArgs } from "../services/code-services";
|
|
16
|
+
|
|
17
|
+
import type { OxLintDiagnostic } from "../services/code-services";
|
|
18
|
+
import type { JxPrototypeDef, JxMutableNode } from "@jxsuite/schema/types";
|
|
19
|
+
import type { JxPath } from "../state";
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
type EditingTarget =
|
|
22
|
+
| { type: "def"; defName: string }
|
|
23
|
+
| { type: "event"; path: JxPath; eventKey: string };
|
|
19
24
|
|
|
20
25
|
/** @param {EditingTarget | null | undefined} editing */
|
|
21
|
-
function getFunctionBody(editing) {
|
|
26
|
+
function getFunctionBody(editing: EditingTarget | null | undefined) {
|
|
22
27
|
const document = activeTab.value?.doc.document;
|
|
23
28
|
if (editing?.type === "def") {
|
|
24
29
|
return document?.state?.[editing.defName]?.body || "";
|
|
25
30
|
} else if (editing?.type === "event") {
|
|
26
|
-
const node = getNodeAtPath(
|
|
31
|
+
const node = getNodeAtPath(document!, editing.path);
|
|
27
32
|
return node?.[editing.eventKey]?.body || "";
|
|
28
33
|
}
|
|
29
34
|
return "";
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
/** @param {() => void} closeFunctionEditor */
|
|
33
|
-
export function renderFunctionEditor(closeFunctionEditor) {
|
|
34
|
-
const editing =
|
|
35
|
-
activeTab.value?.session.ui.editingFunction
|
|
36
|
-
);
|
|
38
|
+
export function renderFunctionEditor(closeFunctionEditor: () => void) {
|
|
39
|
+
const editing = activeTab.value?.session.ui.editingFunction as EditingTarget | null | undefined;
|
|
37
40
|
|
|
38
41
|
// If editor already exists and matches current target, just sync value
|
|
39
42
|
if (view.functionEditor && view.functionEditor._editingTarget === JSON.stringify(editing)) {
|
|
@@ -73,12 +76,11 @@ export function renderFunctionEditor(closeFunctionEditor) {
|
|
|
73
76
|
|
|
74
77
|
const tab = activeTab.value;
|
|
75
78
|
const docName = tab?.documentPath?.split("/").pop() || tab?.doc.document?.tagName || "document";
|
|
76
|
-
const ed =
|
|
79
|
+
const ed = editing as EditingTarget;
|
|
77
80
|
const funcLabel = ed.type === "def" ? `ƒ ${ed.defName}` : `ƒ ${ed.eventKey}`;
|
|
78
81
|
|
|
79
82
|
// Editor container
|
|
80
|
-
|
|
81
|
-
let editorContainer = null;
|
|
83
|
+
let editorContainer: HTMLDivElement | null = null;
|
|
82
84
|
litRender(
|
|
83
85
|
html`<div class="source-wrap">
|
|
84
86
|
<div class="source-toolbar">
|
|
@@ -93,7 +95,7 @@ export function renderFunctionEditor(closeFunctionEditor) {
|
|
|
93
95
|
<div
|
|
94
96
|
class="source-editor"
|
|
95
97
|
${ref((el) => {
|
|
96
|
-
if (el) editorContainer =
|
|
98
|
+
if (el) editorContainer = el as HTMLDivElement;
|
|
97
99
|
})}
|
|
98
100
|
></div>
|
|
99
101
|
</div>`,
|
|
@@ -102,26 +104,23 @@ export function renderFunctionEditor(closeFunctionEditor) {
|
|
|
102
104
|
|
|
103
105
|
const body = getFunctionBody(editing);
|
|
104
106
|
const args = getFunctionArgs(
|
|
105
|
-
/** @type {EditingTarget} */ (editing),
|
|
107
|
+
/** @type {EditingTarget} */ (editing as EditingTarget),
|
|
106
108
|
activeTab.value?.doc.document,
|
|
107
109
|
);
|
|
108
110
|
|
|
109
|
-
view.functionEditor = monaco.editor.create(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
tabSize: 2,
|
|
123
|
-
},
|
|
124
|
-
);
|
|
111
|
+
view.functionEditor = monaco.editor.create(editorContainer as unknown as HTMLElement, {
|
|
112
|
+
value: body,
|
|
113
|
+
language: "javascript",
|
|
114
|
+
theme: "vs-dark",
|
|
115
|
+
automaticLayout: true,
|
|
116
|
+
minimap: { enabled: false },
|
|
117
|
+
fontSize: 12,
|
|
118
|
+
fontFamily: "'SF Mono', 'Fira Code', 'Consolas', monospace",
|
|
119
|
+
lineNumbers: "on",
|
|
120
|
+
scrollBeyondLastLine: false,
|
|
121
|
+
wordWrap: "on",
|
|
122
|
+
tabSize: 2,
|
|
123
|
+
});
|
|
125
124
|
view.functionEditor._editingTarget = JSON.stringify(editing);
|
|
126
125
|
const editor = view.functionEditor;
|
|
127
126
|
|
|
@@ -134,14 +133,14 @@ export function renderFunctionEditor(closeFunctionEditor) {
|
|
|
134
133
|
});
|
|
135
134
|
codeService("lint", { code: body, args }).then((result) => {
|
|
136
135
|
if (result?.diagnostics && view.functionEditor)
|
|
137
|
-
setLintMarkers(view.functionEditor,
|
|
136
|
+
setLintMarkers(view.functionEditor, result.diagnostics as OxLintDiagnostic[]);
|
|
138
137
|
});
|
|
139
138
|
|
|
140
139
|
// Debounced sync back to state + lint on edit
|
|
141
140
|
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
142
|
-
let syncDebounce;
|
|
141
|
+
let syncDebounce: ReturnType<typeof setTimeout> | undefined;
|
|
143
142
|
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
144
|
-
let lintDebounce;
|
|
143
|
+
let lintDebounce: ReturnType<typeof setTimeout> | undefined;
|
|
145
144
|
let lintGen = 0;
|
|
146
145
|
editor.onDidChangeModelContent(() => {
|
|
147
146
|
if (editor._ignoreNextChange) {
|
|
@@ -152,14 +151,11 @@ export function renderFunctionEditor(closeFunctionEditor) {
|
|
|
152
151
|
clearTimeout(syncDebounce);
|
|
153
152
|
syncDebounce = setTimeout(() => {
|
|
154
153
|
const newBody = editor.getValue();
|
|
155
|
-
const ed =
|
|
154
|
+
const ed = editing as EditingTarget;
|
|
156
155
|
if (ed.type === "def") {
|
|
157
156
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, ed.defName, { body: newBody }));
|
|
158
157
|
} else if (ed.type === "event") {
|
|
159
|
-
const node = getNodeAtPath(
|
|
160
|
-
/** @type {JxMutableNode} */ (activeTab.value?.doc.document),
|
|
161
|
-
ed.path,
|
|
162
|
-
);
|
|
158
|
+
const node = getNodeAtPath(activeTab.value?.doc.document as JxMutableNode, ed.path);
|
|
163
159
|
const current = node?.[ed.eventKey] || {};
|
|
164
160
|
transactDoc(activeTab.value, (t) =>
|
|
165
161
|
mutateUpdateProperty(t, ed.path, ed.eventKey, {
|
|
@@ -179,10 +175,7 @@ export function renderFunctionEditor(closeFunctionEditor) {
|
|
|
179
175
|
codeService("lint", { code: currentCode, args }).then((result) => {
|
|
180
176
|
if (gen !== lintGen) return;
|
|
181
177
|
if (result?.diagnostics && view.functionEditor)
|
|
182
|
-
setLintMarkers(
|
|
183
|
-
view.functionEditor,
|
|
184
|
-
/** @type {OxLintDiagnostic[]} */ (result.diagnostics),
|
|
185
|
-
);
|
|
178
|
+
setLintMarkers(view.functionEditor, result.diagnostics as OxLintDiagnostic[]);
|
|
186
179
|
});
|
|
187
180
|
}, 750);
|
|
188
181
|
});
|
|
@@ -207,11 +200,11 @@ export function registerFunctionCompletions() {
|
|
|
207
200
|
const suggestions = Object.entries(defs).map(([key, def]) => {
|
|
208
201
|
let kind = monaco.languages.CompletionItemKind.Variable;
|
|
209
202
|
if (
|
|
210
|
-
|
|
211
|
-
|
|
203
|
+
(def as JxPrototypeDef)?.$prototype === "Function" ||
|
|
204
|
+
(def as Record<string, unknown>)?.$handler
|
|
212
205
|
)
|
|
213
206
|
kind = monaco.languages.CompletionItemKind.Function;
|
|
214
|
-
else if (
|
|
207
|
+
else if ((def as JxPrototypeDef)?.$prototype)
|
|
215
208
|
kind = monaco.languages.CompletionItemKind.Property;
|
|
216
209
|
return {
|
|
217
210
|
label: `state.${key}`,
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/** Elements panel — block/component palette with categorized accordion and search filter. */
|
|
2
3
|
|
|
3
4
|
import { html, nothing } from "lit-html";
|
|
4
|
-
import { getNodeAtPath } from "../store
|
|
5
|
-
import { activeTab } from "../workspace/workspace
|
|
6
|
-
import { transactDoc, mutateInsertNode } from "../tabs/transact
|
|
7
|
-
import { view } from "../view
|
|
8
|
-
import { getEffectiveElements } from "../site-context
|
|
9
|
-
import { componentRegistry } from "../files/components
|
|
5
|
+
import { getNodeAtPath } from "../store";
|
|
6
|
+
import { activeTab } from "../workspace/workspace";
|
|
7
|
+
import { transactDoc, mutateInsertNode } from "../tabs/transact";
|
|
8
|
+
import { view } from "../view";
|
|
9
|
+
import { getEffectiveElements } from "../site-context";
|
|
10
|
+
import { componentRegistry } from "../files/components";
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
import type { ComponentEntry } from "../files/components";
|
|
13
|
+
import type { JxElement, JxMutableNode } from "@jxsuite/schema/types";
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* @param {{
|
|
@@ -18,7 +20,11 @@ import { componentRegistry } from "../files/components.js";
|
|
|
18
20
|
* }} ctx
|
|
19
21
|
* @returns {import("lit-html").TemplateResult}
|
|
20
22
|
*/
|
|
21
|
-
export function renderElementsTemplate(ctx
|
|
23
|
+
export function renderElementsTemplate(ctx: {
|
|
24
|
+
webdata: { elements: Record<string, { tag: string }[]> };
|
|
25
|
+
defaultDef: (tag: string) => JxMutableNode;
|
|
26
|
+
rerender: () => void;
|
|
27
|
+
}) {
|
|
22
28
|
const tab = activeTab.value;
|
|
23
29
|
|
|
24
30
|
const categories = Object.entries(ctx.webdata.elements).map(
|
|
@@ -32,8 +38,8 @@ export function renderElementsTemplate(ctx) {
|
|
|
32
38
|
<sp-accordion-item
|
|
33
39
|
label=${category}
|
|
34
40
|
?open=${!view.elementsCollapsed.has(category)}
|
|
35
|
-
@sp-accordion-item-toggle=${(
|
|
36
|
-
if (
|
|
41
|
+
@sp-accordion-item-toggle=${(e: Event) => {
|
|
42
|
+
if ((e.target as HTMLElement & { open: boolean }).open)
|
|
37
43
|
view.elementsCollapsed.delete(category);
|
|
38
44
|
else view.elementsCollapsed.add(category);
|
|
39
45
|
}}
|
|
@@ -47,9 +53,9 @@ export function renderElementsTemplate(ctx) {
|
|
|
47
53
|
@click=${() => {
|
|
48
54
|
const t = activeTab.value;
|
|
49
55
|
const parentPath = t?.session.selection || [];
|
|
50
|
-
const parent = getNodeAtPath(t
|
|
56
|
+
const parent = getNodeAtPath(t!.doc.document, parentPath);
|
|
51
57
|
const idx = parent?.children ? parent.children.length : 0;
|
|
52
|
-
transactDoc(t
|
|
58
|
+
transactDoc(t!, (tr) =>
|
|
53
59
|
mutateInsertNode(tr, parentPath, idx, structuredClone(def)),
|
|
54
60
|
);
|
|
55
61
|
}}
|
|
@@ -65,14 +71,13 @@ export function renderElementsTemplate(ctx) {
|
|
|
65
71
|
);
|
|
66
72
|
|
|
67
73
|
const effectiveEls = getEffectiveElements(
|
|
68
|
-
|
|
74
|
+
tab?.doc.document?.$elements as (string | JxElement)[] | undefined,
|
|
69
75
|
);
|
|
70
|
-
|
|
71
|
-
const enabledTags = new Set();
|
|
76
|
+
const enabledTags: Set<string> = new Set();
|
|
72
77
|
for (const entry of effectiveEls) {
|
|
73
78
|
if (typeof entry !== "string") continue;
|
|
74
79
|
const comp = componentRegistry.find(
|
|
75
|
-
(
|
|
80
|
+
(c: ComponentEntry) =>
|
|
76
81
|
c.source === "npm" && c.modulePath && entry === `${c.package}/${c.modulePath}`,
|
|
77
82
|
);
|
|
78
83
|
if (comp) {
|
|
@@ -86,11 +91,9 @@ export function renderElementsTemplate(ctx) {
|
|
|
86
91
|
const compsFiltered =
|
|
87
92
|
componentRegistry.length > 0
|
|
88
93
|
? componentRegistry
|
|
94
|
+
.filter((c: ComponentEntry) => c.source !== "npm" || enabledTags.has(c.tagName))
|
|
89
95
|
.filter(
|
|
90
|
-
(
|
|
91
|
-
)
|
|
92
|
-
.filter(
|
|
93
|
-
(/** @type {ComponentEntry} */ c) =>
|
|
96
|
+
(c: ComponentEntry) =>
|
|
94
97
|
!view.elementsFilter || c.tagName.toLowerCase().includes(view.elementsFilter),
|
|
95
98
|
)
|
|
96
99
|
: [];
|
|
@@ -101,15 +104,15 @@ export function renderElementsTemplate(ctx) {
|
|
|
101
104
|
<sp-accordion-item
|
|
102
105
|
label="Components"
|
|
103
106
|
?open=${!view.elementsCollapsed.has("Components")}
|
|
104
|
-
@sp-accordion-item-toggle=${(
|
|
105
|
-
if (
|
|
107
|
+
@sp-accordion-item-toggle=${(e: Event) => {
|
|
108
|
+
if ((e.target as HTMLElement & { open: boolean }).open)
|
|
106
109
|
view.elementsCollapsed.delete("Components");
|
|
107
110
|
else view.elementsCollapsed.add("Components");
|
|
108
111
|
}}
|
|
109
112
|
>
|
|
110
113
|
<div class="components-section">
|
|
111
114
|
${compsFiltered.map(
|
|
112
|
-
(
|
|
115
|
+
(comp: ComponentEntry) => html`
|
|
113
116
|
<div
|
|
114
117
|
class="element-card"
|
|
115
118
|
data-component-tag=${comp.tagName}
|
|
@@ -119,7 +122,7 @@ export function renderElementsTemplate(ctx) {
|
|
|
119
122
|
@click=${() => {
|
|
120
123
|
const t = activeTab.value;
|
|
121
124
|
const parentPath = t?.session.selection || [];
|
|
122
|
-
const parent = getNodeAtPath(t
|
|
125
|
+
const parent = getNodeAtPath(t!.doc.document, parentPath);
|
|
123
126
|
const idx = parent?.children ? parent.children.length : 0;
|
|
124
127
|
const instanceDef = {
|
|
125
128
|
tagName: comp.tagName,
|
|
@@ -132,7 +135,7 @@ export function renderElementsTemplate(ctx) {
|
|
|
132
135
|
),
|
|
133
136
|
),
|
|
134
137
|
};
|
|
135
|
-
transactDoc(t
|
|
138
|
+
transactDoc(t!, (tr) =>
|
|
136
139
|
mutateInsertNode(tr, parentPath, idx, structuredClone(instanceDef)),
|
|
137
140
|
);
|
|
138
141
|
}}
|
|
@@ -156,8 +159,8 @@ export function renderElementsTemplate(ctx) {
|
|
|
156
159
|
size="s"
|
|
157
160
|
placeholder="Filter elements…"
|
|
158
161
|
value=${view.elementsFilter}
|
|
159
|
-
@input=${(
|
|
160
|
-
view.elementsFilter =
|
|
162
|
+
@input=${(e: Event) => {
|
|
163
|
+
view.elementsFilter = (e.target as HTMLInputElement).value.toLowerCase();
|
|
161
164
|
ctx.rerender();
|
|
162
165
|
}}
|
|
163
166
|
></sp-search>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
import { getNodeAtPath } from "../store";
|
|
2
3
|
import { html, nothing } from "lit-html";
|
|
3
4
|
import { live } from "lit-html/directives/live.js";
|
|
4
|
-
import { activeTab } from "../workspace/workspace
|
|
5
|
-
import { transactDoc, mutateUpdateProperty } from "../tabs/transact
|
|
6
|
-
import { renderExpressionEditor } from "../ui/expression-editor
|
|
5
|
+
import { activeTab } from "../workspace/workspace";
|
|
6
|
+
import { transactDoc, mutateUpdateProperty } from "../tabs/transact";
|
|
7
|
+
import { renderExpressionEditor } from "../ui/expression-editor";
|
|
8
|
+
|
|
9
|
+
import type { JxPrototypeDef } from "@jxsuite/schema/types";
|
|
7
10
|
|
|
8
11
|
export const EVENT_NAMES = [
|
|
9
12
|
"onclick",
|
|
@@ -19,28 +22,29 @@ export const EVENT_NAMES = [
|
|
|
19
22
|
];
|
|
20
23
|
|
|
21
24
|
/** @param {{ isCustomElementDoc: () => boolean }} helpers */
|
|
22
|
-
export function eventsSidebarTemplate(helpers) {
|
|
25
|
+
export function eventsSidebarTemplate(helpers: { isCustomElementDoc: () => boolean }) {
|
|
23
26
|
const { isCustomElementDoc } = helpers;
|
|
24
27
|
const tab = activeTab.value;
|
|
25
28
|
const selection = tab?.session.selection;
|
|
26
29
|
const document = tab?.doc.document;
|
|
27
30
|
if (!selection) return html`<div class="empty-state">Select an element to edit events</div>`;
|
|
28
|
-
const node = getNodeAtPath(document
|
|
31
|
+
const node = getNodeAtPath(document!, selection);
|
|
29
32
|
if (!node) return html`<div class="empty-state">Node not found</div>`;
|
|
30
33
|
|
|
31
|
-
const defs = document
|
|
34
|
+
const defs = document!.state || {};
|
|
32
35
|
const functionDefs = Object.entries(defs).filter(
|
|
33
|
-
([, d]) =>
|
|
36
|
+
([, d]) =>
|
|
37
|
+
(d as JxPrototypeDef)?.$prototype === "Function" || (d as Record<string, unknown>)?.$handler,
|
|
34
38
|
);
|
|
35
39
|
|
|
36
40
|
// Declared CEM events (custom element docs)
|
|
37
|
-
|
|
38
|
-
let declaredEventsT = nothing;
|
|
41
|
+
let declaredEventsT: unknown = nothing;
|
|
39
42
|
if (isCustomElementDoc()) {
|
|
40
|
-
const allEmits = [];
|
|
43
|
+
const allEmits: Record<string, unknown>[] = [];
|
|
41
44
|
for (const [fnName, d] of Object.entries(defs)) {
|
|
42
|
-
if (Array.isArray(d.emits)) {
|
|
43
|
-
for (const ev of d.emits
|
|
45
|
+
if (Array.isArray((d as Record<string, unknown>).emits)) {
|
|
46
|
+
for (const ev of (d as Record<string, unknown>).emits as Record<string, unknown>[])
|
|
47
|
+
allEmits.push({ ...ev, _fn: fnName });
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
if (allEmits.length > 0) {
|
|
@@ -52,7 +56,11 @@ export function eventsSidebarTemplate(helpers) {
|
|
|
52
56
|
<div class="declared-event-row" title=${ev.description || ""}>
|
|
53
57
|
<code class="event-code">${ev.name || "(unnamed)"}</code>
|
|
54
58
|
<span class="event-source">← ${ev._fn}</span>
|
|
55
|
-
${ev.type
|
|
59
|
+
${(ev.type as Record<string, unknown>)?.text
|
|
60
|
+
? html`<span class="event-type"
|
|
61
|
+
>${(ev.type as Record<string, unknown>).text}</span
|
|
62
|
+
>`
|
|
63
|
+
: nothing}
|
|
56
64
|
</div>
|
|
57
65
|
`,
|
|
58
66
|
)}
|
|
@@ -89,8 +97,8 @@ export function eventsSidebarTemplate(helpers) {
|
|
|
89
97
|
size="s"
|
|
90
98
|
class="event-name"
|
|
91
99
|
.value=${live(evKey)}
|
|
92
|
-
@change=${(
|
|
93
|
-
const newKey =
|
|
100
|
+
@change=${(e: Event) => {
|
|
101
|
+
const newKey = (e.target as HTMLInputElement).value;
|
|
94
102
|
if (newKey && newKey !== evKey) {
|
|
95
103
|
transactDoc(activeTab.value, (t) => {
|
|
96
104
|
mutateUpdateProperty(t, selection, evKey, undefined);
|
|
@@ -107,8 +115,8 @@ export function eventsSidebarTemplate(helpers) {
|
|
|
107
115
|
size="s"
|
|
108
116
|
class="event-mode"
|
|
109
117
|
.value=${live(currentMode)}
|
|
110
|
-
@change=${(
|
|
111
|
-
const newMode =
|
|
118
|
+
@change=${(e: Event) => {
|
|
119
|
+
const newMode = (e.target as HTMLInputElement).value;
|
|
112
120
|
if (newMode === "inline") {
|
|
113
121
|
transactDoc(activeTab.value, (t) =>
|
|
114
122
|
mutateUpdateProperty(t, selection, evKey, {
|
|
@@ -160,11 +168,11 @@ export function eventsSidebarTemplate(helpers) {
|
|
|
160
168
|
grows
|
|
161
169
|
placeholder="// handler body"
|
|
162
170
|
.value=${live(evVal.body || "")}
|
|
163
|
-
@input=${(
|
|
171
|
+
@input=${(e: Event) => {
|
|
164
172
|
transactDoc(activeTab.value, (t) =>
|
|
165
173
|
mutateUpdateProperty(t, selection, evKey, {
|
|
166
174
|
$prototype: "Function",
|
|
167
|
-
body:
|
|
175
|
+
body: (e.target as HTMLInputElement).value,
|
|
168
176
|
parameters: evVal.parameters || [],
|
|
169
177
|
}),
|
|
170
178
|
);
|
|
@@ -192,7 +200,7 @@ export function eventsSidebarTemplate(helpers) {
|
|
|
192
200
|
<div class="event-body-row">
|
|
193
201
|
${renderExpressionEditor(
|
|
194
202
|
evVal.$expression,
|
|
195
|
-
(
|
|
203
|
+
(newNode: any) =>
|
|
196
204
|
transactDoc(activeTab.value, (t) =>
|
|
197
205
|
mutateUpdateProperty(t, selection, evKey, {
|
|
198
206
|
$expression: newNode,
|
|
@@ -207,14 +215,14 @@ export function eventsSidebarTemplate(helpers) {
|
|
|
207
215
|
size="s"
|
|
208
216
|
class="event-handler"
|
|
209
217
|
.value=${live(evVal.$ref || "__none__")}
|
|
210
|
-
@change=${(
|
|
218
|
+
@change=${(e: Event) => {
|
|
211
219
|
if (
|
|
212
|
-
|
|
213
|
-
|
|
220
|
+
(e.target as HTMLInputElement).value &&
|
|
221
|
+
(e.target as HTMLInputElement).value !== "__none__"
|
|
214
222
|
) {
|
|
215
223
|
transactDoc(activeTab.value, (t) =>
|
|
216
224
|
mutateUpdateProperty(t, selection, evKey, {
|
|
217
|
-
$ref:
|
|
225
|
+
$ref: (e.target as HTMLInputElement).value,
|
|
218
226
|
}),
|
|
219
227
|
);
|
|
220
228
|
} else {
|