@jxsuite/studio 0.23.2 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/studio.js +2230 -714
- 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} +7 -5
- package/src/panels/{signals-panel.js → signals-panel.ts} +322 -362
- package/src/panels/{statusbar.js → statusbar.ts} +14 -14
- package/src/panels/{style-inputs.js → style-inputs.ts} +66 -48
- package/src/panels/{style-panel.js → style-panel.ts} +235 -290
- package/src/panels/{style-utils.js → style-utils.ts} +32 -31
- package/src/panels/{stylebook-layers-panel.js → stylebook-layers-panel.ts} +22 -14
- package/src/panels/{stylebook-panel.js → stylebook-panel.ts} +127 -140
- package/src/panels/{tab-strip.js → tab-strip.ts} +12 -14
- package/src/panels/{toolbar.js → toolbar.ts} +68 -70
- package/src/panels/{welcome-screen.js → welcome-screen.ts} +14 -16
- package/src/{platform.js → platform.ts} +5 -3
- package/src/platforms/{devserver.js → devserver.ts} +53 -44
- package/src/{recent-projects.js → recent-projects.ts} +17 -12
- package/src/{resize-edges.js → resize-edges.ts} +18 -13
- package/src/services/{cem-export.js → cem-export.ts} +14 -7
- package/src/services/{code-services.js → code-services.ts} +29 -20
- package/src/services/{monaco-setup.js → monaco-setup.ts} +2 -3
- package/src/settings/{content-types-editor.js → content-types-editor.ts} +88 -67
- package/src/settings/{css-vars-editor.js → css-vars-editor.ts} +78 -51
- package/src/settings/{defs-editor.js → defs-editor.ts} +70 -56
- package/src/settings/{general-settings.js → general-settings.ts} +29 -28
- package/src/settings/{head-editor.js → head-editor.ts} +37 -35
- package/src/settings/{schema-field-ui.js → schema-field-ui.ts} +86 -76
- package/src/settings/{settings-modal.js → settings-modal.ts} +14 -16
- package/src/{site-context.js → site-context.ts} +35 -32
- package/src/{state.js → state.ts} +95 -78
- package/src/{store.js → store.ts} +60 -63
- package/src/{studio.js → studio.ts} +117 -119
- package/src/tabs/tab.ts +196 -0
- package/src/tabs/{transact.js → transact.ts} +107 -60
- package/src/types.ts +185 -0
- package/src/ui/{button-group.js → button-group.ts} +21 -21
- package/src/ui/{color-selector.js → color-selector.ts} +44 -37
- package/src/ui/{expression-editor.js → expression-editor.ts} +65 -40
- package/src/ui/{field-row.js → field-row.ts} +19 -2
- package/src/ui/{icons.js → icons.ts} +2 -2
- package/src/ui/{layers.js → layers.ts} +33 -24
- package/src/ui/{media-picker.js → media-picker.ts} +13 -9
- package/src/ui/{panel-resize.js → panel-resize.ts} +9 -4
- package/src/ui/{spectrum.js → spectrum.ts} +4 -4
- package/src/ui/{unit-selector.js → unit-selector.ts} +16 -19
- package/src/ui/{value-selector.js → value-selector.ts} +28 -28
- package/src/ui/{widgets.js → widgets.ts} +62 -15
- package/src/utils/{canvas-media.js → canvas-media.ts} +29 -14
- package/src/utils/{edit-display.js → edit-display.ts} +23 -20
- package/src/utils/{google-fonts.js → google-fonts.ts} +14 -13
- package/src/utils/{inherited-style.js → inherited-style.ts} +15 -10
- package/src/utils/{studio-utils.js → studio-utils.ts} +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/{reactivity.js → reactivity.ts} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Color-selector.js — Color input widget with swatch, text field, and popover picker.
|
|
3
4
|
*
|
|
@@ -13,10 +14,15 @@
|
|
|
13
14
|
import { LitElement, html, nothing } from "lit";
|
|
14
15
|
import { html as litHtml } from "lit-html";
|
|
15
16
|
import { live } from "lit-html/directives/live.js";
|
|
16
|
-
import { debouncedStyleCommit } from "../store
|
|
17
|
-
import { activeTab } from "../workspace/workspace
|
|
18
|
-
import { getEffectiveStyle } from "../site-context
|
|
19
|
-
import { kebabToLabel } from "../utils/studio-utils
|
|
17
|
+
import { debouncedStyleCommit } from "../store";
|
|
18
|
+
import { activeTab } from "../workspace/workspace";
|
|
19
|
+
import { getEffectiveStyle } from "../site-context";
|
|
20
|
+
import { kebabToLabel } from "../utils/studio-utils";
|
|
21
|
+
|
|
22
|
+
interface ColorVar {
|
|
23
|
+
name: string;
|
|
24
|
+
value: string;
|
|
25
|
+
}
|
|
20
26
|
|
|
21
27
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
22
28
|
|
|
@@ -37,12 +43,12 @@ function getColorVars() {
|
|
|
37
43
|
* Convert a color variable name to a title-case label. Strips the "--color-" prefix and converts
|
|
38
44
|
* kebab to title case. e.g. "--color-primary-blue" → "Primary Blue"
|
|
39
45
|
*/
|
|
40
|
-
function varToLabel(
|
|
46
|
+
function varToLabel(name: string) {
|
|
41
47
|
return kebabToLabel(name.replace(/^--color-?/, ""));
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
/** Resolve a color value for display — if it's a var() reference, look up the actual color. */
|
|
45
|
-
function resolveColorForDisplay(
|
|
51
|
+
function resolveColorForDisplay(val: string | number | undefined) {
|
|
46
52
|
if (!val) return "transparent";
|
|
47
53
|
const s = String(val);
|
|
48
54
|
const m = s.match(/^var\((--[^)]+)\)$/);
|
|
@@ -55,13 +61,13 @@ function resolveColorForDisplay(/** @type {string | number | undefined} */ val)
|
|
|
55
61
|
return s;
|
|
56
62
|
}
|
|
57
63
|
|
|
58
|
-
function safeColor(
|
|
64
|
+
function safeColor(val: string | number | undefined) {
|
|
59
65
|
if (!val) return "transparent";
|
|
60
66
|
return resolveColorForDisplay(val);
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
/** Normalize a color string to include # prefix for hex values. */
|
|
64
|
-
function normalizeHex(
|
|
70
|
+
function normalizeHex(c: string) {
|
|
65
71
|
if (!c) return c;
|
|
66
72
|
if (c.startsWith("var(") || c.startsWith("rgb") || c.startsWith("hsl")) return c;
|
|
67
73
|
return c.replace(/^#?/, "#");
|
|
@@ -73,7 +79,10 @@ function normalizeHex(/** @type {string} */ c) {
|
|
|
73
79
|
* @param {string | number | undefined} value
|
|
74
80
|
* @param {{ name: string; value: string }[]} colorVars
|
|
75
81
|
*/
|
|
76
|
-
function matchesColorVar(
|
|
82
|
+
function matchesColorVar(
|
|
83
|
+
value: string | number | undefined,
|
|
84
|
+
colorVars: { name: string; value: string }[],
|
|
85
|
+
) {
|
|
77
86
|
if (!value || typeof value !== "string") return null;
|
|
78
87
|
const m = value.match(/^var\((--[^)]+)\)$/);
|
|
79
88
|
if (!m) return null;
|
|
@@ -82,8 +91,6 @@ function matchesColorVar(value, colorVars) {
|
|
|
82
91
|
|
|
83
92
|
// ─── JxColorPopover LitElement ──────────────────────────────────────────────
|
|
84
93
|
|
|
85
|
-
/** @typedef {{ name: string; value: string }} ColorVar */
|
|
86
|
-
|
|
87
94
|
export class JxColorPopover extends LitElement {
|
|
88
95
|
static properties = {
|
|
89
96
|
color: { type: String },
|
|
@@ -91,11 +98,15 @@ export class JxColorPopover extends LitElement {
|
|
|
91
98
|
colorVars: { attribute: false },
|
|
92
99
|
};
|
|
93
100
|
|
|
101
|
+
declare color: string;
|
|
102
|
+
declare displayColor: string;
|
|
103
|
+
declare colorVars: ColorVar[];
|
|
104
|
+
|
|
94
105
|
constructor() {
|
|
95
106
|
super();
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
107
|
+
this.color = "";
|
|
108
|
+
this.displayColor = "#000000";
|
|
109
|
+
this.colorVars = [];
|
|
99
110
|
}
|
|
100
111
|
|
|
101
112
|
/** No shadow DOM — render directly into light DOM for Spectrum theming */
|
|
@@ -104,7 +115,7 @@ export class JxColorPopover extends LitElement {
|
|
|
104
115
|
}
|
|
105
116
|
|
|
106
117
|
/** @param {Map<string, unknown>} changed */
|
|
107
|
-
willUpdate(changed) {
|
|
118
|
+
willUpdate(changed: Map<string, unknown>) {
|
|
108
119
|
if (changed.has("color")) {
|
|
109
120
|
const raw = resolveColorForDisplay(this.color);
|
|
110
121
|
if (!raw || raw === "transparent") {
|
|
@@ -117,33 +128,29 @@ export class JxColorPopover extends LitElement {
|
|
|
117
128
|
}
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
_handleArea(
|
|
121
|
-
const color = normalizeHex(
|
|
122
|
-
String(/** @type {HTMLElement & { color: string }} */ (e.target).color),
|
|
123
|
-
);
|
|
131
|
+
_handleArea(e: Event) {
|
|
132
|
+
const color = normalizeHex(String((e.target as HTMLElement & { color: string }).color));
|
|
124
133
|
this.displayColor = color;
|
|
125
134
|
this.color = color;
|
|
126
135
|
this.dispatchEvent(new CustomEvent("color-change", { detail: color, bubbles: true }));
|
|
127
136
|
}
|
|
128
137
|
|
|
129
|
-
_handleSlider(
|
|
130
|
-
const color = normalizeHex(
|
|
131
|
-
String(/** @type {HTMLElement & { color: string }} */ (e.target).color),
|
|
132
|
-
);
|
|
138
|
+
_handleSlider(e: Event) {
|
|
139
|
+
const color = normalizeHex(String((e.target as HTMLElement & { color: string }).color));
|
|
133
140
|
this.displayColor = color;
|
|
134
141
|
this.color = color;
|
|
135
142
|
this.dispatchEvent(new CustomEvent("color-change", { detail: color, bubbles: true }));
|
|
136
143
|
}
|
|
137
144
|
|
|
138
|
-
_handleText(
|
|
139
|
-
const val =
|
|
145
|
+
_handleText(e: Event) {
|
|
146
|
+
const val = (e.target as HTMLInputElement).value.trim();
|
|
140
147
|
if (!val) return;
|
|
141
148
|
this.displayColor = val;
|
|
142
149
|
this.color = val;
|
|
143
150
|
this.dispatchEvent(new CustomEvent("color-change", { detail: val, bubbles: true }));
|
|
144
151
|
}
|
|
145
152
|
|
|
146
|
-
_handleSwatch(
|
|
153
|
+
_handleSwatch(e: Event, varName: string) {
|
|
147
154
|
e.stopPropagation();
|
|
148
155
|
const varRef = `var(${varName})`;
|
|
149
156
|
this.color = varRef;
|
|
@@ -181,7 +188,7 @@ export class JxColorPopover extends LitElement {
|
|
|
181
188
|
color=${cv.value}
|
|
182
189
|
.value=${cv.name}
|
|
183
190
|
title=${cv.name}
|
|
184
|
-
@click=${(
|
|
191
|
+
@click=${(e: Event) => this._handleSwatch(e, cv.name)}
|
|
185
192
|
></sp-swatch>
|
|
186
193
|
`,
|
|
187
194
|
)}
|
|
@@ -208,9 +215,9 @@ export class JxColorPopover extends LitElement {
|
|
|
208
215
|
* @returns {import("lit-html").TemplateResult}
|
|
209
216
|
*/
|
|
210
217
|
export function renderColorSelector(
|
|
211
|
-
/** @type {string} */ prop,
|
|
212
|
-
/** @type {string | number | undefined} */ value,
|
|
213
|
-
/** @type {(color: string) => void} */ onChange,
|
|
218
|
+
/** @type {string} */ prop: string,
|
|
219
|
+
/** @type {string | number | undefined} */ value: string | number | undefined,
|
|
220
|
+
/** @type {(color: string) => void} */ onChange: (color: string) => void,
|
|
214
221
|
) {
|
|
215
222
|
const colorVars = getColorVars();
|
|
216
223
|
const matchedVar = matchesColorVar(value, colorVars);
|
|
@@ -233,7 +240,7 @@ export function renderColorSelector(
|
|
|
233
240
|
<jx-color-popover
|
|
234
241
|
.color=${value || ""}
|
|
235
242
|
.colorVars=${colorVars}
|
|
236
|
-
@color-change=${(
|
|
243
|
+
@color-change=${(e: CustomEvent) => onChange(e.detail)}
|
|
237
244
|
></jx-color-popover>
|
|
238
245
|
</sp-popover>
|
|
239
246
|
</sp-overlay>
|
|
@@ -242,9 +249,9 @@ export function renderColorSelector(
|
|
|
242
249
|
size="s"
|
|
243
250
|
style="flex:1; min-width:0"
|
|
244
251
|
.value=${`var(${matchedVar.name})`}
|
|
245
|
-
@change=${(
|
|
252
|
+
@change=${(e: Event) => {
|
|
246
253
|
e.stopPropagation();
|
|
247
|
-
onChange(
|
|
254
|
+
onChange((e.target as HTMLInputElement).value);
|
|
248
255
|
}}
|
|
249
256
|
>
|
|
250
257
|
${colorVars.map(
|
|
@@ -279,9 +286,9 @@ export function renderColorSelector(
|
|
|
279
286
|
size="s"
|
|
280
287
|
style="flex:1; min-width:0"
|
|
281
288
|
.value=${live(value || "")}
|
|
282
|
-
@click=${(
|
|
283
|
-
@input=${debouncedStyleCommit(`color:${prop}`, 400, (
|
|
284
|
-
onChange(
|
|
289
|
+
@click=${(e: Event) => e.stopPropagation()}
|
|
290
|
+
@input=${debouncedStyleCommit(`color:${prop}`, 400, (e: Event) => {
|
|
291
|
+
onChange((e.target as HTMLInputElement).value.trim());
|
|
285
292
|
})}
|
|
286
293
|
></sp-textfield>
|
|
287
294
|
<sp-overlay trigger="${triggerId}@click" placement="bottom-start" type="auto">
|
|
@@ -289,7 +296,7 @@ export function renderColorSelector(
|
|
|
289
296
|
<jx-color-popover
|
|
290
297
|
.color=${value || ""}
|
|
291
298
|
.colorVars=${colorVars}
|
|
292
|
-
@color-change=${(
|
|
299
|
+
@color-change=${(e: CustomEvent) => onChange(e.detail)}
|
|
293
300
|
></jx-color-popover>
|
|
294
301
|
</sp-popover>
|
|
295
302
|
</sp-overlay>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
import { html, nothing } from "lit-html";
|
|
2
3
|
import { live } from "lit-html/directives/live.js";
|
|
3
|
-
import { renderFieldRow } from "./field-row
|
|
4
|
+
import { renderFieldRow } from "./field-row";
|
|
4
5
|
|
|
5
6
|
// ─── Operator Categories ────────────────────────────────────────────────────
|
|
6
7
|
|
|
@@ -44,7 +45,7 @@ const OPERATOR_GROUPS = [
|
|
|
44
45
|
* valueIsNode: boolean;
|
|
45
46
|
* }}
|
|
46
47
|
*/
|
|
47
|
-
function operatorInfo(op) {
|
|
48
|
+
function operatorInfo(op: string) {
|
|
48
49
|
if (UNARY_OPS.has(op))
|
|
49
50
|
return {
|
|
50
51
|
needsValue: false,
|
|
@@ -124,7 +125,7 @@ function operatorInfo(op) {
|
|
|
124
125
|
* @param {any} operand
|
|
125
126
|
* @returns {"ref" | "expression" | "literal"}
|
|
126
127
|
*/
|
|
127
|
-
function operandMode(operand) {
|
|
128
|
+
function operandMode(operand: any) {
|
|
128
129
|
if (operand && typeof operand === "object") {
|
|
129
130
|
if ("$ref" in operand) return "ref";
|
|
130
131
|
if ("operator" in operand) return "expression";
|
|
@@ -136,7 +137,7 @@ function operandMode(operand) {
|
|
|
136
137
|
* @param {string} mode
|
|
137
138
|
* @returns {any}
|
|
138
139
|
*/
|
|
139
|
-
function defaultForMode(mode) {
|
|
140
|
+
function defaultForMode(mode: string) {
|
|
140
141
|
if (mode === "ref") return { $ref: "" };
|
|
141
142
|
if (mode === "expression") return { operator: "!", target: null };
|
|
142
143
|
return null;
|
|
@@ -148,7 +149,7 @@ function defaultForMode(mode) {
|
|
|
148
149
|
* @param {any} val
|
|
149
150
|
* @returns {"string" | "number" | "boolean" | "null"}
|
|
150
151
|
*/
|
|
151
|
-
function literalType(val) {
|
|
152
|
+
function literalType(val: any) {
|
|
152
153
|
if (val === null || val === undefined) return "null";
|
|
153
154
|
if (typeof val === "boolean") return "boolean";
|
|
154
155
|
if (typeof val === "number") return "number";
|
|
@@ -159,7 +160,7 @@ function literalType(val) {
|
|
|
159
160
|
* @param {string} type
|
|
160
161
|
* @returns {any}
|
|
161
162
|
*/
|
|
162
|
-
function defaultForLiteralType(type) {
|
|
163
|
+
function defaultForLiteralType(type: string) {
|
|
163
164
|
if (type === "number") return 0;
|
|
164
165
|
if (type === "boolean") return false;
|
|
165
166
|
if (type === "null") return null;
|
|
@@ -172,7 +173,7 @@ function defaultForLiteralType(type) {
|
|
|
172
173
|
* @param {any} node
|
|
173
174
|
* @returns {string}
|
|
174
175
|
*/
|
|
175
|
-
export function expressionHint(node) {
|
|
176
|
+
export function expressionHint(node: any) {
|
|
176
177
|
if (!node || !node.operator) return "$expression";
|
|
177
178
|
const op = node.operator;
|
|
178
179
|
const targetLabel = node.target?.$ref
|
|
@@ -197,7 +198,11 @@ export function expressionHint(node) {
|
|
|
197
198
|
* @param {{ stateDefs: string[]; allowEventRef: boolean }} opts
|
|
198
199
|
* @returns {import("lit-html").TemplateResult}
|
|
199
200
|
*/
|
|
200
|
-
function renderRefPicker(
|
|
201
|
+
function renderRefPicker(
|
|
202
|
+
refVal: string,
|
|
203
|
+
onRefChange: (newRef: string) => void,
|
|
204
|
+
opts: { stateDefs: string[]; allowEventRef: boolean },
|
|
205
|
+
) {
|
|
201
206
|
const stateRefs = (opts.stateDefs || []).map((k) => `#/state/${k}`);
|
|
202
207
|
const eventRefs = opts.allowEventRef ? ["event#/detail", "event#/target/value"] : [];
|
|
203
208
|
const allRefs = [...stateRefs, ...eventRefs];
|
|
@@ -209,8 +214,8 @@ function renderRefPicker(refVal, onRefChange, opts) {
|
|
|
209
214
|
style="flex:1"
|
|
210
215
|
placeholder="Select…"
|
|
211
216
|
.value=${live(isCustom ? "__custom__" : refVal || "")}
|
|
212
|
-
@change=${(
|
|
213
|
-
const val =
|
|
217
|
+
@change=${(e: Event) => {
|
|
218
|
+
const val = (e.target as HTMLInputElement).value;
|
|
214
219
|
if (val === "__custom__") return;
|
|
215
220
|
onRefChange(val);
|
|
216
221
|
}}
|
|
@@ -237,7 +242,7 @@ function renderRefPicker(refVal, onRefChange, opts) {
|
|
|
237
242
|
* @param {(newVal: any) => void} onChange
|
|
238
243
|
* @returns {import("lit-html").TemplateResult}
|
|
239
244
|
*/
|
|
240
|
-
function renderLiteralEditor(operand, onChange) {
|
|
245
|
+
function renderLiteralEditor(operand: any, onChange: (newVal: any) => void) {
|
|
241
246
|
const type = literalType(operand);
|
|
242
247
|
return html`
|
|
243
248
|
<div style="display:flex;gap:4px;align-items:center;flex:1">
|
|
@@ -245,8 +250,8 @@ function renderLiteralEditor(operand, onChange) {
|
|
|
245
250
|
size="s"
|
|
246
251
|
style="min-width:56px"
|
|
247
252
|
.value=${live(type)}
|
|
248
|
-
@change=${(
|
|
249
|
-
const newType =
|
|
253
|
+
@change=${(e: Event) => {
|
|
254
|
+
const newType = (e.target as HTMLInputElement).value;
|
|
250
255
|
onChange(defaultForLiteralType(newType));
|
|
251
256
|
}}
|
|
252
257
|
>
|
|
@@ -260,23 +265,20 @@ function renderLiteralEditor(operand, onChange) {
|
|
|
260
265
|
size="s"
|
|
261
266
|
style="flex:1"
|
|
262
267
|
.value=${live(String(operand ?? ""))}
|
|
263
|
-
@input=${(
|
|
264
|
-
onChange(/** @type {HTMLInputElement} */ (e.target).value)}
|
|
268
|
+
@input=${(e: Event) => onChange((e.target as HTMLInputElement).value)}
|
|
265
269
|
></sp-textfield>`
|
|
266
270
|
: type === "number"
|
|
267
271
|
? html`<sp-number-field
|
|
268
272
|
size="s"
|
|
269
273
|
style="flex:1"
|
|
270
274
|
.value=${live(Number(operand ?? 0))}
|
|
271
|
-
@change=${(
|
|
272
|
-
onChange(Number(/** @type {HTMLInputElement} */ (e.target).value))}
|
|
275
|
+
@change=${(e: Event) => onChange(Number((e.target as HTMLInputElement).value))}
|
|
273
276
|
></sp-number-field>`
|
|
274
277
|
: type === "boolean"
|
|
275
278
|
? html`<sp-checkbox
|
|
276
279
|
size="s"
|
|
277
280
|
?checked=${!!operand}
|
|
278
|
-
@change=${(
|
|
279
|
-
onChange(/** @type {HTMLInputElement} */ (e.target).checked)}
|
|
281
|
+
@change=${(e: Event) => onChange((e.target as HTMLInputElement).checked)}
|
|
280
282
|
>true</sp-checkbox
|
|
281
283
|
>`
|
|
282
284
|
: html`<span style="font-size:12px;color:var(--spectrum-global-color-gray-600)"
|
|
@@ -299,9 +301,13 @@ function renderLiteralEditor(operand, onChange) {
|
|
|
299
301
|
* }} opts
|
|
300
302
|
* @returns {import("lit-html").TemplateResult}
|
|
301
303
|
*/
|
|
302
|
-
function renderOperandEditor(
|
|
304
|
+
function renderOperandEditor(
|
|
305
|
+
operand: unknown,
|
|
306
|
+
onChange: (newOperand: unknown) => void,
|
|
307
|
+
opts: { stateDefs: string[]; allowEventRef: boolean; depth: number; mustBeRef?: boolean },
|
|
308
|
+
): import("lit-html").TemplateResult {
|
|
303
309
|
if (opts.mustBeRef) {
|
|
304
|
-
const refVal = operand?.$ref ?? "";
|
|
310
|
+
const refVal = ((operand as Record<string, unknown> | null)?.$ref as string) ?? "";
|
|
305
311
|
return html`
|
|
306
312
|
<div style="flex:1">${renderRefPicker(refVal, (r) => onChange({ $ref: r }), opts)}</div>
|
|
307
313
|
`;
|
|
@@ -314,8 +320,8 @@ function renderOperandEditor(operand, onChange, opts) {
|
|
|
314
320
|
size="s"
|
|
315
321
|
style="min-width:60px"
|
|
316
322
|
.value=${live(mode)}
|
|
317
|
-
@change=${(
|
|
318
|
-
const newMode =
|
|
323
|
+
@change=${(e: Event) => {
|
|
324
|
+
const newMode = (e.target as HTMLInputElement).value;
|
|
319
325
|
onChange(defaultForMode(newMode));
|
|
320
326
|
}}
|
|
321
327
|
>
|
|
@@ -326,7 +332,11 @@ function renderOperandEditor(operand, onChange, opts) {
|
|
|
326
332
|
${mode === "literal"
|
|
327
333
|
? renderLiteralEditor(operand, onChange)
|
|
328
334
|
: mode === "ref"
|
|
329
|
-
? renderRefPicker(
|
|
335
|
+
? renderRefPicker(
|
|
336
|
+
((operand as Record<string, unknown> | null)?.$ref as string) ?? "",
|
|
337
|
+
(r) => onChange({ $ref: r }),
|
|
338
|
+
opts,
|
|
339
|
+
)
|
|
330
340
|
: renderExpressionEditor(operand, onChange, { ...opts, depth: opts.depth + 1 })}
|
|
331
341
|
</div>
|
|
332
342
|
`;
|
|
@@ -340,7 +350,11 @@ function renderOperandEditor(operand, onChange, opts) {
|
|
|
340
350
|
* @param {{ stateDefs: string[]; allowEventRef: boolean; depth: number }} opts
|
|
341
351
|
* @returns {import("lit-html").TemplateResult}
|
|
342
352
|
*/
|
|
343
|
-
function renderSpliceArgsEditor(
|
|
353
|
+
function renderSpliceArgsEditor(
|
|
354
|
+
args: unknown[],
|
|
355
|
+
onChange: (newArgs: unknown[]) => void,
|
|
356
|
+
opts: { stateDefs: string[]; allowEventRef: boolean; depth: number },
|
|
357
|
+
): import("lit-html").TemplateResult {
|
|
344
358
|
const safeArgs = Array.isArray(args) ? args : [];
|
|
345
359
|
const labels = ["start", "del", "item"];
|
|
346
360
|
|
|
@@ -408,10 +422,17 @@ const _operatorMenuCache = OPERATOR_GROUPS.map(
|
|
|
408
422
|
* }} opts
|
|
409
423
|
* @returns {import("lit-html").TemplateResult}
|
|
410
424
|
*/
|
|
411
|
-
export function renderExpressionEditor(
|
|
425
|
+
export function renderExpressionEditor(
|
|
426
|
+
node: unknown,
|
|
427
|
+
onChange: (node: unknown) => void,
|
|
428
|
+
opts: { stateDefs: string[]; allowEventRef: boolean; depth?: number },
|
|
429
|
+
): import("lit-html").TemplateResult {
|
|
412
430
|
const depth = opts.depth ?? 0;
|
|
413
|
-
const safeNode
|
|
414
|
-
|
|
431
|
+
const safeNode: Record<string, unknown> =
|
|
432
|
+
node && typeof node === "object"
|
|
433
|
+
? (node as Record<string, unknown>)
|
|
434
|
+
: { operator: "=", target: null };
|
|
435
|
+
const op = (safeNode.operator as string) || "=";
|
|
415
436
|
const info = operatorInfo(op);
|
|
416
437
|
|
|
417
438
|
const nestStyle =
|
|
@@ -429,19 +450,17 @@ export function renderExpressionEditor(node, onChange, opts) {
|
|
|
429
450
|
<sp-picker
|
|
430
451
|
size="s"
|
|
431
452
|
.value=${live(op)}
|
|
432
|
-
@change=${(
|
|
433
|
-
const newOp =
|
|
453
|
+
@change=${(e: Event) => {
|
|
454
|
+
const newOp = (e.target as HTMLInputElement).value;
|
|
434
455
|
const newInfo = operatorInfo(newOp);
|
|
435
|
-
|
|
436
|
-
const updated = { operator: newOp, target: safeNode.target };
|
|
456
|
+
const updated: any = { operator: newOp, target: safeNode.target };
|
|
437
457
|
if (newInfo.targetMustBeRef && operandMode(safeNode.target) !== "ref") {
|
|
438
458
|
updated.target = { $ref: "" };
|
|
439
459
|
}
|
|
440
460
|
if (newInfo.needsValue) {
|
|
441
461
|
if (newInfo.valueIsNode) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
: { operator: "!", target: null };
|
|
462
|
+
const val = safeNode.value as Record<string, unknown> | null;
|
|
463
|
+
updated.value = val?.operator ? safeNode.value : { operator: "!", target: null };
|
|
445
464
|
} else if (newInfo.spliceArray) {
|
|
446
465
|
updated.value = Array.isArray(safeNode.value) ? safeNode.value : [null];
|
|
447
466
|
} else {
|
|
@@ -488,7 +507,9 @@ export function renderExpressionEditor(node, onChange, opts) {
|
|
|
488
507
|
widget: nothing,
|
|
489
508
|
})}
|
|
490
509
|
${renderExpressionEditor(
|
|
491
|
-
safeNode.value
|
|
510
|
+
(safeNode.value as Record<string, unknown> | null)?.operator
|
|
511
|
+
? safeNode.value
|
|
512
|
+
: { operator: "!", target: null },
|
|
492
513
|
(v) => onChange({ ...safeNode, value: v }),
|
|
493
514
|
{ ...opts, depth: depth + 1 },
|
|
494
515
|
)}
|
|
@@ -504,10 +525,14 @@ export function renderExpressionEditor(node, onChange, opts) {
|
|
|
504
525
|
hasValue: false,
|
|
505
526
|
widget: nothing,
|
|
506
527
|
})}
|
|
507
|
-
${renderSpliceArgsEditor(
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
528
|
+
${renderSpliceArgsEditor(
|
|
529
|
+
safeNode.value as unknown[],
|
|
530
|
+
(v) => onChange({ ...safeNode, value: v }),
|
|
531
|
+
{
|
|
532
|
+
...opts,
|
|
533
|
+
depth,
|
|
534
|
+
},
|
|
535
|
+
)}
|
|
511
536
|
</div>
|
|
512
537
|
`
|
|
513
538
|
: nothing}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Field-row.js — Universal field row layout for all Studio panels.
|
|
3
4
|
*
|
|
@@ -22,7 +23,23 @@ import { classMap } from "lit-html/directives/class-map.js";
|
|
|
22
23
|
* }} opts
|
|
23
24
|
* @returns {import("lit-html").TemplateResult}
|
|
24
25
|
*/
|
|
25
|
-
export function renderFieldRow({
|
|
26
|
+
export function renderFieldRow({
|
|
27
|
+
prop,
|
|
28
|
+
label,
|
|
29
|
+
hasValue,
|
|
30
|
+
onClear,
|
|
31
|
+
widget,
|
|
32
|
+
span,
|
|
33
|
+
warning,
|
|
34
|
+
}: {
|
|
35
|
+
prop: string;
|
|
36
|
+
label: string;
|
|
37
|
+
hasValue: boolean;
|
|
38
|
+
onClear?: () => void;
|
|
39
|
+
widget: unknown;
|
|
40
|
+
span?: number;
|
|
41
|
+
warning?: boolean;
|
|
42
|
+
}) {
|
|
26
43
|
return html`
|
|
27
44
|
<div
|
|
28
45
|
class=${classMap({ "style-row": true, "style-row--warning": !!warning })}
|
|
@@ -34,7 +51,7 @@ export function renderFieldRow({ prop, label, hasValue, onClear, widget, span, w
|
|
|
34
51
|
? html`<span
|
|
35
52
|
class="set-dot"
|
|
36
53
|
title="Clear ${prop}"
|
|
37
|
-
@click=${(
|
|
54
|
+
@click=${(e: Event) => {
|
|
38
55
|
e.stopPropagation();
|
|
39
56
|
onClear();
|
|
40
57
|
}}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { html } from "lit";
|
|
6
6
|
|
|
7
7
|
// Helper for custom filled-rect icons (alignment/justify diagrams) where no Spectrum match exists
|
|
8
|
-
const _R = (
|
|
8
|
+
const _R = (d: import("lit").TemplateResult) =>
|
|
9
9
|
html`<svg
|
|
10
10
|
xmlns="http://www.w3.org/2000/svg"
|
|
11
11
|
width="16"
|
|
@@ -18,7 +18,7 @@ const _R = (/** @type {import("lit").TemplateResult} */ d) =>
|
|
|
18
18
|
</svg>`;
|
|
19
19
|
|
|
20
20
|
// Helper for custom stroke icons
|
|
21
|
-
const _S = (
|
|
21
|
+
const _S = (d: import("lit").TemplateResult) =>
|
|
22
22
|
html`<svg
|
|
23
23
|
xmlns="http://www.w3.org/2000/svg"
|
|
24
24
|
width="16"
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
import { render as litRender, nothing, html } from "lit-html";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
let
|
|
5
|
-
|
|
6
|
-
let _modalLayer;
|
|
7
|
-
/** @type {HTMLElement} */
|
|
8
|
-
let _dialogLayer;
|
|
4
|
+
let _popoverLayer: HTMLElement;
|
|
5
|
+
let _modalLayer: HTMLElement;
|
|
6
|
+
let _dialogLayer: HTMLElement;
|
|
9
7
|
|
|
10
8
|
export function initLayers() {
|
|
11
|
-
_popoverLayer =
|
|
12
|
-
_modalLayer =
|
|
13
|
-
_dialogLayer =
|
|
9
|
+
_popoverLayer = document.getElementById("layer-popover") as HTMLElement;
|
|
10
|
+
_modalLayer = document.getElementById("layer-modal") as HTMLElement;
|
|
11
|
+
_dialogLayer = document.getElementById("layer-dialog") as HTMLElement;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
/**
|
|
@@ -20,13 +18,15 @@ export function initLayers() {
|
|
|
20
18
|
* @param {(done: (value: T) => void) => import("lit-html").TemplateResult} templateFn
|
|
21
19
|
* @returns {Promise<T>}
|
|
22
20
|
*/
|
|
23
|
-
export function showDialog(
|
|
21
|
+
export function showDialog<T>(
|
|
22
|
+
templateFn: (done: (value: T) => void) => import("lit-html").TemplateResult,
|
|
23
|
+
): Promise<T> {
|
|
24
24
|
return new Promise((resolve) => {
|
|
25
25
|
const slot = document.createElement("div");
|
|
26
26
|
slot.style.pointerEvents = "auto";
|
|
27
27
|
_dialogLayer.appendChild(slot);
|
|
28
28
|
let resolved = false;
|
|
29
|
-
const done = (
|
|
29
|
+
const done = (value: T) => {
|
|
30
30
|
if (resolved) return;
|
|
31
31
|
resolved = true;
|
|
32
32
|
litRender(nothing, slot);
|
|
@@ -45,7 +45,11 @@ export function showDialog(templateFn) {
|
|
|
45
45
|
* @param {{ confirmLabel?: string; cancelLabel?: string; destructive?: boolean }} [opts]
|
|
46
46
|
* @returns {Promise<boolean>}
|
|
47
47
|
*/
|
|
48
|
-
export function showConfirmDialog(
|
|
48
|
+
export function showConfirmDialog(
|
|
49
|
+
headline: string,
|
|
50
|
+
message: string | import("lit-html").TemplateResult,
|
|
51
|
+
opts: { confirmLabel?: string; cancelLabel?: string; destructive?: boolean } = {},
|
|
52
|
+
) {
|
|
49
53
|
const { confirmLabel = "Confirm", cancelLabel = "Cancel", destructive = false } = opts;
|
|
50
54
|
return showDialog(
|
|
51
55
|
(done) => html`
|
|
@@ -72,7 +76,7 @@ export function showConfirmDialog(headline, message, opts = {}) {
|
|
|
72
76
|
*
|
|
73
77
|
* @param {import("lit-html").TemplateResult} template
|
|
74
78
|
*/
|
|
75
|
-
export function openModal(template) {
|
|
79
|
+
export function openModal(template: import("lit-html").TemplateResult) {
|
|
76
80
|
const slot = document.createElement("div");
|
|
77
81
|
slot.style.pointerEvents = "auto";
|
|
78
82
|
_modalLayer.appendChild(slot);
|
|
@@ -80,7 +84,7 @@ export function openModal(template) {
|
|
|
80
84
|
return {
|
|
81
85
|
host: slot,
|
|
82
86
|
/** @param {import("lit-html").TemplateResult} tpl */
|
|
83
|
-
update(tpl) {
|
|
87
|
+
update(tpl: import("lit-html").TemplateResult) {
|
|
84
88
|
litRender(tpl, slot);
|
|
85
89
|
},
|
|
86
90
|
close() {
|
|
@@ -100,7 +104,14 @@ export function openModal(template) {
|
|
|
100
104
|
* layer?: "popover" | "modal" | "dialog";
|
|
101
105
|
* }} [opts]
|
|
102
106
|
*/
|
|
103
|
-
export function renderPopover(
|
|
107
|
+
export function renderPopover(
|
|
108
|
+
template: import("lit-html").TemplateResult,
|
|
109
|
+
opts: {
|
|
110
|
+
dismissOnOutsideClick?: boolean;
|
|
111
|
+
onDismiss?: () => void;
|
|
112
|
+
layer?: "popover" | "modal" | "dialog";
|
|
113
|
+
} = {},
|
|
114
|
+
) {
|
|
104
115
|
const slot = document.createElement("div");
|
|
105
116
|
slot.style.pointerEvents = "auto";
|
|
106
117
|
const target =
|
|
@@ -108,11 +119,10 @@ export function renderPopover(template, opts = {}) {
|
|
|
108
119
|
target.appendChild(slot);
|
|
109
120
|
litRender(template, slot);
|
|
110
121
|
|
|
111
|
-
|
|
112
|
-
let outsideClickHandler = null;
|
|
122
|
+
let outsideClickHandler: ((e: MouseEvent) => void) | null = null;
|
|
113
123
|
if (opts.dismissOnOutsideClick !== false) {
|
|
114
|
-
outsideClickHandler = (
|
|
115
|
-
if (!slot.contains(
|
|
124
|
+
outsideClickHandler = (e: MouseEvent) => {
|
|
125
|
+
if (!slot.contains(e.target as Node)) {
|
|
116
126
|
handle.dismiss();
|
|
117
127
|
opts.onDismiss?.();
|
|
118
128
|
}
|
|
@@ -125,7 +135,7 @@ export function renderPopover(template, opts = {}) {
|
|
|
125
135
|
const handle = {
|
|
126
136
|
host: slot,
|
|
127
137
|
/** @param {import("lit-html").TemplateResult} tpl */
|
|
128
|
-
update(tpl) {
|
|
138
|
+
update(tpl: import("lit-html").TemplateResult) {
|
|
129
139
|
litRender(tpl, slot);
|
|
130
140
|
},
|
|
131
141
|
dismiss() {
|
|
@@ -139,8 +149,7 @@ export function renderPopover(template, opts = {}) {
|
|
|
139
149
|
return handle;
|
|
140
150
|
}
|
|
141
151
|
|
|
142
|
-
|
|
143
|
-
const _namedSlots = new Map();
|
|
152
|
+
const _namedSlots: Map<string, HTMLElement> = new Map();
|
|
144
153
|
|
|
145
154
|
/**
|
|
146
155
|
* Get or create a named slot in a layer. Useful for persistent popovers like zoom indicator.
|
|
@@ -149,7 +158,7 @@ const _namedSlots = new Map();
|
|
|
149
158
|
* @param {string} id
|
|
150
159
|
* @returns {HTMLElement}
|
|
151
160
|
*/
|
|
152
|
-
export function getLayerSlot(layer, id) {
|
|
161
|
+
export function getLayerSlot(layer: "popover" | "modal" | "dialog", id: string) {
|
|
153
162
|
const key = `${layer}:${id}`;
|
|
154
163
|
let slot = _namedSlots.get(key);
|
|
155
164
|
if (slot && slot.parentElement) return slot;
|
|
@@ -170,7 +179,7 @@ export function getLayerSlot(layer, id) {
|
|
|
170
179
|
* @param {"popover" | "modal" | "dialog"} layer
|
|
171
180
|
* @param {string} id
|
|
172
181
|
*/
|
|
173
|
-
export function clearLayerSlot(layer, id) {
|
|
182
|
+
export function clearLayerSlot(layer: "popover" | "modal" | "dialog", id: string) {
|
|
174
183
|
const key = `${layer}:${id}`;
|
|
175
184
|
const slot = _namedSlots.get(key);
|
|
176
185
|
if (slot) {
|