@jxsuite/studio 0.19.0 → 0.20.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.css +98 -98
- package/dist/studio.js +12577 -12183
- package/dist/studio.js.map +146 -144
- package/dist/workers/editor.worker.js +79 -79
- package/dist/workers/json.worker.js +109 -109
- package/dist/workers/ts.worker.js +82 -82
- package/package.json +17 -6
- package/src/browse/browse.js +25 -19
- package/src/canvas/canvas-diff.js +24 -16
- package/src/canvas/canvas-helpers.js +24 -19
- package/src/canvas/canvas-live-render.js +94 -39
- package/src/canvas/canvas-render.js +119 -73
- package/src/canvas/canvas-utils.js +38 -15
- package/src/canvas/nested-site-style.js +50 -0
- package/src/editor/component-inline-edit.js +14 -13
- package/src/editor/content-inline-edit.js +22 -10
- package/src/editor/context-menu.js +1 -1
- package/src/editor/convert-to-component.js +12 -10
- package/src/editor/inline-edit.js +66 -28
- package/src/editor/insertion-helper.js +16 -12
- package/src/editor/shortcuts.js +4 -2
- package/src/editor/slash-menu.js +6 -4
- package/src/files/components.js +1 -1
- package/src/files/file-ops.js +37 -16
- package/src/files/files.js +78 -52
- package/src/github/github-auth.js +122 -0
- package/src/github/github-publish.js +115 -0
- package/src/markdown/md-convert.js +172 -107
- package/src/new-project/new-project-modal.js +204 -0
- package/src/panels/activity-bar.js +22 -20
- package/src/panels/ai-panel.js +399 -0
- package/src/panels/block-action-bar.js +5 -5
- package/src/panels/canvas-dnd.js +8 -2
- package/src/panels/data-explorer.js +19 -13
- package/src/panels/dnd.js +144 -92
- package/src/panels/editors.js +55 -35
- package/src/panels/elements-panel.js +33 -19
- package/src/panels/events-panel.js +15 -10
- package/src/panels/git-panel.js +469 -98
- package/src/panels/head-panel.js +121 -81
- package/src/panels/imports-panel.js +88 -64
- package/src/panels/layers-panel.js +64 -43
- package/src/panels/left-panel.js +85 -47
- package/src/panels/overlays.js +1 -0
- package/src/panels/panel-events.js +45 -30
- package/src/panels/preview-render.js +23 -18
- package/src/panels/properties-panel.js +365 -249
- package/src/panels/pseudo-preview.js +2 -2
- package/src/panels/quick-search.js +7 -5
- package/src/panels/right-panel.js +26 -2
- package/src/panels/shared.js +4 -4
- package/src/panels/signals-panel.js +295 -166
- package/src/panels/statusbar.js +4 -4
- package/src/panels/style-inputs.js +67 -35
- package/src/panels/style-panel.js +233 -132
- package/src/panels/style-utils.js +34 -16
- package/src/panels/stylebook-layers-panel.js +12 -10
- package/src/panels/stylebook-panel.js +134 -66
- package/src/panels/toolbar.js +333 -109
- package/src/panels/welcome-screen.js +121 -0
- package/src/platform.js +2 -4
- package/src/platforms/devserver.js +113 -7
- package/src/resize-edges.js +98 -0
- package/src/services/cem-export.js +12 -7
- package/src/services/code-services.js +30 -12
- package/src/settings/content-types-editor.js +7 -7
- package/src/settings/css-vars-editor.js +30 -24
- package/src/settings/defs-editor.js +12 -7
- package/src/settings/general-settings.js +85 -3
- package/src/settings/head-editor.js +30 -24
- package/src/settings/schema-field-ui.js +58 -39
- package/src/site-context.js +41 -31
- package/src/state.js +70 -29
- package/src/store.js +21 -26
- package/src/studio.js +103 -81
- package/src/tabs/tab.js +67 -43
- package/src/tabs/transact.js +23 -13
- package/src/ui/button-group.js +24 -24
- package/src/ui/color-selector.js +28 -23
- package/src/ui/field-row.js +3 -3
- package/src/ui/icons.js +2 -2
- package/src/ui/media-picker.js +7 -7
- package/src/ui/spectrum.js +5 -1
- package/src/ui/unit-selector.js +18 -16
- package/src/ui/value-selector.js +21 -15
- package/src/ui/widgets.js +22 -19
- package/src/utils/canvas-media.js +5 -4
- package/src/utils/edit-display.js +31 -20
- package/src/utils/google-fonts.js +11 -11
- package/src/utils/inherited-style.js +9 -8
- package/src/utils/studio-utils.js +7 -7
- package/src/view.js +58 -1
- package/src/workspace/workspace.js +10 -7
|
@@ -20,17 +20,82 @@ import { renderFieldRow } from "../ui/field-row.js";
|
|
|
20
20
|
import { renderMediaPicker } from "../ui/media-picker.js";
|
|
21
21
|
import { fetchPluginSchema, pluginSchemaCache } from "../services/code-services.js";
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {{
|
|
25
|
+
* document: JxMutableNode;
|
|
26
|
+
* ui?: Record<string, unknown>;
|
|
27
|
+
* mode?: string;
|
|
28
|
+
* selection?: (string | number)[] | null;
|
|
29
|
+
* canvas?: Record<string, unknown>;
|
|
30
|
+
* _collapsedSignalCats?: Set<string>;
|
|
31
|
+
* documentPath?: string | null;
|
|
32
|
+
* }} SignalsPanelState
|
|
33
|
+
*
|
|
34
|
+
* @typedef {{ renderLeftPanel(): void; renderCanvas(): void; updateSession(patch: object): void }} SignalsPanelCtx
|
|
35
|
+
*
|
|
36
|
+
* @typedef {Record<string, unknown> & {
|
|
37
|
+
* $prototype?: string;
|
|
38
|
+
* $compute?: string;
|
|
39
|
+
* $deps?: string[];
|
|
40
|
+
* $handler?: unknown;
|
|
41
|
+
* $src?: string;
|
|
42
|
+
* $export?: string;
|
|
43
|
+
* type?: string;
|
|
44
|
+
* default?: unknown;
|
|
45
|
+
* description?: string;
|
|
46
|
+
* attribute?: string;
|
|
47
|
+
* reflects?: boolean;
|
|
48
|
+
* deprecated?: string | boolean;
|
|
49
|
+
* format?: string;
|
|
50
|
+
* url?: string;
|
|
51
|
+
* method?: string;
|
|
52
|
+
* timing?: string;
|
|
53
|
+
* key?: string;
|
|
54
|
+
* database?: string;
|
|
55
|
+
* store?: string;
|
|
56
|
+
* version?: number;
|
|
57
|
+
* name?: string;
|
|
58
|
+
* body?: string;
|
|
59
|
+
* parameters?: Record<string, unknown>[];
|
|
60
|
+
* emits?: Record<string, unknown>[];
|
|
61
|
+
* fields?: unknown;
|
|
62
|
+
* }} SignalDef
|
|
63
|
+
*
|
|
64
|
+
* @typedef {{ name: string; type?: { text?: string }; description?: string; optional?: boolean }} CemParameter
|
|
65
|
+
*
|
|
66
|
+
* @typedef {{ name: string; type?: { text?: string }; description?: string }} CemEvent
|
|
67
|
+
*
|
|
68
|
+
* @typedef {{
|
|
69
|
+
* type?: string;
|
|
70
|
+
* properties?: Record<string, SchemaProperty>;
|
|
71
|
+
* required?: string[];
|
|
72
|
+
* description?: string;
|
|
73
|
+
* }} JsonSchema
|
|
74
|
+
*
|
|
75
|
+
* @typedef {{
|
|
76
|
+
* type?: string;
|
|
77
|
+
* enum?: string[];
|
|
78
|
+
* default?: unknown;
|
|
79
|
+
* format?: string;
|
|
80
|
+
* minimum?: number;
|
|
81
|
+
* maximum?: number;
|
|
82
|
+
* description?: string;
|
|
83
|
+
* examples?: string[];
|
|
84
|
+
* name?: string;
|
|
85
|
+
* }} SchemaProperty
|
|
86
|
+
*/
|
|
87
|
+
|
|
23
88
|
// ─── Module-local state ─────────────────────────────────────────────────────
|
|
24
89
|
|
|
25
90
|
/** Expanded signal editor state (persists across renders). */
|
|
26
|
-
/** @type {
|
|
91
|
+
/** @type {string | null} */
|
|
27
92
|
let expandedSignal = null;
|
|
28
93
|
|
|
29
94
|
/** Track which functions have the advanced param editor open. */
|
|
30
95
|
const advancedParamOpen = new Set();
|
|
31
96
|
|
|
32
97
|
/** Default templates for creating new signal definitions. */
|
|
33
|
-
const DEF_TEMPLATES = /** @type {Record<string,
|
|
98
|
+
const DEF_TEMPLATES = /** @type {Record<string, SignalDef>} */ ({
|
|
34
99
|
state: { type: "string", default: "" },
|
|
35
100
|
computed: { $compute: "", $deps: [] },
|
|
36
101
|
request: { $prototype: "Request", url: "", method: "GET", timing: "client" },
|
|
@@ -67,34 +132,36 @@ const STUDIO_RESERVED_KEYS = new Set([
|
|
|
67
132
|
/**
|
|
68
133
|
* Classify a state entry into a category string.
|
|
69
134
|
*
|
|
70
|
-
* @param {
|
|
135
|
+
* @param {SignalDef | unknown} def
|
|
71
136
|
*/
|
|
72
137
|
export function defCategory(def) {
|
|
73
138
|
if (!def) return "state";
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
if (
|
|
139
|
+
const d = /** @type {SignalDef} */ (def);
|
|
140
|
+
if (d.$handler || d.$prototype === "Function") return "function";
|
|
141
|
+
if (d.$compute) return "computed";
|
|
142
|
+
if (d.$prototype) return "data";
|
|
77
143
|
return "state";
|
|
78
144
|
}
|
|
79
145
|
|
|
80
146
|
/**
|
|
81
147
|
* Badge label for a def category.
|
|
82
148
|
*
|
|
83
|
-
* @param {
|
|
149
|
+
* @param {SignalDef | unknown} def
|
|
84
150
|
*/
|
|
85
151
|
export function defBadgeLabel(def) {
|
|
86
152
|
if (!def) return "S";
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
if (
|
|
153
|
+
const d = /** @type {SignalDef} */ (def);
|
|
154
|
+
if (d.$handler || d.$prototype === "Function") return "F";
|
|
155
|
+
if (d.$compute) return "C";
|
|
156
|
+
if (d.$prototype) return d.$prototype.charAt(0);
|
|
90
157
|
return "S";
|
|
91
158
|
}
|
|
92
159
|
|
|
93
160
|
/**
|
|
94
161
|
* Hint text for a signal row.
|
|
95
162
|
*
|
|
96
|
-
* @param {
|
|
97
|
-
* @param {
|
|
163
|
+
* @param {string} name
|
|
164
|
+
* @param {SignalDef | null | undefined} def
|
|
98
165
|
*/
|
|
99
166
|
export function defHint(name, def) {
|
|
100
167
|
if (!def) return "";
|
|
@@ -120,7 +187,7 @@ export function defHint(name, def) {
|
|
|
120
187
|
/**
|
|
121
188
|
* Whether the current document defines a custom element (hyphenated tagName).
|
|
122
189
|
*
|
|
123
|
-
* @param {
|
|
190
|
+
* @param {SignalsPanelState} S
|
|
124
191
|
*/
|
|
125
192
|
export function isCustomElementDoc(S) {
|
|
126
193
|
return (S.document.tagName || "").includes("-");
|
|
@@ -129,14 +196,16 @@ export function isCustomElementDoc(S) {
|
|
|
129
196
|
/**
|
|
130
197
|
* Recursively collect CSS `part` attributes from the document tree.
|
|
131
198
|
*
|
|
132
|
-
* @param {
|
|
133
|
-
* @param {
|
|
199
|
+
* @param {JxMutableNode | null | undefined} node
|
|
200
|
+
* @param {{ name: string; tag: string }[]} [parts]
|
|
134
201
|
*/
|
|
135
202
|
export function collectCssParts(node, parts = []) {
|
|
136
203
|
if (node?.attributes?.part)
|
|
137
204
|
parts.push({ name: node.attributes.part, tag: node.tagName || "div" });
|
|
138
205
|
if (Array.isArray(node?.children))
|
|
139
|
-
node.children.forEach((
|
|
206
|
+
node.children.forEach((c) => {
|
|
207
|
+
if (typeof c !== "string") collectCssParts(c, parts);
|
|
208
|
+
});
|
|
140
209
|
return parts;
|
|
141
210
|
}
|
|
142
211
|
|
|
@@ -144,13 +213,14 @@ export function collectCssParts(node, parts = []) {
|
|
|
144
213
|
* Resolve a $ref value to a display string using signal defaults. Used by the canvas to show real
|
|
145
214
|
* values instead of raw refs.
|
|
146
215
|
*
|
|
147
|
-
* @param {
|
|
148
|
-
* @param {
|
|
216
|
+
* @param {unknown} value
|
|
217
|
+
* @param {Record<string, SignalDef> | null | undefined} defs
|
|
149
218
|
*/
|
|
150
219
|
export function resolveDefaultForCanvas(value, defs) {
|
|
151
|
-
if (!value || typeof value !== "object" || !value.$ref)
|
|
152
|
-
|
|
153
|
-
/** @type {
|
|
220
|
+
if (!value || typeof value !== "object" || !(/** @type {Record<string, unknown>} */ (value).$ref))
|
|
221
|
+
return value;
|
|
222
|
+
const ref = /** @type {string} */ (/** @type {Record<string, unknown>} */ (value).$ref);
|
|
223
|
+
/** @type {string | undefined} */
|
|
154
224
|
let defName;
|
|
155
225
|
if (ref.startsWith("#/state/")) defName = ref.slice(8);
|
|
156
226
|
else if (ref.startsWith("$")) defName = ref;
|
|
@@ -187,11 +257,11 @@ export function resolveDefaultForCanvas(value, defs) {
|
|
|
187
257
|
|
|
188
258
|
/** Simple field row for signal editors — vertical stacked layout. */
|
|
189
259
|
export function signalFieldRow(
|
|
190
|
-
/** @type {
|
|
191
|
-
/** @type {
|
|
192
|
-
/** @type {
|
|
260
|
+
/** @type {string} */ label,
|
|
261
|
+
/** @type {string} */ value,
|
|
262
|
+
/** @type {(value: string) => void} */ onChange,
|
|
193
263
|
) {
|
|
194
|
-
/** @type {
|
|
264
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
195
265
|
let debounce;
|
|
196
266
|
return renderFieldRow({
|
|
197
267
|
prop: label,
|
|
@@ -201,9 +271,12 @@ export function signalFieldRow(
|
|
|
201
271
|
<sp-textfield
|
|
202
272
|
size="s"
|
|
203
273
|
value=${value}
|
|
204
|
-
@input=${(/** @type {
|
|
274
|
+
@input=${(/** @type {Event} */ e) => {
|
|
205
275
|
clearTimeout(debounce);
|
|
206
|
-
debounce = setTimeout(
|
|
276
|
+
debounce = setTimeout(
|
|
277
|
+
() => onChange(/** @type {HTMLInputElement} */ (e.target).value),
|
|
278
|
+
400,
|
|
279
|
+
);
|
|
207
280
|
}}
|
|
208
281
|
></sp-textfield>
|
|
209
282
|
`,
|
|
@@ -211,22 +284,22 @@ export function signalFieldRow(
|
|
|
211
284
|
}
|
|
212
285
|
|
|
213
286
|
/** Normalize a parameter entry to a CEM object. */
|
|
214
|
-
export function normParam(/** @type {
|
|
215
|
-
return typeof p === "string" ? { name: p } : p;
|
|
287
|
+
export function normParam(/** @type {string | Record<string, unknown>} */ p) {
|
|
288
|
+
return typeof p === "string" ? { name: p } : /** @type {CemParameter} */ (p);
|
|
216
289
|
}
|
|
217
290
|
|
|
218
291
|
// ─── Left panel: Signals ─────────────────────────────────────────────────────
|
|
219
292
|
|
|
220
293
|
/**
|
|
221
|
-
* @param {
|
|
222
|
-
* @param {
|
|
294
|
+
* @param {SignalsPanelState} S
|
|
295
|
+
* @param {SignalsPanelCtx} ctx
|
|
223
296
|
*/
|
|
224
297
|
export function renderSignalsTemplate(S, ctx) {
|
|
225
298
|
const defs = S.document.state || {};
|
|
226
299
|
const entries = Object.entries(defs);
|
|
227
300
|
|
|
228
301
|
// Group by category
|
|
229
|
-
const groups = /** @type {Record<string,
|
|
302
|
+
const groups = /** @type {Record<string, [string, SignalDef][]>} */ ({
|
|
230
303
|
state: [],
|
|
231
304
|
computed: [],
|
|
232
305
|
data: [],
|
|
@@ -259,7 +332,7 @@ export function renderSignalsTemplate(S, ctx) {
|
|
|
259
332
|
}}
|
|
260
333
|
>
|
|
261
334
|
${items.map(([name, def]) => {
|
|
262
|
-
/** @type {
|
|
335
|
+
/** @type {boolean} */
|
|
263
336
|
const isExpanded = expandedSignal === name;
|
|
264
337
|
return html`
|
|
265
338
|
<div
|
|
@@ -276,7 +349,7 @@ export function renderSignalsTemplate(S, ctx) {
|
|
|
276
349
|
quiet
|
|
277
350
|
size="xs"
|
|
278
351
|
class="signal-del"
|
|
279
|
-
@click=${(/** @type {
|
|
352
|
+
@click=${(/** @type {Event} */ e) => {
|
|
280
353
|
e.stopPropagation();
|
|
281
354
|
transactDoc(activeTab.value, (t) => mutateRemoveDef(t, name));
|
|
282
355
|
}}
|
|
@@ -304,8 +377,8 @@ export function renderSignalsTemplate(S, ctx) {
|
|
|
304
377
|
size="s"
|
|
305
378
|
label="+ Add…"
|
|
306
379
|
placeholder="+ Add…"
|
|
307
|
-
@change=${(/** @type {
|
|
308
|
-
const type = e.target.value;
|
|
380
|
+
@change=${(/** @type {Event} */ e) => {
|
|
381
|
+
const type = /** @type {HTMLInputElement} */ (e.target).value;
|
|
309
382
|
if (!type) return;
|
|
310
383
|
const template = DEF_TEMPLATES[type];
|
|
311
384
|
if (!template) return;
|
|
@@ -316,7 +389,13 @@ export function renderSignalsTemplate(S, ctx) {
|
|
|
316
389
|
while (S.document.state && S.document.state[n]) {
|
|
317
390
|
n = nameBase + i++;
|
|
318
391
|
}
|
|
319
|
-
transactDoc(activeTab.value, (t) =>
|
|
392
|
+
transactDoc(activeTab.value, (t) =>
|
|
393
|
+
mutateAddDef(
|
|
394
|
+
t,
|
|
395
|
+
n,
|
|
396
|
+
/** @type {Record<string, JsonValue>} */ (structuredClone(template)),
|
|
397
|
+
),
|
|
398
|
+
);
|
|
320
399
|
expandedSignal = n;
|
|
321
400
|
ctx.renderLeftPanel();
|
|
322
401
|
}}
|
|
@@ -343,10 +422,10 @@ export function renderSignalsTemplate(S, ctx) {
|
|
|
343
422
|
|
|
344
423
|
/** Render inline editor fields for a specific signal/def type. */
|
|
345
424
|
function renderSignalEditorTemplate(
|
|
346
|
-
/** @type {
|
|
347
|
-
/** @type {
|
|
348
|
-
/** @type {
|
|
349
|
-
/** @type {
|
|
425
|
+
/** @type {SignalsPanelState} */ S,
|
|
426
|
+
/** @type {string} */ name,
|
|
427
|
+
/** @type {SignalDef} */ def,
|
|
428
|
+
/** @type {SignalsPanelCtx} */ ctx,
|
|
350
429
|
) {
|
|
351
430
|
if (typeof def !== "object" || def === null) {
|
|
352
431
|
def = { default: def };
|
|
@@ -355,10 +434,10 @@ function renderSignalEditorTemplate(
|
|
|
355
434
|
|
|
356
435
|
// Helper for picker rows
|
|
357
436
|
const pickerRow = (
|
|
358
|
-
/** @type {
|
|
359
|
-
/** @type {
|
|
360
|
-
/** @type {
|
|
361
|
-
/** @type {
|
|
437
|
+
/** @type {string} */ label,
|
|
438
|
+
/** @type {string[]} */ options,
|
|
439
|
+
/** @type {string} */ currentVal,
|
|
440
|
+
/** @type {(value: string) => void} */ onChange,
|
|
362
441
|
) => {
|
|
363
442
|
return renderFieldRow({
|
|
364
443
|
prop: label,
|
|
@@ -368,10 +447,11 @@ function renderSignalEditorTemplate(
|
|
|
368
447
|
<sp-picker
|
|
369
448
|
size="s"
|
|
370
449
|
value=${currentVal}
|
|
371
|
-
@change=${(/** @type {
|
|
450
|
+
@change=${(/** @type {Event} */ e) =>
|
|
451
|
+
onChange(/** @type {HTMLInputElement} */ (e.target).value)}
|
|
372
452
|
>
|
|
373
453
|
${options.map(
|
|
374
|
-
(/** @type {
|
|
454
|
+
(/** @type {string} */ opt) => html`<sp-menu-item value=${opt}>${opt}</sp-menu-item>`,
|
|
375
455
|
)}
|
|
376
456
|
</sp-picker>
|
|
377
457
|
`,
|
|
@@ -380,12 +460,12 @@ function renderSignalEditorTemplate(
|
|
|
380
460
|
|
|
381
461
|
// Helper for textarea rows
|
|
382
462
|
const textareaRow = (
|
|
383
|
-
/** @type {
|
|
384
|
-
/** @type {
|
|
385
|
-
/** @type {
|
|
386
|
-
/** @type {
|
|
463
|
+
/** @type {string} */ label,
|
|
464
|
+
/** @type {string} */ value,
|
|
465
|
+
/** @type {(value: string) => void} */ onChange,
|
|
466
|
+
/** @type {{ minHeight?: string; mono?: boolean }} */ opts = {},
|
|
387
467
|
) => {
|
|
388
|
-
/** @type {
|
|
468
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
389
469
|
let debounce;
|
|
390
470
|
return renderFieldRow({
|
|
391
471
|
prop: label,
|
|
@@ -402,9 +482,12 @@ function renderSignalEditorTemplate(
|
|
|
402
482
|
}),
|
|
403
483
|
})}
|
|
404
484
|
.value=${value}
|
|
405
|
-
@input=${(/** @type {
|
|
485
|
+
@input=${(/** @type {Event} */ e) => {
|
|
406
486
|
clearTimeout(debounce);
|
|
407
|
-
debounce = setTimeout(
|
|
487
|
+
debounce = setTimeout(
|
|
488
|
+
() => onChange(/** @type {HTMLInputElement} */ (e.target).value),
|
|
489
|
+
500,
|
|
490
|
+
);
|
|
408
491
|
}}
|
|
409
492
|
></textarea>
|
|
410
493
|
`,
|
|
@@ -412,14 +495,14 @@ function renderSignalEditorTemplate(
|
|
|
412
495
|
};
|
|
413
496
|
|
|
414
497
|
// Name field (common to all)
|
|
415
|
-
const nameField = signalFieldRow("Name", name, (/** @type {
|
|
498
|
+
const nameField = signalFieldRow("Name", name, (/** @type {string} */ v) => {
|
|
416
499
|
if (v && v !== name && !(S.document.state && S.document.state[v])) {
|
|
417
500
|
expandedSignal = v;
|
|
418
501
|
transactDoc(activeTab.value, (t) => mutateRenameDef(t, name, v));
|
|
419
502
|
}
|
|
420
503
|
});
|
|
421
504
|
|
|
422
|
-
/** @type {
|
|
505
|
+
/** @type {import("lit-html").TemplateResult | typeof nothing} */
|
|
423
506
|
let fields = nothing;
|
|
424
507
|
|
|
425
508
|
if (cat === "state") {
|
|
@@ -432,7 +515,7 @@ function renderSignalEditorTemplate(
|
|
|
432
515
|
|
|
433
516
|
const cemFields = isCustomElementDoc(S)
|
|
434
517
|
? html`
|
|
435
|
-
${signalFieldRow("Attribute", def.attribute || "", (/** @type {
|
|
518
|
+
${signalFieldRow("Attribute", def.attribute || "", (/** @type {string} */ v) =>
|
|
436
519
|
transactDoc(activeTab.value, (t) =>
|
|
437
520
|
mutateUpdateDef(t, name, { attribute: v || undefined }),
|
|
438
521
|
),
|
|
@@ -445,9 +528,11 @@ function renderSignalEditorTemplate(
|
|
|
445
528
|
<sp-checkbox
|
|
446
529
|
class="field-check"
|
|
447
530
|
?checked=${!!def.reflects}
|
|
448
|
-
@change=${(/** @type {
|
|
531
|
+
@change=${(/** @type {Event} */ e) =>
|
|
449
532
|
transactDoc(activeTab.value, (t) =>
|
|
450
|
-
mutateUpdateDef(t, name, {
|
|
533
|
+
mutateUpdateDef(t, name, {
|
|
534
|
+
reflects: /** @type {HTMLInputElement} */ (e.target).checked || undefined,
|
|
535
|
+
}),
|
|
451
536
|
)}
|
|
452
537
|
></sp-checkbox>
|
|
453
538
|
`,
|
|
@@ -455,7 +540,7 @@ function renderSignalEditorTemplate(
|
|
|
455
540
|
${signalFieldRow(
|
|
456
541
|
"Deprecated",
|
|
457
542
|
typeof def.deprecated === "string" ? def.deprecated : "",
|
|
458
|
-
(/** @type {
|
|
543
|
+
(/** @type {string} */ v) =>
|
|
459
544
|
transactDoc(activeTab.value, (t) =>
|
|
460
545
|
mutateUpdateDef(t, name, { deprecated: v || undefined }),
|
|
461
546
|
),
|
|
@@ -468,7 +553,7 @@ function renderSignalEditorTemplate(
|
|
|
468
553
|
"Type",
|
|
469
554
|
["string", "integer", "number", "boolean", "array", "object"],
|
|
470
555
|
def.type || "string",
|
|
471
|
-
(/** @type {
|
|
556
|
+
(/** @type {string} */ v) =>
|
|
472
557
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { type: v })),
|
|
473
558
|
)}
|
|
474
559
|
${def.type === "string" || !def.type
|
|
@@ -476,7 +561,7 @@ function renderSignalEditorTemplate(
|
|
|
476
561
|
"Format",
|
|
477
562
|
["", "image", "date", "color"],
|
|
478
563
|
def.format || "",
|
|
479
|
-
(/** @type {
|
|
564
|
+
(/** @type {string} */ v) =>
|
|
480
565
|
transactDoc(activeTab.value, (t) =>
|
|
481
566
|
mutateUpdateDef(t, name, { format: v || undefined }),
|
|
482
567
|
),
|
|
@@ -487,13 +572,14 @@ function renderSignalEditorTemplate(
|
|
|
487
572
|
prop: "Default",
|
|
488
573
|
label: "Default",
|
|
489
574
|
hasValue: false,
|
|
490
|
-
widget: renderMediaPicker("default", defaultVal, (/** @type {
|
|
575
|
+
widget: renderMediaPicker("default", defaultVal, (/** @type {string} */ v) => {
|
|
491
576
|
transactDoc(activeTab.value, (t) =>
|
|
492
577
|
mutateUpdateDef(t, name, { default: v || undefined }),
|
|
493
578
|
);
|
|
494
579
|
}),
|
|
495
580
|
})
|
|
496
|
-
: signalFieldRow("Default", defaultVal, (/** @type {
|
|
581
|
+
: signalFieldRow("Default", defaultVal, (/** @type {string} */ v) => {
|
|
582
|
+
/** @type {unknown} */
|
|
497
583
|
let parsed = v;
|
|
498
584
|
if (def.type === "integer") parsed = parseInt(v, 10) || 0;
|
|
499
585
|
else if (def.type === "number") parsed = parseFloat(v) || 0;
|
|
@@ -505,9 +591,11 @@ function renderSignalEditorTemplate(
|
|
|
505
591
|
parsed = v;
|
|
506
592
|
}
|
|
507
593
|
}
|
|
508
|
-
transactDoc(activeTab.value, (t) =>
|
|
594
|
+
transactDoc(activeTab.value, (t) =>
|
|
595
|
+
mutateUpdateDef(t, name, { default: /** @type {JsonValue} */ (parsed) }),
|
|
596
|
+
);
|
|
509
597
|
})}
|
|
510
|
-
${signalFieldRow("Description", def.description || "", (/** @type {
|
|
598
|
+
${signalFieldRow("Description", def.description || "", (/** @type {string} */ v) =>
|
|
511
599
|
transactDoc(activeTab.value, (t) =>
|
|
512
600
|
mutateUpdateDef(t, name, { description: v || undefined }),
|
|
513
601
|
),
|
|
@@ -515,7 +603,7 @@ function renderSignalEditorTemplate(
|
|
|
515
603
|
${cemFields}
|
|
516
604
|
`;
|
|
517
605
|
} else if (cat === "computed") {
|
|
518
|
-
/** @type {
|
|
606
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
519
607
|
let debounce;
|
|
520
608
|
fields = html`
|
|
521
609
|
${renderFieldRow({
|
|
@@ -527,10 +615,10 @@ function renderSignalEditorTemplate(
|
|
|
527
615
|
class="field-input"
|
|
528
616
|
style="min-height:40px"
|
|
529
617
|
.value=${def.$compute || ""}
|
|
530
|
-
@input=${(/** @type {
|
|
618
|
+
@input=${(/** @type {Event} */ e) => {
|
|
531
619
|
clearTimeout(debounce);
|
|
532
620
|
debounce = setTimeout(() => {
|
|
533
|
-
const expr = e.target.value;
|
|
621
|
+
const expr = /** @type {HTMLInputElement} */ (e.target).value;
|
|
534
622
|
const depMatches = expr.match(/\$[a-zA-Z_]\w*/g) || [];
|
|
535
623
|
const deps = [...new Set(depMatches)].map((d) => `#/state/${d}`);
|
|
536
624
|
transactDoc(activeTab.value, (t) =>
|
|
@@ -549,7 +637,7 @@ function renderSignalEditorTemplate(
|
|
|
549
637
|
widget: html`
|
|
550
638
|
<span class="signal-hint" style="flex:1;max-width:none"
|
|
551
639
|
>${def.$deps
|
|
552
|
-
.map((/** @type {
|
|
640
|
+
.map((/** @type {string} */ d) => d.replace("#/state/", ""))
|
|
553
641
|
.join(", ")}</span
|
|
554
642
|
>
|
|
555
643
|
`,
|
|
@@ -567,29 +655,33 @@ function renderSignalEditorTemplate(
|
|
|
567
655
|
|
|
568
656
|
/** Data source fields for signal editor */
|
|
569
657
|
function renderDataSourceFields(
|
|
570
|
-
/** @type {
|
|
571
|
-
/** @type {
|
|
572
|
-
/** @type {
|
|
573
|
-
/** @type {
|
|
574
|
-
/** @type {
|
|
575
|
-
/** @type {
|
|
658
|
+
/** @type {SignalsPanelState} */ S,
|
|
659
|
+
/** @type {string} */ name,
|
|
660
|
+
/** @type {SignalDef} */ def,
|
|
661
|
+
/** @type {Function} */ textareaRow,
|
|
662
|
+
/** @type {Function} */ pickerRow,
|
|
663
|
+
/** @type {SignalsPanelCtx} */ ctx,
|
|
576
664
|
) {
|
|
577
665
|
const proto = def.$prototype;
|
|
578
666
|
|
|
579
667
|
if (proto === "Request") {
|
|
580
668
|
return html`
|
|
581
|
-
${signalFieldRow("URL", def.url || "", (/** @type {
|
|
669
|
+
${signalFieldRow("URL", def.url || "", (/** @type {string} */ v) =>
|
|
582
670
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { url: v })),
|
|
583
671
|
)}
|
|
584
672
|
${pickerRow(
|
|
585
673
|
"Method",
|
|
586
674
|
["GET", "POST", "PUT", "DELETE", "PATCH"],
|
|
587
675
|
def.method || "GET",
|
|
588
|
-
(/** @type {
|
|
676
|
+
(/** @type {string} */ v) =>
|
|
589
677
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { method: v })),
|
|
590
678
|
)}
|
|
591
|
-
${pickerRow(
|
|
592
|
-
|
|
679
|
+
${pickerRow(
|
|
680
|
+
"Timing",
|
|
681
|
+
["client", "server"],
|
|
682
|
+
def.timing || "client",
|
|
683
|
+
(/** @type {string} */ v) =>
|
|
684
|
+
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { timing: v })),
|
|
593
685
|
)}
|
|
594
686
|
`;
|
|
595
687
|
}
|
|
@@ -601,10 +693,10 @@ function renderDataSourceFields(
|
|
|
601
693
|
: String(def.default)
|
|
602
694
|
: "";
|
|
603
695
|
return html`
|
|
604
|
-
${signalFieldRow("Key", def.key || "", (/** @type {
|
|
696
|
+
${signalFieldRow("Key", def.key || "", (/** @type {string} */ v) =>
|
|
605
697
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { key: v })),
|
|
606
698
|
)}
|
|
607
|
-
${textareaRow("Default", defaultStr, (/** @type {
|
|
699
|
+
${textareaRow("Default", defaultStr, (/** @type {string} */ v) => {
|
|
608
700
|
try {
|
|
609
701
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { default: JSON.parse(v) }));
|
|
610
702
|
} catch {
|
|
@@ -615,13 +707,13 @@ function renderDataSourceFields(
|
|
|
615
707
|
}
|
|
616
708
|
if (proto === "IndexedDB") {
|
|
617
709
|
return html`
|
|
618
|
-
${signalFieldRow("Database", def.database || "", (/** @type {
|
|
710
|
+
${signalFieldRow("Database", def.database || "", (/** @type {string} */ v) =>
|
|
619
711
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { database: v })),
|
|
620
712
|
)}
|
|
621
|
-
${signalFieldRow("Store", def.store || "", (/** @type {
|
|
713
|
+
${signalFieldRow("Store", def.store || "", (/** @type {string} */ v) =>
|
|
622
714
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { store: v })),
|
|
623
715
|
)}
|
|
624
|
-
${signalFieldRow("Version", String(def.version || 1), (/** @type {
|
|
716
|
+
${signalFieldRow("Version", String(def.version || 1), (/** @type {string} */ v) =>
|
|
625
717
|
transactDoc(activeTab.value, (t) =>
|
|
626
718
|
mutateUpdateDef(t, name, { version: parseInt(v, 10) || 1 }),
|
|
627
719
|
),
|
|
@@ -630,10 +722,10 @@ function renderDataSourceFields(
|
|
|
630
722
|
}
|
|
631
723
|
if (proto === "Cookie") {
|
|
632
724
|
return html`
|
|
633
|
-
${signalFieldRow("Cookie", def.name || "", (/** @type {
|
|
725
|
+
${signalFieldRow("Cookie", def.name || "", (/** @type {string} */ v) =>
|
|
634
726
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { name: v })),
|
|
635
727
|
)}
|
|
636
|
-
${signalFieldRow("Default", def.default || "", (/** @type {
|
|
728
|
+
${signalFieldRow("Default", String(def.default || ""), (/** @type {string} */ v) =>
|
|
637
729
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { default: v })),
|
|
638
730
|
)}
|
|
639
731
|
`;
|
|
@@ -647,7 +739,7 @@ function renderDataSourceFields(
|
|
|
647
739
|
: proto === "FormData"
|
|
648
740
|
? JSON.stringify(def.fields || {}, null, 2)
|
|
649
741
|
: "";
|
|
650
|
-
return textareaRow(fieldLabel, defaultStr, (/** @type {
|
|
742
|
+
return textareaRow(fieldLabel, defaultStr, (/** @type {string} */ v) => {
|
|
651
743
|
try {
|
|
652
744
|
transactDoc(activeTab.value, (t) =>
|
|
653
745
|
mutateUpdateDef(t, name, { [fieldName]: JSON.parse(v) }),
|
|
@@ -661,16 +753,16 @@ function renderDataSourceFields(
|
|
|
661
753
|
|
|
662
754
|
/** Function fields for signal editor */
|
|
663
755
|
function renderFunctionFields(
|
|
664
|
-
/** @type {
|
|
665
|
-
/** @type {
|
|
666
|
-
/** @type {
|
|
667
|
-
/** @type {
|
|
668
|
-
/** @type {
|
|
756
|
+
/** @type {SignalsPanelState} */ S,
|
|
757
|
+
/** @type {string} */ name,
|
|
758
|
+
/** @type {SignalDef} */ def,
|
|
759
|
+
/** @type {Function} */ textareaRow,
|
|
760
|
+
/** @type {SignalsPanelCtx} */ ctx,
|
|
669
761
|
) {
|
|
670
762
|
const descriptionField = signalFieldRow(
|
|
671
763
|
"Description",
|
|
672
764
|
def.description || "",
|
|
673
|
-
(/** @type {
|
|
765
|
+
(/** @type {string} */ v) =>
|
|
674
766
|
transactDoc(activeTab.value, (t) =>
|
|
675
767
|
mutateUpdateDef(t, name, { description: v || undefined }),
|
|
676
768
|
),
|
|
@@ -678,10 +770,10 @@ function renderFunctionFields(
|
|
|
678
770
|
|
|
679
771
|
const bodyField = def.$src
|
|
680
772
|
? html`
|
|
681
|
-
${signalFieldRow("Source", def.$src || "", (/** @type {
|
|
773
|
+
${signalFieldRow("Source", def.$src || "", (/** @type {string} */ v) =>
|
|
682
774
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { $src: v || undefined })),
|
|
683
775
|
)}
|
|
684
|
-
${signalFieldRow("Export", def.$export || "", (/** @type {
|
|
776
|
+
${signalFieldRow("Export", def.$export || "", (/** @type {string} */ v) =>
|
|
685
777
|
transactDoc(activeTab.value, (t) =>
|
|
686
778
|
mutateUpdateDef(t, name, { $export: v || undefined }),
|
|
687
779
|
),
|
|
@@ -706,8 +798,8 @@ function renderFunctionFields(
|
|
|
706
798
|
class="field-input"
|
|
707
799
|
style="min-height:60px;font-family:monospace;font-size:11px"
|
|
708
800
|
.value=${def.body || ""}
|
|
709
|
-
@input=${(/** @type {
|
|
710
|
-
const v = e.target.value;
|
|
801
|
+
@input=${(/** @type {Event} */ e) => {
|
|
802
|
+
const v = /** @type {HTMLInputElement} */ (e.target).value;
|
|
711
803
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { body: v }));
|
|
712
804
|
}}
|
|
713
805
|
></textarea>
|
|
@@ -723,10 +815,10 @@ function renderFunctionFields(
|
|
|
723
815
|
|
|
724
816
|
/** Render CEM parameter editor with basic/advanced toggle. */
|
|
725
817
|
function renderParameterEditorTemplate(
|
|
726
|
-
/** @type {
|
|
727
|
-
/** @type {
|
|
728
|
-
/** @type {
|
|
729
|
-
/** @type {
|
|
818
|
+
/** @type {SignalsPanelState} */ S,
|
|
819
|
+
/** @type {string} */ name,
|
|
820
|
+
/** @type {SignalDef} */ def,
|
|
821
|
+
/** @type {SignalsPanelCtx} */ ctx,
|
|
730
822
|
) {
|
|
731
823
|
const params = (def.parameters || []).map(normParam);
|
|
732
824
|
const isAdvanced = advancedParamOpen.has(name);
|
|
@@ -740,7 +832,7 @@ function renderParameterEditorTemplate(
|
|
|
740
832
|
widget: html`
|
|
741
833
|
<div style="display:flex;flex-wrap:wrap;gap:4px;align-items:center">
|
|
742
834
|
${params.map(
|
|
743
|
-
(/** @type {
|
|
835
|
+
(/** @type {CemParameter} */ p, /** @type {number} */ i) => html`
|
|
744
836
|
<span
|
|
745
837
|
style="display:inline-flex;align-items:center;gap:2px;padding:1px 6px;border-radius:3px;background:var(--bg-hover);font-size:11px;font-family:monospace"
|
|
746
838
|
>
|
|
@@ -751,9 +843,11 @@ function renderParameterEditorTemplate(
|
|
|
751
843
|
transactDoc(activeTab.value, (t) =>
|
|
752
844
|
mutateUpdateDef(t, name, {
|
|
753
845
|
parameters: params.filter(
|
|
754
|
-
(/** @type {
|
|
846
|
+
(/** @type {unknown} */ _, /** @type {number} */ j) => j !== i,
|
|
755
847
|
).length
|
|
756
|
-
? params.filter(
|
|
848
|
+
? params.filter(
|
|
849
|
+
(/** @type {unknown} */ _, /** @type {number} */ j) => j !== i,
|
|
850
|
+
)
|
|
757
851
|
: undefined,
|
|
758
852
|
}),
|
|
759
853
|
);
|
|
@@ -767,11 +861,14 @@ function renderParameterEditorTemplate(
|
|
|
767
861
|
class="field-input"
|
|
768
862
|
style="width:60px;flex:0 0 auto;font-size:11px"
|
|
769
863
|
placeholder="+"
|
|
770
|
-
@keydown=${(/** @type {
|
|
771
|
-
if (e.key === "Enter" && e.target.value.trim()) {
|
|
864
|
+
@keydown=${(/** @type {KeyboardEvent} */ e) => {
|
|
865
|
+
if (e.key === "Enter" && /** @type {HTMLInputElement} */ (e.target).value.trim()) {
|
|
772
866
|
transactDoc(activeTab.value, (t) =>
|
|
773
867
|
mutateUpdateDef(t, name, {
|
|
774
|
-
parameters: [
|
|
868
|
+
parameters: [
|
|
869
|
+
...params,
|
|
870
|
+
{ name: /** @type {HTMLInputElement} */ (e.target).value.trim() },
|
|
871
|
+
],
|
|
775
872
|
}),
|
|
776
873
|
);
|
|
777
874
|
}
|
|
@@ -798,16 +895,16 @@ function renderParameterEditorTemplate(
|
|
|
798
895
|
widget: html`
|
|
799
896
|
<div style="display:flex;flex-direction:column;gap:4px">
|
|
800
897
|
${params.map(
|
|
801
|
-
(/** @type {
|
|
898
|
+
(/** @type {CemParameter} */ p, /** @type {number} */ i) => html`
|
|
802
899
|
<div style="display:flex;gap:4px;align-items:center">
|
|
803
900
|
<input
|
|
804
901
|
class="field-input"
|
|
805
902
|
.value=${p.name || ""}
|
|
806
903
|
placeholder="name"
|
|
807
904
|
style="flex:1"
|
|
808
|
-
@change=${(/** @type {
|
|
905
|
+
@change=${(/** @type {Event} */ e) => {
|
|
809
906
|
const next = [...params];
|
|
810
|
-
next[i] = { ...next[i], name: e.target.value };
|
|
907
|
+
next[i] = { ...next[i], name: /** @type {HTMLInputElement} */ (e.target).value };
|
|
811
908
|
transactDoc(activeTab.value, (t) =>
|
|
812
909
|
mutateUpdateDef(t, name, { parameters: next }),
|
|
813
910
|
);
|
|
@@ -818,11 +915,13 @@ function renderParameterEditorTemplate(
|
|
|
818
915
|
.value=${p.type?.text || ""}
|
|
819
916
|
placeholder="type"
|
|
820
917
|
style="flex:1"
|
|
821
|
-
@change=${(/** @type {
|
|
918
|
+
@change=${(/** @type {Event} */ e) => {
|
|
822
919
|
const next = [...params];
|
|
823
920
|
next[i] = {
|
|
824
921
|
...next[i],
|
|
825
|
-
type:
|
|
922
|
+
type: /** @type {HTMLInputElement} */ (e.target).value
|
|
923
|
+
? { text: /** @type {HTMLInputElement} */ (e.target).value }
|
|
924
|
+
: undefined,
|
|
826
925
|
};
|
|
827
926
|
transactDoc(activeTab.value, (t) =>
|
|
828
927
|
mutateUpdateDef(t, name, { parameters: next }),
|
|
@@ -834,9 +933,12 @@ function renderParameterEditorTemplate(
|
|
|
834
933
|
.value=${p.description || ""}
|
|
835
934
|
placeholder="desc"
|
|
836
935
|
style="flex:2"
|
|
837
|
-
@change=${(/** @type {
|
|
936
|
+
@change=${(/** @type {Event} */ e) => {
|
|
838
937
|
const next = [...params];
|
|
839
|
-
next[i] = {
|
|
938
|
+
next[i] = {
|
|
939
|
+
...next[i],
|
|
940
|
+
description: /** @type {HTMLInputElement} */ (e.target).value || undefined,
|
|
941
|
+
};
|
|
840
942
|
transactDoc(activeTab.value, (t) =>
|
|
841
943
|
mutateUpdateDef(t, name, { parameters: next }),
|
|
842
944
|
);
|
|
@@ -846,9 +948,12 @@ function renderParameterEditorTemplate(
|
|
|
846
948
|
type="checkbox"
|
|
847
949
|
title="optional"
|
|
848
950
|
.checked=${!!p.optional}
|
|
849
|
-
@change=${(/** @type {
|
|
951
|
+
@change=${(/** @type {Event} */ e) => {
|
|
850
952
|
const next = [...params];
|
|
851
|
-
next[i] = {
|
|
953
|
+
next[i] = {
|
|
954
|
+
...next[i],
|
|
955
|
+
optional: /** @type {HTMLInputElement} */ (e.target).checked || undefined,
|
|
956
|
+
};
|
|
852
957
|
transactDoc(activeTab.value, (t) =>
|
|
853
958
|
mutateUpdateDef(t, name, { parameters: next }),
|
|
854
959
|
);
|
|
@@ -858,7 +963,7 @@ function renderParameterEditorTemplate(
|
|
|
858
963
|
style="cursor:pointer;opacity:0.5"
|
|
859
964
|
@click=${() => {
|
|
860
965
|
const next = params.filter(
|
|
861
|
-
(/** @type {
|
|
966
|
+
(/** @type {unknown} */ _, /** @type {number} */ j) => j !== i,
|
|
862
967
|
);
|
|
863
968
|
transactDoc(activeTab.value, (t) =>
|
|
864
969
|
mutateUpdateDef(t, name, { parameters: next.length ? next : undefined }),
|
|
@@ -893,11 +998,11 @@ function renderParameterEditorTemplate(
|
|
|
893
998
|
|
|
894
999
|
/** Render CEM emits editor for function state entries. */
|
|
895
1000
|
function renderEmitsEditorTemplate(
|
|
896
|
-
/** @type {
|
|
897
|
-
/** @type {
|
|
898
|
-
/** @type {
|
|
1001
|
+
/** @type {SignalsPanelState} */ S,
|
|
1002
|
+
/** @type {string} */ name,
|
|
1003
|
+
/** @type {SignalDef} */ def,
|
|
899
1004
|
) {
|
|
900
|
-
const emits = def.emits || [];
|
|
1005
|
+
const emits = /** @type {CemEvent[]} */ (def.emits || []);
|
|
901
1006
|
if (emits.length === 0 && !isCustomElementDoc(S)) return nothing;
|
|
902
1007
|
|
|
903
1008
|
return html`
|
|
@@ -907,16 +1012,16 @@ function renderEmitsEditorTemplate(
|
|
|
907
1012
|
Emits
|
|
908
1013
|
</div>
|
|
909
1014
|
${emits.map(
|
|
910
|
-
(/** @type {
|
|
1015
|
+
(/** @type {CemEvent} */ ev, /** @type {number} */ i) => html`
|
|
911
1016
|
<div style="display:flex;gap:4px;align-items:center;margin-bottom:4px">
|
|
912
1017
|
<input
|
|
913
1018
|
class="field-input"
|
|
914
1019
|
.value=${ev.name || ""}
|
|
915
1020
|
placeholder="event name"
|
|
916
1021
|
style="flex:1"
|
|
917
|
-
@change=${(/** @type {
|
|
1022
|
+
@change=${(/** @type {Event} */ e) => {
|
|
918
1023
|
const next = [...emits];
|
|
919
|
-
next[i] = { ...next[i], name: e.target.value };
|
|
1024
|
+
next[i] = { ...next[i], name: /** @type {HTMLInputElement} */ (e.target).value };
|
|
920
1025
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { emits: next }));
|
|
921
1026
|
}}
|
|
922
1027
|
/>
|
|
@@ -925,9 +1030,14 @@ function renderEmitsEditorTemplate(
|
|
|
925
1030
|
.value=${ev.type?.text || ""}
|
|
926
1031
|
placeholder="type"
|
|
927
1032
|
style="flex:1"
|
|
928
|
-
@change=${(/** @type {
|
|
1033
|
+
@change=${(/** @type {Event} */ e) => {
|
|
929
1034
|
const next = [...emits];
|
|
930
|
-
next[i] = {
|
|
1035
|
+
next[i] = {
|
|
1036
|
+
...next[i],
|
|
1037
|
+
type: /** @type {HTMLInputElement} */ (e.target).value
|
|
1038
|
+
? { text: /** @type {HTMLInputElement} */ (e.target).value }
|
|
1039
|
+
: undefined,
|
|
1040
|
+
};
|
|
931
1041
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { emits: next }));
|
|
932
1042
|
}}
|
|
933
1043
|
/>
|
|
@@ -936,9 +1046,12 @@ function renderEmitsEditorTemplate(
|
|
|
936
1046
|
.value=${ev.description || ""}
|
|
937
1047
|
placeholder="description"
|
|
938
1048
|
style="flex:2"
|
|
939
|
-
@change=${(/** @type {
|
|
1049
|
+
@change=${(/** @type {Event} */ e) => {
|
|
940
1050
|
const next = [...emits];
|
|
941
|
-
next[i] = {
|
|
1051
|
+
next[i] = {
|
|
1052
|
+
...next[i],
|
|
1053
|
+
description: /** @type {HTMLInputElement} */ (e.target).value || undefined,
|
|
1054
|
+
};
|
|
942
1055
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { emits: next }));
|
|
943
1056
|
}}
|
|
944
1057
|
/>
|
|
@@ -947,9 +1060,10 @@ function renderEmitsEditorTemplate(
|
|
|
947
1060
|
@click=${() => {
|
|
948
1061
|
transactDoc(activeTab.value, (t) =>
|
|
949
1062
|
mutateUpdateDef(t, name, {
|
|
950
|
-
emits: emits.filter(
|
|
951
|
-
|
|
952
|
-
|
|
1063
|
+
emits: emits.filter(
|
|
1064
|
+
(/** @type {unknown} */ _, /** @type {number} */ j) => j !== i,
|
|
1065
|
+
).length
|
|
1066
|
+
? emits.filter((/** @type {unknown} */ _, /** @type {number} */ j) => j !== i)
|
|
953
1067
|
: undefined,
|
|
954
1068
|
}),
|
|
955
1069
|
);
|
|
@@ -978,10 +1092,10 @@ function renderEmitsEditorTemplate(
|
|
|
978
1092
|
* appropriate form controls.
|
|
979
1093
|
*/
|
|
980
1094
|
export function renderSchemaFieldsTemplate(
|
|
981
|
-
/** @type {
|
|
982
|
-
/** @type {
|
|
983
|
-
/** @type {
|
|
984
|
-
/** @type {
|
|
1095
|
+
/** @type {JsonSchema | null | undefined} */ schema,
|
|
1096
|
+
/** @type {SignalDef} */ def,
|
|
1097
|
+
/** @type {string} */ name,
|
|
1098
|
+
/** @type {SignalsPanelState} */ _S,
|
|
985
1099
|
) {
|
|
986
1100
|
if (!schema?.properties) return nothing;
|
|
987
1101
|
|
|
@@ -1003,29 +1117,33 @@ export function renderSchemaFieldsTemplate(
|
|
|
1003
1117
|
: ps.default !== undefined
|
|
1004
1118
|
? String(ps.default)
|
|
1005
1119
|
: "__none__"}
|
|
1006
|
-
@change=${(/** @type {
|
|
1120
|
+
@change=${(/** @type {Event} */ e) =>
|
|
1007
1121
|
transactDoc(activeTab.value, (t) =>
|
|
1008
1122
|
mutateUpdateDef(t, name, {
|
|
1009
|
-
[prop]: e.target.value === "__none__"
|
|
1123
|
+
[prop]: /** @type {HTMLInputElement} */ (e.target).value === "__none__"
|
|
1124
|
+
? undefined
|
|
1125
|
+
: /** @type {HTMLInputElement} */ (e.target).value,
|
|
1010
1126
|
}),
|
|
1011
1127
|
)}
|
|
1012
1128
|
>
|
|
1013
1129
|
${!required.has(prop) ? html`<sp-menu-item value="__none__">—</sp-menu-item>` : nothing}
|
|
1014
1130
|
${ps.enum.map(
|
|
1015
|
-
(/** @type {
|
|
1131
|
+
(/** @type {string} */ val) => html`<sp-menu-item value=${val}>${val}</sp-menu-item>`,
|
|
1016
1132
|
)}
|
|
1017
1133
|
</sp-picker>
|
|
1018
1134
|
`;
|
|
1019
1135
|
} else if (ps.type === "boolean") {
|
|
1020
1136
|
control = html`<sp-checkbox
|
|
1021
1137
|
?checked=${currentValue ?? ps.default ?? false}
|
|
1022
|
-
@change=${(/** @type {
|
|
1138
|
+
@change=${(/** @type {Event} */ e) =>
|
|
1023
1139
|
transactDoc(activeTab.value, (t) =>
|
|
1024
|
-
mutateUpdateDef(t, name, {
|
|
1140
|
+
mutateUpdateDef(t, name, {
|
|
1141
|
+
[prop]: /** @type {HTMLInputElement} */ (e.target).checked,
|
|
1142
|
+
}),
|
|
1025
1143
|
)}
|
|
1026
1144
|
></sp-checkbox>`;
|
|
1027
1145
|
} else if (ps.type === "integer" || ps.type === "number") {
|
|
1028
|
-
/** @type {
|
|
1146
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
1029
1147
|
let debounce;
|
|
1030
1148
|
control = html`<sp-number-field
|
|
1031
1149
|
size="s"
|
|
@@ -1034,11 +1152,13 @@ export function renderSchemaFieldsTemplate(
|
|
|
1034
1152
|
step=${ps.type === "integer" ? "1" : nothing}
|
|
1035
1153
|
.value=${currentValue !== undefined ? currentValue : nothing}
|
|
1036
1154
|
placeholder=${ps.default !== undefined ? String(ps.default) : nothing}
|
|
1037
|
-
@change=${(/** @type {
|
|
1155
|
+
@change=${(/** @type {Event} */ e) => {
|
|
1038
1156
|
clearTimeout(debounce);
|
|
1039
1157
|
debounce = setTimeout(() => {
|
|
1040
1158
|
const parsed =
|
|
1041
|
-
ps.type === "integer"
|
|
1159
|
+
ps.type === "integer"
|
|
1160
|
+
? parseInt(/** @type {HTMLInputElement} */ (e.target).value, 10)
|
|
1161
|
+
: parseFloat(/** @type {HTMLInputElement} */ (e.target).value);
|
|
1042
1162
|
transactDoc(activeTab.value, (t) =>
|
|
1043
1163
|
mutateUpdateDef(t, name, { [prop]: isNaN(parsed) ? undefined : parsed }),
|
|
1044
1164
|
);
|
|
@@ -1048,15 +1168,18 @@ export function renderSchemaFieldsTemplate(
|
|
|
1048
1168
|
} else if (ps.format === "json-schema") {
|
|
1049
1169
|
const hasValue =
|
|
1050
1170
|
currentValue && typeof currentValue === "object" && Object.keys(currentValue).length > 0;
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1171
|
+
const cv = /** @type {Record<string, unknown>} */ (currentValue);
|
|
1172
|
+
const isRef = hasValue && cv.$ref;
|
|
1173
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
1053
1174
|
let debounce;
|
|
1054
1175
|
control = html`
|
|
1055
1176
|
<div class="schema-param-editor">
|
|
1056
|
-
${hasValue && !isRef &&
|
|
1177
|
+
${hasValue && !isRef && cv.properties
|
|
1057
1178
|
? html`
|
|
1058
1179
|
<div style="display:flex;flex-wrap:wrap;gap:3px;margin-bottom:4px">
|
|
1059
|
-
${Object.entries(
|
|
1180
|
+
${Object.entries(
|
|
1181
|
+
/** @type {Record<string, Record<string, unknown>>} */ (cv.properties),
|
|
1182
|
+
).map(
|
|
1060
1183
|
([k, v]) => html`
|
|
1061
1184
|
<span
|
|
1062
1185
|
style="background:var(--bg-alt);padding:1px 6px;border-radius:3px;font-size:10px;color:var(--fg-dim)"
|
|
@@ -1077,12 +1200,14 @@ export function renderSchemaFieldsTemplate(
|
|
|
1077
1200
|
})}
|
|
1078
1201
|
.value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : ""}
|
|
1079
1202
|
placeholder=${ps.description ?? "JSON Schema defining the data shape\u2026"}
|
|
1080
|
-
@input=${(/** @type {
|
|
1203
|
+
@input=${(/** @type {Event} */ e) => {
|
|
1081
1204
|
clearTimeout(debounce);
|
|
1082
1205
|
debounce = setTimeout(() => {
|
|
1083
1206
|
try {
|
|
1084
1207
|
transactDoc(activeTab.value, (t) =>
|
|
1085
|
-
mutateUpdateDef(t, name, {
|
|
1208
|
+
mutateUpdateDef(t, name, {
|
|
1209
|
+
[prop]: JSON.parse(/** @type {HTMLInputElement} */ (e.target).value),
|
|
1210
|
+
}),
|
|
1086
1211
|
);
|
|
1087
1212
|
} catch {}
|
|
1088
1213
|
}, 500);
|
|
@@ -1091,7 +1216,7 @@ export function renderSchemaFieldsTemplate(
|
|
|
1091
1216
|
</div>
|
|
1092
1217
|
`;
|
|
1093
1218
|
} else if (ps.type === "array" || ps.type === "object") {
|
|
1094
|
-
/** @type {
|
|
1219
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
1095
1220
|
let debounce;
|
|
1096
1221
|
control = html`<sp-textfield
|
|
1097
1222
|
multiline
|
|
@@ -1099,19 +1224,21 @@ export function renderSchemaFieldsTemplate(
|
|
|
1099
1224
|
style="min-height:40px"
|
|
1100
1225
|
.value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : ""}
|
|
1101
1226
|
placeholder=${ps.default !== undefined ? JSON.stringify(ps.default) : nothing}
|
|
1102
|
-
@input=${(/** @type {
|
|
1227
|
+
@input=${(/** @type {Event} */ e) => {
|
|
1103
1228
|
clearTimeout(debounce);
|
|
1104
1229
|
debounce = setTimeout(() => {
|
|
1105
1230
|
try {
|
|
1106
1231
|
transactDoc(activeTab.value, (t) =>
|
|
1107
|
-
mutateUpdateDef(t, name, {
|
|
1232
|
+
mutateUpdateDef(t, name, {
|
|
1233
|
+
[prop]: JSON.parse(/** @type {HTMLInputElement} */ (e.target).value),
|
|
1234
|
+
}),
|
|
1108
1235
|
);
|
|
1109
1236
|
} catch {}
|
|
1110
1237
|
}, 500);
|
|
1111
1238
|
}}
|
|
1112
1239
|
></sp-textfield>`;
|
|
1113
1240
|
} else {
|
|
1114
|
-
/** @type {
|
|
1241
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
1115
1242
|
let debounce;
|
|
1116
1243
|
const ph = ps.default !== undefined ? String(ps.default) : (ps.examples?.[0] ?? "");
|
|
1117
1244
|
control = html`<sp-textfield
|
|
@@ -1119,12 +1246,14 @@ export function renderSchemaFieldsTemplate(
|
|
|
1119
1246
|
.value=${currentValue ?? ""}
|
|
1120
1247
|
placeholder=${ph || nothing}
|
|
1121
1248
|
title=${ps.description || nothing}
|
|
1122
|
-
@input=${(/** @type {
|
|
1249
|
+
@input=${(/** @type {Event} */ e) => {
|
|
1123
1250
|
clearTimeout(debounce);
|
|
1124
1251
|
debounce = setTimeout(
|
|
1125
1252
|
() =>
|
|
1126
1253
|
transactDoc(activeTab.value, (t) =>
|
|
1127
|
-
mutateUpdateDef(t, name, {
|
|
1254
|
+
mutateUpdateDef(t, name, {
|
|
1255
|
+
[prop]: /** @type {HTMLInputElement} */ (e.target).value || undefined,
|
|
1256
|
+
}),
|
|
1128
1257
|
),
|
|
1129
1258
|
400,
|
|
1130
1259
|
);
|
|
@@ -1133,7 +1262,7 @@ export function renderSchemaFieldsTemplate(
|
|
|
1133
1262
|
}
|
|
1134
1263
|
|
|
1135
1264
|
return renderFieldRow({
|
|
1136
|
-
prop: ps.name,
|
|
1265
|
+
prop: ps.name || prop,
|
|
1137
1266
|
label: labelText,
|
|
1138
1267
|
hasValue: false,
|
|
1139
1268
|
widget: control,
|
|
@@ -1146,13 +1275,13 @@ export function renderSchemaFieldsTemplate(
|
|
|
1146
1275
|
* schema-driven config fields.
|
|
1147
1276
|
*/
|
|
1148
1277
|
export function renderExternalPrototypeEditorTemplate(
|
|
1149
|
-
/** @type {
|
|
1150
|
-
/** @type {
|
|
1151
|
-
/** @type {
|
|
1152
|
-
/** @type {
|
|
1278
|
+
/** @type {SignalsPanelState} */ S,
|
|
1279
|
+
/** @type {string} */ name,
|
|
1280
|
+
/** @type {SignalDef} */ def,
|
|
1281
|
+
/** @type {SignalsPanelCtx} */ ctx,
|
|
1153
1282
|
) {
|
|
1154
1283
|
// Schema-driven config fields (async with cache)
|
|
1155
|
-
/** @type {
|
|
1284
|
+
/** @type {import("lit-html").TemplateResult | typeof nothing} */
|
|
1156
1285
|
let schemaContent = nothing;
|
|
1157
1286
|
if (def.$src && def.$prototype) {
|
|
1158
1287
|
const cacheKey = `${def.$src}::${def.$prototype}`;
|
|
@@ -1173,23 +1302,23 @@ export function renderExternalPrototypeEditorTemplate(
|
|
|
1173
1302
|
>
|
|
1174
1303
|
Loading schema…
|
|
1175
1304
|
</div>`;
|
|
1176
|
-
fetchPluginSchema(def, S).then((schema) => {
|
|
1305
|
+
fetchPluginSchema(def, /** @type {{ documentPath?: string }} */ (S)).then((schema) => {
|
|
1177
1306
|
if (schema) ctx.renderLeftPanel();
|
|
1178
1307
|
});
|
|
1179
1308
|
}
|
|
1180
1309
|
}
|
|
1181
1310
|
|
|
1182
1311
|
return html`
|
|
1183
|
-
${signalFieldRow("Source", def.$src || "", (/** @type {
|
|
1312
|
+
${signalFieldRow("Source", def.$src || "", (/** @type {string} */ v) => {
|
|
1184
1313
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { $src: v || undefined }));
|
|
1185
1314
|
pluginSchemaCache.delete(`${v}::${def.$prototype}`);
|
|
1186
1315
|
})}
|
|
1187
|
-
${signalFieldRow("Prototype", def.$prototype || "", (/** @type {
|
|
1316
|
+
${signalFieldRow("Prototype", def.$prototype || "", (/** @type {string} */ v) => {
|
|
1188
1317
|
transactDoc(activeTab.value, (t) => mutateUpdateDef(t, name, { $prototype: v || undefined }));
|
|
1189
1318
|
pluginSchemaCache.delete(`${def.$src}::${v}`);
|
|
1190
1319
|
})}
|
|
1191
1320
|
${def.$export
|
|
1192
|
-
? signalFieldRow("Export", def.$export || "", (/** @type {
|
|
1321
|
+
? signalFieldRow("Export", def.$export || "", (/** @type {string} */ v) =>
|
|
1193
1322
|
transactDoc(activeTab.value, (t) =>
|
|
1194
1323
|
mutateUpdateDef(t, name, { $export: v || undefined }),
|
|
1195
1324
|
),
|