@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,25 +1,25 @@
1
+ /// <reference lib="dom" />
1
2
  /** Statusbar — status message display for Jx Studio */
2
3
 
3
- import { statusbarEl, getNodeAtPath, nodeLabel, updateSession, renderOnly } from "../store.js";
4
- import { effect, effectScope } from "../reactivity.js";
5
- import { activeTab } from "../workspace/workspace.js";
4
+ import { statusbarEl, getNodeAtPath, nodeLabel, updateSession, renderOnly } from "../store";
5
+ import { effect, effectScope } from "../reactivity";
6
+ import { activeTab } from "../workspace/workspace";
7
+ import type { JxPath } from "../state";
6
8
 
7
9
  // ─── Module state ────────────────────────────────────────────────────────────
8
10
 
9
11
  let statusMsg = "";
10
12
  /** @type {ReturnType<typeof setTimeout> | undefined} */
11
- let statusTimeout;
12
- /** @type {(() => void) | null} */
13
- let _rerender = null;
14
- /** @type {import("@vue/reactivity").EffectScope | null} */
15
- let _scope = null;
13
+ let statusTimeout: ReturnType<typeof setTimeout> | undefined;
14
+ let _rerender: (() => void) | null = null;
15
+ let _scope: import("@vue/reactivity").EffectScope | null = null;
16
16
 
17
17
  /**
18
18
  * Register the callback used to re-render the statusbar. Called once from studio.js during init.
19
19
  *
20
20
  * @param {() => void} fn
21
21
  */
22
- export function setStatusbarRenderer(fn) {
22
+ export function setStatusbarRenderer(fn: () => void) {
23
23
  _rerender = fn;
24
24
  }
25
25
 
@@ -51,7 +51,7 @@ export function unmountStatusbar() {
51
51
  // ─── Statusbar ───────────────────────────────────────────────────────────────
52
52
 
53
53
  /** @param {string} text */
54
- function esc(text) {
54
+ function esc(text: string) {
55
55
  return String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
56
56
  }
57
57
 
@@ -61,7 +61,7 @@ export function renderStatusbar() {
61
61
  const parts = [];
62
62
  if (tab?.doc.mode === "content") parts.push("Content Mode");
63
63
  if (tab?.session.selection?.length) {
64
- const sel = /** @type {JxPath} */ (tab.session.selection);
64
+ const sel = tab.session.selection as JxPath;
65
65
  const node = getNodeAtPath(tab.doc.document, sel);
66
66
  parts.push(`Selected: ${esc(nodeLabel(node))}`);
67
67
 
@@ -85,8 +85,8 @@ export function renderStatusbar() {
85
85
  }
86
86
 
87
87
  /** @param {Event} e */
88
- function _onStatusbarClick(e) {
89
- const target = /** @type {HTMLElement} */ (e.target);
88
+ function _onStatusbarClick(e: Event) {
89
+ const target = e.target as HTMLElement;
90
90
  if (!target.classList.contains("sb-path-seg")) return;
91
91
  const pathStr = target.dataset.path;
92
92
  if (!pathStr) return;
@@ -105,7 +105,7 @@ function _onStatusbarClick(e) {
105
105
  * @param {string} msg
106
106
  * @param {number} [duration]
107
107
  */
108
- export function statusMessage(msg, duration = 3000) {
108
+ export function statusMessage(msg: string, duration: number = 3000) {
109
109
  statusMsg = msg;
110
110
  _rerender?.();
111
111
  clearTimeout(statusTimeout);
@@ -1,19 +1,20 @@
1
+ /// <reference lib="dom" />
1
2
  /** Style input widgets — keyword, select, combobox, and font renderers for the style panel. */
2
3
 
3
4
  import { html } from "lit-html";
4
5
  import { live } from "lit-html/directives/live.js";
5
- import { debouncedStyleCommit } from "../store.js";
6
- import { activeTab } from "../workspace/workspace.js";
7
- import { transactDoc, mutateUpdateStyle } from "../tabs/transact.js";
8
- import { widgetForType as _widgetForType } from "../ui/widgets.js";
9
- import { kebabToLabel, friendlyNameToVar, varDisplayName } from "../utils/studio-utils.js";
6
+ import { debouncedStyleCommit } from "../store";
7
+ import { activeTab } from "../workspace/workspace";
8
+ import { transactDoc, mutateUpdateStyle } from "../tabs/transact";
9
+ import { widgetForType as _widgetForType } from "../ui/widgets";
10
+ import { kebabToLabel, friendlyNameToVar, varDisplayName } from "../utils/studio-utils";
10
11
  import {
11
12
  TYPO_PREVIEW_PROPS,
12
13
  currentFontFamily,
13
14
  getFontVars,
14
15
  getCssInitialMap,
15
16
  camelToKebab,
16
- } from "./style-utils.js";
17
+ } from "./style-utils";
17
18
 
18
19
  /**
19
20
  * Dual-mode keyword input — shared by select (enum) and combobox (examples) widgets.
@@ -21,16 +22,21 @@ import {
21
22
  * @param {string[]} options @param {string} prop @param {string} value @param {(value: string) =>
22
23
  * void} onChange
23
24
  */
24
- export function renderKeywordInput(options, prop, value, onChange) {
25
+ export function renderKeywordInput(
26
+ options: string[],
27
+ prop: string,
28
+ value: string,
29
+ onChange: (value: string) => void,
30
+ ) {
25
31
  const cssInitialMap = getCssInitialMap();
26
32
  const isTypoPreview = TYPO_PREVIEW_PROPS.has(prop) || prop === "fontWeight";
27
33
  const font = isTypoPreview ? currentFontFamily() : "";
28
34
  const cssProp = isTypoPreview ? camelToKebab(prop) : "";
29
35
 
30
- const comboOptions = options.map((/** @type {string} */ v) => {
36
+ const comboOptions = options.map((v: string) => {
31
37
  const label = v.includes("-")
32
38
  ? kebabToLabel(v)
33
- : v.replace(/^./, (/** @type {string} */ c) => c.toUpperCase());
39
+ : v.replace(/^./, (c: string) => c.toUpperCase());
34
40
  const style = isTypoPreview ? `${cssProp}: ${v};${font ? ` font-family: ${font}` : ""}` : "";
35
41
  return { value: v, label, style };
36
42
  });
@@ -40,10 +46,9 @@ export function renderKeywordInput(options, prop, value, onChange) {
40
46
  .value=${value || ""}
41
47
  placeholder=${cssInitialMap.get(prop) || ""}
42
48
  .options=${comboOptions}
43
- @change=${(/** @type {Event} */ e) =>
44
- onChange(/** @type {HTMLInputElement} */ (e.target).value)}
45
- @input=${debouncedStyleCommit(`kw:${prop}`, 400, (/** @type {Event} */ e) =>
46
- onChange(/** @type {HTMLInputElement} */ (e.target).value),
49
+ @change=${(e: Event) => onChange((e.target as HTMLInputElement).value)}
50
+ @input=${debouncedStyleCommit(`kw:${prop}`, 400, (e: Event) =>
51
+ onChange((e.target as HTMLInputElement).value),
47
52
  )}
48
53
  ></jx-value-selector>`;
49
54
  }
@@ -52,12 +57,20 @@ export function renderKeywordInput(options, prop, value, onChange) {
52
57
  * @param {{ enum?: string[] }} entry @param {string} prop @param {string} value @param {(value:
53
58
  * string) => void} onChange
54
59
  */
55
- export function renderSelectInput(entry, prop, value, onChange) {
60
+ export function renderSelectInput(
61
+ entry: { enum?: string[] },
62
+ prop: string,
63
+ value: string,
64
+ onChange: (value: string) => void,
65
+ ) {
56
66
  return renderKeywordInput(entry.enum || [], prop, value, onChange);
57
67
  }
58
68
 
59
69
  /** @param {{ title: string; value: string }} preset @param {(value: string) => void} onChange */
60
- function handleFontPresetSelection(preset, onChange) {
70
+ function handleFontPresetSelection(
71
+ preset: { title: string; value: string },
72
+ onChange: (value: string) => void,
73
+ ) {
61
74
  const varName = friendlyNameToVar(preset.title, "--font-");
62
75
  if (!activeTab.value?.doc.document?.style?.[varName]) {
63
76
  transactDoc(activeTab.value, (t) => mutateUpdateStyle(t, [], varName, preset.value));
@@ -69,7 +82,11 @@ function handleFontPresetSelection(preset, onChange) {
69
82
  * @param {string} val @param {{ title: string; value: string }[]} presets @param {(value: string)
70
83
  * => void} onChange
71
84
  */
72
- function handleFontSelection(val, presets, onChange) {
85
+ function handleFontSelection(
86
+ val: string,
87
+ presets: { title: string; value: string }[],
88
+ onChange: (value: string) => void,
89
+ ) {
73
90
  if (!val) return;
74
91
  if (val.startsWith("__preset__:")) {
75
92
  const title = val.slice("__preset__:".length);
@@ -109,13 +126,16 @@ function handleFontSelection(val, presets, onChange) {
109
126
  * presets
110
127
  * @returns {({ value: string; label: string; style: string } | { divider: true })[]}
111
128
  */
112
- export function buildFontOptions(fontVars, presets) {
113
- /** @type {({ value: string; label: string; style: string } | { divider: true })[]} */
114
- const opts = fontVars.map((/** @type {{ name: string; value: string }} */ fv) => ({
115
- value: fv.name,
116
- label: varDisplayName(fv.name, "--font-"),
117
- style: `font-family: ${fv.value}`,
118
- }));
129
+ export function buildFontOptions(
130
+ fontVars: { name: string; value: string }[],
131
+ presets: { title: string; value: string }[],
132
+ ) {
133
+ const opts: ({ value: string; label: string; style: string } | { divider: true })[] =
134
+ fontVars.map((fv) => ({
135
+ value: fv.name,
136
+ label: varDisplayName(fv.name, "--font-"),
137
+ style: `font-family: ${fv.value}`,
138
+ }));
119
139
  const unadded = presets.filter(
120
140
  (/** @type {{ title: string; value: string }} */ p) =>
121
141
  !fontVars.some(
@@ -142,7 +162,12 @@ export function buildFontOptions(fontVars, presets) {
142
162
  * }} entry
143
163
  * @param {string} prop @param {string} value @param {(value: string) => void} onChange
144
164
  */
145
- export function renderComboboxInput(entry, prop, value, onChange) {
165
+ export function renderComboboxInput(
166
+ entry: { enum?: string[]; examples?: string[]; presets?: { title: string; value: string }[] },
167
+ prop: string,
168
+ value: string,
169
+ onChange: (value: string) => void,
170
+ ) {
146
171
  const cssInitialMap = getCssInitialMap();
147
172
  const fontVars = prop === "fontFamily" ? getFontVars() : [];
148
173
  const presets = entry.presets || [];
@@ -157,10 +182,10 @@ export function renderComboboxInput(entry, prop, value, onChange) {
157
182
  .value=${comboValue}
158
183
  placeholder=${cssInitialMap.get("fontFamily") || ""}
159
184
  .options=${fontOptions}
160
- @change=${(/** @type {Event} */ e) =>
161
- handleFontSelection(/** @type {HTMLInputElement} */ (e.target).value, presets, onChange)}
162
- @input=${debouncedStyleCommit("combo:fontFamily", 400, (/** @type {Event} */ e) =>
163
- onChange(/** @type {HTMLInputElement} */ (e.target).value),
185
+ @change=${(e: Event) =>
186
+ handleFontSelection((e.target as HTMLInputElement).value, presets, onChange)}
187
+ @input=${debouncedStyleCommit("combo:fontFamily", 400, (e: Event) =>
188
+ onChange((e.target as HTMLInputElement).value),
164
189
  )}
165
190
  ></jx-value-selector>`;
166
191
  }
@@ -174,8 +199,8 @@ export function renderComboboxInput(entry, prop, value, onChange) {
174
199
  size="s"
175
200
  placeholder=${cssInitialMap.get(prop) || ""}
176
201
  .value=${live(value || "")}
177
- @input=${debouncedStyleCommit(`combo:${prop}`, 400, (/** @type {Event} */ e) =>
178
- onChange(/** @type {HTMLInputElement} */ (e.target).value),
202
+ @input=${debouncedStyleCommit(`combo:${prop}`, 400, (e: Event) =>
203
+ onChange((e.target as HTMLInputElement).value),
179
204
  )}
180
205
  ></sp-textfield>
181
206
  `;
@@ -186,24 +211,17 @@ export function renderComboboxInput(entry, prop, value, onChange) {
186
211
  * inputs and CSS initial-value placeholders.
187
212
  */
188
213
  export function widgetForType(
189
- /** @type {string} */ type,
190
- /** @type {Record<string, unknown>} */ entry,
191
- /** @type {string} */ prop,
192
- /** @type {string} */ value,
193
- /** @type {(value: string) => void} */ onCommit,
194
- /** @type {{ placeholder?: string }} */ opts = {},
214
+ type: string,
215
+ entry: Record<string, unknown>,
216
+ prop: string,
217
+ value: string,
218
+ onCommit: (value: string) => void,
219
+ opts: { placeholder?: string } = {},
195
220
  ) {
196
221
  const cssInitialMap = getCssInitialMap();
197
- return _widgetForType(
198
- type,
199
- entry,
200
- prop,
201
- value,
202
- /** @type {(val: string | number) => void} */ (onCommit),
203
- {
204
- placeholder: opts.placeholder || cssInitialMap.get(prop) || "",
205
- renderSelect: renderSelectInput,
206
- renderCombobox: renderComboboxInput,
207
- },
208
- );
222
+ return _widgetForType(type, entry, prop, value, onCommit as (val: string | number) => void, {
223
+ placeholder: opts.placeholder || cssInitialMap.get(prop) || "",
224
+ renderSelect: renderSelectInput,
225
+ renderCombobox: renderComboboxInput,
226
+ });
209
227
  }