@jxsuite/studio 0.23.1 → 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.
Files changed (105) hide show
  1. package/dist/studio.js +2231 -715
  2. package/dist/studio.js.map +121 -104
  3. package/package.json +8 -7
  4. package/src/browse/{browse-modal.js → browse-modal.ts} +9 -10
  5. package/src/browse/{browse.js → browse.ts} +110 -85
  6. package/src/canvas/{canvas-diff.js → canvas-diff.ts} +42 -35
  7. package/src/canvas/{canvas-helpers.js → canvas-helpers.ts} +25 -19
  8. package/src/canvas/{canvas-live-render.js → canvas-live-render.ts} +53 -63
  9. package/src/canvas/{canvas-render.js → canvas-render.ts} +110 -121
  10. package/src/canvas/{canvas-utils.js → canvas-utils.ts} +48 -44
  11. package/src/canvas/{nested-site-style.js → nested-site-style.ts} +3 -3
  12. package/src/editor/{component-inline-edit.js → component-inline-edit.ts} +45 -33
  13. package/src/editor/{content-inline-edit.js → content-inline-edit.ts} +27 -45
  14. package/src/editor/{context-menu.js → context-menu.ts} +38 -36
  15. package/src/editor/{convert-targets.js → convert-targets.ts} +15 -12
  16. package/src/editor/{convert-to-component.js → convert-to-component.ts} +25 -26
  17. package/src/editor/{convert-to-repeater.js → convert-to-repeater.ts} +60 -40
  18. package/src/editor/{inline-edit.js → inline-edit.ts} +91 -55
  19. package/src/editor/{inline-format.js → inline-format.ts} +46 -51
  20. package/src/editor/{insertion-helper.js → insertion-helper.ts} +47 -63
  21. package/src/editor/{shortcuts.js → shortcuts.ts} +45 -31
  22. package/src/editor/{slash-menu.js → slash-menu.ts} +34 -35
  23. package/src/files/{components.js → components.ts} +12 -15
  24. package/src/files/{file-ops.js → file-ops.ts} +36 -29
  25. package/src/files/{files.js → files.ts} +102 -84
  26. package/src/github/{github-auth.js → github-auth.ts} +3 -3
  27. package/src/github/{github-publish.js → github-publish.ts} +20 -18
  28. package/src/markdown/{md-allowlist.js → md-allowlist.ts} +5 -2
  29. package/src/markdown/{md-convert.js → md-convert.ts} +146 -169
  30. package/src/new-project/{new-project-modal.js → new-project-modal.ts} +16 -18
  31. package/src/panels/{activity-bar.js → activity-bar.ts} +26 -34
  32. package/src/panels/{ai-panel.js → ai-panel.ts} +30 -30
  33. package/src/panels/{block-action-bar.js → block-action-bar.ts} +64 -73
  34. package/src/panels/{canvas-dnd.js → canvas-dnd.ts} +44 -49
  35. package/src/panels/{data-explorer.js → data-explorer.ts} +21 -15
  36. package/src/panels/dnd.ts +417 -0
  37. package/src/panels/{editors.js → editors.ts} +43 -50
  38. package/src/panels/{elements-panel.js → elements-panel.ts} +30 -27
  39. package/src/panels/{events-panel.js → events-panel.ts} +33 -25
  40. package/src/panels/{git-panel.js → git-panel.ts} +97 -83
  41. package/src/panels/{head-panel.js → head-panel.ts} +117 -139
  42. package/src/panels/{imports-panel.js → imports-panel.ts} +69 -89
  43. package/src/panels/{layers-panel.js → layers-panel.ts} +61 -57
  44. package/src/panels/{left-panel.js → left-panel.ts} +56 -63
  45. package/src/panels/{overlays.js → overlays.ts} +28 -36
  46. package/src/panels/{panel-events.js → panel-events.ts} +53 -51
  47. package/src/panels/{preview-render.js → preview-render.ts} +20 -15
  48. package/src/panels/{properties-panel.js → properties-panel.ts} +212 -246
  49. package/src/panels/{pseudo-preview.js → pseudo-preview.ts} +9 -8
  50. package/src/panels/{quick-search.js → quick-search.ts} +16 -17
  51. package/src/panels/{right-panel.js → right-panel.ts} +41 -59
  52. package/src/panels/{shared.js → shared.ts} +7 -5
  53. package/src/panels/{signals-panel.js → signals-panel.ts} +322 -362
  54. package/src/panels/{statusbar.js → statusbar.ts} +14 -14
  55. package/src/panels/{style-inputs.js → style-inputs.ts} +66 -48
  56. package/src/panels/{style-panel.js → style-panel.ts} +235 -290
  57. package/src/panels/{style-utils.js → style-utils.ts} +32 -31
  58. package/src/panels/{stylebook-layers-panel.js → stylebook-layers-panel.ts} +22 -14
  59. package/src/panels/{stylebook-panel.js → stylebook-panel.ts} +127 -140
  60. package/src/panels/{tab-strip.js → tab-strip.ts} +12 -14
  61. package/src/panels/{toolbar.js → toolbar.ts} +68 -70
  62. package/src/panels/{welcome-screen.js → welcome-screen.ts} +14 -16
  63. package/src/{platform.js → platform.ts} +5 -3
  64. package/src/platforms/{devserver.js → devserver.ts} +53 -44
  65. package/src/{recent-projects.js → recent-projects.ts} +17 -12
  66. package/src/{resize-edges.js → resize-edges.ts} +18 -13
  67. package/src/services/{cem-export.js → cem-export.ts} +14 -7
  68. package/src/services/{code-services.js → code-services.ts} +29 -20
  69. package/src/services/{monaco-setup.js → monaco-setup.ts} +2 -3
  70. package/src/settings/{content-types-editor.js → content-types-editor.ts} +88 -67
  71. package/src/settings/{css-vars-editor.js → css-vars-editor.ts} +78 -51
  72. package/src/settings/{defs-editor.js → defs-editor.ts} +70 -56
  73. package/src/settings/{general-settings.js → general-settings.ts} +29 -28
  74. package/src/settings/{head-editor.js → head-editor.ts} +37 -35
  75. package/src/settings/{schema-field-ui.js → schema-field-ui.ts} +86 -76
  76. package/src/settings/{settings-modal.js → settings-modal.ts} +14 -16
  77. package/src/{site-context.js → site-context.ts} +35 -32
  78. package/src/{state.js → state.ts} +95 -78
  79. package/src/{store.js → store.ts} +60 -63
  80. package/src/{studio.js → studio.ts} +117 -119
  81. package/src/tabs/tab.ts +196 -0
  82. package/src/tabs/{transact.js → transact.ts} +107 -60
  83. package/src/types.ts +185 -0
  84. package/src/ui/{button-group.js → button-group.ts} +21 -21
  85. package/src/ui/{color-selector.js → color-selector.ts} +44 -37
  86. package/src/ui/{expression-editor.js → expression-editor.ts} +65 -40
  87. package/src/ui/{field-row.js → field-row.ts} +19 -2
  88. package/src/ui/{icons.js → icons.ts} +2 -2
  89. package/src/ui/{layers.js → layers.ts} +33 -24
  90. package/src/ui/{media-picker.js → media-picker.ts} +13 -9
  91. package/src/ui/{panel-resize.js → panel-resize.ts} +9 -4
  92. package/src/ui/{spectrum.js → spectrum.ts} +4 -4
  93. package/src/ui/{unit-selector.js → unit-selector.ts} +16 -19
  94. package/src/ui/{value-selector.js → value-selector.ts} +28 -28
  95. package/src/ui/{widgets.js → widgets.ts} +62 -15
  96. package/src/utils/{canvas-media.js → canvas-media.ts} +29 -14
  97. package/src/utils/{edit-display.js → edit-display.ts} +23 -20
  98. package/src/utils/{google-fonts.js → google-fonts.ts} +14 -13
  99. package/src/utils/{inherited-style.js → inherited-style.ts} +15 -10
  100. package/src/utils/{studio-utils.js → studio-utils.ts} +38 -26
  101. package/src/{view.js → view.ts} +53 -55
  102. package/src/workspace/{workspace.js → workspace.ts} +44 -33
  103. package/src/panels/dnd.js +0 -426
  104. package/src/tabs/tab.js +0 -192
  105. /package/src/{reactivity.js → reactivity.ts} +0 -0
@@ -1,3 +1,4 @@
1
+ /// <reference lib="dom" />
1
2
  /**
2
3
  * Style panel — CSS property editor with media breakpoint tabs, selector dropdown, section
3
4
  * accordion, shorthand expand/compress, and filter.
@@ -6,14 +7,9 @@
6
7
  import { html, nothing } from "lit-html";
7
8
  import { live } from "lit-html/directives/live.js";
8
9
  import { ifDefined } from "lit-html/directives/if-defined.js";
9
- import {
10
- getNodeAtPath,
11
- COMMON_SELECTORS,
12
- isNestedSelector,
13
- debouncedStyleCommit,
14
- } from "../store.js";
15
- import { activeTab } from "../workspace/workspace.js";
16
- import { selectStylebookTag } from "./stylebook-panel.js";
10
+ import { getNodeAtPath, COMMON_SELECTORS, isNestedSelector, debouncedStyleCommit } from "../store";
11
+ import { activeTab } from "../workspace/workspace";
12
+ import { selectStylebookTag } from "./stylebook-panel";
17
13
  import {
18
14
  transactDoc,
19
15
  mutateUpdateStyle,
@@ -22,13 +18,13 @@ import {
22
18
  mutateUpdateMediaNestedStyle,
23
19
  mutateUpdateNestedStylePath,
24
20
  mutateUpdateMediaNestedStylePath,
25
- } from "../tabs/transact.js";
26
- import { inferInputType, propLabel } from "../utils/studio-utils.js";
27
- import { renderFieldRow } from "../ui/field-row.js";
28
- import { parseMediaEntries } from "../utils/canvas-media.js";
29
- import { getEffectiveMedia, getEffectiveStyle } from "../site-context.js";
30
- import { computeInheritedStyle } from "../utils/inherited-style.js";
31
- import { mediaDisplayName } from "./shared.js";
21
+ } from "../tabs/transact";
22
+ import { inferInputType, propLabel } from "../utils/studio-utils";
23
+ import { renderFieldRow } from "../ui/field-row";
24
+ import { parseMediaEntries } from "../utils/canvas-media";
25
+ import { getEffectiveMedia, getEffectiveStyle } from "../site-context";
26
+ import { computeInheritedStyle } from "../utils/inherited-style";
27
+ import { mediaDisplayName } from "./shared";
32
28
  import {
33
29
  cssMeta,
34
30
  getCssInitialMap,
@@ -39,18 +35,25 @@ import {
39
35
  compressShorthand,
40
36
  expandBorderSide,
41
37
  compressBorderSide,
42
- } from "./style-utils.js";
43
- import { widgetForType } from "./style-inputs.js";
38
+ } from "./style-utils";
39
+ import { widgetForType } from "./style-inputs";
44
40
 
45
- /**
46
- * @typedef {{ name: string; entry: Record<string, unknown> }} CssLonghand
47
- *
48
- * @typedef {Record<string, unknown>} CssPropertyEntry
49
- *
50
- * @typedef {import("../tabs/tab.js").Tab} Tab
51
- *
52
- * @typedef {import("../state.js").JxPath} JxPath
53
- */
41
+ import type { Tab } from "../tabs/tab";
42
+ import type { JxPath } from "../state";
43
+ import type { JxMutableNode } from "@jxsuite/schema/types";
44
+
45
+ interface CssLonghand {
46
+ name: string;
47
+ entry: Record<string, unknown>;
48
+ }
49
+
50
+ type CssPropertyEntry = Record<string, unknown>;
51
+
52
+ type StyleMutateFn = (
53
+ t: Tab,
54
+ prop: string,
55
+ val: string | Record<string, unknown> | undefined,
56
+ ) => void;
54
57
 
55
58
  /**
56
59
  * Check if a selector is a stylebook tag path (e.g., "table" or "table th"). Tag paths don't start
@@ -59,7 +62,7 @@ import { widgetForType } from "./style-inputs.js";
59
62
  * @param {string} selector
60
63
  * @returns {boolean}
61
64
  */
62
- function isTagPath(selector) {
65
+ function isTagPath(selector: string) {
63
66
  return /^[a-z]/.test(selector);
64
67
  }
65
68
 
@@ -70,39 +73,39 @@ function isTagPath(selector) {
70
73
  * @param {string} tagPath
71
74
  * @returns {Record<string, unknown>}
72
75
  */
73
- function resolveNestedTagStyle(style, tagPath) {
76
+ function resolveNestedTagStyle(style: Record<string, unknown>, tagPath: string) {
74
77
  const parts = tagPath.split(" ");
75
- /** @type {unknown} */
76
- let obj = style;
78
+ let obj: unknown = style;
77
79
  for (const part of parts) {
78
80
  if (!obj || typeof obj !== "object") return {};
79
- obj = /** @type {Record<string, unknown>} */ (obj)[part];
81
+ obj = (obj as Record<string, unknown>)[part];
80
82
  }
81
- return obj && typeof obj === "object" ? /** @type {Record<string, unknown>} */ (obj) : {};
83
+ return obj && typeof obj === "object" ? (obj as Record<string, unknown>) : {};
82
84
  }
83
85
 
84
86
  // ─── Row renderers ──────────────────────────────────────────────────────────
85
87
 
86
88
  function renderStyleRow(
87
- /** @type {CssPropertyEntry} */ entry,
88
- /** @type {string} */ prop,
89
- /** @type {string} */ value,
90
- /** @type {(v: string | undefined) => void} */ onCommit,
91
- /** @type {() => void} */ onDelete,
92
- /** @type {boolean} */ isWarning,
93
- /** @type {boolean} */ gridMode,
94
- /** @type {string | undefined} */ inheritedValue,
89
+ entry: CssPropertyEntry,
90
+ prop: string,
91
+ value: string,
92
+ onCommit: (v: string | undefined) => void,
93
+ onDelete: () => void,
94
+ isWarning: boolean,
95
+ gridMode: boolean,
96
+ inheritedValue: string | undefined,
95
97
  ) {
96
98
  const type = inferInputType(entry);
97
99
  const hasVal = value !== undefined && value !== "";
98
100
  const placeholder = !hasVal && inheritedValue ? String(inheritedValue) : "";
101
+ const spanVal = gridMode && (entry as Record<string, unknown>).$span === 2 ? 2 : undefined;
99
102
  return renderFieldRow({
100
103
  prop,
101
104
  label: propLabel(entry, prop),
102
105
  hasValue: hasVal,
103
106
  onClear: onDelete,
104
107
  widget: widgetForType(type, entry, prop, value, onCommit, { placeholder }),
105
- span: gridMode && /** @type {Record<string, unknown>} */ (entry).$span === 2 ? 2 : undefined,
108
+ ...(spanVal != null && { span: spanVal }),
106
109
  warning: isWarning,
107
110
  });
108
111
  }
@@ -115,17 +118,21 @@ function renderStyleRow(
115
118
  * @param {() => void} _deleteFn
116
119
  * @param {Record<string, string | number>} inherited
117
120
  */
118
- function renderShorthandRow(shortProp, entry, style, mutateFn, _deleteFn, inherited = {}) {
119
- const tab = activeTab.value;
120
- const longhands = /** @type {CssLonghand[]} */ (getLonghands(shortProp));
121
+ function renderShorthandRow(
122
+ shortProp: string,
123
+ entry: CssPropertyEntry,
124
+ style: Record<string, unknown>,
125
+ mutateFn: StyleMutateFn,
126
+ _deleteFn: () => void,
127
+ inherited: Record<string, string | number> = {},
128
+ ) {
129
+ const tab = activeTab.value!;
130
+ const longhands = getLonghands(shortProp) as CssLonghand[];
121
131
  const shortVal = style[shortProp];
122
- const hasLonghands = longhands.some(
123
- (/** @type {CssLonghand} */ l) => style[l.name] !== undefined,
124
- );
132
+ const hasLonghands = longhands.some((l: CssLonghand) => style[l.name] !== undefined);
125
133
  const isExpanded = tab.session.ui.styleShorthands[shortProp] ?? hasLonghands;
126
134
  const hasAnyVal =
127
- shortVal !== undefined ||
128
- longhands.some((/** @type {CssLonghand} */ l) => style[l.name] !== undefined);
135
+ shortVal !== undefined || longhands.some((l: CssLonghand) => style[l.name] !== undefined);
129
136
 
130
137
  return html`
131
138
  <div class="style-row" data-prop=${shortProp}>
@@ -134,7 +141,7 @@ function renderShorthandRow(shortProp, entry, style, mutateFn, _deleteFn, inheri
134
141
  ? html`<span
135
142
  class="set-dot"
136
143
  title="Clear ${shortProp}"
137
- @click=${(/** @type {Event} */ e) => {
144
+ @click=${(e: Event) => {
138
145
  e.stopPropagation();
139
146
  transactDoc(activeTab.value, (t) => {
140
147
  if (shortVal !== undefined) mutateFn(t, shortProp, undefined);
@@ -152,30 +159,28 @@ function renderShorthandRow(shortProp, entry, style, mutateFn, _deleteFn, inheri
152
159
  size="s"
153
160
  .value=${live(shortVal || "")}
154
161
  placeholder=${!shortVal && hasLonghands
155
- ? longhands.map((/** @type {CssLonghand} */ l) => style[l.name] || "0").join(" ")
162
+ ? longhands.map((l: CssLonghand) => style[l.name] || "0").join(" ")
156
163
  : !shortVal && inherited[shortProp]
157
164
  ? inherited[shortProp]
158
- : !shortVal && longhands.some((/** @type {CssLonghand} */ l) => inherited[l.name])
159
- ? longhands
160
- .map((/** @type {CssLonghand} */ l) => inherited[l.name] || "0")
161
- .join(" ")
165
+ : !shortVal && longhands.some((l: CssLonghand) => inherited[l.name])
166
+ ? longhands.map((l: CssLonghand) => inherited[l.name] || "0").join(" ")
162
167
  : ""}
163
- @input=${debouncedStyleCommit(`short:${shortProp}`, 400, (/** @type {Event} */ e) => {
168
+ @input=${debouncedStyleCommit(`short:${shortProp}`, 400, (e: Event) => {
164
169
  transactDoc(activeTab.value, (t) => {
165
170
  for (const l of longhands) {
166
171
  if (style[l.name] !== undefined) mutateFn(t, l.name, undefined);
167
172
  }
168
- mutateFn(t, shortProp, /** @type {HTMLInputElement} */ (e.target).value || undefined);
173
+ mutateFn(t, shortProp, (e.target as HTMLInputElement).value || undefined);
169
174
  });
170
175
  })}
171
176
  ></sp-textfield>
172
177
  <sp-action-button
173
178
  size="xs"
174
179
  quiet
175
- @click=${(/** @type {Event} */ e) => {
180
+ @click=${(e: Event) => {
176
181
  e.stopPropagation();
177
- activeTab.value.session.ui.styleShorthands = {
178
- ...activeTab.value.session.ui.styleShorthands,
182
+ activeTab.value!.session.ui.styleShorthands = {
183
+ ...activeTab.value!.session.ui.styleShorthands,
179
184
  [shortProp]: !isExpanded,
180
185
  };
181
186
  }}
@@ -188,71 +193,64 @@ function renderShorthandRow(shortProp, entry, style, mutateFn, _deleteFn, inheri
188
193
  </div>
189
194
  ${isExpanded
190
195
  ? (() => {
191
- const isBorderSide = /** @type {Record<string, unknown>} */ (entry).$shorthandType ===
192
- "border-side";
196
+ const isBorderSide = (entry as Record<string, unknown>).$shorthandType === "border-side";
193
197
  const expanded = shortVal
194
198
  ? isBorderSide
195
- ? expandBorderSide(/** @type {string} */ (shortVal))
196
- : expandShorthand(/** @type {string} */ (shortVal), longhands.length)
199
+ ? expandBorderSide(shortVal as string)
200
+ : expandShorthand(shortVal as string, longhands.length)
197
201
  : null;
198
202
  const compress = isBorderSide ? compressBorderSide : compressShorthand;
199
203
  const emptyVal = isBorderSide ? "" : "0";
200
- return longhands.map(
201
- (/** @type {CssLonghand} */ { name, entry: lEntry }, /** @type {number} */ idx) => {
202
- const lVal = style[name] ?? (expanded ? expanded[idx] : "");
203
- return html`
204
- <div class="style-row style-row--child" data-prop=${name}>
205
- <div class="style-row-label">
206
- ${lVal !== undefined && lVal !== ""
207
- ? html`<span
208
- class="set-dot"
209
- title="Clear ${name}"
210
- @click=${(/** @type {Event} */ e) => {
211
- e.stopPropagation();
212
- const vals = longhands.map(
213
- (/** @type {CssLonghand} */ l, /** @type {number} */ i) =>
214
- i === idx
215
- ? emptyVal
216
- : (style[l.name] ?? (expanded ? expanded[i] : emptyVal)),
217
- );
218
- transactDoc(activeTab.value, (t) => {
219
- for (const l of longhands) {
220
- if (style[l.name] !== undefined) mutateFn(t, l.name, undefined);
221
- }
222
- mutateFn(t, shortProp, compress(/** @type {string[]} */ (vals)));
223
- });
224
- }}
225
- ></span>`
226
- : nothing}
227
- <sp-field-label size="s" title=${name}
228
- >${propLabel(lEntry, name)}</sp-field-label
229
- >
230
- </div>
231
- ${widgetForType(
232
- inferInputType(lEntry),
233
- lEntry,
234
- name,
235
- lVal,
236
- (/** @type {string} */ newVal) => {
237
- const vals = longhands.map(
238
- (/** @type {CssLonghand} */ l, /** @type {number} */ i) =>
239
- i === idx
240
- ? newVal || emptyVal
241
- : (style[l.name] ?? (expanded ? expanded[i] : emptyVal)),
242
- );
243
- transactDoc(activeTab.value, (t) => {
244
- for (const l of longhands) {
245
- if (style[l.name] !== undefined) mutateFn(t, l.name, undefined);
246
- }
247
- mutateFn(t, shortProp, compress(/** @type {string[]} */ (vals)));
248
- });
249
- },
250
- { placeholder: !lVal && inherited[name] ? String(inherited[name]) : "" },
251
- )}
204
+ return longhands.map(({ name, entry: lEntry }: CssLonghand, idx: number) => {
205
+ const lVal = style[name] ?? (expanded ? expanded[idx] : "");
206
+ return html`
207
+ <div class="style-row style-row--child" data-prop=${name}>
208
+ <div class="style-row-label">
209
+ ${lVal !== undefined && lVal !== ""
210
+ ? html`<span
211
+ class="set-dot"
212
+ title="Clear ${name}"
213
+ @click=${(e: Event) => {
214
+ e.stopPropagation();
215
+ const vals = longhands.map((l: CssLonghand, i: number) =>
216
+ i === idx
217
+ ? emptyVal
218
+ : (style[l.name] ?? (expanded ? expanded[i] : emptyVal)),
219
+ );
220
+ transactDoc(activeTab.value, (t) => {
221
+ for (const l of longhands) {
222
+ if (style[l.name] !== undefined) mutateFn(t, l.name, undefined);
223
+ }
224
+ mutateFn(t, shortProp, compress(vals as string[]));
225
+ });
226
+ }}
227
+ ></span>`
228
+ : nothing}
229
+ <sp-field-label size="s" title=${name}>${propLabel(lEntry, name)}</sp-field-label>
252
230
  </div>
253
- `;
254
- },
255
- );
231
+ ${widgetForType(
232
+ inferInputType(lEntry),
233
+ lEntry,
234
+ name,
235
+ lVal,
236
+ (newVal: string) => {
237
+ const vals = longhands.map((l: CssLonghand, i: number) =>
238
+ i === idx
239
+ ? newVal || emptyVal
240
+ : (style[l.name] ?? (expanded ? expanded[i] : emptyVal)),
241
+ );
242
+ transactDoc(activeTab.value, (t) => {
243
+ for (const l of longhands) {
244
+ if (style[l.name] !== undefined) mutateFn(t, l.name, undefined);
245
+ }
246
+ mutateFn(t, shortProp, compress(vals as string[]));
247
+ });
248
+ },
249
+ { placeholder: !lVal && inherited[name] ? String(inherited[name]) : "" },
250
+ )}
251
+ </div>
252
+ `;
253
+ });
256
254
  })()
257
255
  : nothing}
258
256
  `;
@@ -266,9 +264,14 @@ function renderShorthandRow(shortProp, entry, style, mutateFn, _deleteFn, inheri
266
264
  * @param {string | null} activeSelector
267
265
  * @param {Record<string, unknown>} [effectiveStyle]
268
266
  */
269
- function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveStyle) {
270
- const tab = activeTab.value;
271
- const sel = /** @type {JxPath} */ (tab.session.selection);
267
+ function styleSidebarTemplate(
268
+ node: JxMutableNode,
269
+ activeMediaTab: string | null,
270
+ activeSelector: string | null,
271
+ effectiveStyle?: Record<string, unknown>,
272
+ ) {
273
+ const tab = activeTab.value!;
274
+ const sel = tab.session.selection as JxPath;
272
275
  const style = effectiveStyle || node.style || {};
273
276
  const { sizeBreakpoints } = parseMediaEntries(getEffectiveMedia(tab.doc.document.$media));
274
277
  const mediaNames = sizeBreakpoints.map((bp) => bp.name);
@@ -281,8 +284,8 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
281
284
  <sp-tabs
282
285
  size="s"
283
286
  selected=${mediaTab || "base"}
284
- @change=${(/** @type {Event} */ e) => {
285
- const val = /** @type {HTMLElement & { selected: string }} */ (e.target).selected;
287
+ @change=${(e: Event) => {
288
+ const val = (e.target as HTMLElement & { selected: string }).selected;
286
289
  const newMedia = val === "base" ? null : val;
287
290
  if (newMedia !== tab.session.ui.activeMedia) {
288
291
  tab.session.ui.activeMedia = newMedia;
@@ -298,9 +301,7 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
298
301
  : nothing;
299
302
 
300
303
  // ── Selector dropdown ──────────────────────────────────────────────────────
301
- const contextStyle = mediaTab
302
- ? /** @type {Record<string, unknown>} */ (style[`@${mediaTab}`]) || {}
303
- : style;
304
+ const contextStyle = mediaTab ? (style[`@${mediaTab}`] as Record<string, unknown>) || {} : style;
304
305
  const existingSelectors = Object.keys(contextStyle).filter(isNestedSelector);
305
306
  const existingSet = new Set(existingSelectors);
306
307
  const commonSet = new Set(COMMON_SELECTORS);
@@ -316,15 +317,14 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
316
317
  class="selector-select"
317
318
  quiet
318
319
  .value=${live(_selectorVal)}
319
- @change=${(/** @type {Event} */ e) => {
320
- const val = /** @type {HTMLElement & { value: string }} */ (e.target).value;
320
+ @change=${(e: Event) => {
321
+ const val = (e.target as HTMLElement & { value: string }).value;
321
322
  if (val === "__add_custom__") {
322
323
  requestAnimationFrame(() => {
323
- /** @type {HTMLElement & { value: string }} */ (e.target).value =
324
- activeSelector || "__base__";
324
+ (e.target as HTMLElement & { value: string }).value = activeSelector || "__base__";
325
325
  });
326
- const picker = /** @type {HTMLElement} */ (e.target);
327
- const bar = /** @type {HTMLElement} */ (picker.closest(".style-toolbar"));
326
+ const picker = e.target as HTMLElement;
327
+ const bar = picker.closest(".style-toolbar") as HTMLElement;
328
328
  picker.style.display = "none";
329
329
  const inp = document.createElement("input");
330
330
  inp.type = "text";
@@ -333,14 +333,14 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
333
333
  bar.appendChild(inp);
334
334
  inp.focus();
335
335
  let done = false;
336
- const finish = (/** @type {boolean} */ accept) => {
336
+ const finish = (accept: boolean) => {
337
337
  if (done) return;
338
338
  done = true;
339
339
  const v = inp.value.trim();
340
340
  inp.remove();
341
341
  picker.style.display = "";
342
342
  if (accept && v && isNestedSelector(v)) {
343
- activeTab.value.session.ui.activeSelector = v;
343
+ activeTab.value!.session.ui.activeSelector = v;
344
344
  }
345
345
  };
346
346
  inp.addEventListener("keydown", (ev) => {
@@ -351,7 +351,7 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
351
351
  return;
352
352
  }
353
353
  const newSelector = val === "__base__" ? null : val;
354
- activeTab.value.session.ui.activeSelector = newSelector;
354
+ activeTab.value!.session.ui.activeSelector = newSelector;
355
355
  }}
356
356
  >
357
357
  <sp-menu-item value="__base__">(base)</sp-menu-item>
@@ -388,8 +388,8 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
388
388
  class="style-filter-input"
389
389
  placeholder="Filter properties…"
390
390
  .value=${live(tab.session.ui.styleFilter || "")}
391
- @input=${(/** @type {Event} */ e) => {
392
- activeTab.value.session.ui.styleFilter = /** @type {HTMLInputElement} */ (e.target).value;
391
+ @input=${(e: Event) => {
392
+ activeTab.value!.session.ui.styleFilter = (e.target as HTMLInputElement).value;
393
393
  }}
394
394
  ></sp-textfield>
395
395
  <sp-action-button
@@ -397,8 +397,8 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
397
397
  class="style-filter-toggle"
398
398
  ?selected=${tab.session.ui.styleFilterActive}
399
399
  @click=${() => {
400
- activeTab.value.session.ui.styleFilterActive =
401
- !activeTab.value.session.ui.styleFilterActive;
400
+ activeTab.value!.session.ui.styleFilterActive =
401
+ !activeTab.value!.session.ui.styleFilterActive;
402
402
  }}
403
403
  >
404
404
  Active
@@ -407,120 +407,78 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
407
407
  `;
408
408
 
409
409
  // ── Determine the active style object ──────────────────────────────────────
410
- /** @type {Record<string, unknown>} */
411
- let activeStyle;
412
- /** @type {(prop: string, val: string | Record<string, unknown> | undefined) => void} */
413
- let commitStyle;
414
- /** @type {(t: Tab, prop: string, val: string | Record<string, unknown> | undefined) => void} */
415
- let commitMutate;
410
+ let activeStyle: Record<string, unknown>;
411
+ let commitStyle: (prop: string, val: string | Record<string, unknown> | undefined) => void;
412
+ let commitMutate: StyleMutateFn;
416
413
  if (activeSelector && isTagPath(activeSelector) && mediaTab && mediaNames.length > 0) {
417
- const mediaObj = /** @type {Record<string, unknown>} */ (style[`@${mediaTab}`]) || {};
414
+ const mediaObj = (style[`@${mediaTab}`] as Record<string, unknown>) || {};
418
415
  activeStyle = resolveNestedTagStyle(mediaObj, activeSelector);
419
416
  const stylePath = activeSelector.split(" ");
420
- commitMutate = (
421
- /** @type {Tab} */ t,
422
- /** @type {string} */ prop,
423
- /** @type {string | Record<string, unknown> | undefined} */ val,
424
- ) =>
417
+ commitMutate = (t: Tab, prop: string, val: string | Record<string, unknown> | undefined) =>
425
418
  mutateUpdateMediaNestedStylePath(
426
419
  t,
427
420
  sel,
428
421
  mediaTab,
429
422
  stylePath,
430
423
  prop,
431
- /** @type {string | undefined} */ (val),
424
+ val as string | undefined,
432
425
  );
433
- commitStyle = (
434
- /** @type {string} */ prop,
435
- /** @type {string | Record<string, unknown> | undefined} */ val,
436
- ) => transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
426
+ commitStyle = (prop: string, val: string | Record<string, unknown> | undefined) =>
427
+ transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
437
428
  } else if (activeSelector && isTagPath(activeSelector)) {
438
429
  activeStyle = resolveNestedTagStyle(style, activeSelector);
439
430
  const stylePath = activeSelector.split(" ");
440
- commitMutate = (
441
- /** @type {Tab} */ t,
442
- /** @type {string} */ prop,
443
- /** @type {string | Record<string, unknown> | undefined} */ val,
444
- ) =>
445
- mutateUpdateNestedStylePath(t, sel, stylePath, prop, /** @type {string | undefined} */ (val));
446
- commitStyle = (
447
- /** @type {string} */ prop,
448
- /** @type {string | Record<string, unknown> | undefined} */ val,
449
- ) => transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
431
+ commitMutate = (t: Tab, prop: string, val: string | Record<string, unknown> | undefined) =>
432
+ mutateUpdateNestedStylePath(t, sel, stylePath, prop, val as string | undefined);
433
+ commitStyle = (prop: string, val: string | Record<string, unknown> | undefined) =>
434
+ transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
450
435
  } else if (activeSelector && mediaTab && mediaNames.length > 0) {
451
- activeStyle = /** @type {Record<string, unknown>} */ (
452
- /** @type {Record<string, unknown>} */ (style[`@${mediaTab}`] || {})[activeSelector]
453
- ) || {};
454
- commitMutate = (
455
- /** @type {Tab} */ t,
456
- /** @type {string} */ prop,
457
- /** @type {string | Record<string, unknown> | undefined} */ val,
458
- ) =>
436
+ const mediaObj = (style[`@${mediaTab}`] || {}) as Record<string, unknown>;
437
+ activeStyle = (mediaObj[activeSelector] as Record<string, unknown>) || {};
438
+ commitMutate = (t: Tab, prop: string, val: string | Record<string, unknown> | undefined) =>
459
439
  mutateUpdateMediaNestedStyle(
460
440
  t,
461
441
  sel,
462
442
  mediaTab,
463
443
  activeSelector,
464
444
  prop,
465
- /** @type {string | undefined} */ (val),
445
+ val as string | undefined,
466
446
  );
467
- commitStyle = (
468
- /** @type {string} */ prop,
469
- /** @type {string | Record<string, unknown> | undefined} */ val,
470
- ) => transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
447
+ commitStyle = (prop: string, val: string | Record<string, unknown> | undefined) =>
448
+ transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
471
449
  } else if (activeSelector) {
472
- activeStyle = /** @type {Record<string, unknown>} */ (style[activeSelector]) || {};
473
- commitMutate = (
474
- /** @type {Tab} */ t,
475
- /** @type {string} */ prop,
476
- /** @type {string | Record<string, unknown> | undefined} */ val,
477
- ) =>
478
- mutateUpdateNestedStyle(
479
- t,
480
- sel,
481
- activeSelector,
482
- prop,
483
- /** @type {string | undefined} */ (val),
484
- );
485
- commitStyle = (
486
- /** @type {string} */ prop,
487
- /** @type {string | Record<string, unknown> | undefined} */ val,
488
- ) => transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
450
+ activeStyle = (style[activeSelector] as Record<string, unknown>) || {};
451
+ commitMutate = (t: Tab, prop: string, val: string | Record<string, unknown> | undefined) =>
452
+ mutateUpdateNestedStyle(t, sel, activeSelector, prop, val as string | undefined);
453
+ commitStyle = (prop: string, val: string | Record<string, unknown> | undefined) =>
454
+ transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
489
455
  } else if (mediaTab !== null && mediaNames.length > 0) {
490
456
  activeStyle = {};
491
- for (const [p, v] of Object.entries(
492
- /** @type {Record<string, unknown>} */ (style[`@${mediaTab}`]) || {},
493
- )) {
457
+ for (const [p, v] of Object.entries((style[`@${mediaTab}`] as Record<string, unknown>) || {})) {
494
458
  if (typeof v !== "object") activeStyle[p] = v;
495
459
  }
496
- commitMutate = (
497
- /** @type {Tab} */ t,
498
- /** @type {string} */ prop,
499
- /** @type {string | Record<string, unknown> | undefined} */ val,
500
- ) => mutateUpdateMediaStyle(t, sel, mediaTab, prop, /** @type {string | undefined} */ (val));
501
- commitStyle = (
502
- /** @type {string} */ prop,
503
- /** @type {string | Record<string, unknown> | undefined} */ val,
504
- ) => transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
460
+ commitMutate = (t: Tab, prop: string, val: string | Record<string, unknown> | undefined) =>
461
+ mutateUpdateMediaStyle(t, sel, mediaTab, prop, val as string | undefined);
462
+ commitStyle = (prop: string, val: string | Record<string, unknown> | undefined) =>
463
+ transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
505
464
  } else {
506
465
  activeStyle = {};
507
466
  for (const [p, v] of Object.entries(style)) {
508
467
  if (typeof v !== "object") activeStyle[p] = v;
509
468
  }
510
- commitMutate = (
511
- /** @type {Tab} */ t,
512
- /** @type {string} */ prop,
513
- /** @type {string | Record<string, unknown> | undefined} */ val,
514
- ) => mutateUpdateStyle(t, sel, prop, /** @type {string | undefined} */ (val));
515
- commitStyle = (
516
- /** @type {string} */ prop,
517
- /** @type {string | Record<string, unknown> | undefined} */ val,
518
- ) => transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
469
+ commitMutate = (t: Tab, prop: string, val: string | Record<string, unknown> | undefined) =>
470
+ mutateUpdateStyle(t, sel, prop, val as string | undefined);
471
+ commitStyle = (prop: string, val: string | Record<string, unknown> | undefined) =>
472
+ transactDoc(activeTab.value, (t) => commitMutate(t, prop, val));
519
473
  }
520
474
 
521
475
  // ── Compute inherited style from higher breakpoints ──────────────────────
522
- /** @type {Record<string, string | number>} */
523
- const inheritedStyle = computeInheritedStyle(style, mediaNames, mediaTab, activeSelector);
476
+ const inheritedStyle: Record<string, string | number> = computeInheritedStyle(
477
+ style,
478
+ mediaNames,
479
+ mediaTab,
480
+ activeSelector,
481
+ );
524
482
 
525
483
  // Auto-open sections that have properties
526
484
  const newSections = autoOpenSections({ style: activeStyle }, tab.session.ui.styleSections);
@@ -529,40 +487,35 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
529
487
  }
530
488
 
531
489
  // Partition properties into sections
532
- const sectionProps =
533
- /** @type {Record<string, { prop: string; entry: CssPropertyEntry }[]>} */ ({});
490
+ const sectionProps: Record<string, { prop: string; entry: CssPropertyEntry }[]> = {};
534
491
  for (const sec of cssMeta.$sections) sectionProps[sec.key] = [];
535
492
 
536
- for (const [prop, entry] of /** @type {[string, CssPropertyEntry][]} */ (
537
- Object.entries(cssMeta.$defs)
538
- )) {
539
- if (typeof (/** @type {Record<string, unknown>} */ (entry).$shorthand) === "string") continue;
540
- const sec = /** @type {string} */ (/** @type {Record<string, unknown>} */ (entry).$section) ||
541
- "other";
493
+ for (const [prop, entry] of Object.entries(cssMeta.$defs) as [string, CssPropertyEntry][]) {
494
+ if (typeof (entry as Record<string, unknown>).$shorthand === "string") continue;
495
+ const sec = ((entry as Record<string, unknown>).$section as string) || "other";
542
496
  sectionProps[sec].push({ prop, entry });
543
497
  }
544
498
  for (const sec of cssMeta.$sections) {
545
499
  sectionProps[sec.key].sort(
546
500
  (
547
- /** @type {{ prop: string; entry: CssPropertyEntry }} */ a,
548
- /** @type {{ prop: string; entry: CssPropertyEntry }} */ b,
501
+ a: { prop: string; entry: CssPropertyEntry },
502
+ b: { prop: string; entry: CssPropertyEntry },
549
503
  ) =>
550
- /** @type {number} */ (/** @type {Record<string, unknown>} */ (a.entry).$order) -
551
- /** @type {number} */ (/** @type {Record<string, unknown>} */ (b.entry).$order),
504
+ ((a.entry as Record<string, unknown>).$order as number) -
505
+ ((b.entry as Record<string, unknown>).$order as number),
552
506
  );
553
507
  }
554
508
 
555
509
  const otherProps = [];
556
510
  for (const prop of Object.keys(activeStyle)) {
557
- if (!(/** @type {Record<string, unknown>} */ (cssMeta.$defs)[prop])) {
511
+ if (!(cssMeta.$defs as Record<string, unknown>)[prop]) {
558
512
  const val = activeStyle[prop];
559
513
  if (val !== null && typeof val === "object") continue;
560
514
  otherProps.push(prop);
561
515
  }
562
516
  }
563
517
 
564
- /** @type {string[]} */
565
- const nestedRules = [];
518
+ const nestedRules: string[] = [];
566
519
  for (const [prop, val] of Object.entries(activeStyle)) {
567
520
  if (val !== null && typeof val === "object" && !Array.isArray(val) && !prop.startsWith("@")) {
568
521
  nestedRules.push(prop);
@@ -581,11 +534,11 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
581
534
  const entries = sectionProps[sec.key];
582
535
 
583
536
  const sectionActiveProps = entries.filter(
584
- (/** @type {{ prop: string; entry: CssPropertyEntry }} */ { prop, entry }) => {
537
+ ({ prop, entry }: { prop: string; entry: CssPropertyEntry }) => {
585
538
  if (activeStyle[prop] !== undefined) return true;
586
539
  if (inferInputType(entry) === "shorthand") {
587
- return /** @type {CssLonghand[]} */ (getLonghands(prop)).some(
588
- (/** @type {CssLonghand} */ l) => activeStyle[l.name] !== undefined,
540
+ return (getLonghands(prop) as CssLonghand[]).some(
541
+ (l: CssLonghand) => activeStyle[l.name] !== undefined,
589
542
  );
590
543
  }
591
544
  return false;
@@ -599,10 +552,10 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
599
552
  <sp-accordion-item
600
553
  label=${sec.label}
601
554
  .open=${false}
602
- @sp-accordion-item-toggle=${(/** @type {Event} */ e) => {
603
- activeTab.value.session.ui.styleSections = {
604
- ...activeTab.value.session.ui.styleSections,
605
- [sec.key]: /** @type {HTMLElement & { open: boolean }} */ (e.target).open,
555
+ @sp-accordion-item-toggle=${(e: Event) => {
556
+ activeTab.value!.session.ui.styleSections = {
557
+ ...activeTab.value!.session.ui.styleSections,
558
+ [sec.key]: (e.target as HTMLElement & { open: boolean }).open,
606
559
  };
607
560
  }}
608
561
  >
@@ -613,14 +566,14 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
613
566
  <span
614
567
  class="set-dot set-dot--section"
615
568
  title="Clear all ${sec.label.toLowerCase()} properties"
616
- @click=${(/** @type {Event} */ e) => {
569
+ @click=${(e: Event) => {
617
570
  e.stopPropagation();
618
571
  e.preventDefault();
619
572
  transactDoc(activeTab.value, (t) => {
620
573
  for (const { prop, entry } of sectionActiveProps) {
621
574
  if (activeStyle[prop] !== undefined) commitMutate(t, prop, undefined);
622
575
  if (inferInputType(entry) === "shorthand") {
623
- for (const l of /** @type {CssLonghand[]} */ (getLonghands(prop))) {
576
+ for (const l of getLonghands(prop) as CssLonghand[]) {
624
577
  if (activeStyle[l.name] !== undefined)
625
578
  commitMutate(t, l.name, undefined);
626
579
  }
@@ -650,19 +603,17 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
650
603
  }
651
604
  if (filterActive) {
652
605
  if (type === "shorthand") {
653
- const longhands = /** @type {CssLonghand[]} */ (getLonghands(prop));
606
+ const longhands = getLonghands(prop) as CssLonghand[];
654
607
  const hasAnySet =
655
- hasVal ||
656
- longhands.some((/** @type {CssLonghand} */ l) => activeStyle[l.name] !== undefined);
608
+ hasVal || longhands.some((l: CssLonghand) => activeStyle[l.name] !== undefined);
657
609
  if (!hasAnySet) continue;
658
610
  } else if (!hasVal) continue;
659
611
  }
660
612
 
661
613
  if (type === "shorthand") {
662
- const longhands = /** @type {CssLonghand[]} */ (getLonghands(prop));
614
+ const longhands = getLonghands(prop) as CssLonghand[];
663
615
  const hasAny =
664
- hasVal ||
665
- longhands.some((/** @type {CssLonghand} */ l) => activeStyle[l.name] !== undefined);
616
+ hasVal || longhands.some((l: CssLonghand) => activeStyle[l.name] !== undefined);
666
617
  if (!hasAny && !condMet) continue;
667
618
  rows.push(
668
619
  renderShorthandRow(prop, entry, activeStyle, commitMutate, () => {}, inheritedStyle),
@@ -674,13 +625,12 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
674
625
  renderStyleRow(
675
626
  entry,
676
627
  prop,
677
- /** @type {string} */ (val) ?? "",
678
- (/** @type {string | undefined} */ newVal) =>
679
- commitStyle(prop, newVal || undefined),
628
+ (val as string) ?? "",
629
+ (newVal: string | undefined) => commitStyle(prop, newVal || undefined),
680
630
  () => commitStyle(prop, undefined),
681
631
  isWarning,
682
632
  sec.$layout === "grid",
683
- /** @type {string | undefined} */ (inheritedStyle[prop]),
633
+ inheritedStyle[prop] as string | undefined,
684
634
  ),
685
635
  );
686
636
  }
@@ -693,10 +643,10 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
693
643
  <sp-accordion-item
694
644
  label=${sec.label}
695
645
  .open=${isOpen}
696
- @sp-accordion-item-toggle=${(/** @type {Event} */ e) => {
697
- activeTab.value.session.ui.styleSections = {
698
- ...activeTab.value.session.ui.styleSections,
699
- [sec.key]: /** @type {HTMLElement & { open: boolean }} */ (e.target).open,
646
+ @sp-accordion-item-toggle=${(e: Event) => {
647
+ activeTab.value!.session.ui.styleSections = {
648
+ ...activeTab.value!.session.ui.styleSections,
649
+ [sec.key]: (e.target as HTMLElement & { open: boolean }).open,
700
650
  };
701
651
  }}
702
652
  >
@@ -707,14 +657,14 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
707
657
  <span
708
658
  class="set-dot set-dot--section"
709
659
  title="Clear all ${sec.label.toLowerCase()} properties"
710
- @click=${(/** @type {Event} */ e) => {
660
+ @click=${(e: Event) => {
711
661
  e.stopPropagation();
712
662
  e.preventDefault();
713
663
  transactDoc(activeTab.value, (t) => {
714
664
  for (const { prop, entry } of sectionActiveProps) {
715
665
  if (activeStyle[prop] !== undefined) commitMutate(t, prop, undefined);
716
666
  if (inferInputType(entry) === "shorthand") {
717
- for (const l of /** @type {CssLonghand[]} */ (getLonghands(prop))) {
667
+ for (const l of getLonghands(prop) as CssLonghand[]) {
718
668
  if (activeStyle[l.name] !== undefined)
719
669
  commitMutate(t, l.name, undefined);
720
670
  }
@@ -738,10 +688,10 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
738
688
  <sp-accordion-item
739
689
  label="Custom"
740
690
  .open=${customIsOpen}
741
- @sp-accordion-item-toggle=${(/** @type {Event} */ e) => {
742
- activeTab.value.session.ui.styleSections = {
743
- ...activeTab.value.session.ui.styleSections,
744
- other: /** @type {HTMLElement & { open: boolean }} */ (e.target).open,
691
+ @sp-accordion-item-toggle=${(e: Event) => {
692
+ activeTab.value!.session.ui.styleSections = {
693
+ ...activeTab.value!.session.ui.styleSections,
694
+ other: (e.target as HTMLElement & { open: boolean }).open,
745
695
  };
746
696
  }}
747
697
  >
@@ -753,8 +703,8 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
753
703
  size="s"
754
704
  class="kv-key"
755
705
  .value=${live(prop)}
756
- @change=${(/** @type {Event} */ e) => {
757
- const newProp = /** @type {HTMLInputElement} */ (e.target).value.trim();
706
+ @change=${(e: Event) => {
707
+ const newProp = (e.target as HTMLInputElement).value.trim();
758
708
  if (newProp && newProp !== prop) {
759
709
  transactDoc(activeTab.value, (t) => {
760
710
  commitMutate(t, prop, undefined);
@@ -768,8 +718,8 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
768
718
  class="kv-val"
769
719
  .value=${live(String(activeStyle[prop]))}
770
720
  placeholder=${ifDefined(cssInitialMap.get(prop))}
771
- @input=${debouncedStyleCommit(`custom:${prop}`, 400, (/** @type {Event} */ e) => {
772
- commitStyle(prop, /** @type {HTMLInputElement} */ (e.target).value);
721
+ @input=${debouncedStyleCommit(`custom:${prop}`, 400, (e: Event) => {
722
+ commitStyle(prop, (e.target as HTMLInputElement).value);
773
723
  })}
774
724
  ></sp-textfield>
775
725
  <sp-action-button size="xs" quiet @click=${() => commitStyle(prop, undefined)}>
@@ -783,14 +733,14 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
783
733
  size="s"
784
734
  placeholder="Property name…"
785
735
  style="flex:1"
786
- @keydown=${(/** @type {KeyboardEvent} */ e) => {
736
+ @keydown=${(e: KeyboardEvent) => {
787
737
  if (e.key === "Enter") {
788
738
  e.preventDefault();
789
- const prop = /** @type {HTMLInputElement} */ (e.target).value.trim();
739
+ const prop = (e.target as HTMLInputElement).value.trim();
790
740
  if (prop) {
791
741
  const initial = cssInitialMap.get(prop) || "";
792
742
  commitStyle(prop, initial || "");
793
- /** @type {HTMLInputElement} */ (e.target).value = "";
743
+ (e.target as HTMLInputElement).value = "";
794
744
  }
795
745
  }
796
746
  }}
@@ -808,10 +758,10 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
808
758
  <sp-accordion-item
809
759
  label="Relative Styling"
810
760
  .open=${nestedIsOpen}
811
- @sp-accordion-item-toggle=${(/** @type {Event} */ e) => {
812
- activeTab.value.session.ui.styleSections = {
813
- ...activeTab.value.session.ui.styleSections,
814
- nested: /** @type {HTMLElement & { open: boolean }} */ (e.target).open,
761
+ @sp-accordion-item-toggle=${(e: Event) => {
762
+ activeTab.value!.session.ui.styleSections = {
763
+ ...activeTab.value!.session.ui.styleSections,
764
+ nested: (e.target as HTMLElement & { open: boolean }).open,
815
765
  };
816
766
  }}
817
767
  >
@@ -868,7 +818,7 @@ function styleSidebarTemplate(node, activeMediaTab, activeSelector, effectiveSty
868
818
  * @param {{ getCanvasMode: () => string }} ctx
869
819
  * @returns {import("lit-html").TemplateResult}
870
820
  */
871
- export function renderStylePanelTemplate(ctx) {
821
+ export function renderStylePanelTemplate(ctx: { getCanvasMode: () => string }) {
872
822
  const tab = activeTab.value;
873
823
  if (!tab) return html`<div class="empty-state">No document loaded</div>`;
874
824
  if (ctx.getCanvasMode() === "stylebook" && tab.session.ui.stylebookSelection) {
@@ -895,20 +845,16 @@ export function renderStylePanelTemplate(ctx) {
895
845
 
896
846
  /** Single property input row (generic field row helper) */
897
847
  export function _fieldRow(
898
- /** @type {string} */ label,
899
- /** @type {string} */ type,
900
- /** @type {string} */ value,
901
- /** @type {(v: string | boolean) => void} */ onChange,
902
- /** @type {string | undefined} */ _datalistId,
848
+ label: string,
849
+ type: string,
850
+ value: string,
851
+ onChange: (v: string | boolean) => void,
852
+ _datalistId: string | undefined,
903
853
  ) {
904
- /** @type {ReturnType<typeof setTimeout> | undefined} */
905
- let debounceTimer;
906
- const onInput = (/** @type {Event} */ e) => {
854
+ let debounceTimer: ReturnType<typeof setTimeout> | undefined;
855
+ const onInput = (e: Event) => {
907
856
  clearTimeout(debounceTimer);
908
- debounceTimer = setTimeout(
909
- () => onChange(/** @type {HTMLInputElement} */ (e.target).value),
910
- 400,
911
- );
857
+ debounceTimer = setTimeout(() => onChange((e.target as HTMLInputElement).value), 400);
912
858
  };
913
859
  const inputTpl =
914
860
  type === "textarea"
@@ -921,8 +867,7 @@ export function _fieldRow(
921
867
  : type === "checkbox"
922
868
  ? html`<sp-checkbox
923
869
  ?checked=${!!value}
924
- @change=${(/** @type {Event} */ e) =>
925
- onChange(/** @type {HTMLInputElement} */ (e.target).checked)}
870
+ @change=${(e: Event) => onChange((e.target as HTMLInputElement).checked)}
926
871
  ></sp-checkbox>`
927
872
  : html`<sp-textfield
928
873
  size="s"