@jxsuite/studio 0.19.0 → 0.20.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.css +98 -98
- package/dist/studio.js +12577 -12183
- package/dist/studio.js.map +146 -144
- package/dist/workers/editor.worker.js +79 -79
- package/dist/workers/json.worker.js +109 -109
- package/dist/workers/ts.worker.js +82 -82
- package/package.json +17 -6
- package/src/browse/browse.js +25 -19
- package/src/canvas/canvas-diff.js +24 -16
- package/src/canvas/canvas-helpers.js +24 -19
- package/src/canvas/canvas-live-render.js +94 -39
- package/src/canvas/canvas-render.js +119 -73
- package/src/canvas/canvas-utils.js +38 -15
- package/src/canvas/nested-site-style.js +50 -0
- package/src/editor/component-inline-edit.js +14 -13
- package/src/editor/content-inline-edit.js +22 -10
- package/src/editor/context-menu.js +1 -1
- package/src/editor/convert-to-component.js +12 -10
- package/src/editor/inline-edit.js +66 -28
- package/src/editor/insertion-helper.js +16 -12
- package/src/editor/shortcuts.js +4 -2
- package/src/editor/slash-menu.js +6 -4
- package/src/files/components.js +1 -1
- package/src/files/file-ops.js +37 -16
- package/src/files/files.js +78 -52
- package/src/github/github-auth.js +122 -0
- package/src/github/github-publish.js +115 -0
- package/src/markdown/md-convert.js +172 -107
- package/src/new-project/new-project-modal.js +204 -0
- package/src/panels/activity-bar.js +22 -20
- package/src/panels/ai-panel.js +399 -0
- package/src/panels/block-action-bar.js +5 -5
- package/src/panels/canvas-dnd.js +8 -2
- package/src/panels/data-explorer.js +19 -13
- package/src/panels/dnd.js +144 -92
- package/src/panels/editors.js +55 -35
- package/src/panels/elements-panel.js +33 -19
- package/src/panels/events-panel.js +15 -10
- package/src/panels/git-panel.js +469 -98
- package/src/panels/head-panel.js +121 -81
- package/src/panels/imports-panel.js +88 -64
- package/src/panels/layers-panel.js +64 -43
- package/src/panels/left-panel.js +85 -47
- package/src/panels/overlays.js +1 -0
- package/src/panels/panel-events.js +45 -30
- package/src/panels/preview-render.js +23 -18
- package/src/panels/properties-panel.js +365 -249
- package/src/panels/pseudo-preview.js +2 -2
- package/src/panels/quick-search.js +7 -5
- package/src/panels/right-panel.js +26 -2
- package/src/panels/shared.js +4 -4
- package/src/panels/signals-panel.js +295 -166
- package/src/panels/statusbar.js +4 -4
- package/src/panels/style-inputs.js +67 -35
- package/src/panels/style-panel.js +233 -132
- package/src/panels/style-utils.js +34 -16
- package/src/panels/stylebook-layers-panel.js +12 -10
- package/src/panels/stylebook-panel.js +134 -66
- package/src/panels/toolbar.js +333 -109
- package/src/panels/welcome-screen.js +121 -0
- package/src/platform.js +2 -4
- package/src/platforms/devserver.js +113 -7
- package/src/resize-edges.js +98 -0
- package/src/services/cem-export.js +12 -7
- package/src/services/code-services.js +30 -12
- package/src/settings/content-types-editor.js +7 -7
- package/src/settings/css-vars-editor.js +30 -24
- package/src/settings/defs-editor.js +12 -7
- package/src/settings/general-settings.js +85 -3
- package/src/settings/head-editor.js +30 -24
- package/src/settings/schema-field-ui.js +58 -39
- package/src/site-context.js +41 -31
- package/src/state.js +70 -29
- package/src/store.js +21 -26
- package/src/studio.js +103 -81
- package/src/tabs/tab.js +67 -43
- package/src/tabs/transact.js +23 -13
- package/src/ui/button-group.js +24 -24
- package/src/ui/color-selector.js +28 -23
- package/src/ui/field-row.js +3 -3
- package/src/ui/icons.js +2 -2
- package/src/ui/media-picker.js +7 -7
- package/src/ui/spectrum.js +5 -1
- package/src/ui/unit-selector.js +18 -16
- package/src/ui/value-selector.js +21 -15
- package/src/ui/widgets.js +22 -19
- package/src/utils/canvas-media.js +5 -4
- package/src/utils/edit-display.js +31 -20
- package/src/utils/google-fonts.js +11 -11
- package/src/utils/inherited-style.js +9 -8
- package/src/utils/studio-utils.js +7 -7
- package/src/view.js +58 -1
- package/src/workspace/workspace.js +10 -7
package/src/panels/statusbar.js
CHANGED
|
@@ -7,7 +7,7 @@ import { activeTab } from "../workspace/workspace.js";
|
|
|
7
7
|
// ─── Module state ────────────────────────────────────────────────────────────
|
|
8
8
|
|
|
9
9
|
let statusMsg = "";
|
|
10
|
-
/** @type {
|
|
10
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
11
11
|
let statusTimeout;
|
|
12
12
|
/** @type {(() => void) | null} */
|
|
13
13
|
let _rerender = null;
|
|
@@ -47,7 +47,7 @@ export function unmountStatusbar() {
|
|
|
47
47
|
|
|
48
48
|
// ─── Statusbar ───────────────────────────────────────────────────────────────
|
|
49
49
|
|
|
50
|
-
/** @param {
|
|
50
|
+
/** @param {string} text */
|
|
51
51
|
function esc(text) {
|
|
52
52
|
return String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
53
53
|
}
|
|
@@ -58,7 +58,7 @@ export function renderStatusbar() {
|
|
|
58
58
|
const parts = [];
|
|
59
59
|
if (tab?.doc.mode === "content") parts.push("Content Mode");
|
|
60
60
|
if (tab?.session.selection?.length) {
|
|
61
|
-
const sel = /** @type {
|
|
61
|
+
const sel = /** @type {JxPath} */ (tab.session.selection);
|
|
62
62
|
const node = getNodeAtPath(tab.doc.document, sel);
|
|
63
63
|
parts.push(`Selected: ${esc(nodeLabel(node))}`);
|
|
64
64
|
|
|
@@ -98,7 +98,7 @@ statusbarEl?.addEventListener("click", (e) => {
|
|
|
98
98
|
/**
|
|
99
99
|
* Show a temporary status message.
|
|
100
100
|
*
|
|
101
|
-
* @param {
|
|
101
|
+
* @param {string} msg
|
|
102
102
|
* @param {number} [duration]
|
|
103
103
|
*/
|
|
104
104
|
export function statusMessage(msg, duration = 3000) {
|
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
/**
|
|
19
19
|
* Dual-mode keyword input — shared by select (enum) and combobox (examples) widgets.
|
|
20
20
|
*
|
|
21
|
-
* @param {
|
|
21
|
+
* @param {string[]} options @param {string} prop @param {string} value @param {(value: string) =>
|
|
22
|
+
* void} onChange
|
|
22
23
|
*/
|
|
23
24
|
export function renderKeywordInput(options, prop, value, onChange) {
|
|
24
25
|
const cssInitialMap = getCssInitialMap();
|
|
@@ -26,10 +27,10 @@ export function renderKeywordInput(options, prop, value, onChange) {
|
|
|
26
27
|
const font = isTypoPreview ? currentFontFamily() : "";
|
|
27
28
|
const cssProp = isTypoPreview ? camelToKebab(prop) : "";
|
|
28
29
|
|
|
29
|
-
const comboOptions = options.map((/** @type {
|
|
30
|
+
const comboOptions = options.map((/** @type {string} */ v) => {
|
|
30
31
|
const label = v.includes("-")
|
|
31
32
|
? kebabToLabel(v)
|
|
32
|
-
: v.replace(/^./, (/** @type {
|
|
33
|
+
: v.replace(/^./, (/** @type {string} */ c) => c.toUpperCase());
|
|
33
34
|
const style = isTypoPreview ? `${cssProp}: ${v};${font ? ` font-family: ${font}` : ""}` : "";
|
|
34
35
|
return { value: v, label, style };
|
|
35
36
|
});
|
|
@@ -39,19 +40,23 @@ export function renderKeywordInput(options, prop, value, onChange) {
|
|
|
39
40
|
.value=${value || ""}
|
|
40
41
|
placeholder=${cssInitialMap.get(prop) || ""}
|
|
41
42
|
.options=${comboOptions}
|
|
42
|
-
@change=${(/** @type {
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
@change=${(/** @type {Event} */ e) =>
|
|
44
|
+
onChange(/** @type {HTMLInputElement} */ (e.target).value)}
|
|
45
|
+
@input=${debouncedStyleCommit(`kw:${prop}`, 400, (/** @type {Event} */ e) =>
|
|
46
|
+
onChange(/** @type {HTMLInputElement} */ (e.target).value),
|
|
45
47
|
)}
|
|
46
48
|
></jx-value-selector>`;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* @param {{ enum?: string[] }} entry @param {string} prop @param {string} value @param {(value:
|
|
53
|
+
* string) => void} onChange
|
|
54
|
+
*/
|
|
50
55
|
export function renderSelectInput(entry, prop, value, onChange) {
|
|
51
56
|
return renderKeywordInput(entry.enum || [], prop, value, onChange);
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
/** @param {
|
|
59
|
+
/** @param {{ title: string; value: string }} preset @param {(value: string) => void} onChange */
|
|
55
60
|
function handleFontPresetSelection(preset, onChange) {
|
|
56
61
|
const varName = friendlyNameToVar(preset.title, "--font-");
|
|
57
62
|
if (!activeTab.value?.doc.document?.style?.[varName]) {
|
|
@@ -60,12 +65,17 @@ function handleFontPresetSelection(preset, onChange) {
|
|
|
60
65
|
onChange(`var(${varName})`);
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* @param {string} val @param {{ title: string; value: string }[]} presets @param {(value: string)
|
|
70
|
+
* => void} onChange
|
|
71
|
+
*/
|
|
64
72
|
function handleFontSelection(val, presets, onChange) {
|
|
65
73
|
if (!val) return;
|
|
66
74
|
if (val.startsWith("__preset__:")) {
|
|
67
75
|
const title = val.slice("__preset__:".length);
|
|
68
|
-
const preset = presets.find(
|
|
76
|
+
const preset = presets.find(
|
|
77
|
+
(/** @type {{ title: string; value: string }} */ p) => p.title === title,
|
|
78
|
+
);
|
|
69
79
|
if (preset) handleFontPresetSelection(preset, onChange);
|
|
70
80
|
return;
|
|
71
81
|
}
|
|
@@ -73,14 +83,17 @@ function handleFontSelection(val, presets, onChange) {
|
|
|
73
83
|
onChange(`var(${val})`);
|
|
74
84
|
return;
|
|
75
85
|
}
|
|
76
|
-
const preset = presets.find(
|
|
86
|
+
const preset = presets.find(
|
|
87
|
+
(/** @type {{ title: string; value: string }} */ p) => p.title === val,
|
|
88
|
+
);
|
|
77
89
|
if (preset) {
|
|
78
90
|
handleFontPresetSelection(preset, onChange);
|
|
79
91
|
return;
|
|
80
92
|
}
|
|
81
93
|
const fontVars = getFontVars();
|
|
82
94
|
const matchedVar = fontVars.find(
|
|
83
|
-
(/** @type {
|
|
95
|
+
(/** @type {{ name: string; value: string }} */ fv) =>
|
|
96
|
+
varDisplayName(fv.name, "--font-") === val,
|
|
84
97
|
);
|
|
85
98
|
if (matchedVar) {
|
|
86
99
|
onChange(`var(${matchedVar.name})`);
|
|
@@ -92,19 +105,23 @@ function handleFontSelection(val, presets, onChange) {
|
|
|
92
105
|
/**
|
|
93
106
|
* Build font options array for jx-value-selector.
|
|
94
107
|
*
|
|
95
|
-
* @param {
|
|
96
|
-
*
|
|
108
|
+
* @param {{ name: string; value: string }[]} fontVars @param {{ title: string; value: string }[]}
|
|
109
|
+
* presets
|
|
110
|
+
* @returns {({ value: string; label: string; style: string } | { divider: true })[]}
|
|
97
111
|
*/
|
|
98
112
|
export function buildFontOptions(fontVars, presets) {
|
|
99
|
-
/** @type {
|
|
100
|
-
const opts = fontVars.map((/** @type {
|
|
113
|
+
/** @type {({ value: string; label: string; style: string } | { divider: true })[]} */
|
|
114
|
+
const opts = fontVars.map((/** @type {{ name: string; value: string }} */ fv) => ({
|
|
101
115
|
value: fv.name,
|
|
102
116
|
label: varDisplayName(fv.name, "--font-"),
|
|
103
117
|
style: `font-family: ${fv.value}`,
|
|
104
118
|
}));
|
|
105
119
|
const unadded = presets.filter(
|
|
106
|
-
(/** @type {
|
|
107
|
-
!fontVars.some(
|
|
120
|
+
(/** @type {{ title: string; value: string }} */ p) =>
|
|
121
|
+
!fontVars.some(
|
|
122
|
+
(/** @type {{ name: string; value: string }} */ fv) =>
|
|
123
|
+
fv.name === friendlyNameToVar(p.title, "--font-"),
|
|
124
|
+
),
|
|
108
125
|
);
|
|
109
126
|
if (unadded.length > 0 && opts.length > 0) opts.push({ divider: true });
|
|
110
127
|
for (const p of unadded) {
|
|
@@ -117,7 +134,14 @@ export function buildFontOptions(fontVars, presets) {
|
|
|
117
134
|
return opts;
|
|
118
135
|
}
|
|
119
136
|
|
|
120
|
-
/**
|
|
137
|
+
/**
|
|
138
|
+
* @param {{
|
|
139
|
+
* enum?: string[];
|
|
140
|
+
* examples?: string[];
|
|
141
|
+
* presets?: { title: string; value: string }[];
|
|
142
|
+
* }} entry
|
|
143
|
+
* @param {string} prop @param {string} value @param {(value: string) => void} onChange
|
|
144
|
+
*/
|
|
121
145
|
export function renderComboboxInput(entry, prop, value, onChange) {
|
|
122
146
|
const cssInitialMap = getCssInitialMap();
|
|
123
147
|
const fontVars = prop === "fontFamily" ? getFontVars() : [];
|
|
@@ -133,9 +157,10 @@ export function renderComboboxInput(entry, prop, value, onChange) {
|
|
|
133
157
|
.value=${comboValue}
|
|
134
158
|
placeholder=${cssInitialMap.get("fontFamily") || ""}
|
|
135
159
|
.options=${fontOptions}
|
|
136
|
-
@change=${(/** @type {
|
|
137
|
-
|
|
138
|
-
|
|
160
|
+
@change=${(/** @type {Event} */ e) =>
|
|
161
|
+
handleFontSelection(/** @type {HTMLInputElement} */ (e.target).value, presets, onChange)}
|
|
162
|
+
@input=${debouncedStyleCommit("combo:fontFamily", 400, (/** @type {Event} */ e) =>
|
|
163
|
+
onChange(/** @type {HTMLInputElement} */ (e.target).value),
|
|
139
164
|
)}
|
|
140
165
|
></jx-value-selector>`;
|
|
141
166
|
}
|
|
@@ -149,8 +174,8 @@ export function renderComboboxInput(entry, prop, value, onChange) {
|
|
|
149
174
|
size="s"
|
|
150
175
|
placeholder=${cssInitialMap.get(prop) || ""}
|
|
151
176
|
.value=${live(value || "")}
|
|
152
|
-
@input=${debouncedStyleCommit(`combo:${prop}`, 400, (/** @type {
|
|
153
|
-
onChange(e.target.value),
|
|
177
|
+
@input=${debouncedStyleCommit(`combo:${prop}`, 400, (/** @type {Event} */ e) =>
|
|
178
|
+
onChange(/** @type {HTMLInputElement} */ (e.target).value),
|
|
154
179
|
)}
|
|
155
180
|
></sp-textfield>
|
|
156
181
|
`;
|
|
@@ -161,17 +186,24 @@ export function renderComboboxInput(entry, prop, value, onChange) {
|
|
|
161
186
|
* inputs and CSS initial-value placeholders.
|
|
162
187
|
*/
|
|
163
188
|
export function widgetForType(
|
|
164
|
-
/** @type {
|
|
165
|
-
/** @type {
|
|
166
|
-
/** @type {
|
|
167
|
-
/** @type {
|
|
168
|
-
/** @type {
|
|
169
|
-
/** @type {
|
|
189
|
+
/** @type {string} */ type,
|
|
190
|
+
/** @type {Record<string, unknown>} */ entry,
|
|
191
|
+
/** @type {string} */ prop,
|
|
192
|
+
/** @type {string} */ value,
|
|
193
|
+
/** @type {(value: string) => void} */ onCommit,
|
|
194
|
+
/** @type {{ placeholder?: string }} */ opts = {},
|
|
170
195
|
) {
|
|
171
196
|
const cssInitialMap = getCssInitialMap();
|
|
172
|
-
return _widgetForType(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
197
|
+
return _widgetForType(
|
|
198
|
+
type,
|
|
199
|
+
entry,
|
|
200
|
+
prop,
|
|
201
|
+
value,
|
|
202
|
+
/** @type {(val: string | number) => void} */ (onCommit),
|
|
203
|
+
{
|
|
204
|
+
placeholder: opts.placeholder || cssInitialMap.get(prop) || "",
|
|
205
|
+
renderSelect: renderSelectInput,
|
|
206
|
+
renderCombobox: renderComboboxInput,
|
|
207
|
+
},
|
|
208
|
+
);
|
|
177
209
|
}
|