@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,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
import { toRaw } from "../reactivity";
|
|
3
|
+
import { getNodeAtPath, parentElementPath, childIndex, pathsEqual, isAncestor } from "../state";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* @typedef {string | number | boolean | object | null | undefined} JsonValue
|
|
10
|
-
*/
|
|
5
|
+
import type { Tab } from "../tabs/tab";
|
|
6
|
+
import type { JxPath } from "../state";
|
|
7
|
+
|
|
8
|
+
import type { JsonValue } from "../types";
|
|
9
|
+
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
11
10
|
|
|
12
11
|
const HISTORY_LIMIT = 100;
|
|
13
12
|
|
|
@@ -21,7 +20,11 @@ const HISTORY_LIMIT = 100;
|
|
|
21
20
|
* @param {(tab: Tab) => void} mutationFn
|
|
22
21
|
* @param {{ skipHistory?: boolean }} [opts]
|
|
23
22
|
*/
|
|
24
|
-
export function transactDoc(
|
|
23
|
+
export function transactDoc(
|
|
24
|
+
tab: Tab | null,
|
|
25
|
+
mutationFn: (tab: Tab) => void,
|
|
26
|
+
{ skipHistory = false }: { skipHistory?: boolean } = {},
|
|
27
|
+
) {
|
|
25
28
|
if (!tab) return;
|
|
26
29
|
mutationFn(tab);
|
|
27
30
|
|
|
@@ -52,14 +55,18 @@ export function transactDoc(tab, mutationFn, { skipHistory = false } = {}) {
|
|
|
52
55
|
* @param {(doc: JxMutableNode) => void} fn
|
|
53
56
|
* @param {{ skipHistory?: boolean }} [opts]
|
|
54
57
|
*/
|
|
55
|
-
export function transact(
|
|
58
|
+
export function transact(
|
|
59
|
+
tab: Tab | null,
|
|
60
|
+
fn: (doc: JxMutableNode) => void,
|
|
61
|
+
opts?: { skipHistory?: boolean },
|
|
62
|
+
) {
|
|
56
63
|
transactDoc(tab, (t) => fn(t.doc.document), opts);
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
// ─── Undo / Redo ─────────────────────────────────────────────────────────────
|
|
60
67
|
|
|
61
68
|
/** @param {Tab} tab */
|
|
62
|
-
export function undo(tab) {
|
|
69
|
+
export function undo(tab: Tab) {
|
|
63
70
|
if (tab.history.index <= 0) return;
|
|
64
71
|
tab.history.index--;
|
|
65
72
|
const snap = tab.history.snapshots[tab.history.index];
|
|
@@ -69,7 +76,7 @@ export function undo(tab) {
|
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
/** @param {Tab} tab */
|
|
72
|
-
export function redo(tab) {
|
|
79
|
+
export function redo(tab: Tab) {
|
|
73
80
|
if (tab.history.index >= tab.history.snapshots.length - 1) return;
|
|
74
81
|
tab.history.index++;
|
|
75
82
|
const snap = tab.history.snapshots[tab.history.index];
|
|
@@ -86,7 +93,12 @@ export function redo(tab) {
|
|
|
86
93
|
* @param {number} index
|
|
87
94
|
* @param {JxMutableNode} nodeDef
|
|
88
95
|
*/
|
|
89
|
-
export function mutateInsertNode(
|
|
96
|
+
export function mutateInsertNode(
|
|
97
|
+
tab: Tab,
|
|
98
|
+
parentPath: JxPath,
|
|
99
|
+
index: number,
|
|
100
|
+
nodeDef: JxMutableNode,
|
|
101
|
+
) {
|
|
90
102
|
const parent = getNodeAtPath(tab.doc.document, parentPath);
|
|
91
103
|
if (!parent.children) parent.children = [];
|
|
92
104
|
parent.children.splice(index, 0, structuredClone(nodeDef));
|
|
@@ -96,14 +108,11 @@ export function mutateInsertNode(tab, parentPath, index, nodeDef) {
|
|
|
96
108
|
* @param {Tab} tab
|
|
97
109
|
* @param {JxPath} path
|
|
98
110
|
*/
|
|
99
|
-
export function mutateRemoveNode(tab, path) {
|
|
111
|
+
export function mutateRemoveNode(tab: Tab, path: JxPath) {
|
|
100
112
|
if (!path || path.length < 2) return;
|
|
101
|
-
const elemPath =
|
|
102
|
-
const idx =
|
|
103
|
-
|
|
104
|
-
idx,
|
|
105
|
-
1,
|
|
106
|
-
);
|
|
113
|
+
const elemPath = parentElementPath(path) as JxPath;
|
|
114
|
+
const idx = childIndex(path) as number;
|
|
115
|
+
(getNodeAtPath(tab.doc.document, elemPath).children as JxMutableNode[]).splice(idx, 1);
|
|
107
116
|
if (tab.session.selection && isAncestor(path, tab.session.selection)) {
|
|
108
117
|
tab.session.selection = null;
|
|
109
118
|
}
|
|
@@ -113,18 +122,14 @@ export function mutateRemoveNode(tab, path) {
|
|
|
113
122
|
* @param {Tab} tab
|
|
114
123
|
* @param {JxPath} path
|
|
115
124
|
*/
|
|
116
|
-
export function mutateDuplicateNode(tab, path) {
|
|
125
|
+
export function mutateDuplicateNode(tab: Tab, path: JxPath) {
|
|
117
126
|
if (!path || path.length < 2) return;
|
|
118
127
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
119
128
|
if (!node) return;
|
|
120
|
-
const elemPath =
|
|
121
|
-
const idx =
|
|
129
|
+
const elemPath = parentElementPath(path) as JxPath;
|
|
130
|
+
const idx = childIndex(path) as number;
|
|
122
131
|
const clone = structuredClone(toRaw(node));
|
|
123
|
-
|
|
124
|
-
idx + 1,
|
|
125
|
-
0,
|
|
126
|
-
clone,
|
|
127
|
-
);
|
|
132
|
+
(getNodeAtPath(tab.doc.document, elemPath).children as JxMutableNode[]).splice(idx + 1, 0, clone);
|
|
128
133
|
tab.session.selection = [...elemPath, "children", idx + 1];
|
|
129
134
|
}
|
|
130
135
|
|
|
@@ -133,18 +138,14 @@ export function mutateDuplicateNode(tab, path) {
|
|
|
133
138
|
* @param {JxPath} path
|
|
134
139
|
* @param {string} wrapperTag
|
|
135
140
|
*/
|
|
136
|
-
export function mutateWrapNode(tab, path, wrapperTag = "div") {
|
|
141
|
+
export function mutateWrapNode(tab: Tab, path: JxPath, wrapperTag: string = "div") {
|
|
137
142
|
if (!path || path.length < 2) return;
|
|
138
143
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
139
144
|
if (!node) return;
|
|
140
|
-
const elemPath =
|
|
141
|
-
const idx =
|
|
145
|
+
const elemPath = parentElementPath(path) as JxPath;
|
|
146
|
+
const idx = childIndex(path) as number;
|
|
142
147
|
const wrapper = { tagName: wrapperTag, children: [structuredClone(toRaw(node))] };
|
|
143
|
-
|
|
144
|
-
idx,
|
|
145
|
-
1,
|
|
146
|
-
wrapper,
|
|
147
|
-
);
|
|
148
|
+
(getNodeAtPath(tab.doc.document, elemPath).children as JxMutableNode[]).splice(idx, 1, wrapper);
|
|
148
149
|
tab.session.selection = [...elemPath, "children", idx];
|
|
149
150
|
}
|
|
150
151
|
|
|
@@ -154,12 +155,12 @@ export function mutateWrapNode(tab, path, wrapperTag = "div") {
|
|
|
154
155
|
* @param {JxPath} toParentPath
|
|
155
156
|
* @param {number} toIndex
|
|
156
157
|
*/
|
|
157
|
-
export function mutateMoveNode(tab, fromPath, toParentPath, toIndex) {
|
|
158
|
+
export function mutateMoveNode(tab: Tab, fromPath: JxPath, toParentPath: JxPath, toIndex: number) {
|
|
158
159
|
const doc = tab.doc.document;
|
|
159
|
-
const fromParentPath =
|
|
160
|
-
const fromIdx =
|
|
160
|
+
const fromParentPath = parentElementPath(fromPath) as JxPath;
|
|
161
|
+
const fromIdx = childIndex(fromPath) as number;
|
|
161
162
|
const fromParent = getNodeAtPath(doc, fromParentPath);
|
|
162
|
-
const [node] =
|
|
163
|
+
const [node] = (fromParent.children as JxMutableNode[]).splice(fromIdx, 1);
|
|
163
164
|
const toParent = getNodeAtPath(doc, toParentPath);
|
|
164
165
|
if (!toParent.children) toParent.children = [];
|
|
165
166
|
let adjustedIndex = toIndex;
|
|
@@ -185,7 +186,7 @@ export function mutateMoveNode(tab, fromPath, toParentPath, toIndex) {
|
|
|
185
186
|
* @param {string} key
|
|
186
187
|
* @param {JsonValue} value
|
|
187
188
|
*/
|
|
188
|
-
export function mutateUpdateProperty(tab, path, key, value) {
|
|
189
|
+
export function mutateUpdateProperty(tab: Tab, path: JxPath, key: string, value: JsonValue) {
|
|
189
190
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
190
191
|
if (value === undefined || value === null || value === "") delete node[key];
|
|
191
192
|
else node[key] = value;
|
|
@@ -197,7 +198,7 @@ export function mutateUpdateProperty(tab, path, key, value) {
|
|
|
197
198
|
* @param {string} prop
|
|
198
199
|
* @param {string | undefined} value
|
|
199
200
|
*/
|
|
200
|
-
export function mutateUpdateStyle(tab, path, prop, value) {
|
|
201
|
+
export function mutateUpdateStyle(tab: Tab, path: JxPath, prop: string, value: string | undefined) {
|
|
201
202
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
202
203
|
if (!node.style) node.style = {};
|
|
203
204
|
if (value === undefined || value === "") delete node.style[prop];
|
|
@@ -211,7 +212,12 @@ export function mutateUpdateStyle(tab, path, prop, value) {
|
|
|
211
212
|
* @param {string} attr
|
|
212
213
|
* @param {string | undefined} value
|
|
213
214
|
*/
|
|
214
|
-
export function mutateUpdateAttribute(
|
|
215
|
+
export function mutateUpdateAttribute(
|
|
216
|
+
tab: Tab,
|
|
217
|
+
path: JxPath,
|
|
218
|
+
attr: string,
|
|
219
|
+
value: string | undefined,
|
|
220
|
+
) {
|
|
215
221
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
216
222
|
if (!node.attributes) node.attributes = {};
|
|
217
223
|
if (value === undefined || value === "") delete node.attributes[attr];
|
|
@@ -226,7 +232,13 @@ export function mutateUpdateAttribute(tab, path, attr, value) {
|
|
|
226
232
|
* @param {string} prop
|
|
227
233
|
* @param {string | undefined} value
|
|
228
234
|
*/
|
|
229
|
-
export function mutateUpdateMediaStyle(
|
|
235
|
+
export function mutateUpdateMediaStyle(
|
|
236
|
+
tab: Tab,
|
|
237
|
+
path: JxPath,
|
|
238
|
+
mediaName: string,
|
|
239
|
+
prop: string,
|
|
240
|
+
value: string | undefined,
|
|
241
|
+
) {
|
|
230
242
|
if (!mediaName) return mutateUpdateStyle(tab, path, prop, value);
|
|
231
243
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
232
244
|
if (!node.style) node.style = {};
|
|
@@ -248,7 +260,13 @@ export function mutateUpdateMediaStyle(tab, path, mediaName, prop, value) {
|
|
|
248
260
|
* @param {string} prop
|
|
249
261
|
* @param {string | undefined} value
|
|
250
262
|
*/
|
|
251
|
-
export function mutateUpdateNestedStyle(
|
|
263
|
+
export function mutateUpdateNestedStyle(
|
|
264
|
+
tab: Tab,
|
|
265
|
+
path: JxPath,
|
|
266
|
+
selector: string,
|
|
267
|
+
prop: string,
|
|
268
|
+
value: string | undefined,
|
|
269
|
+
) {
|
|
252
270
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
253
271
|
if (!node.style) node.style = {};
|
|
254
272
|
if (!node.style[selector]) node.style[selector] = {};
|
|
@@ -269,7 +287,14 @@ export function mutateUpdateNestedStyle(tab, path, selector, prop, value) {
|
|
|
269
287
|
* @param {string} prop
|
|
270
288
|
* @param {string | undefined} value
|
|
271
289
|
*/
|
|
272
|
-
export function mutateUpdateMediaNestedStyle(
|
|
290
|
+
export function mutateUpdateMediaNestedStyle(
|
|
291
|
+
tab: Tab,
|
|
292
|
+
path: JxPath,
|
|
293
|
+
mediaName: string,
|
|
294
|
+
selector: string,
|
|
295
|
+
prop: string,
|
|
296
|
+
value: string | undefined,
|
|
297
|
+
) {
|
|
273
298
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
274
299
|
if (!node.style) node.style = {};
|
|
275
300
|
const key = `@${mediaName}`;
|
|
@@ -295,7 +320,13 @@ export function mutateUpdateMediaNestedStyle(tab, path, mediaName, selector, pro
|
|
|
295
320
|
* @param {string} prop
|
|
296
321
|
* @param {string | undefined} value
|
|
297
322
|
*/
|
|
298
|
-
export function mutateUpdateNestedStylePath(
|
|
323
|
+
export function mutateUpdateNestedStylePath(
|
|
324
|
+
tab: Tab,
|
|
325
|
+
path: JxPath,
|
|
326
|
+
stylePath: string[],
|
|
327
|
+
prop: string,
|
|
328
|
+
value: string | undefined,
|
|
329
|
+
) {
|
|
299
330
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
300
331
|
if (!node.style) node.style = {};
|
|
301
332
|
let obj = node.style;
|
|
@@ -331,7 +362,14 @@ export function mutateUpdateNestedStylePath(tab, path, stylePath, prop, value) {
|
|
|
331
362
|
* @param {string} prop
|
|
332
363
|
* @param {string | undefined} value
|
|
333
364
|
*/
|
|
334
|
-
export function mutateUpdateMediaNestedStylePath(
|
|
365
|
+
export function mutateUpdateMediaNestedStylePath(
|
|
366
|
+
tab: Tab,
|
|
367
|
+
path: JxPath,
|
|
368
|
+
mediaName: string,
|
|
369
|
+
stylePath: string[],
|
|
370
|
+
prop: string,
|
|
371
|
+
value: string | undefined,
|
|
372
|
+
) {
|
|
335
373
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
336
374
|
if (!node.style) node.style = {};
|
|
337
375
|
const key = `@${mediaName}`;
|
|
@@ -364,7 +402,11 @@ export function mutateUpdateMediaNestedStylePath(tab, path, mediaName, stylePath
|
|
|
364
402
|
* @param {JxPath} path
|
|
365
403
|
* @param {Record<string, string | undefined> | undefined} style
|
|
366
404
|
*/
|
|
367
|
-
export function mutateReplaceStyle(
|
|
405
|
+
export function mutateReplaceStyle(
|
|
406
|
+
tab: Tab,
|
|
407
|
+
path: JxPath,
|
|
408
|
+
style: Record<string, string | undefined> | undefined,
|
|
409
|
+
) {
|
|
368
410
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
369
411
|
if (style && Object.keys(style).length > 0) {
|
|
370
412
|
node.style = style;
|
|
@@ -378,7 +420,7 @@ export function mutateReplaceStyle(tab, path, style) {
|
|
|
378
420
|
* @param {string} name
|
|
379
421
|
* @param {Record<string, JsonValue>} def
|
|
380
422
|
*/
|
|
381
|
-
export function mutateAddDef(tab, name, def) {
|
|
423
|
+
export function mutateAddDef(tab: Tab, name: string, def: Record<string, JsonValue>) {
|
|
382
424
|
const doc = tab.doc.document;
|
|
383
425
|
if (!doc.state) doc.state = {};
|
|
384
426
|
doc.state[name] = def;
|
|
@@ -388,7 +430,7 @@ export function mutateAddDef(tab, name, def) {
|
|
|
388
430
|
* @param {Tab} tab
|
|
389
431
|
* @param {string} name
|
|
390
432
|
*/
|
|
391
|
-
export function mutateRemoveDef(tab, name) {
|
|
433
|
+
export function mutateRemoveDef(tab: Tab, name: string) {
|
|
392
434
|
const doc = tab.doc.document;
|
|
393
435
|
if (doc.state) {
|
|
394
436
|
delete doc.state[name];
|
|
@@ -401,7 +443,7 @@ export function mutateRemoveDef(tab, name) {
|
|
|
401
443
|
* @param {string} name
|
|
402
444
|
* @param {Record<string, JsonValue>} updates
|
|
403
445
|
*/
|
|
404
|
-
export function mutateUpdateDef(tab, name, updates) {
|
|
446
|
+
export function mutateUpdateDef(tab: Tab, name: string, updates: Record<string, JsonValue>) {
|
|
405
447
|
const doc = tab.doc.document;
|
|
406
448
|
if (!doc.state) doc.state = {};
|
|
407
449
|
if (doc.state[name] == null) {
|
|
@@ -422,7 +464,7 @@ export function mutateUpdateDef(tab, name, updates) {
|
|
|
422
464
|
* @param {string} oldName
|
|
423
465
|
* @param {string} newName
|
|
424
466
|
*/
|
|
425
|
-
export function mutateRenameDef(tab, oldName, newName) {
|
|
467
|
+
export function mutateRenameDef(tab: Tab, oldName: string, newName: string) {
|
|
426
468
|
const doc = tab.doc.document;
|
|
427
469
|
if (!doc.state || !doc.state[oldName]) return;
|
|
428
470
|
doc.state[newName] = doc.state[oldName];
|
|
@@ -434,7 +476,7 @@ export function mutateRenameDef(tab, oldName, newName) {
|
|
|
434
476
|
* @param {string} name
|
|
435
477
|
* @param {string | undefined} query
|
|
436
478
|
*/
|
|
437
|
-
export function mutateUpdateMedia(tab, name, query) {
|
|
479
|
+
export function mutateUpdateMedia(tab: Tab, name: string, query: string | undefined) {
|
|
438
480
|
const doc = tab.doc.document;
|
|
439
481
|
if (!doc.$media) doc.$media = {};
|
|
440
482
|
if (query === undefined || query === "") {
|
|
@@ -451,7 +493,7 @@ export function mutateUpdateMedia(tab, name, query) {
|
|
|
451
493
|
* @param {string} propName
|
|
452
494
|
* @param {JsonValue} value
|
|
453
495
|
*/
|
|
454
|
-
export function mutateUpdateProp(tab, path, propName, value) {
|
|
496
|
+
export function mutateUpdateProp(tab: Tab, path: JxPath, propName: string, value: JsonValue) {
|
|
455
497
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
456
498
|
if (!node.$props) node.$props = {};
|
|
457
499
|
if (value === undefined || value === null || value === "") delete node.$props[propName];
|
|
@@ -465,7 +507,12 @@ export function mutateUpdateProp(tab, path, propName, value) {
|
|
|
465
507
|
* @param {string} caseName
|
|
466
508
|
* @param {JxMutableNode} [caseDef]
|
|
467
509
|
*/
|
|
468
|
-
export function mutateAddSwitchCase(
|
|
510
|
+
export function mutateAddSwitchCase(
|
|
511
|
+
tab: Tab,
|
|
512
|
+
path: JxPath,
|
|
513
|
+
caseName: string,
|
|
514
|
+
caseDef?: JxMutableNode,
|
|
515
|
+
) {
|
|
469
516
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
470
517
|
if (!node.cases) node.cases = {};
|
|
471
518
|
node.cases[caseName] = caseDef || { tagName: "div", textContent: caseName };
|
|
@@ -476,7 +523,7 @@ export function mutateAddSwitchCase(tab, path, caseName, caseDef) {
|
|
|
476
523
|
* @param {JxPath} path
|
|
477
524
|
* @param {string} caseName
|
|
478
525
|
*/
|
|
479
|
-
export function mutateRemoveSwitchCase(tab, path, caseName) {
|
|
526
|
+
export function mutateRemoveSwitchCase(tab: Tab, path: JxPath, caseName: string) {
|
|
480
527
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
481
528
|
if (node.cases) delete node.cases[caseName];
|
|
482
529
|
}
|
|
@@ -487,7 +534,7 @@ export function mutateRemoveSwitchCase(tab, path, caseName) {
|
|
|
487
534
|
* @param {string} oldName
|
|
488
535
|
* @param {string} newName
|
|
489
536
|
*/
|
|
490
|
-
export function mutateRenameSwitchCase(tab, path, oldName, newName) {
|
|
537
|
+
export function mutateRenameSwitchCase(tab: Tab, path: JxPath, oldName: string, newName: string) {
|
|
491
538
|
const node = getNodeAtPath(tab.doc.document, path);
|
|
492
539
|
if (!node.cases || !node.cases[oldName]) return;
|
|
493
540
|
node.cases[newName] = node.cases[oldName];
|
|
@@ -503,7 +550,7 @@ export function mutateRenameSwitchCase(tab, path, oldName, newName) {
|
|
|
503
550
|
* @param {string} field
|
|
504
551
|
* @param {JsonValue} value
|
|
505
552
|
*/
|
|
506
|
-
export function mutateUpdateFrontmatter(tab, field, value) {
|
|
553
|
+
export function mutateUpdateFrontmatter(tab: Tab, field: string, value: JsonValue) {
|
|
507
554
|
if (value === undefined || value === null || value === "") {
|
|
508
555
|
delete tab.doc.content.frontmatter[field];
|
|
509
556
|
} else {
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
import type { JxMutableNode, JxPath, ProjectConfig } from "@jxsuite/schema/types";
|
|
3
|
+
|
|
4
|
+
// ─── Git & Platform Types ───────────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
export interface GitFileStatus {
|
|
7
|
+
status: string;
|
|
8
|
+
path: string;
|
|
9
|
+
staged?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface GitStatusResult {
|
|
13
|
+
branch: string;
|
|
14
|
+
files: GitFileStatus[];
|
|
15
|
+
ahead: number;
|
|
16
|
+
behind: number;
|
|
17
|
+
isRepo: boolean;
|
|
18
|
+
remotes: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface GitBranchesResult {
|
|
22
|
+
current: string;
|
|
23
|
+
branches: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface GitLogEntry {
|
|
27
|
+
hash: string;
|
|
28
|
+
message: string;
|
|
29
|
+
author: string;
|
|
30
|
+
date: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ComponentMeta {
|
|
34
|
+
tagName: string;
|
|
35
|
+
$id?: string | null;
|
|
36
|
+
path: string;
|
|
37
|
+
props?: { name: string; type?: string; default?: unknown }[];
|
|
38
|
+
hasElements?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface PackageInfo {
|
|
42
|
+
name: string;
|
|
43
|
+
version: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface CodeServiceResult {
|
|
47
|
+
code?: string;
|
|
48
|
+
diagnostics?: unknown[];
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface DirEntry {
|
|
53
|
+
name: string;
|
|
54
|
+
path: string;
|
|
55
|
+
type: "file" | "directory";
|
|
56
|
+
size?: number;
|
|
57
|
+
modified?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface StudioPlatform {
|
|
61
|
+
id: string;
|
|
62
|
+
projectRoot: string;
|
|
63
|
+
activate(root?: string): Promise<void>;
|
|
64
|
+
openProject(): Promise<{
|
|
65
|
+
config: ProjectConfig;
|
|
66
|
+
handle: { root: string; name: string; projectConfig: ProjectConfig };
|
|
67
|
+
} | null>;
|
|
68
|
+
probeRootProject(): Promise<{
|
|
69
|
+
meta: { root: string; name: string };
|
|
70
|
+
info: { isSiteProject: boolean; projectConfig?: ProjectConfig | null; directories?: string[] };
|
|
71
|
+
} | null>;
|
|
72
|
+
listDirectory(dir: string): Promise<DirEntry[]>;
|
|
73
|
+
readFile(path: string): Promise<string>;
|
|
74
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
75
|
+
uploadFile(path: string, data: string | File | Blob | ArrayBuffer): Promise<unknown>;
|
|
76
|
+
deleteFile(path: string): Promise<void>;
|
|
77
|
+
renameFile(from: string, to: string): Promise<void>;
|
|
78
|
+
createDirectory(path: string): Promise<void>;
|
|
79
|
+
discoverComponents(dir?: string): Promise<ComponentMeta[]>;
|
|
80
|
+
addPackage(name: string): Promise<unknown>;
|
|
81
|
+
removePackage(name: string): Promise<unknown>;
|
|
82
|
+
listPackages(): Promise<PackageInfo[]>;
|
|
83
|
+
codeService(action: string, payload: unknown): Promise<CodeServiceResult | null>;
|
|
84
|
+
resolveSiteContext(
|
|
85
|
+
filePath: string,
|
|
86
|
+
): Promise<{ sitePath: string | null; projectConfig?: ProjectConfig; fileRelPath?: string }>;
|
|
87
|
+
locateFile(name: string): Promise<string | null>;
|
|
88
|
+
searchFiles(query: string): Promise<DirEntry[]>;
|
|
89
|
+
fetchPluginSchema(src: string, prototype?: string, base?: string): Promise<unknown>;
|
|
90
|
+
gitStatus(): Promise<GitStatusResult>;
|
|
91
|
+
gitBranches(): Promise<GitBranchesResult>;
|
|
92
|
+
gitLog(limit?: number): Promise<GitLogEntry[]>;
|
|
93
|
+
gitStage(files: string[]): Promise<void>;
|
|
94
|
+
gitUnstage(files: string[]): Promise<void>;
|
|
95
|
+
gitCommit(message: string): Promise<void>;
|
|
96
|
+
gitPush(opts?: { setUpstream?: boolean }): Promise<void>;
|
|
97
|
+
gitPull(): Promise<void>;
|
|
98
|
+
gitFetch(): Promise<void>;
|
|
99
|
+
gitCheckout(branch: string): Promise<void>;
|
|
100
|
+
gitCreateBranch(name: string): Promise<void>;
|
|
101
|
+
gitDiff(path?: string): Promise<string>;
|
|
102
|
+
gitShow(opts: { path: string; ref?: string }): Promise<string>;
|
|
103
|
+
gitDiscard(files: string[]): Promise<void>;
|
|
104
|
+
gitClone?(url: string): Promise<{ ok: boolean; root: string }>;
|
|
105
|
+
gitInit(): Promise<void>;
|
|
106
|
+
gitAddRemote(name: string, url: string): Promise<void>;
|
|
107
|
+
createProject(opts: {
|
|
108
|
+
name: string;
|
|
109
|
+
description?: string;
|
|
110
|
+
url?: string;
|
|
111
|
+
adapter?: string;
|
|
112
|
+
directory: string;
|
|
113
|
+
}): Promise<{ root: string; config: ProjectConfig }>;
|
|
114
|
+
aiAuthStatus(): Promise<{ authenticated: boolean; error?: string }>;
|
|
115
|
+
aiCreateSession(opts: { message: string; systemPrompt?: string }): Promise<{ id: string }>;
|
|
116
|
+
aiSendMessage(id: string, message: string): Promise<void>;
|
|
117
|
+
aiStreamUrl(id: string): string | Promise<string>;
|
|
118
|
+
aiStopSession(id: string): Promise<void>;
|
|
119
|
+
aiDeleteSession(id: string): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ─── Studio Types ───────────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
export interface CanvasPanel {
|
|
125
|
+
mediaName: string;
|
|
126
|
+
element: HTMLElement;
|
|
127
|
+
canvas: HTMLElement;
|
|
128
|
+
overlay: HTMLElement;
|
|
129
|
+
overlayClk: HTMLElement;
|
|
130
|
+
viewport: HTMLElement;
|
|
131
|
+
scrollContainer: HTMLElement;
|
|
132
|
+
dropLine: HTMLElement;
|
|
133
|
+
_width: number | null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface DocumentStackEntry {
|
|
137
|
+
document: JxMutableNode;
|
|
138
|
+
documentPath: string | null;
|
|
139
|
+
selection: JxPath | null;
|
|
140
|
+
dirty?: boolean;
|
|
141
|
+
mode?: string;
|
|
142
|
+
sourceFormat?: string | null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface FunctionEditDef {
|
|
146
|
+
type: string;
|
|
147
|
+
defName?: string;
|
|
148
|
+
path?: JxPath;
|
|
149
|
+
eventKey?: string;
|
|
150
|
+
key?: string;
|
|
151
|
+
body?: string;
|
|
152
|
+
parameters?: string[];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface GitDiffState {
|
|
156
|
+
filePath: string;
|
|
157
|
+
originalContent: string;
|
|
158
|
+
currentContent: string;
|
|
159
|
+
isMarkdown: boolean;
|
|
160
|
+
fileStatus: string;
|
|
161
|
+
originalDoc?: unknown;
|
|
162
|
+
currentDoc?: unknown;
|
|
163
|
+
original?: unknown;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface InlineEditDef {
|
|
167
|
+
path: JxPath;
|
|
168
|
+
mediaName?: string;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface ProjectState {
|
|
172
|
+
root?: string;
|
|
173
|
+
name: string;
|
|
174
|
+
projectRoot: string;
|
|
175
|
+
isSiteProject: boolean;
|
|
176
|
+
projectConfig: ProjectConfig | null;
|
|
177
|
+
dirs: Map<string, DirEntry[]>;
|
|
178
|
+
expanded: Set<string>;
|
|
179
|
+
selectedPath: string | null;
|
|
180
|
+
searchQuery: string;
|
|
181
|
+
projectDirs?: string[];
|
|
182
|
+
[key: string]: unknown;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export type JsonValue = string | number | boolean | object | null | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Button-group.js — Action group + overflow picker widget.
|
|
3
4
|
*
|
|
@@ -7,8 +8,8 @@
|
|
|
7
8
|
|
|
8
9
|
import { html, nothing } from "lit-html";
|
|
9
10
|
import { classMap } from "lit-html/directives/class-map.js";
|
|
10
|
-
import { abbreviateValue, kebabToLabel } from "../utils/studio-utils
|
|
11
|
-
import icons from "./icons
|
|
11
|
+
import { abbreviateValue, kebabToLabel } from "../utils/studio-utils";
|
|
12
|
+
import icons from "./icons";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Render a button group widget with optional overflow menu.
|
|
@@ -20,30 +21,29 @@ import icons from "./icons.js";
|
|
|
20
21
|
* @returns {import("lit-html").TemplateResult}
|
|
21
22
|
*/
|
|
22
23
|
export function renderButtonGroup(
|
|
23
|
-
/** @type {Record<string, unknown>} */ entry,
|
|
24
|
-
/** @type {string} */ prop,
|
|
25
|
-
/** @type {string | number | undefined} */ value,
|
|
26
|
-
/** @type {(val: string) => void} */ onChange,
|
|
24
|
+
/** @type {Record<string, unknown>} */ entry: Record<string, unknown>,
|
|
25
|
+
/** @type {string} */ prop: string,
|
|
26
|
+
/** @type {string | number | undefined} */ value: string | number | undefined,
|
|
27
|
+
/** @type {(val: string) => void} */ onChange: (val: string) => void,
|
|
27
28
|
) {
|
|
28
|
-
const values =
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const enumValues = /** @type {string[] | undefined} */ (entry.enum);
|
|
29
|
+
const values = (entry.$buttonValues || entry.enum || []) as string[];
|
|
30
|
+
const iconMap: Record<string, string> = (entry.$icons || {}) as Record<string, string>;
|
|
31
|
+
const buttonValues = entry.$buttonValues as string[] | undefined;
|
|
32
|
+
const enumValues = entry.enum as string[] | undefined;
|
|
33
33
|
const extra =
|
|
34
34
|
buttonValues && enumValues && enumValues.length > buttonValues.length
|
|
35
|
-
? enumValues.filter((
|
|
35
|
+
? enumValues.filter((v: string) => !buttonValues.includes(v))
|
|
36
36
|
: [];
|
|
37
37
|
|
|
38
38
|
const menuId = `style-btngrp-${prop}`;
|
|
39
39
|
const hasExtra = extra.length > 0;
|
|
40
|
-
const extraSelected = hasExtra && extra.includes(
|
|
40
|
+
const extraSelected = hasExtra && extra.includes(String(value));
|
|
41
41
|
|
|
42
42
|
return html`
|
|
43
43
|
<div class=${classMap({ "button-group-combo": true, "has-overflow": hasExtra })}>
|
|
44
44
|
<sp-action-group size="s" compact>
|
|
45
45
|
${values.map(
|
|
46
|
-
(
|
|
46
|
+
(v: string) => html`
|
|
47
47
|
<sp-action-button
|
|
48
48
|
size="s"
|
|
49
49
|
value=${v}
|
|
@@ -51,8 +51,8 @@ export function renderButtonGroup(
|
|
|
51
51
|
?selected=${v === value}
|
|
52
52
|
@click=${() => onChange(v === value ? "" : v)}
|
|
53
53
|
>
|
|
54
|
-
${iconMap[v] &&
|
|
55
|
-
?
|
|
54
|
+
${iconMap[v] && (icons as Record<string, unknown>)[iconMap[v]]
|
|
55
|
+
? (icons as Record<string, unknown>)[iconMap[v]]
|
|
56
56
|
: abbreviateValue(v)}
|
|
57
57
|
</sp-action-button>
|
|
58
58
|
`,
|
|
@@ -68,16 +68,16 @@ export function renderButtonGroup(
|
|
|
68
68
|
<sp-overlay trigger="${menuId}@click" placement="bottom-end" type="auto">
|
|
69
69
|
<sp-popover>
|
|
70
70
|
<sp-menu
|
|
71
|
-
@change=${(
|
|
72
|
-
if (
|
|
73
|
-
onChange(
|
|
71
|
+
@change=${(e: Event) => {
|
|
72
|
+
if ((e.target as HTMLInputElement).value)
|
|
73
|
+
onChange((e.target as HTMLInputElement).value);
|
|
74
74
|
}}
|
|
75
75
|
>
|
|
76
76
|
<sp-menu-item value="__none__">—</sp-menu-item>
|
|
77
|
-
${extra.map((
|
|
77
|
+
${extra.map((v: string) => {
|
|
78
78
|
const label = v.includes("-")
|
|
79
79
|
? kebabToLabel(v)
|
|
80
|
-
: v.replace(/^./, (
|
|
80
|
+
: v.replace(/^./, (c: string) => c.toUpperCase());
|
|
81
81
|
return html`<sp-menu-item value=${v} ?selected=${v === value}
|
|
82
82
|
>${label}</sp-menu-item
|
|
83
83
|
>`;
|