@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.
- package/dist/studio.js +2231 -715
- package/dist/studio.js.map +121 -104
- package/package.json +8 -7
- package/src/browse/{browse-modal.js → browse-modal.ts} +9 -10
- package/src/browse/{browse.js → browse.ts} +110 -85
- package/src/canvas/{canvas-diff.js → canvas-diff.ts} +42 -35
- package/src/canvas/{canvas-helpers.js → canvas-helpers.ts} +25 -19
- package/src/canvas/{canvas-live-render.js → canvas-live-render.ts} +53 -63
- package/src/canvas/{canvas-render.js → canvas-render.ts} +110 -121
- package/src/canvas/{canvas-utils.js → canvas-utils.ts} +48 -44
- package/src/canvas/{nested-site-style.js → nested-site-style.ts} +3 -3
- package/src/editor/{component-inline-edit.js → component-inline-edit.ts} +45 -33
- package/src/editor/{content-inline-edit.js → content-inline-edit.ts} +27 -45
- package/src/editor/{context-menu.js → context-menu.ts} +38 -36
- package/src/editor/{convert-targets.js → convert-targets.ts} +15 -12
- package/src/editor/{convert-to-component.js → convert-to-component.ts} +25 -26
- package/src/editor/{convert-to-repeater.js → convert-to-repeater.ts} +60 -40
- package/src/editor/{inline-edit.js → inline-edit.ts} +91 -55
- package/src/editor/{inline-format.js → inline-format.ts} +46 -51
- package/src/editor/{insertion-helper.js → insertion-helper.ts} +47 -63
- package/src/editor/{shortcuts.js → shortcuts.ts} +45 -31
- package/src/editor/{slash-menu.js → slash-menu.ts} +34 -35
- package/src/files/{components.js → components.ts} +12 -15
- package/src/files/{file-ops.js → file-ops.ts} +36 -29
- package/src/files/{files.js → files.ts} +102 -84
- package/src/github/{github-auth.js → github-auth.ts} +3 -3
- package/src/github/{github-publish.js → github-publish.ts} +20 -18
- package/src/markdown/{md-allowlist.js → md-allowlist.ts} +5 -2
- package/src/markdown/{md-convert.js → md-convert.ts} +146 -169
- package/src/new-project/{new-project-modal.js → new-project-modal.ts} +16 -18
- package/src/panels/{activity-bar.js → activity-bar.ts} +26 -34
- package/src/panels/{ai-panel.js → ai-panel.ts} +30 -30
- package/src/panels/{block-action-bar.js → block-action-bar.ts} +64 -73
- package/src/panels/{canvas-dnd.js → canvas-dnd.ts} +44 -49
- package/src/panels/{data-explorer.js → data-explorer.ts} +21 -15
- package/src/panels/dnd.ts +417 -0
- package/src/panels/{editors.js → editors.ts} +43 -50
- package/src/panels/{elements-panel.js → elements-panel.ts} +30 -27
- package/src/panels/{events-panel.js → events-panel.ts} +33 -25
- package/src/panels/{git-panel.js → git-panel.ts} +97 -83
- package/src/panels/{head-panel.js → head-panel.ts} +117 -139
- package/src/panels/{imports-panel.js → imports-panel.ts} +69 -89
- package/src/panels/{layers-panel.js → layers-panel.ts} +61 -57
- package/src/panels/{left-panel.js → left-panel.ts} +56 -63
- package/src/panels/{overlays.js → overlays.ts} +28 -36
- package/src/panels/{panel-events.js → panel-events.ts} +53 -51
- package/src/panels/{preview-render.js → preview-render.ts} +20 -15
- package/src/panels/{properties-panel.js → properties-panel.ts} +212 -246
- package/src/panels/{pseudo-preview.js → pseudo-preview.ts} +9 -8
- package/src/panels/{quick-search.js → quick-search.ts} +16 -17
- package/src/panels/{right-panel.js → right-panel.ts} +41 -59
- package/src/panels/{shared.js → shared.ts} +7 -5
- package/src/panels/{signals-panel.js → signals-panel.ts} +322 -362
- package/src/panels/{statusbar.js → statusbar.ts} +14 -14
- package/src/panels/{style-inputs.js → style-inputs.ts} +66 -48
- package/src/panels/{style-panel.js → style-panel.ts} +235 -290
- package/src/panels/{style-utils.js → style-utils.ts} +32 -31
- package/src/panels/{stylebook-layers-panel.js → stylebook-layers-panel.ts} +22 -14
- package/src/panels/{stylebook-panel.js → stylebook-panel.ts} +127 -140
- package/src/panels/{tab-strip.js → tab-strip.ts} +12 -14
- package/src/panels/{toolbar.js → toolbar.ts} +68 -70
- package/src/panels/{welcome-screen.js → welcome-screen.ts} +14 -16
- package/src/{platform.js → platform.ts} +5 -3
- package/src/platforms/{devserver.js → devserver.ts} +53 -44
- package/src/{recent-projects.js → recent-projects.ts} +17 -12
- package/src/{resize-edges.js → resize-edges.ts} +18 -13
- package/src/services/{cem-export.js → cem-export.ts} +14 -7
- package/src/services/{code-services.js → code-services.ts} +29 -20
- package/src/services/{monaco-setup.js → monaco-setup.ts} +2 -3
- package/src/settings/{content-types-editor.js → content-types-editor.ts} +88 -67
- package/src/settings/{css-vars-editor.js → css-vars-editor.ts} +78 -51
- package/src/settings/{defs-editor.js → defs-editor.ts} +70 -56
- package/src/settings/{general-settings.js → general-settings.ts} +29 -28
- package/src/settings/{head-editor.js → head-editor.ts} +37 -35
- package/src/settings/{schema-field-ui.js → schema-field-ui.ts} +86 -76
- package/src/settings/{settings-modal.js → settings-modal.ts} +14 -16
- package/src/{site-context.js → site-context.ts} +35 -32
- package/src/{state.js → state.ts} +95 -78
- package/src/{store.js → store.ts} +60 -63
- package/src/{studio.js → studio.ts} +117 -119
- package/src/tabs/tab.ts +196 -0
- package/src/tabs/{transact.js → transact.ts} +107 -60
- package/src/types.ts +185 -0
- package/src/ui/{button-group.js → button-group.ts} +21 -21
- package/src/ui/{color-selector.js → color-selector.ts} +44 -37
- package/src/ui/{expression-editor.js → expression-editor.ts} +65 -40
- package/src/ui/{field-row.js → field-row.ts} +19 -2
- package/src/ui/{icons.js → icons.ts} +2 -2
- package/src/ui/{layers.js → layers.ts} +33 -24
- package/src/ui/{media-picker.js → media-picker.ts} +13 -9
- package/src/ui/{panel-resize.js → panel-resize.ts} +9 -4
- package/src/ui/{spectrum.js → spectrum.ts} +4 -4
- package/src/ui/{unit-selector.js → unit-selector.ts} +16 -19
- package/src/ui/{value-selector.js → value-selector.ts} +28 -28
- package/src/ui/{widgets.js → widgets.ts} +62 -15
- package/src/utils/{canvas-media.js → canvas-media.ts} +29 -14
- package/src/utils/{edit-display.js → edit-display.ts} +23 -20
- package/src/utils/{google-fonts.js → google-fonts.ts} +14 -13
- package/src/utils/{inherited-style.js → inherited-style.ts} +15 -10
- package/src/utils/{studio-utils.js → studio-utils.ts} +38 -26
- package/src/{view.js → view.ts} +53 -55
- package/src/workspace/{workspace.js → workspace.ts} +44 -33
- package/src/panels/dnd.js +0 -426
- package/src/tabs/tab.js +0 -192
- /package/src/{reactivity.js → reactivity.ts} +0 -0
|
@@ -1,54 +1,51 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Toolbar panel — extracted from studio.js renderToolbar(). Owns rendering of breadcrumbs, file
|
|
3
4
|
* ops, feature toggles, and mode switcher.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import { html, render as litRender, nothing } from "lit-html";
|
|
7
|
-
import { updateSession, updateUi } from "../store
|
|
8
|
-
import { undo as tabUndo, redo as tabRedo } from "../tabs/transact
|
|
9
|
-
import { effect, effectScope } from "../reactivity
|
|
10
|
-
import { activeTab } from "../workspace/workspace
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
8
|
+
import { updateSession, updateUi } from "../store";
|
|
9
|
+
import { undo as tabUndo, redo as tabRedo } from "../tabs/transact";
|
|
10
|
+
import { effect, effectScope } from "../reactivity";
|
|
11
|
+
import { activeTab } from "../workspace/workspace";
|
|
12
|
+
import type { DocumentStackEntry } from "../types";
|
|
13
|
+
import { getEffectiveMedia } from "../site-context";
|
|
14
|
+
import { mediaDisplayName } from "./shared";
|
|
15
|
+
import { view, applyPanelCollapse } from "../view";
|
|
16
|
+
import { getRecentProjects } from "../recent-projects";
|
|
17
|
+
import { openQuickSearch } from "./quick-search";
|
|
18
|
+
import { getPlatform } from "../platform";
|
|
19
|
+
import { refreshGitStatus } from "./git-panel";
|
|
20
|
+
import { openBrowseModal } from "../browse/browse-modal";
|
|
21
|
+
import { openNewProjectModal } from "../new-project/new-project-modal";
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
interface ToolbarCtx {
|
|
24
|
+
navigateBack: () => void;
|
|
25
|
+
navigateToLevel: (level: number) => void;
|
|
26
|
+
openProject: () => void;
|
|
27
|
+
openFile?: (path: string) => void;
|
|
28
|
+
saveFile: () => void;
|
|
29
|
+
parseMediaEntries: (media: Record<string, string> | null | undefined) => {
|
|
30
|
+
sizeBreakpoints: { name: string; query: string; width: number; type: string }[];
|
|
31
|
+
featureQueries: { name: string; query: string }[];
|
|
32
|
+
baseWidth: number;
|
|
33
|
+
};
|
|
34
|
+
getCanvasMode: () => string;
|
|
35
|
+
setCanvasMode: (mode: string) => void;
|
|
36
|
+
renderCanvas: () => void;
|
|
37
|
+
safeRenderRightPanel: () => void;
|
|
38
|
+
openRecentProject: (root: string) => Promise<void>;
|
|
39
|
+
closeFunctionEditor: () => void;
|
|
40
|
+
}
|
|
23
41
|
|
|
24
|
-
|
|
25
|
-
* @typedef {{
|
|
26
|
-
* navigateBack: () => void;
|
|
27
|
-
* navigateToLevel: (level: number) => void;
|
|
28
|
-
* openProject: () => void;
|
|
29
|
-
* openFile?: (path: string) => void;
|
|
30
|
-
* saveFile: () => void;
|
|
31
|
-
* parseMediaEntries: (media: Record<string, string> | null | undefined) => {
|
|
32
|
-
* sizeBreakpoints: { name: string; query: string; width: number; type: string }[];
|
|
33
|
-
* featureQueries: { name: string; query: string }[];
|
|
34
|
-
* baseWidth: number;
|
|
35
|
-
* };
|
|
36
|
-
* getCanvasMode: () => string;
|
|
37
|
-
* setCanvasMode: (mode: string) => void;
|
|
38
|
-
* renderCanvas: () => void;
|
|
39
|
-
* safeRenderRightPanel: () => void;
|
|
40
|
-
* openRecentProject: (root: string) => Promise<void>;
|
|
41
|
-
* closeFunctionEditor: () => void;
|
|
42
|
-
* }} ToolbarCtx
|
|
43
|
-
*/
|
|
42
|
+
let _rootEl: HTMLElement | null = null;
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
let _ctx = null;
|
|
44
|
+
let _ctx: ToolbarCtx | null = null;
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
let _scope = null;
|
|
46
|
+
let _scope: import("@vue/reactivity").EffectScope | null = null;
|
|
50
47
|
|
|
51
|
-
const toolbarIconMap =
|
|
48
|
+
const toolbarIconMap = {
|
|
52
49
|
"sp-icon-folder-open": html`<sp-icon-folder-open slot="icon"></sp-icon-folder-open>`,
|
|
53
50
|
"sp-icon-save-floppy": html`<sp-icon-save-floppy slot="icon"></sp-icon-save-floppy>`,
|
|
54
51
|
"sp-icon-back": html`<sp-icon-back slot="icon"></sp-icon-back>`,
|
|
@@ -64,14 +61,14 @@ const toolbarIconMap = /** @type {Record<string, import("lit-html").TemplateResu
|
|
|
64
61
|
"sp-icon-view-list": html`<sp-icon-view-list slot="icon"></sp-icon-view-list>`,
|
|
65
62
|
"sp-icon-gears": html`<sp-icon-gears slot="icon"></sp-icon-gears>`,
|
|
66
63
|
"sp-icon-document": html`<sp-icon-document slot="icon"></sp-icon-document>`,
|
|
67
|
-
})
|
|
64
|
+
} as Record<string, import("lit-html").TemplateResult>;
|
|
68
65
|
|
|
69
66
|
/**
|
|
70
67
|
* @param {string} label
|
|
71
|
-
* @param {
|
|
68
|
+
* @param {() => void} onClick
|
|
72
69
|
* @param {string} [iconTag]
|
|
73
70
|
*/
|
|
74
|
-
function tbBtnTpl(label, onClick, iconTag) {
|
|
71
|
+
function tbBtnTpl(label: string, onClick: () => void, iconTag?: string) {
|
|
75
72
|
return html`
|
|
76
73
|
<sp-action-button size="s" @click=${onClick}>
|
|
77
74
|
${iconTag ? toolbarIconMap[iconTag] : nothing} ${label}
|
|
@@ -86,13 +83,12 @@ function tbBtnTpl(label, onClick, iconTag) {
|
|
|
86
83
|
* @param {ToolbarCtx} ctx — { navigateBack, closeFunctionEditor, openProject, openFile, saveFile,
|
|
87
84
|
* parseMediaEntries, getCanvasMode, setCanvasMode, renderCanvas, safeRenderRightPanel }
|
|
88
85
|
*/
|
|
89
|
-
export function mount(rootEl, ctx) {
|
|
86
|
+
export function mount(rootEl: HTMLElement, ctx: ToolbarCtx) {
|
|
90
87
|
_rootEl = rootEl;
|
|
91
88
|
_ctx = ctx;
|
|
92
89
|
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
).__jxPlatform?.windowControls
|
|
90
|
+
(globalThis as unknown as { __jxPlatform?: { windowControls?: unknown } }).__jxPlatform
|
|
91
|
+
?.windowControls
|
|
96
92
|
) {
|
|
97
93
|
rootEl.classList.add("electrobun-webkit-app-region-drag");
|
|
98
94
|
}
|
|
@@ -143,7 +139,7 @@ async function handleNewProject() {
|
|
|
143
139
|
}
|
|
144
140
|
|
|
145
141
|
/** @param {ToolbarCtx} ctx */
|
|
146
|
-
function minimalToolbarTemplate(ctx) {
|
|
142
|
+
function minimalToolbarTemplate(ctx: ToolbarCtx) {
|
|
147
143
|
const recentProjects = getRecentProjects();
|
|
148
144
|
const recentProjectsTpl = html`
|
|
149
145
|
<overlay-trigger placement="bottom-start" triggered-by="click">
|
|
@@ -152,8 +148,8 @@ function minimalToolbarTemplate(ctx) {
|
|
|
152
148
|
</sp-action-button>
|
|
153
149
|
<sp-popover slot="click-content" tip>
|
|
154
150
|
<sp-menu
|
|
155
|
-
@change=${(
|
|
156
|
-
const val =
|
|
151
|
+
@change=${(e: Event) => {
|
|
152
|
+
const val = (e.target as unknown as HTMLInputElement).value;
|
|
157
153
|
if (val === "__new__") {
|
|
158
154
|
handleNewProject();
|
|
159
155
|
} else {
|
|
@@ -172,13 +168,13 @@ function minimalToolbarTemplate(ctx) {
|
|
|
172
168
|
</overlay-trigger>
|
|
173
169
|
`;
|
|
174
170
|
|
|
175
|
-
const windowControls =
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
171
|
+
const windowControls = (
|
|
172
|
+
globalThis as unknown as {
|
|
173
|
+
__jxPlatform?: {
|
|
174
|
+
windowControls?: { minimize: () => void; maximize: () => void; close: () => void };
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
).__jxPlatform?.windowControls;
|
|
182
178
|
const csdTpl = windowControls
|
|
183
179
|
? html`
|
|
184
180
|
<sp-action-group class="window-controls" size="s">
|
|
@@ -303,7 +299,7 @@ function toolbarTemplate() {
|
|
|
303
299
|
${toolbarIconMap["sp-icon-back"]}Back
|
|
304
300
|
</sp-action-button>
|
|
305
301
|
${S.documentStack.map(
|
|
306
|
-
(
|
|
302
|
+
(frame: DocumentStackEntry, i: number) => html`
|
|
307
303
|
<span class="breadcrumb-item clickable" @click=${() => ctx.navigateToLevel(i)}
|
|
308
304
|
>${frame.documentPath?.split("/").pop() || "untitled"}</span
|
|
309
305
|
>
|
|
@@ -366,7 +362,9 @@ function toolbarTemplate() {
|
|
|
366
362
|
view.panX = 0;
|
|
367
363
|
view.panY = 0;
|
|
368
364
|
/** @type {{ editingFunction: null; rightTab?: string }} */
|
|
369
|
-
const uiPatch
|
|
365
|
+
const uiPatch: { editingFunction: null; rightTab?: string } = {
|
|
366
|
+
editingFunction: null,
|
|
367
|
+
};
|
|
370
368
|
if (m.key === "stylebook") uiPatch.rightTab = "style";
|
|
371
369
|
updateSession({ ui: uiPatch });
|
|
372
370
|
ctx.renderCanvas();
|
|
@@ -380,13 +378,13 @@ function toolbarTemplate() {
|
|
|
380
378
|
</sp-action-group>
|
|
381
379
|
`;
|
|
382
380
|
|
|
383
|
-
const windowControls =
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
381
|
+
const windowControls = (
|
|
382
|
+
globalThis as unknown as {
|
|
383
|
+
__jxPlatform?: {
|
|
384
|
+
windowControls?: { minimize: () => void; maximize: () => void; close: () => void };
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
).__jxPlatform?.windowControls;
|
|
390
388
|
const isMac = navigator.platform.startsWith("Mac");
|
|
391
389
|
const csdTpl = windowControls
|
|
392
390
|
? isMac
|
|
@@ -462,8 +460,8 @@ function toolbarTemplate() {
|
|
|
462
460
|
</sp-action-button>
|
|
463
461
|
<sp-popover slot="click-content" tip>
|
|
464
462
|
<sp-menu
|
|
465
|
-
@change=${(
|
|
466
|
-
const val =
|
|
463
|
+
@change=${(e: Event) => {
|
|
464
|
+
const val = (e.target as unknown as HTMLInputElement).value;
|
|
467
465
|
if (val === "__new__") {
|
|
468
466
|
handleNewProject();
|
|
469
467
|
} else {
|
|
@@ -495,10 +493,10 @@ function toolbarTemplate() {
|
|
|
495
493
|
${toolbarIconMap["sp-icon-save-floppy"]} Save
|
|
496
494
|
</sp-action-button>
|
|
497
495
|
<sp-action-group compact size="s">
|
|
498
|
-
<sp-action-button size="s" ?disabled=${!canUndo} @click=${() => tabUndo(activeTab.value)}>
|
|
496
|
+
<sp-action-button size="s" ?disabled=${!canUndo} @click=${() => tabUndo(activeTab.value!)}>
|
|
499
497
|
${toolbarIconMap["sp-icon-undo"]} Undo
|
|
500
498
|
</sp-action-button>
|
|
501
|
-
<sp-action-button size="s" ?disabled=${!canRedo} @click=${() => tabRedo(activeTab.value)}>
|
|
499
|
+
<sp-action-button size="s" ?disabled=${!canRedo} @click=${() => tabRedo(activeTab.value!)}>
|
|
502
500
|
${toolbarIconMap["sp-icon-redo"]} Redo
|
|
503
501
|
</sp-action-button>
|
|
504
502
|
</sp-action-group>
|
|
@@ -1,32 +1,30 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Welcome screen — shown when no project is loaded and no document tabs are open. Mimics VS Code's
|
|
3
4
|
* welcome tab with start actions and recent projects.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import { html, render as litRender, nothing } from "lit-html";
|
|
7
|
-
import { getRecentProjects } from "../recent-projects
|
|
8
|
-
import { platformSupportsClone } from "./git-panel
|
|
8
|
+
import { getRecentProjects } from "../recent-projects";
|
|
9
|
+
import { platformSupportsClone } from "./git-panel";
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* }} WelcomeCtx
|
|
17
|
-
*/
|
|
11
|
+
interface WelcomeCtx {
|
|
12
|
+
openProject: () => void;
|
|
13
|
+
openRecentProject: (root: string) => void;
|
|
14
|
+
openNewProject: () => void;
|
|
15
|
+
cloneRepository: () => void;
|
|
16
|
+
}
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
let _ctx = null;
|
|
18
|
+
let _ctx: WelcomeCtx | null = null;
|
|
21
19
|
|
|
22
20
|
/** @param {WelcomeCtx} ctx */
|
|
23
|
-
export function initWelcome(ctx) {
|
|
21
|
+
export function initWelcome(ctx: WelcomeCtx) {
|
|
24
22
|
_ctx = ctx;
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
/** @param {HTMLElement} host */
|
|
28
|
-
export function renderWelcome(host) {
|
|
29
|
-
const ctx =
|
|
26
|
+
export function renderWelcome(host: HTMLElement) {
|
|
27
|
+
const ctx = _ctx as WelcomeCtx;
|
|
30
28
|
const recent = getRecentProjects();
|
|
31
29
|
const showClone = platformSupportsClone();
|
|
32
30
|
|
|
@@ -112,7 +110,7 @@ export function renderWelcome(host) {
|
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
/** @param {string} path */
|
|
115
|
-
function shortenPath(path) {
|
|
113
|
+
function shortenPath(path: string) {
|
|
116
114
|
if (path.startsWith("/home/")) {
|
|
117
115
|
const parts = path.split("/");
|
|
118
116
|
return "~/" + parts.slice(3).join("/");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Platform.js — Platform Abstraction Layer (PAL)
|
|
3
4
|
*
|
|
@@ -11,11 +12,12 @@
|
|
|
11
12
|
* See spec/desktop.md §3 for the full StudioPlatform interface.
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
import type { StudioPlatform } from "./types";
|
|
16
|
+
|
|
17
|
+
const g = globalThis as unknown as { __jxPlatform?: StudioPlatform };
|
|
16
18
|
|
|
17
19
|
/** @param {StudioPlatform} platform */
|
|
18
|
-
export function registerPlatform(platform) {
|
|
20
|
+
export function registerPlatform(platform: StudioPlatform) {
|
|
19
21
|
g.__jxPlatform = platform;
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -24,7 +24,7 @@ export function createDevServerPlatform() {
|
|
|
24
24
|
*
|
|
25
25
|
* @param {string} rel
|
|
26
26
|
*/
|
|
27
|
-
function serverPath(rel) {
|
|
27
|
+
function serverPath(rel: string) {
|
|
28
28
|
const r = rel.replaceAll("\\", "/");
|
|
29
29
|
if (!_projectRoot) return r;
|
|
30
30
|
if (r === ".") return _projectRoot;
|
|
@@ -36,7 +36,7 @@ export function createDevServerPlatform() {
|
|
|
36
36
|
*
|
|
37
37
|
* @param {string} path
|
|
38
38
|
*/
|
|
39
|
-
function stripRoot(path) {
|
|
39
|
+
function stripRoot(path: string) {
|
|
40
40
|
const p = path.replaceAll("\\", "/");
|
|
41
41
|
if (!_projectRoot) return p;
|
|
42
42
|
return p.startsWith(_projectRoot + "/") ? p.slice(_projectRoot.length + 1) : p;
|
|
@@ -60,7 +60,7 @@ export function createDevServerPlatform() {
|
|
|
60
60
|
*
|
|
61
61
|
* @param {string} [root]
|
|
62
62
|
*/
|
|
63
|
-
async activate(root) {
|
|
63
|
+
async activate(root?: string) {
|
|
64
64
|
const r = root ?? _projectRoot;
|
|
65
65
|
await fetch("/__studio/activate", {
|
|
66
66
|
method: "POST",
|
|
@@ -79,13 +79,14 @@ export function createDevServerPlatform() {
|
|
|
79
79
|
|
|
80
80
|
let dirHandle;
|
|
81
81
|
try {
|
|
82
|
-
dirHandle =
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
dirHandle = await (
|
|
83
|
+
window as unknown as {
|
|
84
|
+
showDirectoryPicker(opts: { mode: string }): Promise<FileSystemDirectoryHandle>;
|
|
85
|
+
}
|
|
86
|
+
).showDirectoryPicker({ mode: "readwrite" });
|
|
87
|
+
} catch (e) {
|
|
87
88
|
// User cancelled the picker
|
|
88
|
-
if (
|
|
89
|
+
if ((e as Error).name === "AbortError") return null;
|
|
89
90
|
throw e;
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -105,8 +106,10 @@ export function createDevServerPlatform() {
|
|
|
105
106
|
if (!sitesRes.ok) throw new Error("Failed to fetch site list from server");
|
|
106
107
|
const sites = await sitesRes.json();
|
|
107
108
|
const match = sites.find(
|
|
108
|
-
/** @param {{ config: unknown; path: string }} s */ (s
|
|
109
|
-
|
|
109
|
+
/** @param {{ config: unknown; path: string }} s */ (s: {
|
|
110
|
+
config: unknown;
|
|
111
|
+
path: string;
|
|
112
|
+
}) => JSON.stringify(s.config) === JSON.stringify(config),
|
|
110
113
|
);
|
|
111
114
|
|
|
112
115
|
if (!match) {
|
|
@@ -164,7 +167,13 @@ export function createDevServerPlatform() {
|
|
|
164
167
|
* directory: string;
|
|
165
168
|
* }} opts
|
|
166
169
|
*/
|
|
167
|
-
async createProject(opts
|
|
170
|
+
async createProject(opts: {
|
|
171
|
+
name: string;
|
|
172
|
+
description?: string;
|
|
173
|
+
url?: string;
|
|
174
|
+
adapter?: string;
|
|
175
|
+
directory: string;
|
|
176
|
+
}) {
|
|
168
177
|
const res = await fetch("/__studio/create-project", {
|
|
169
178
|
method: "POST",
|
|
170
179
|
headers: { "Content-Type": "application/json" },
|
|
@@ -180,7 +189,7 @@ export function createDevServerPlatform() {
|
|
|
180
189
|
// ─── File operations ──────────────────────────────────────────────────
|
|
181
190
|
|
|
182
191
|
/** @param {string} dir */
|
|
183
|
-
async listDirectory(dir) {
|
|
192
|
+
async listDirectory(dir: string) {
|
|
184
193
|
const res = await fetch(`/__studio/files?dir=${encodeURIComponent(serverPath(dir))}`);
|
|
185
194
|
if (!res.ok) throw new Error(`Failed to list directory: ${dir}`);
|
|
186
195
|
const entries = await res.json();
|
|
@@ -189,7 +198,7 @@ export function createDevServerPlatform() {
|
|
|
189
198
|
},
|
|
190
199
|
|
|
191
200
|
/** @param {string} path */
|
|
192
|
-
async readFile(path) {
|
|
201
|
+
async readFile(path: string) {
|
|
193
202
|
const res = await fetch(`/__studio/file?path=${encodeURIComponent(serverPath(path))}`);
|
|
194
203
|
if (!res.ok) throw new Error(`Failed to read file: ${path}`);
|
|
195
204
|
const data = await res.json();
|
|
@@ -200,7 +209,7 @@ export function createDevServerPlatform() {
|
|
|
200
209
|
* @param {string} path
|
|
201
210
|
* @param {string} content
|
|
202
211
|
*/
|
|
203
|
-
async writeFile(path, content) {
|
|
212
|
+
async writeFile(path: string, content: string) {
|
|
204
213
|
const res = await fetch(`/__studio/file?path=${encodeURIComponent(serverPath(path))}`, {
|
|
205
214
|
method: "PUT",
|
|
206
215
|
body: content,
|
|
@@ -214,7 +223,7 @@ export function createDevServerPlatform() {
|
|
|
214
223
|
* @param {string} path — project-relative destination path
|
|
215
224
|
* @param {File | Blob | ArrayBuffer} data — file content
|
|
216
225
|
*/
|
|
217
|
-
async uploadFile(path, data) {
|
|
226
|
+
async uploadFile(path: string, data: File | Blob | ArrayBuffer) {
|
|
218
227
|
const res = await fetch(
|
|
219
228
|
`/__studio/file/upload?path=${encodeURIComponent(serverPath(path))}`,
|
|
220
229
|
{ method: "POST", body: data },
|
|
@@ -224,7 +233,7 @@ export function createDevServerPlatform() {
|
|
|
224
233
|
},
|
|
225
234
|
|
|
226
235
|
/** @param {string} path */
|
|
227
|
-
async deleteFile(path) {
|
|
236
|
+
async deleteFile(path: string) {
|
|
228
237
|
const res = await fetch(`/__studio/file?path=${encodeURIComponent(serverPath(path))}`, {
|
|
229
238
|
method: "DELETE",
|
|
230
239
|
});
|
|
@@ -235,7 +244,7 @@ export function createDevServerPlatform() {
|
|
|
235
244
|
* @param {string} from
|
|
236
245
|
* @param {string} to
|
|
237
246
|
*/
|
|
238
|
-
async renameFile(from, to) {
|
|
247
|
+
async renameFile(from: string, to: string) {
|
|
239
248
|
const res = await fetch("/__studio/file/rename", {
|
|
240
249
|
method: "POST",
|
|
241
250
|
headers: { "Content-Type": "application/json" },
|
|
@@ -245,7 +254,7 @@ export function createDevServerPlatform() {
|
|
|
245
254
|
},
|
|
246
255
|
|
|
247
256
|
/** @param {string} _path */
|
|
248
|
-
async createDirectory(_path) {
|
|
257
|
+
async createDirectory(_path: string) {
|
|
249
258
|
// The server creates directories implicitly when writing files.
|
|
250
259
|
// Write a placeholder and delete it, or rely on mkdir behavior.
|
|
251
260
|
// For now, use the writeFile + delete approach if directory creation
|
|
@@ -255,7 +264,7 @@ export function createDevServerPlatform() {
|
|
|
255
264
|
// ─── Component discovery ──────────────────────────────────────────────
|
|
256
265
|
|
|
257
266
|
/** @param {string} dir */
|
|
258
|
-
async discoverComponents(dir) {
|
|
267
|
+
async discoverComponents(dir: string) {
|
|
259
268
|
const scanDir = dir || _projectRoot;
|
|
260
269
|
if (!scanDir) return [];
|
|
261
270
|
const url = `/__studio/components?dir=${encodeURIComponent(scanDir)}`;
|
|
@@ -267,7 +276,7 @@ export function createDevServerPlatform() {
|
|
|
267
276
|
// ─── Package management ──────────────────────────────────────────────
|
|
268
277
|
|
|
269
278
|
/** @param {string} name */
|
|
270
|
-
async addPackage(name) {
|
|
279
|
+
async addPackage(name: string) {
|
|
271
280
|
const res = await fetch("/__studio/packages/add", {
|
|
272
281
|
method: "POST",
|
|
273
282
|
headers: { "Content-Type": "application/json" },
|
|
@@ -278,7 +287,7 @@ export function createDevServerPlatform() {
|
|
|
278
287
|
},
|
|
279
288
|
|
|
280
289
|
/** @param {string} name */
|
|
281
|
-
async removePackage(name) {
|
|
290
|
+
async removePackage(name: string) {
|
|
282
291
|
const res = await fetch("/__studio/packages/remove", {
|
|
283
292
|
method: "POST",
|
|
284
293
|
headers: { "Content-Type": "application/json" },
|
|
@@ -300,7 +309,7 @@ export function createDevServerPlatform() {
|
|
|
300
309
|
* @param {string} action
|
|
301
310
|
* @param {unknown} payload
|
|
302
311
|
*/
|
|
303
|
-
async codeService(action, payload) {
|
|
312
|
+
async codeService(action: string, payload: unknown) {
|
|
304
313
|
try {
|
|
305
314
|
const res = await fetch(`/__studio/code/${action}`, {
|
|
306
315
|
method: "POST",
|
|
@@ -322,7 +331,7 @@ export function createDevServerPlatform() {
|
|
|
322
331
|
*
|
|
323
332
|
* @param {string} filePath — absolute system path
|
|
324
333
|
*/
|
|
325
|
-
async resolveSiteContext(filePath) {
|
|
334
|
+
async resolveSiteContext(filePath: string) {
|
|
326
335
|
const res = await fetch(`/__studio/resolve-site?path=${encodeURIComponent(filePath)}`);
|
|
327
336
|
if (!res.ok) return { sitePath: null };
|
|
328
337
|
return await res.json();
|
|
@@ -331,7 +340,7 @@ export function createDevServerPlatform() {
|
|
|
331
340
|
// ─── File location ────────────────────────────────────────────────────
|
|
332
341
|
|
|
333
342
|
/** @param {string} name */
|
|
334
|
-
async locateFile(name) {
|
|
343
|
+
async locateFile(name: string) {
|
|
335
344
|
try {
|
|
336
345
|
const res = await fetch("/__studio/locate", {
|
|
337
346
|
method: "POST",
|
|
@@ -344,7 +353,7 @@ export function createDevServerPlatform() {
|
|
|
344
353
|
},
|
|
345
354
|
|
|
346
355
|
/** @param {string} query */
|
|
347
|
-
async searchFiles(query) {
|
|
356
|
+
async searchFiles(query: string) {
|
|
348
357
|
const glob = `**/*${query}*.{json,md}`;
|
|
349
358
|
const res = await fetch(
|
|
350
359
|
`/__studio/files?dir=${encodeURIComponent(serverPath("."))}&glob=${encodeURIComponent(glob)}`,
|
|
@@ -362,7 +371,7 @@ export function createDevServerPlatform() {
|
|
|
362
371
|
* @param {string} prototype
|
|
363
372
|
* @param {string} base
|
|
364
373
|
*/
|
|
365
|
-
async fetchPluginSchema(src, prototype, base) {
|
|
374
|
+
async fetchPluginSchema(src: string, prototype: string, base: string) {
|
|
366
375
|
const params = new URLSearchParams({ src });
|
|
367
376
|
if (prototype) params.set("prototype", prototype);
|
|
368
377
|
if (base) params.set("base", base);
|
|
@@ -387,7 +396,7 @@ export function createDevServerPlatform() {
|
|
|
387
396
|
},
|
|
388
397
|
|
|
389
398
|
/** @param {number} [limit] */
|
|
390
|
-
async gitLog(limit) {
|
|
399
|
+
async gitLog(limit?: number) {
|
|
391
400
|
const q = limit ? `?limit=${limit}` : "";
|
|
392
401
|
const res = await fetch(`/__studio/git/log${q}`);
|
|
393
402
|
if (!res.ok) throw new Error(await res.text());
|
|
@@ -395,7 +404,7 @@ export function createDevServerPlatform() {
|
|
|
395
404
|
},
|
|
396
405
|
|
|
397
406
|
/** @param {string[]} files */
|
|
398
|
-
async gitStage(files) {
|
|
407
|
+
async gitStage(files: string[]) {
|
|
399
408
|
const res = await fetch("/__studio/git/stage", {
|
|
400
409
|
method: "POST",
|
|
401
410
|
headers: { "Content-Type": "application/json" },
|
|
@@ -406,7 +415,7 @@ export function createDevServerPlatform() {
|
|
|
406
415
|
},
|
|
407
416
|
|
|
408
417
|
/** @param {string[]} files */
|
|
409
|
-
async gitUnstage(files) {
|
|
418
|
+
async gitUnstage(files: string[]) {
|
|
410
419
|
const res = await fetch("/__studio/git/unstage", {
|
|
411
420
|
method: "POST",
|
|
412
421
|
headers: { "Content-Type": "application/json" },
|
|
@@ -417,7 +426,7 @@ export function createDevServerPlatform() {
|
|
|
417
426
|
},
|
|
418
427
|
|
|
419
428
|
/** @param {string} message */
|
|
420
|
-
async gitCommit(message) {
|
|
429
|
+
async gitCommit(message: string) {
|
|
421
430
|
const res = await fetch("/__studio/git/commit", {
|
|
422
431
|
method: "POST",
|
|
423
432
|
headers: { "Content-Type": "application/json" },
|
|
@@ -428,7 +437,7 @@ export function createDevServerPlatform() {
|
|
|
428
437
|
},
|
|
429
438
|
|
|
430
439
|
/** @param {{ setUpstream?: boolean }} [opts] */
|
|
431
|
-
async gitPush(opts) {
|
|
440
|
+
async gitPush(opts?: { setUpstream?: boolean }) {
|
|
432
441
|
const res = await fetch("/__studio/git/push", {
|
|
433
442
|
method: "POST",
|
|
434
443
|
headers: { "Content-Type": "application/json" },
|
|
@@ -451,7 +460,7 @@ export function createDevServerPlatform() {
|
|
|
451
460
|
},
|
|
452
461
|
|
|
453
462
|
/** @param {string} branch */
|
|
454
|
-
async gitCheckout(branch) {
|
|
463
|
+
async gitCheckout(branch: string) {
|
|
455
464
|
const res = await fetch("/__studio/git/checkout", {
|
|
456
465
|
method: "POST",
|
|
457
466
|
headers: { "Content-Type": "application/json" },
|
|
@@ -462,7 +471,7 @@ export function createDevServerPlatform() {
|
|
|
462
471
|
},
|
|
463
472
|
|
|
464
473
|
/** @param {string} name */
|
|
465
|
-
async gitCreateBranch(name) {
|
|
474
|
+
async gitCreateBranch(name: string) {
|
|
466
475
|
const res = await fetch("/__studio/git/create-branch", {
|
|
467
476
|
method: "POST",
|
|
468
477
|
headers: { "Content-Type": "application/json" },
|
|
@@ -473,14 +482,14 @@ export function createDevServerPlatform() {
|
|
|
473
482
|
},
|
|
474
483
|
|
|
475
484
|
/** @param {string} path */
|
|
476
|
-
async gitDiff(path) {
|
|
485
|
+
async gitDiff(path: string) {
|
|
477
486
|
const res = await fetch(`/__studio/git/diff?path=${encodeURIComponent(path)}`);
|
|
478
487
|
if (!res.ok) throw new Error(await res.text());
|
|
479
488
|
return await res.json();
|
|
480
489
|
},
|
|
481
490
|
|
|
482
491
|
/** @param {{ path: string; ref?: string }} opts */
|
|
483
|
-
async gitShow(opts) {
|
|
492
|
+
async gitShow(opts: { path: string; ref?: string }) {
|
|
484
493
|
const params = new URLSearchParams({ path: opts.path });
|
|
485
494
|
if (opts.ref) params.set("ref", opts.ref);
|
|
486
495
|
const res = await fetch(`/__studio/git/show?${params}`);
|
|
@@ -490,7 +499,7 @@ export function createDevServerPlatform() {
|
|
|
490
499
|
},
|
|
491
500
|
|
|
492
501
|
/** @param {string[]} files */
|
|
493
|
-
async gitDiscard(files) {
|
|
502
|
+
async gitDiscard(files: string[]) {
|
|
494
503
|
const res = await fetch("/__studio/git/discard", {
|
|
495
504
|
method: "POST",
|
|
496
505
|
headers: { "Content-Type": "application/json" },
|
|
@@ -501,7 +510,7 @@ export function createDevServerPlatform() {
|
|
|
501
510
|
},
|
|
502
511
|
|
|
503
512
|
/** @param {string} url */
|
|
504
|
-
async gitClone(url) {
|
|
513
|
+
async gitClone(url: string) {
|
|
505
514
|
const res = await fetch("/__studio/git/clone", {
|
|
506
515
|
method: "POST",
|
|
507
516
|
headers: { "Content-Type": "application/json" },
|
|
@@ -520,7 +529,7 @@ export function createDevServerPlatform() {
|
|
|
520
529
|
* @param {string} name
|
|
521
530
|
* @param {string} url
|
|
522
531
|
*/
|
|
523
|
-
async gitAddRemote(name, url) {
|
|
532
|
+
async gitAddRemote(name: string, url: string) {
|
|
524
533
|
const res = await fetch("/__studio/git/add-remote", {
|
|
525
534
|
method: "POST",
|
|
526
535
|
headers: { "Content-Type": "application/json" },
|
|
@@ -537,7 +546,7 @@ export function createDevServerPlatform() {
|
|
|
537
546
|
},
|
|
538
547
|
|
|
539
548
|
/** @param {{ message: string; systemPrompt?: string }} opts */
|
|
540
|
-
async aiCreateSession(opts) {
|
|
549
|
+
async aiCreateSession(opts: { message: string; systemPrompt?: string }) {
|
|
541
550
|
const res = await fetch("/__studio/ai/session", {
|
|
542
551
|
method: "POST",
|
|
543
552
|
headers: { "Content-Type": "application/json" },
|
|
@@ -548,7 +557,7 @@ export function createDevServerPlatform() {
|
|
|
548
557
|
},
|
|
549
558
|
|
|
550
559
|
/** @param {string} id @param {string} message */
|
|
551
|
-
async aiSendMessage(id, message) {
|
|
560
|
+
async aiSendMessage(id: string, message: string) {
|
|
552
561
|
const res = await fetch(`/__studio/ai/session/${id}/message`, {
|
|
553
562
|
method: "POST",
|
|
554
563
|
headers: { "Content-Type": "application/json" },
|
|
@@ -559,17 +568,17 @@ export function createDevServerPlatform() {
|
|
|
559
568
|
},
|
|
560
569
|
|
|
561
570
|
/** @param {string} id */
|
|
562
|
-
aiStreamUrl(id) {
|
|
571
|
+
aiStreamUrl(id: string) {
|
|
563
572
|
return `/__studio/ai/session/${id}/stream`;
|
|
564
573
|
},
|
|
565
574
|
|
|
566
575
|
/** @param {string} id */
|
|
567
|
-
async aiStopSession(id) {
|
|
576
|
+
async aiStopSession(id: string) {
|
|
568
577
|
await fetch(`/__studio/ai/session/${id}/stop`, { method: "POST" });
|
|
569
578
|
},
|
|
570
579
|
|
|
571
580
|
/** @param {string} id */
|
|
572
|
-
async aiDeleteSession(id) {
|
|
581
|
+
async aiDeleteSession(id: string) {
|
|
573
582
|
await fetch(`/__studio/ai/session/${id}`, { method: "DELETE" });
|
|
574
583
|
},
|
|
575
584
|
};
|