@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.
- package/dist/studio.js +86144 -83971
- package/dist/studio.js.map +229 -219
- package/package.json +5 -5
- package/src/browse/browse-modal.ts +9 -3
- package/src/browse/browse.ts +139 -82
- package/src/canvas/canvas-diff.ts +35 -18
- package/src/canvas/canvas-helpers.ts +55 -21
- package/src/canvas/canvas-live-render.ts +140 -89
- package/src/canvas/canvas-render.ts +127 -82
- package/src/canvas/canvas-utils.ts +68 -42
- package/src/canvas/nested-site-style.ts +15 -7
- package/src/editor/component-inline-edit.ts +90 -51
- package/src/editor/content-inline-edit.ts +75 -72
- package/src/editor/context-menu.ts +125 -71
- package/src/editor/convert-targets.ts +17 -13
- package/src/editor/convert-to-component.ts +51 -28
- package/src/editor/convert-to-repeater.ts +44 -19
- package/src/editor/inline-edit.ts +107 -52
- package/src/editor/inline-format.ts +128 -60
- package/src/editor/insertion-helper.ts +26 -14
- package/src/editor/shortcuts.ts +89 -43
- package/src/editor/slash-menu.ts +41 -26
- package/src/files/components.ts +9 -7
- package/src/files/file-ops.ts +53 -33
- package/src/files/files.ts +246 -143
- package/src/format/constraints.ts +25 -15
- package/src/format/format-host.ts +33 -10
- package/src/github/github-auth.ts +24 -14
- package/src/github/github-publish.ts +20 -14
- package/src/new-project/new-project-modal.ts +27 -18
- package/src/panels/activity-bar.ts +27 -26
- package/src/panels/ai-panel.ts +100 -44
- package/src/panels/block-action-bar.ts +84 -52
- package/src/panels/canvas-dnd.ts +47 -28
- package/src/panels/data-explorer.ts +24 -11
- package/src/panels/dnd.ts +148 -100
- package/src/panels/editors.ts +54 -37
- package/src/panels/elements-panel.ts +23 -13
- package/src/panels/events-panel.ts +48 -38
- package/src/panels/git-panel.ts +95 -60
- package/src/panels/head-panel.ts +138 -84
- package/src/panels/imports-panel.ts +66 -29
- package/src/panels/layers-panel.ts +80 -36
- package/src/panels/left-panel.ts +86 -53
- package/src/panels/overlays.ts +36 -19
- package/src/panels/panel-events.ts +48 -27
- package/src/panels/panel-scheduler.ts +41 -23
- package/src/panels/preview-render.ts +26 -26
- package/src/panels/properties-panel.ts +155 -118
- package/src/panels/pseudo-preview.ts +31 -15
- package/src/panels/quick-search.ts +28 -13
- package/src/panels/right-panel.ts +35 -24
- package/src/panels/shared.ts +46 -29
- package/src/panels/signals-panel.ts +303 -186
- package/src/panels/statusbar.ts +27 -12
- package/src/panels/style-inputs.ts +30 -24
- package/src/panels/style-panel.ts +130 -90
- package/src/panels/style-utils.ts +63 -23
- package/src/panels/stylebook-layers-panel.ts +27 -30
- package/src/panels/stylebook-panel.ts +140 -72
- package/src/panels/tab-strip.ts +21 -10
- package/src/panels/toolbar.ts +52 -40
- package/src/panels/welcome-screen.ts +1 -1
- package/src/platform.ts +2 -1
- package/src/platforms/devserver.ts +221 -105
- package/src/recent-projects.ts +15 -7
- package/src/resize-edges.ts +7 -5
- package/src/services/cem-export.ts +73 -57
- package/src/services/code-services.ts +52 -25
- package/src/services/monaco-setup.ts +5 -5
- package/src/settings/content-types-editor.ts +133 -62
- package/src/settings/css-vars-editor.ts +31 -14
- package/src/settings/defs-editor.ts +125 -63
- package/src/settings/general-settings.ts +11 -6
- package/src/settings/head-editor.ts +30 -15
- package/src/settings/schema-field-ui.ts +75 -35
- package/src/settings/settings-modal.ts +35 -17
- package/src/site-context.ts +80 -47
- package/src/state.ts +98 -65
- package/src/store.ts +42 -23
- package/src/studio.ts +165 -144
- package/src/tabs/tab.ts +51 -45
- package/src/tabs/transact.ts +230 -109
- package/src/types.ts +60 -51
- package/src/ui/button-group.ts +3 -2
- package/src/ui/color-selector.ts +33 -15
- package/src/ui/expression-editor.ts +139 -86
- package/src/ui/field-input.ts +35 -18
- package/src/ui/field-row.ts +1 -1
- package/src/ui/icons.ts +5 -6
- package/src/ui/layers.ts +33 -26
- package/src/ui/media-picker.ts +13 -7
- package/src/ui/panel-resize.ts +39 -20
- package/src/ui/spectrum.ts +4 -2
- package/src/ui/unit-selector.ts +20 -11
- package/src/ui/value-selector.ts +13 -7
- package/src/ui/widgets.ts +34 -18
- package/src/utils/canvas-media.ts +66 -33
- package/src/utils/edit-display.ts +43 -44
- package/src/utils/google-fonts.ts +10 -6
- package/src/utils/inherited-style.ts +22 -8
- package/src/utils/studio-utils.ts +88 -45
- package/src/view.ts +9 -5
- package/src/workspace/workspace.ts +49 -29
package/src/panels/tab-strip.ts
CHANGED
|
@@ -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 {
|
|
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:
|
|
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)
|
|
50
|
+
if (!_host) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
50
53
|
|
|
51
|
-
if (workspace.tabOrder.length
|
|
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)
|
|
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
|
|
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)
|
|
114
|
+
if (!path) {
|
|
115
|
+
return "Untitled";
|
|
116
|
+
}
|
|
110
117
|
const parts = path.split("/");
|
|
111
|
-
return parts
|
|
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)
|
|
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)
|
|
137
|
+
if (!confirmed) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
129
140
|
}
|
|
130
141
|
closeTab(id);
|
|
131
142
|
}
|
package/src/panels/toolbar.ts
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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:
|
|
53
|
+
let _scope: EffectScope | null = null;
|
|
52
54
|
|
|
53
55
|
const toolbarIconMap = {
|
|
54
|
-
"sp-icon-
|
|
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-
|
|
58
|
-
"sp-icon-
|
|
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-
|
|
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-
|
|
65
|
-
"sp-icon-
|
|
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
|
-
|
|
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)
|
|
133
|
+
if (!_rootEl || !_ctx) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
132
136
|
try {
|
|
133
137
|
litRender(toolbarTemplate(), _rootEl);
|
|
134
|
-
} catch (
|
|
135
|
-
console.error("toolbar render error:",
|
|
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
|
-
{
|
|
273
|
-
{
|
|
274
|
-
{
|
|
275
|
-
{
|
|
276
|
-
{
|
|
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)
|
|
285
|
+
if (!_ctx) {
|
|
286
|
+
return html``;
|
|
287
|
+
}
|
|
282
288
|
const ctx = _ctx;
|
|
283
289
|
|
|
284
|
-
if (!tab)
|
|
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=${
|
|
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)
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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")
|
|
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
|
|
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
|
|