@jxsuite/studio 0.28.2 → 0.28.4

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 (104) hide show
  1. package/dist/studio.js +86144 -83971
  2. package/dist/studio.js.map +229 -219
  3. package/package.json +5 -5
  4. package/src/browse/browse-modal.ts +9 -3
  5. package/src/browse/browse.ts +139 -82
  6. package/src/canvas/canvas-diff.ts +35 -18
  7. package/src/canvas/canvas-helpers.ts +55 -21
  8. package/src/canvas/canvas-live-render.ts +140 -89
  9. package/src/canvas/canvas-render.ts +127 -82
  10. package/src/canvas/canvas-utils.ts +68 -42
  11. package/src/canvas/nested-site-style.ts +15 -7
  12. package/src/editor/component-inline-edit.ts +90 -51
  13. package/src/editor/content-inline-edit.ts +75 -72
  14. package/src/editor/context-menu.ts +125 -71
  15. package/src/editor/convert-targets.ts +17 -13
  16. package/src/editor/convert-to-component.ts +51 -28
  17. package/src/editor/convert-to-repeater.ts +44 -19
  18. package/src/editor/inline-edit.ts +107 -52
  19. package/src/editor/inline-format.ts +128 -60
  20. package/src/editor/insertion-helper.ts +26 -14
  21. package/src/editor/shortcuts.ts +89 -43
  22. package/src/editor/slash-menu.ts +41 -26
  23. package/src/files/components.ts +9 -7
  24. package/src/files/file-ops.ts +53 -33
  25. package/src/files/files.ts +246 -143
  26. package/src/format/constraints.ts +25 -15
  27. package/src/format/format-host.ts +33 -10
  28. package/src/github/github-auth.ts +24 -14
  29. package/src/github/github-publish.ts +20 -14
  30. package/src/new-project/new-project-modal.ts +27 -18
  31. package/src/panels/activity-bar.ts +27 -26
  32. package/src/panels/ai-panel.ts +100 -44
  33. package/src/panels/block-action-bar.ts +84 -52
  34. package/src/panels/canvas-dnd.ts +47 -28
  35. package/src/panels/data-explorer.ts +24 -11
  36. package/src/panels/dnd.ts +148 -100
  37. package/src/panels/editors.ts +54 -37
  38. package/src/panels/elements-panel.ts +23 -13
  39. package/src/panels/events-panel.ts +48 -38
  40. package/src/panels/git-panel.ts +95 -60
  41. package/src/panels/head-panel.ts +138 -84
  42. package/src/panels/imports-panel.ts +66 -29
  43. package/src/panels/layers-panel.ts +80 -36
  44. package/src/panels/left-panel.ts +86 -53
  45. package/src/panels/overlays.ts +36 -19
  46. package/src/panels/panel-events.ts +48 -27
  47. package/src/panels/panel-scheduler.ts +41 -23
  48. package/src/panels/preview-render.ts +26 -26
  49. package/src/panels/properties-panel.ts +155 -118
  50. package/src/panels/pseudo-preview.ts +31 -15
  51. package/src/panels/quick-search.ts +28 -13
  52. package/src/panels/right-panel.ts +35 -24
  53. package/src/panels/shared.ts +46 -29
  54. package/src/panels/signals-panel.ts +303 -186
  55. package/src/panels/statusbar.ts +27 -12
  56. package/src/panels/style-inputs.ts +30 -24
  57. package/src/panels/style-panel.ts +130 -90
  58. package/src/panels/style-utils.ts +63 -23
  59. package/src/panels/stylebook-layers-panel.ts +27 -30
  60. package/src/panels/stylebook-panel.ts +140 -72
  61. package/src/panels/tab-strip.ts +21 -10
  62. package/src/panels/toolbar.ts +52 -40
  63. package/src/panels/welcome-screen.ts +1 -1
  64. package/src/platform.ts +2 -1
  65. package/src/platforms/devserver.ts +221 -105
  66. package/src/recent-projects.ts +15 -7
  67. package/src/resize-edges.ts +7 -5
  68. package/src/services/cem-export.ts +73 -57
  69. package/src/services/code-services.ts +52 -25
  70. package/src/services/monaco-setup.ts +5 -5
  71. package/src/settings/content-types-editor.ts +133 -62
  72. package/src/settings/css-vars-editor.ts +31 -14
  73. package/src/settings/defs-editor.ts +125 -63
  74. package/src/settings/general-settings.ts +11 -6
  75. package/src/settings/head-editor.ts +30 -15
  76. package/src/settings/schema-field-ui.ts +75 -35
  77. package/src/settings/settings-modal.ts +35 -17
  78. package/src/site-context.ts +80 -47
  79. package/src/state.ts +98 -65
  80. package/src/store.ts +42 -23
  81. package/src/studio.ts +165 -144
  82. package/src/tabs/tab.ts +51 -45
  83. package/src/tabs/transact.ts +230 -109
  84. package/src/types.ts +60 -51
  85. package/src/ui/button-group.ts +3 -2
  86. package/src/ui/color-selector.ts +33 -15
  87. package/src/ui/expression-editor.ts +139 -86
  88. package/src/ui/field-input.ts +35 -18
  89. package/src/ui/field-row.ts +1 -1
  90. package/src/ui/icons.ts +5 -6
  91. package/src/ui/layers.ts +33 -26
  92. package/src/ui/media-picker.ts +13 -7
  93. package/src/ui/panel-resize.ts +39 -20
  94. package/src/ui/spectrum.ts +4 -2
  95. package/src/ui/unit-selector.ts +20 -11
  96. package/src/ui/value-selector.ts +13 -7
  97. package/src/ui/widgets.ts +34 -18
  98. package/src/utils/canvas-media.ts +66 -33
  99. package/src/utils/edit-display.ts +43 -44
  100. package/src/utils/google-fonts.ts +10 -6
  101. package/src/utils/inherited-style.ts +22 -8
  102. package/src/utils/studio-utils.ts +88 -45
  103. package/src/view.ts +9 -5
  104. package/src/workspace/workspace.ts +49 -29
@@ -10,13 +10,14 @@ import { html, render as litRender, nothing } from "lit-html";
10
10
  import { classMap } from "lit-html/directives/class-map.js";
11
11
  import { repeat } from "lit-html/directives/repeat.js";
12
12
  import { effect, effectScope } from "../reactivity";
13
- import { workspace, activateTab, closeTab } from "../workspace/workspace";
13
+ import { activateTab, closeTab, workspace } from "../workspace/workspace";
14
14
  import type { Tab } from "../tabs/tab";
15
15
  import { showConfirmDialog } from "../ui/layers";
16
+ import type { EffectScope } from "@vue/reactivity";
16
17
 
17
18
  let _host: HTMLElement | null = null;
18
19
 
19
- let _scope: import("@vue/reactivity").EffectScope | null = null;
20
+ let _scope: EffectScope | null = null;
20
21
 
21
22
  /**
22
23
  * Mount the tab strip into the given host element.
@@ -46,9 +47,11 @@ export function unmount() {
46
47
  }
47
48
 
48
49
  function render() {
49
- if (!_host) return;
50
+ if (!_host) {
51
+ return;
52
+ }
50
53
 
51
- if (workspace.tabOrder.length < 1) {
54
+ if (workspace.tabOrder.length === 0) {
52
55
  litRender(nothing, _host);
53
56
  return;
54
57
  }
@@ -61,13 +64,15 @@ function render() {
61
64
  (id) => id,
62
65
  (id) => {
63
66
  const tab = workspace.tabs.get(id);
64
- if (!tab) return nothing;
67
+ if (!tab) {
68
+ return nothing;
69
+ }
65
70
  const isActive = id === workspace.activeTabId;
66
71
  const isDirty = tab.doc.dirty;
67
72
  const label = tabLabel(tab);
68
73
  return html`
69
74
  <div
70
- class=${classMap({ "tab-strip-tab": true, active: isActive })}
75
+ class=${classMap({ active: isActive, "tab-strip-tab": true })}
71
76
  @click=${() => activateTab(id)}
72
77
  @auxclick=${(e: MouseEvent) => {
73
78
  if (e.button === 1) {
@@ -106,9 +111,11 @@ function render() {
106
111
  */
107
112
  function tabLabel(tab: Tab) {
108
113
  const path = tab.documentPath;
109
- if (!path) return "Untitled";
114
+ if (!path) {
115
+ return "Untitled";
116
+ }
110
117
  const parts = path.split("/");
111
- return parts[parts.length - 1];
118
+ return parts.at(-1);
112
119
  }
113
120
 
114
121
  /**
@@ -118,14 +125,18 @@ function tabLabel(tab: Tab) {
118
125
  */
119
126
  async function requestClose(id: string) {
120
127
  const tab = workspace.tabs.get(id);
121
- if (!tab) return;
128
+ if (!tab) {
129
+ return;
130
+ }
122
131
  if (tab.doc.dirty) {
123
132
  const confirmed = await showConfirmDialog(
124
133
  "Unsaved Changes",
125
134
  `"${tabLabel(tab)}" has unsaved changes. Close without saving?`,
126
135
  { confirmLabel: "Close", destructive: true },
127
136
  );
128
- if (!confirmed) return;
137
+ if (!confirmed) {
138
+ return;
139
+ }
129
140
  }
130
141
  closeTab(id);
131
142
  }
@@ -6,19 +6,21 @@
6
6
 
7
7
  import { html, render as litRender, nothing } from "lit-html";
8
8
  import { updateSession, updateUi } from "../store";
9
- import { undo as tabUndo, redo as tabRedo } from "../tabs/transact";
9
+ import { redo as tabRedo, undo as tabUndo } from "../tabs/transact";
10
10
  import { effect, effectScope } from "../reactivity";
11
11
  import { activeTab } from "../workspace/workspace";
12
12
  import type { DocumentStackEntry } from "../types";
13
13
  import { getEffectiveMedia } from "../site-context";
14
14
  import { mediaDisplayName } from "./shared";
15
- import { view, applyPanelCollapse } from "../view";
15
+ import { applyPanelCollapse, view } from "../view";
16
16
  import { getRecentProjects } from "../recent-projects";
17
17
  import { openQuickSearch } from "./quick-search";
18
18
  import { getPlatform } from "../platform";
19
19
  import { refreshGitStatus } from "./git-panel";
20
20
  import { openBrowseModal } from "../browse/browse-modal";
21
21
  import { openNewProjectModal } from "../new-project/new-project-modal";
22
+ import type { EffectScope } from "@vue/reactivity";
23
+ import type { TemplateResult } from "lit-html";
22
24
 
23
25
  interface ToolbarCtx {
24
26
  navigateBack: () => void;
@@ -48,25 +50,25 @@ let _rootEl: HTMLElement | null = null;
48
50
 
49
51
  let _ctx: ToolbarCtx | null = null;
50
52
 
51
- let _scope: import("@vue/reactivity").EffectScope | null = null;
53
+ let _scope: EffectScope | null = null;
52
54
 
53
55
  const toolbarIconMap = {
54
- "sp-icon-folder-open": html`<sp-icon-folder-open slot="icon"></sp-icon-folder-open>`,
55
- "sp-icon-save-floppy": html`<sp-icon-save-floppy slot="icon"></sp-icon-save-floppy>`,
56
+ "sp-icon-artboard": html`<sp-icon-artboard slot="icon"></sp-icon-artboard>`,
56
57
  "sp-icon-back": html`<sp-icon-back slot="icon"></sp-icon-back>`,
57
- "sp-icon-undo": html`<sp-icon-undo slot="icon"></sp-icon-undo>`,
58
- "sp-icon-redo": html`<sp-icon-redo slot="icon"></sp-icon-redo>`,
59
- "sp-icon-duplicate": html`<sp-icon-duplicate slot="icon"></sp-icon-duplicate>`,
58
+ "sp-icon-brush": html`<sp-icon-brush slot="icon"></sp-icon-brush>`,
59
+ "sp-icon-code": html`<sp-icon-code slot="icon"></sp-icon-code>`,
60
60
  "sp-icon-delete": html`<sp-icon-delete slot="icon"></sp-icon-delete>`,
61
+ "sp-icon-document": html`<sp-icon-document slot="icon"></sp-icon-document>`,
62
+ "sp-icon-duplicate": html`<sp-icon-duplicate slot="icon"></sp-icon-duplicate>`,
61
63
  "sp-icon-edit": html`<sp-icon-edit slot="icon"></sp-icon-edit>`,
62
- "sp-icon-artboard": html`<sp-icon-artboard slot="icon"></sp-icon-artboard>`,
64
+ "sp-icon-folder-open": html`<sp-icon-folder-open slot="icon"></sp-icon-folder-open>`,
65
+ "sp-icon-gears": html`<sp-icon-gears slot="icon"></sp-icon-gears>`,
63
66
  "sp-icon-preview": html`<sp-icon-preview slot="icon"></sp-icon-preview>`,
64
- "sp-icon-code": html`<sp-icon-code slot="icon"></sp-icon-code>`,
65
- "sp-icon-brush": html`<sp-icon-brush slot="icon"></sp-icon-brush>`,
67
+ "sp-icon-redo": html`<sp-icon-redo slot="icon"></sp-icon-redo>`,
68
+ "sp-icon-save-floppy": html`<sp-icon-save-floppy slot="icon"></sp-icon-save-floppy>`,
69
+ "sp-icon-undo": html`<sp-icon-undo slot="icon"></sp-icon-undo>`,
66
70
  "sp-icon-view-list": html`<sp-icon-view-list slot="icon"></sp-icon-view-list>`,
67
- "sp-icon-gears": html`<sp-icon-gears slot="icon"></sp-icon-gears>`,
68
- "sp-icon-document": html`<sp-icon-document slot="icon"></sp-icon-document>`,
69
- } as Record<string, import("lit-html").TemplateResult>;
71
+ } as Record<string, TemplateResult>;
70
72
 
71
73
  /**
72
74
  * @param {string} label
@@ -128,11 +130,13 @@ export function unmount() {
128
130
  }
129
131
 
130
132
  export function render() {
131
- if (!_rootEl || !_ctx) return;
133
+ if (!_rootEl || !_ctx) {
134
+ return;
135
+ }
132
136
  try {
133
137
  litRender(toolbarTemplate(), _rootEl);
134
- } catch (e) {
135
- console.error("toolbar render error:", e);
138
+ } catch (error) {
139
+ console.error("toolbar render error:", error);
136
140
  }
137
141
  }
138
142
 
@@ -163,7 +167,7 @@ function minimalToolbarTemplate(ctx: ToolbarCtx) {
163
167
  }}
164
168
  >
165
169
  <sp-menu-item value="__new__">New Project…</sp-menu-item>
166
- ${recentProjects.length
170
+ ${recentProjects.length > 0
167
171
  ? html`<sp-menu-divider></sp-menu-divider> ${recentProjects.map(
168
172
  (p) => html`<sp-menu-item value=${p.root}>${p.name}</sp-menu-item>`,
169
173
  )}`
@@ -269,19 +273,23 @@ function minimalToolbarTemplate(ctx: ToolbarCtx) {
269
273
  }
270
274
 
271
275
  const modes = [
272
- { key: "edit", label: "Edit", iconTag: "sp-icon-edit" },
273
- { key: "design", label: "Design", iconTag: "sp-icon-artboard" },
274
- { key: "preview", label: "Preview", iconTag: "sp-icon-preview" },
275
- { key: "source", label: "Code", iconTag: "sp-icon-code" },
276
- { key: "stylebook", label: "Stylebook", iconTag: "sp-icon-brush" },
276
+ { iconTag: "sp-icon-edit", key: "edit", label: "Edit" },
277
+ { iconTag: "sp-icon-artboard", key: "design", label: "Design" },
278
+ { iconTag: "sp-icon-preview", key: "preview", label: "Preview" },
279
+ { iconTag: "sp-icon-code", key: "source", label: "Code" },
280
+ { iconTag: "sp-icon-brush", key: "stylebook", label: "Stylebook" },
277
281
  ];
278
282
 
279
283
  function toolbarTemplate() {
280
284
  const tab = activeTab.value;
281
- if (!_ctx) return html``;
285
+ if (!_ctx) {
286
+ return html``;
287
+ }
282
288
  const ctx = _ctx;
283
289
 
284
- if (!tab) return minimalToolbarTemplate(ctx);
290
+ if (!tab) {
291
+ return minimalToolbarTemplate(ctx);
292
+ }
285
293
 
286
294
  const allowedModes = new Set(tab.capabilities.modes);
287
295
  const canUndo = tab.history.index > 0;
@@ -289,14 +297,14 @@ function toolbarTemplate() {
289
297
  const canSave = tab.doc.dirty;
290
298
 
291
299
  const S = {
292
- document: tab.doc.document,
293
- ui: tab.session.ui,
294
- mode: tab.doc.mode,
295
- selection: tab.session.selection,
296
300
  dirty: tab.doc.dirty,
301
+ document: tab.doc.document,
297
302
  documentPath: tab.documentPath,
298
- fileHandle: tab.fileHandle,
299
303
  documentStack: tab.session.documentStack,
304
+ fileHandle: tab.fileHandle,
305
+ mode: tab.doc.mode,
306
+ selection: tab.session.selection,
307
+ ui: tab.session.ui,
300
308
  };
301
309
  const canvasMode = ctx.getCanvasMode();
302
310
  const hasStack = S.documentStack && S.documentStack.length > 0;
@@ -333,7 +341,7 @@ function toolbarTemplate() {
333
341
  toggles
334
342
  size="s"
335
343
  title=${query}
336
- ?selected=${!!S.ui.featureToggles[name]}
344
+ ?selected=${Boolean(S.ui.featureToggles[name])}
337
345
  @click=${() => {
338
346
  const newToggles = {
339
347
  ...S.ui.featureToggles,
@@ -359,13 +367,15 @@ function toolbarTemplate() {
359
367
  ?selected=${canvasMode === m.key}
360
368
  ?disabled=${!allowedModes.has(m.key)}
361
369
  @click=${() => {
362
- if (canvasMode === m.key) return;
363
- if (!allowedModes.has(m.key)) return;
364
- if (S.ui.editingFunction) {
365
- if (view.functionEditor) {
366
- view.functionEditor.dispose();
367
- view.functionEditor = null;
368
- }
370
+ if (canvasMode === m.key) {
371
+ return;
372
+ }
373
+ if (!allowedModes.has(m.key)) {
374
+ return;
375
+ }
376
+ if (S.ui.editingFunction && view.functionEditor) {
377
+ view.functionEditor.dispose();
378
+ view.functionEditor = null;
369
379
  }
370
380
  ctx.setCanvasMode(m.key);
371
381
  view.panX = 0;
@@ -374,7 +384,9 @@ function toolbarTemplate() {
374
384
  const uiPatch: { editingFunction: null; rightTab?: string } = {
375
385
  editingFunction: null,
376
386
  };
377
- if (m.key === "stylebook") uiPatch.rightTab = "style";
387
+ if (m.key === "stylebook") {
388
+ uiPatch.rightTab = "style";
389
+ }
378
390
  updateSession({ ui: uiPatch });
379
391
  ctx.renderCanvas();
380
392
  ctx.safeRenderRightPanel();
@@ -483,7 +495,7 @@ function toolbarTemplate() {
483
495
  }}
484
496
  >
485
497
  <sp-menu-item value="__new__">New Project…</sp-menu-item>
486
- ${recentProjects.length
498
+ ${recentProjects.length > 0
487
499
  ? html`<sp-menu-divider></sp-menu-divider> ${recentProjects.map(
488
500
  (p) => html`<sp-menu-item value=${p.root}>${p.name}</sp-menu-item>`,
489
501
  )}`
@@ -113,7 +113,7 @@ export function renderWelcome(host: HTMLElement) {
113
113
  function shortenPath(path: string) {
114
114
  if (path.startsWith("/home/")) {
115
115
  const parts = path.split("/");
116
- return "~/" + parts.slice(3).join("/");
116
+ return `~/${parts.slice(3).join("/")}`;
117
117
  }
118
118
  return path;
119
119
  }
package/src/platform.ts CHANGED
@@ -23,8 +23,9 @@ export function registerPlatform(platform: StudioPlatform) {
23
23
 
24
24
  /** @returns {StudioPlatform} */
25
25
  export function getPlatform() {
26
- if (!g.__jxPlatform)
26
+ if (!g.__jxPlatform) {
27
27
  throw new Error("No platform registered. Call registerPlatform() before starting Studio.");
28
+ }
28
29
  return g.__jxPlatform;
29
30
  }
30
31