@jxsuite/studio 0.23.2 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/studio.js +2311 -718
  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} +109 -84
  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} +8 -6
  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.ts +298 -0
  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} +35 -23
  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/utils/edit-display.js +0 -203
  106. /package/src/{reactivity.js → reactivity.ts} +0 -0
@@ -1,3 +1,4 @@
1
+ /// <reference lib="dom" />
1
2
  /**
2
3
  * CSS Variables editor — form-based editor for managing design tokens. Colors and fonts are NOT
3
4
  * media-aware; sizes/spacing are media-aware.
@@ -5,13 +6,15 @@
5
6
 
6
7
  import { html, render as litRender, nothing } from "lit-html";
7
8
  import { ref } from "lit-html/directives/ref.js";
8
- import { projectState } from "../store.js";
9
- import { updateSiteConfig } from "../site-context.js";
10
- import { getEffectiveMedia } from "../site-context.js";
11
- import { friendlyNameToVar, varDisplayName } from "../utils/studio-utils.js";
9
+ import { projectState } from "../store";
10
+ import { updateSiteConfig } from "../site-context";
11
+ import { getEffectiveMedia } from "../site-context";
12
+ import { friendlyNameToVar, varDisplayName } from "../utils/studio-utils";
13
+
14
+ import type { JxStyle } from "@jxsuite/schema/types";
12
15
 
13
16
  /** @param {HTMLElement} container */
14
- export function renderCssVarsEditor(container) {
17
+ export function renderCssVarsEditor(container: HTMLElement) {
15
18
  const config = projectState?.projectConfig || {};
16
19
  const rootStyle = config.style || {};
17
20
  const media = getEffectiveMedia(config.$media);
@@ -24,7 +27,12 @@ export function renderCssVarsEditor(container) {
24
27
  * other: [string, string | number][];
25
28
  * }}
26
29
  */
27
- const groups = { color: [], font: [], size: [], other: [] };
30
+ const groups: {
31
+ color: [string, string | number][];
32
+ font: [string, string | number][];
33
+ size: [string, string | number][];
34
+ other: [string, string | number][];
35
+ } = { color: [], font: [], size: [], other: [] };
28
36
  for (const [k, v] of Object.entries(rootStyle)) {
29
37
  if (!k.startsWith("--")) continue;
30
38
  if (typeof v !== "string" && typeof v !== "number") continue;
@@ -41,22 +49,18 @@ export function renderCssVarsEditor(container) {
41
49
  updateSiteConfig({ style: { ...rootStyle } });
42
50
  };
43
51
 
44
- const updateVar = (/** @type {string} */ name, /** @type {string} */ val) => {
52
+ const updateVar = (name: string, val: string) => {
45
53
  rootStyle[name] = val;
46
54
  save();
47
55
  };
48
56
 
49
- const deleteVar = (/** @type {string} */ name) => {
57
+ const deleteVar = (name: string) => {
50
58
  delete rootStyle[name];
51
59
  save();
52
60
  renderCssVarsEditor(container);
53
61
  };
54
62
 
55
- const addVar = (
56
- /** @type {string} */ prefix,
57
- /** @type {string} */ friendlyName,
58
- /** @type {string} */ val,
59
- ) => {
63
+ const addVar = (prefix: string, friendlyName: string, val: string) => {
60
64
  const varName = friendlyNameToVar(friendlyName, prefix);
61
65
  if (!varName || !val) return;
62
66
  rootStyle[varName] = val;
@@ -82,11 +86,16 @@ export function renderCssVarsEditor(container) {
82
86
 
83
87
  /**
84
88
  * @param {[string, string | number][]} vars
85
- * @param {Function} updateVar
86
- * @param {Function} deleteVar
87
- * @param {Function} addVar
89
+ * @param {(name: string, val: string) => void} updateVar
90
+ * @param {(name: string) => void} deleteVar
91
+ * @param {(prefix: string, friendlyName: string, val: string) => void} addVar
88
92
  */
89
- function renderColorSection(vars, updateVar, deleteVar, addVar) {
93
+ function renderColorSection(
94
+ vars: [string, string | number][],
95
+ updateVar: (name: string, val: string) => void,
96
+ deleteVar: (name: string) => void,
97
+ addVar: (prefix: string, friendlyName: string, val: string) => void,
98
+ ) {
90
99
  return html`
91
100
  <div class="css-vars-group">
92
101
  <h4 class="css-vars-group-title">Colors</h4>
@@ -97,16 +106,14 @@ function renderColorSection(vars, updateVar, deleteVar, addVar) {
97
106
  <input
98
107
  type="color"
99
108
  .value=${val && String(val).startsWith("#") ? val : "#007acc"}
100
- @input=${(/** @type {Event} */ e) =>
101
- updateVar(name, /** @type {HTMLInputElement} */ (e.target).value)}
109
+ @input=${(e: Event) => updateVar(name, (e.target as HTMLInputElement).value)}
102
110
  />
103
111
  </div>
104
112
  <span class="css-var-name">${varDisplayName(name, "--color-")}</span>
105
113
  <sp-textfield
106
114
  size="s"
107
115
  .value=${String(val)}
108
- @change=${(/** @type {Event} */ e) =>
109
- updateVar(name, /** @type {HTMLInputElement} */ (e.target).value)}
116
+ @change=${(e: Event) => updateVar(name, (e.target as HTMLInputElement).value)}
110
117
  style="flex:1;max-width:160px"
111
118
  ></sp-textfield>
112
119
  <sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
@@ -122,11 +129,16 @@ function renderColorSection(vars, updateVar, deleteVar, addVar) {
122
129
 
123
130
  /**
124
131
  * @param {[string, string | number][]} vars
125
- * @param {Function} updateVar
126
- * @param {Function} deleteVar
127
- * @param {Function} addVar
132
+ * @param {(name: string, val: string) => void} updateVar
133
+ * @param {(name: string) => void} deleteVar
134
+ * @param {(prefix: string, friendlyName: string, val: string) => void} addVar
128
135
  */
129
- function renderFontSection(vars, updateVar, deleteVar, addVar) {
136
+ function renderFontSection(
137
+ vars: [string, string | number][],
138
+ updateVar: (name: string, val: string) => void,
139
+ deleteVar: (name: string) => void,
140
+ addVar: (prefix: string, friendlyName: string, val: string) => void,
141
+ ) {
130
142
  return html`
131
143
  <div class="css-vars-group">
132
144
  <h4 class="css-vars-group-title">Fonts</h4>
@@ -137,8 +149,7 @@ function renderFontSection(vars, updateVar, deleteVar, addVar) {
137
149
  <sp-textfield
138
150
  size="s"
139
151
  .value=${String(val)}
140
- @change=${(/** @type {Event} */ e) =>
141
- updateVar(name, /** @type {HTMLInputElement} */ (e.target).value)}
152
+ @change=${(e: Event) => updateVar(name, (e.target as HTMLInputElement).value)}
142
153
  style="flex:1"
143
154
  ></sp-textfield>
144
155
  <sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
@@ -157,13 +168,20 @@ function renderFontSection(vars, updateVar, deleteVar, addVar) {
157
168
 
158
169
  /**
159
170
  * @param {[string, string | number][]} vars
160
- * @param {Function} updateVar
161
- * @param {Function} deleteVar
162
- * @param {Function} addVar
171
+ * @param {(name: string, val: string) => void} updateVar
172
+ * @param {(name: string) => void} deleteVar
173
+ * @param {(prefix: string, friendlyName: string, val: string) => void} addVar
163
174
  * @param {JxStyle} rootStyle
164
175
  * @param {string[]} mediaNames
165
176
  */
166
- function renderSizeSection(vars, updateVar, deleteVar, addVar, rootStyle, mediaNames) {
177
+ function renderSizeSection(
178
+ vars: [string, string | number][],
179
+ updateVar: (name: string, val: string) => void,
180
+ deleteVar: (name: string) => void,
181
+ addVar: (prefix: string, friendlyName: string, val: string) => void,
182
+ rootStyle: JxStyle,
183
+ mediaNames: string[],
184
+ ) {
167
185
  return html`
168
186
  <div class="css-vars-group">
169
187
  <h4 class="css-vars-group-title">Sizes &amp; Spacing</h4>
@@ -179,8 +197,7 @@ function renderSizeSection(vars, updateVar, deleteVar, addVar, rootStyle, mediaN
179
197
  <sp-textfield
180
198
  size="s"
181
199
  .value=${String(val)}
182
- @change=${(/** @type {Event} */ e) =>
183
- updateVar(name, /** @type {HTMLInputElement} */ (e.target).value)}
200
+ @change=${(e: Event) => updateVar(name, (e.target as HTMLInputElement).value)}
184
201
  style="max-width:120px"
185
202
  ></sp-textfield>
186
203
  <sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
@@ -197,13 +214,20 @@ function renderSizeSection(vars, updateVar, deleteVar, addVar, rootStyle, mediaN
197
214
 
198
215
  /**
199
216
  * @param {[string, string | number][]} vars
200
- * @param {Function} updateVar
201
- * @param {Function} deleteVar
202
- * @param {Function} addVar
217
+ * @param {(name: string, val: string) => void} updateVar
218
+ * @param {(name: string) => void} deleteVar
219
+ * @param {(prefix: string, friendlyName: string, val: string) => void} addVar
203
220
  * @param {JxStyle} rootStyle
204
221
  * @param {string[]} mediaNames
205
222
  */
206
- function renderOtherSection(vars, updateVar, deleteVar, addVar, rootStyle, mediaNames) {
223
+ function renderOtherSection(
224
+ vars: [string, string | number][],
225
+ updateVar: (name: string, val: string) => void,
226
+ deleteVar: (name: string) => void,
227
+ addVar: (prefix: string, friendlyName: string, val: string) => void,
228
+ rootStyle: JxStyle,
229
+ mediaNames: string[],
230
+ ) {
207
231
  return html`
208
232
  <div class="css-vars-group">
209
233
  <h4 class="css-vars-group-title">Other</h4>
@@ -214,8 +238,7 @@ function renderOtherSection(vars, updateVar, deleteVar, addVar, rootStyle, media
214
238
  <sp-textfield
215
239
  size="s"
216
240
  .value=${String(val)}
217
- @change=${(/** @type {Event} */ e) =>
218
- updateVar(name, /** @type {HTMLInputElement} */ (e.target).value)}
241
+ @change=${(e: Event) => updateVar(name, (e.target as HTMLInputElement).value)}
219
242
  style="flex:1"
220
243
  ></sp-textfield>
221
244
  <sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
@@ -235,7 +258,7 @@ function renderOtherSection(vars, updateVar, deleteVar, addVar, rootStyle, media
235
258
  * @param {JxStyle} rootStyle
236
259
  * @param {string[]} mediaNames
237
260
  */
238
- function renderMediaOverrides(varName, rootStyle, mediaNames) {
261
+ function renderMediaOverrides(varName: string, rootStyle: JxStyle, mediaNames: string[]) {
239
262
  const overrides = [];
240
263
  for (const mediaName of mediaNames) {
241
264
  const mediaKey = `@${mediaName}`;
@@ -256,10 +279,11 @@ function renderMediaOverrides(varName, rootStyle, mediaNames) {
256
279
  <sp-textfield
257
280
  size="s"
258
281
  .value=${String(o.value)}
259
- @change=${(/** @type {Event} */ e) => {
282
+ @change=${(e: Event) => {
260
283
  if (!rootStyle[`@${o.mediaName}`]) rootStyle[`@${o.mediaName}`] = {};
261
- /** @type {Record<string, unknown>} */ (rootStyle[`@${o.mediaName}`])[varName] =
262
- /** @type {HTMLInputElement} */ (e.target).value;
284
+ (rootStyle[`@${o.mediaName}`] as Record<string, unknown>)[varName] = (
285
+ e.target as HTMLInputElement
286
+ ).value;
263
287
  updateSiteConfig({ style: { ...rootStyle } });
264
288
  }}
265
289
  style="max-width:120px"
@@ -275,13 +299,16 @@ function renderMediaOverrides(varName, rootStyle, mediaNames) {
275
299
  * @param {string} prefix
276
300
  * @param {string} placeholder
277
301
  * @param {string} valuePlaceholder
278
- * @param {Function} addVar
302
+ * @param {(prefix: string, friendlyName: string, val: string) => void} addVar
279
303
  */
280
- function renderAddRow(prefix, placeholder, valuePlaceholder, addVar) {
281
- /** @type {HTMLInputElement | null} */
282
- let nameEl = null;
283
- /** @type {HTMLInputElement | null} */
284
- let valEl = null;
304
+ function renderAddRow(
305
+ prefix: string,
306
+ placeholder: string,
307
+ valuePlaceholder: string,
308
+ addVar: (prefix: string, friendlyName: string, val: string) => void,
309
+ ) {
310
+ let nameEl: HTMLInputElement | null = null;
311
+ let valEl: HTMLInputElement | null = null;
285
312
 
286
313
  return html`
287
314
  <div class="css-var-add-row">
@@ -289,14 +316,14 @@ function renderAddRow(prefix, placeholder, valuePlaceholder, addVar) {
289
316
  size="s"
290
317
  placeholder=${placeholder}
291
318
  ${ref((el) => {
292
- if (el) nameEl = /** @type {HTMLInputElement} */ (el);
319
+ if (el) nameEl = el as HTMLInputElement;
293
320
  })}
294
321
  ></sp-textfield>
295
322
  <sp-textfield
296
323
  size="s"
297
324
  placeholder=${valuePlaceholder}
298
325
  ${ref((el) => {
299
- if (el) valEl = /** @type {HTMLInputElement} */ (el);
326
+ if (el) valEl = el as HTMLInputElement;
300
327
  })}
301
328
  ></sp-textfield>
302
329
  <sp-action-button
@@ -1,3 +1,4 @@
1
+ /// <reference lib="dom" />
1
2
  /**
2
3
  * Definitions Editor — visual editor for project-level $defs (JSON Schema type definitions).
3
4
  *
@@ -7,19 +8,15 @@
7
8
  */
8
9
 
9
10
  import { html, render as litRender } from "lit-html";
10
- import { getPlatform } from "../platform.js";
11
- import { projectState } from "../store.js";
12
- import {
13
- fieldCardTpl,
14
- addFieldFormTpl,
15
- schemaForType,
16
- detectFieldFormat,
17
- } from "./schema-field-ui.js";
11
+ import { getPlatform } from "../platform";
12
+ import { projectState } from "../store";
13
+ import { fieldCardTpl, addFieldFormTpl, schemaForType, detectFieldFormat } from "./schema-field-ui";
14
+
15
+ import type { ProjectConfig, ContentTypeSchema } from "@jxsuite/schema/types";
18
16
 
19
17
  // ─── Module state ─────────────────────────────────────────────────────────────
20
18
 
21
- /** @type {string | null} */
22
- let selectedDef = null;
19
+ let selectedDef: string | null = null;
23
20
  let showAddField = false;
24
21
  let newFieldState = { name: "", type: "string", format: "", required: false };
25
22
  let showNewDef = false;
@@ -29,22 +26,22 @@ let newDefName = "";
29
26
 
30
27
  async function saveProjectConfig() {
31
28
  const platform = getPlatform();
32
- const config = /** @type {{ projectConfig: ProjectConfig }} */ (projectState).projectConfig;
29
+ const config = (projectState as { projectConfig: ProjectConfig }).projectConfig;
33
30
  await platform.writeFile("project.json", JSON.stringify(config, null, "\t"));
34
31
  }
35
32
 
36
33
  // ─── Helpers ─────────────────────────────────────────────────────────────────
37
34
 
38
35
  /** Get the selected $def schema object. */
39
- function getSelectedDef() {
36
+ function getSelectedDef(): ContentTypeSchema | undefined {
40
37
  const config = projectState?.projectConfig;
41
- return config?.$defs?.[/** @type {string} */ (selectedDef)];
38
+ return config?.$defs?.[selectedDef as string] as ContentTypeSchema | undefined;
42
39
  }
43
40
 
44
41
  // ─── Handlers ─────────────────────────────────────────────────────────────────
45
42
 
46
43
  /** @param {() => void} rerender */
47
- function handleNewDef(rerender) {
44
+ function handleNewDef(rerender: () => void) {
48
45
  const name = newDefName.trim();
49
46
  if (!name) return;
50
47
 
@@ -67,7 +64,7 @@ function handleNewDef(rerender) {
67
64
  }
68
65
 
69
66
  /** @param {() => void} rerender */
70
- function handleAddField(rerender) {
67
+ function handleAddField(rerender: () => void) {
71
68
  const name = newFieldState.name.trim();
72
69
  if (!name || !selectedDef) return;
73
70
 
@@ -92,13 +89,13 @@ function handleAddField(rerender) {
92
89
  * @param {string} fieldName
93
90
  * @param {() => void} rerender
94
91
  */
95
- function handleDeleteField(fieldName, rerender) {
92
+ function handleDeleteField(fieldName: string, rerender: () => void) {
96
93
  const def = getSelectedDef();
97
94
  if (!def?.properties) return;
98
95
 
99
96
  delete def.properties[fieldName];
100
97
  if (def.required) {
101
- def.required = def.required.filter((/** @type {string} */ r) => r !== fieldName);
98
+ def.required = def.required.filter((r: string) => r !== fieldName);
102
99
  }
103
100
 
104
101
  rerender();
@@ -109,7 +106,7 @@ function handleDeleteField(fieldName, rerender) {
109
106
  * @param {string} fieldName
110
107
  * @param {() => void} rerender
111
108
  */
112
- function handleToggleRequired(fieldName, rerender) {
109
+ function handleToggleRequired(fieldName: string, rerender: () => void) {
113
110
  const def = getSelectedDef();
114
111
  if (!def) return;
115
112
  if (!def.required) def.required = [];
@@ -127,19 +124,18 @@ function handleToggleRequired(fieldName, rerender) {
127
124
  * @param {string} newName
128
125
  * @param {() => void} rerender
129
126
  */
130
- function handleRenameField(oldName, newName, rerender) {
127
+ function handleRenameField(oldName: string, newName: string, rerender: () => void) {
131
128
  const def = getSelectedDef();
132
129
  if (!def?.properties || !newName || def.properties[newName]) return;
133
130
 
134
- /** @type {Record<string, unknown>} */
135
- const newProps = {};
131
+ const newProps: Record<string, unknown> = {};
136
132
  for (const [key, val] of Object.entries(def.properties)) {
137
133
  newProps[key === oldName ? newName : key] = val;
138
134
  }
139
135
  def.properties = newProps;
140
136
 
141
137
  if (def.required) {
142
- def.required = def.required.map((/** @type {string} */ r) => (r === oldName ? newName : r));
138
+ def.required = def.required.map((r: string) => (r === oldName ? newName : r));
143
139
  }
144
140
 
145
141
  rerender();
@@ -151,7 +147,7 @@ function handleRenameField(oldName, newName, rerender) {
151
147
  * @param {string} newType
152
148
  * @param {() => void} rerender
153
149
  */
154
- function handleChangeType(fieldName, newType, rerender) {
150
+ function handleChangeType(fieldName: string, newType: string, rerender: () => void) {
155
151
  const def = getSelectedDef();
156
152
  if (!def?.properties?.[fieldName]) return;
157
153
 
@@ -169,7 +165,7 @@ function handleChangeType(fieldName, newType, rerender) {
169
165
  * @param {string} format
170
166
  * @param {() => void} rerender
171
167
  */
172
- function handleChangeFormat(fieldName, format, rerender) {
168
+ function handleChangeFormat(fieldName: string, format: string, rerender: () => void) {
173
169
  const def = getSelectedDef();
174
170
  if (!def?.properties?.[fieldName]) return;
175
171
 
@@ -187,7 +183,11 @@ function handleChangeFormat(fieldName, format, rerender) {
187
183
  * @param {{ name: string; type: string; required: boolean }} fieldState
188
184
  * @param {() => void} rerender
189
185
  */
190
- function handleAddNestedField(parentName, fieldState, rerender) {
186
+ function handleAddNestedField(
187
+ parentName: string,
188
+ fieldState: { name: string; type: string; required: boolean },
189
+ rerender: () => void,
190
+ ) {
191
191
  const def = getSelectedDef();
192
192
  const parent = def?.properties?.[parentName];
193
193
  if (!parent) return;
@@ -209,14 +209,14 @@ function handleAddNestedField(parentName, fieldState, rerender) {
209
209
  * @param {string} childName
210
210
  * @param {() => void} rerender
211
211
  */
212
- function handleDeleteNested(parentName, childName, rerender) {
212
+ function handleDeleteNested(parentName: string, childName: string, rerender: () => void) {
213
213
  const def = getSelectedDef();
214
214
  const parent = def?.properties?.[parentName];
215
215
  if (!parent?.properties) return;
216
216
 
217
217
  delete parent.properties[childName];
218
218
  if (parent.required) {
219
- parent.required = parent.required.filter((/** @type {string} */ r) => r !== childName);
219
+ parent.required = parent.required.filter((r: string) => r !== childName);
220
220
  }
221
221
 
222
222
  rerender();
@@ -228,7 +228,7 @@ function handleDeleteNested(parentName, childName, rerender) {
228
228
  * @param {string} childName
229
229
  * @param {() => void} rerender
230
230
  */
231
- function handleToggleNestedRequired(parentName, childName, rerender) {
231
+ function handleToggleNestedRequired(parentName: string, childName: string, rerender: () => void) {
232
232
  const def = getSelectedDef();
233
233
  const parent = def?.properties?.[parentName];
234
234
  if (!parent) return;
@@ -248,22 +248,24 @@ function handleToggleNestedRequired(parentName, childName, rerender) {
248
248
  * @param {string} newChild
249
249
  * @param {() => void} rerender
250
250
  */
251
- function handleRenameNested(parentName, oldChild, newChild, rerender) {
251
+ function handleRenameNested(
252
+ parentName: string,
253
+ oldChild: string,
254
+ newChild: string,
255
+ rerender: () => void,
256
+ ) {
252
257
  const def = getSelectedDef();
253
258
  const parent = def?.properties?.[parentName];
254
259
  if (!parent?.properties || !newChild || parent.properties[newChild]) return;
255
260
 
256
- /** @type {Record<string, unknown>} */
257
- const newProps = {};
261
+ const newProps: Record<string, unknown> = {};
258
262
  for (const [key, val] of Object.entries(parent.properties)) {
259
263
  newProps[key === oldChild ? newChild : key] = val;
260
264
  }
261
265
  parent.properties = newProps;
262
266
 
263
267
  if (parent.required) {
264
- parent.required = parent.required.map((/** @type {string} */ r) =>
265
- r === oldChild ? newChild : r,
266
- );
268
+ parent.required = parent.required.map((r: string) => (r === oldChild ? newChild : r));
267
269
  }
268
270
 
269
271
  rerender();
@@ -276,7 +278,12 @@ function handleRenameNested(parentName, oldChild, newChild, rerender) {
276
278
  * @param {string} newType
277
279
  * @param {() => void} rerender
278
280
  */
279
- function handleChangeNestedType(parentName, childName, newType, rerender) {
281
+ function handleChangeNestedType(
282
+ parentName: string,
283
+ childName: string,
284
+ newType: string,
285
+ rerender: () => void,
286
+ ) {
280
287
  const def = getSelectedDef();
281
288
  const parent = def?.properties?.[parentName];
282
289
  if (!parent?.properties?.[childName]) return;
@@ -296,7 +303,12 @@ function handleChangeNestedType(parentName, childName, newType, rerender) {
296
303
  * @param {string} format
297
304
  * @param {() => void} rerender
298
305
  */
299
- function handleChangeNestedFormat(parentName, childName, format, rerender) {
306
+ function handleChangeNestedFormat(
307
+ parentName: string,
308
+ childName: string,
309
+ format: string,
310
+ rerender: () => void,
311
+ ) {
300
312
  const def = getSelectedDef();
301
313
  const parent = def?.properties?.[parentName];
302
314
  if (!parent?.properties?.[childName]) return;
@@ -309,7 +321,7 @@ function handleChangeNestedFormat(parentName, childName, format, rerender) {
309
321
  }
310
322
 
311
323
  /** @param {() => void} rerender */
312
- function handleDeleteDef(rerender) {
324
+ function handleDeleteDef(rerender: () => void) {
313
325
  if (!selectedDef) return;
314
326
  const config = projectState?.projectConfig;
315
327
  if (!config?.$defs?.[selectedDef]) return;
@@ -328,7 +340,7 @@ function handleDeleteDef(rerender) {
328
340
  *
329
341
  * @param {HTMLElement} container
330
342
  */
331
- export function renderDefsEditor(container) {
343
+ export function renderDefsEditor(container: HTMLElement) {
332
344
  const rerender = () => renderDefsEditor(container);
333
345
  const config = projectState?.projectConfig;
334
346
  const defs = config?.$defs || {};
@@ -359,10 +371,10 @@ export function renderDefsEditor(container) {
359
371
  size="s"
360
372
  placeholder="TypeName"
361
373
  .value=${newDefName}
362
- @input=${(/** @type {Event} */ e) => {
363
- newDefName = /** @type {HTMLInputElement} */ (e.target).value;
374
+ @input=${(e: Event) => {
375
+ newDefName = (e.target as HTMLInputElement).value;
364
376
  }}
365
- @keydown=${(/** @type {KeyboardEvent} */ e) => {
377
+ @keydown=${(e: KeyboardEvent) => {
366
378
  if (e.key === "Enter") handleNewDef(rerender);
367
379
  if (e.key === "Escape") {
368
380
  showNewDef = false;
@@ -395,29 +407,31 @@ export function renderDefsEditor(container) {
395
407
  if (!selectedDef || !defs[selectedDef]) {
396
408
  editorTpl = html`<div class="settings-empty-state">Select or create a type definition</div>`;
397
409
  } else {
398
- const def = defs[selectedDef];
410
+ const def = defs[selectedDef] as ContentTypeSchema;
399
411
  const properties = def.properties || {};
400
412
  const required = def.required || [];
401
413
 
402
- /** @type {import("./schema-field-ui.js").FieldHandlers} */
403
- const handlers = {
404
- onDelete: (n) => handleDeleteField(n, rerender),
405
- onToggleRequired: (n) => handleToggleRequired(n, rerender),
406
- onRename: (oldN, newN) => handleRenameField(oldN, newN, rerender),
407
- onChangeType: (n, t) => handleChangeType(n, t, rerender),
408
- onChangeFormat: (n, f) => handleChangeFormat(n, f, rerender),
409
- onAddNestedField: (p, s) => handleAddNestedField(p, s, rerender),
410
- onDeleteNested: (p, c) => handleDeleteNested(p, c, rerender),
411
- onToggleNestedRequired: (p, c) => handleToggleNestedRequired(p, c, rerender),
412
- onRenameNested: (p, o, n) => handleRenameNested(p, o, n, rerender),
413
- onChangeNestedType: (p, c, t) => handleChangeNestedType(p, c, t, rerender),
414
- onChangeNestedFormat: (p, c, f) => handleChangeNestedFormat(p, c, f, rerender),
414
+ const handlers: import("./schema-field-ui.js").FieldHandlers = {
415
+ onDelete: (n: string) => handleDeleteField(n, rerender),
416
+ onToggleRequired: (n: string) => handleToggleRequired(n, rerender),
417
+ onRename: (oldN: string, newN: string) => handleRenameField(oldN, newN, rerender),
418
+ onChangeType: (n: string, t: string) => handleChangeType(n, t, rerender),
419
+ onChangeFormat: (n: string, f: string) => handleChangeFormat(n, f, rerender),
420
+ onAddNestedField: (p: string, s: { name: string; type: string; required: boolean }) =>
421
+ handleAddNestedField(p, s, rerender),
422
+ onDeleteNested: (p: string, c: string) => handleDeleteNested(p, c, rerender),
423
+ onToggleNestedRequired: (p: string, c: string) => handleToggleNestedRequired(p, c, rerender),
424
+ onRenameNested: (p: string, o: string, n: string) => handleRenameNested(p, o, n, rerender),
425
+ onChangeNestedType: (p: string, c: string, t: string) =>
426
+ handleChangeNestedType(p, c, t, rerender),
427
+ onChangeNestedFormat: (p: string, c: string, f: string) =>
428
+ handleChangeNestedFormat(p, c, f, rerender),
415
429
  };
416
430
 
417
431
  const fieldCards = Object.entries(properties).map(([name, fieldDef]) =>
418
432
  fieldCardTpl(
419
433
  name,
420
- /** @type {import("./schema-field-ui.js").SchemaProperty} */ (fieldDef),
434
+ fieldDef as import("./schema-field-ui.js").SchemaProperty,
421
435
  required.includes(name),
422
436
  handlers,
423
437
  ),
@@ -1,15 +1,18 @@
1
+ /// <reference lib="dom" />
1
2
  /** General settings section — favicon, platform adapter, breakpoints, and other site-wide config. */
2
3
 
3
4
  import { html, render as litRender, nothing } from "lit-html";
4
- import { projectState } from "../store.js";
5
- import { updateSiteConfig } from "../site-context.js";
6
- import { getPlatform } from "../platform.js";
7
- import { openFileInTab } from "../files/files.js";
8
- import { closeSettingsModal } from "./settings-modal.js";
5
+ import { projectState } from "../store";
6
+ import { updateSiteConfig } from "../site-context";
7
+ import { getPlatform } from "../platform";
8
+ import { openFileInTab } from "../files/files";
9
+ import { closeSettingsModal } from "./settings-modal";
10
+
11
+ import type { ProjectConfig } from "@jxsuite/schema/types";
9
12
 
10
13
  /** @param {HTMLElement} container */
11
- export function renderGeneralSettings(container) {
12
- const config = /** @type {ProjectConfig} */ (projectState?.projectConfig || {});
14
+ export function renderGeneralSettings(container: HTMLElement) {
15
+ const config = (projectState?.projectConfig || {}) as ProjectConfig;
13
16
 
14
17
  const onFaviconUpload = async () => {
15
18
  const input = document.createElement("input");
@@ -26,8 +29,8 @@ export function renderGeneralSettings(container) {
26
29
  input.click();
27
30
  };
28
31
 
29
- const onAdapterChange = (/** @type {Event & { target: { value: string } }} */ e) => {
30
- updateSiteConfig({ build: { ...config.build, adapter: e.target.value } });
32
+ const onAdapterChange = (e: Event) => {
33
+ updateSiteConfig({ build: { ...config.build, adapter: (e.target as HTMLInputElement).value } });
31
34
  };
32
35
 
33
36
  const onEditGlobalStyles = () => {
@@ -37,29 +40,27 @@ export function renderGeneralSettings(container) {
37
40
 
38
41
  // ─── Breakpoints ($media) ───────────────────────────────────────────────────
39
42
 
40
- const media = /** @type {Record<string, string>} */ (config.$media || {});
43
+ const media = (config.$media || {}) as Record<string, string>;
41
44
  const mediaEntries = Object.entries(media);
42
45
 
43
- const onMediaValueChange =
44
- (/** @type {string} */ key) => (/** @type {Event & { target: { value: string } }} */ e) => {
45
- const updated = { ...media, [key]: e.target.value };
46
- updateSiteConfig({ $media: updated });
47
- };
46
+ const onMediaValueChange = (key: string) => (e: Event) => {
47
+ const updated = { ...media, [key]: (e.target as HTMLInputElement).value };
48
+ updateSiteConfig({ $media: updated });
49
+ };
48
50
 
49
- const onMediaNameChange =
50
- (/** @type {string} */ oldKey) => (/** @type {Event & { target: { value: string } }} */ e) => {
51
- const rawName = e.target.value.trim();
52
- const newKey = rawName.startsWith("--") ? rawName : `--${rawName}`;
53
- if (newKey === oldKey) return;
54
- const updated = /** @type {Record<string, string>} */ ({});
55
- for (const [k, v] of Object.entries(media)) {
56
- updated[k === oldKey ? newKey : k] = v;
57
- }
58
- updateSiteConfig({ $media: updated });
59
- renderGeneralSettings(container);
60
- };
51
+ const onMediaNameChange = (oldKey: string) => (e: Event) => {
52
+ const rawName = (e.target as HTMLInputElement).value.trim();
53
+ const newKey = rawName.startsWith("--") ? rawName : `--${rawName}`;
54
+ if (newKey === oldKey) return;
55
+ const updated = {} as Record<string, string>;
56
+ for (const [k, v] of Object.entries(media)) {
57
+ updated[k === oldKey ? newKey : k] = v;
58
+ }
59
+ updateSiteConfig({ $media: updated });
60
+ renderGeneralSettings(container);
61
+ };
61
62
 
62
- const onRemoveBreakpoint = (/** @type {string} */ key) => () => {
63
+ const onRemoveBreakpoint = (key: string) => () => {
63
64
  const updated = { ...media };
64
65
  delete updated[key];
65
66
  updateSiteConfig({ $media: updated });