@jxsuite/studio 0.5.0 → 0.5.1
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 +4289 -2290
- package/dist/studio.js.map +31 -20
- package/package.json +2 -2
- package/src/panels/overlays.js +9 -1
- package/src/panels/right-panel.js +27 -1
- package/src/panels/statusbar.js +15 -1
- package/src/panels/toolbar.js +7 -1
- package/src/store.js +35 -0
- package/src/studio.js +96 -258
- package/src/utils/canvas-media.js +151 -0
- package/src/view.js +23 -0
package/src/studio.js
CHANGED
|
@@ -37,7 +37,6 @@ import {
|
|
|
37
37
|
isAncestor,
|
|
38
38
|
canvasWrap,
|
|
39
39
|
leftPanel,
|
|
40
|
-
rightPanel,
|
|
41
40
|
toolbarEl,
|
|
42
41
|
elToPath,
|
|
43
42
|
canvasPanels,
|
|
@@ -55,6 +54,7 @@ import {
|
|
|
55
54
|
runUpdateMiddleware,
|
|
56
55
|
addPostRenderHook,
|
|
57
56
|
runPostRenderHooks,
|
|
57
|
+
notify,
|
|
58
58
|
projectState,
|
|
59
59
|
setProjectState,
|
|
60
60
|
updateFrontmatter,
|
|
@@ -99,7 +99,12 @@ import {
|
|
|
99
99
|
varDisplayName,
|
|
100
100
|
parseCemType,
|
|
101
101
|
} from "./utils/studio-utils.js";
|
|
102
|
-
import {
|
|
102
|
+
import {
|
|
103
|
+
renderStatusbar,
|
|
104
|
+
statusMessage,
|
|
105
|
+
setStatusbarRenderer,
|
|
106
|
+
mountStatusbar,
|
|
107
|
+
} from "./panels/statusbar.js";
|
|
103
108
|
import {
|
|
104
109
|
openFile as _openFile,
|
|
105
110
|
loadMarkdown as _loadMarkdown,
|
|
@@ -119,6 +124,13 @@ import { renderHeadTemplate } from "./panels/head-panel.js";
|
|
|
119
124
|
import { exportCemManifest as _exportCemManifest } from "./services/cem-export.js";
|
|
120
125
|
|
|
121
126
|
import { registerPlatform, getPlatform, hasPlatform } from "./platform.js";
|
|
127
|
+
import {
|
|
128
|
+
parseMediaEntries,
|
|
129
|
+
activeBreakpointsForWidth,
|
|
130
|
+
applyCanvasStyle,
|
|
131
|
+
collectMediaOverrides,
|
|
132
|
+
applyOverridesToCanvas,
|
|
133
|
+
} from "./utils/canvas-media.js";
|
|
122
134
|
import { createDevServerPlatform } from "./platforms/devserver.js";
|
|
123
135
|
import { codeService, setLintMarkers, getFunctionArgs } from "./services/code-services.js";
|
|
124
136
|
import {
|
|
@@ -170,7 +182,6 @@ import { renderDataExplorerTemplate } from "./panels/data-explorer.js";
|
|
|
170
182
|
// by Bun's bundler despite sideEffects declarations in Spectrum's package.json.
|
|
171
183
|
import { components as _swc } from "./ui/spectrum.js"; // eslint-disable-line no-unused-vars
|
|
172
184
|
import { renderFieldRow } from "./ui/field-row.js";
|
|
173
|
-
import { isColorPopoverOpen } from "./ui/color-selector.js";
|
|
174
185
|
import { widgetForType as _widgetForType } from "./ui/widgets.js";
|
|
175
186
|
import { computeInheritedStyle } from "./utils/inherited-style.js";
|
|
176
187
|
import "./ui/panel-resize.js";
|
|
@@ -739,9 +750,6 @@ document.body.appendChild(zoomIndicatorHost);
|
|
|
739
750
|
|
|
740
751
|
// ─── Module-level UI state (must be before render() call) ─────────────────────
|
|
741
752
|
|
|
742
|
-
let elementsCollapsed = new Set();
|
|
743
|
-
let elementsFilter = "";
|
|
744
|
-
|
|
745
753
|
// ─── Bootstrap ────────────────────────────────────────────────────────────────
|
|
746
754
|
|
|
747
755
|
// Register the dev server platform adapter (PAL) as default if none pre-registered
|
|
@@ -804,6 +812,7 @@ registerRenderer("rightPanel", () => rightPanelMod.render());
|
|
|
804
812
|
registerRenderer("overlays", () => overlaysPanel.render());
|
|
805
813
|
registerRenderer("statusbar", () => renderStatusbar(S));
|
|
806
814
|
setStatusbarRenderer(() => renderStatusbar(S));
|
|
815
|
+
mountStatusbar();
|
|
807
816
|
|
|
808
817
|
function safeRenderLeftPanel() {
|
|
809
818
|
try {
|
|
@@ -853,12 +862,6 @@ setUpdateFn(function _update(/** @type {any} */ newState) {
|
|
|
853
862
|
const leftUiChanged =
|
|
854
863
|
uiChanged && (prev.ui?.leftTab !== S.ui?.leftTab || prev.ui?.settingsTab !== S.ui?.settingsTab);
|
|
855
864
|
|
|
856
|
-
try {
|
|
857
|
-
renderToolbar();
|
|
858
|
-
} catch (e) {
|
|
859
|
-
console.error("renderToolbar error:", e);
|
|
860
|
-
}
|
|
861
|
-
|
|
862
865
|
if (docChanged || modeChanged || canvasUiChanged) {
|
|
863
866
|
try {
|
|
864
867
|
renderCanvas();
|
|
@@ -874,38 +877,16 @@ setUpdateFn(function _update(/** @type {any} */ newState) {
|
|
|
874
877
|
updateActivePanelHeaders();
|
|
875
878
|
}
|
|
876
879
|
|
|
877
|
-
// Skip right-panel rebuild when an input inside it is focused (user is typing)
|
|
878
|
-
// unless the selection changed — that always needs a full re-render
|
|
879
|
-
// Also re-render when color popover is open (changes come from outside rightPanel)
|
|
880
|
-
const colorPopoverOpen = isColorPopoverOpen();
|
|
881
|
-
const activeTag = document.activeElement?.tagName;
|
|
882
|
-
const rightHasFocus =
|
|
883
|
-
!colorPopoverOpen &&
|
|
884
|
-
rightPanel.contains(document.activeElement) &&
|
|
885
|
-
(activeTag === "INPUT" ||
|
|
886
|
-
activeTag === "TEXTAREA" ||
|
|
887
|
-
activeTag === "SP-TEXTFIELD" ||
|
|
888
|
-
activeTag === "SP-NUMBER-FIELD" ||
|
|
889
|
-
activeTag === "SP-PICKER" ||
|
|
890
|
-
activeTag === "SP-COMBOBOX" ||
|
|
891
|
-
activeTag === "SP-SEARCH");
|
|
892
|
-
if (!rightHasFocus || selChanged || uiChanged) {
|
|
893
|
-
safeRenderRightPanel();
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
try {
|
|
897
|
-
renderOverlays();
|
|
898
|
-
} catch (e) {
|
|
899
|
-
console.error("renderOverlays error:", e);
|
|
900
|
-
}
|
|
901
|
-
try {
|
|
902
|
-
renderStatusbar(S);
|
|
903
|
-
} catch (e) {
|
|
904
|
-
console.error("renderStatusbar error:", e);
|
|
905
|
-
}
|
|
906
|
-
|
|
907
880
|
runPostRenderHooks(prevDoc, prevSel);
|
|
908
881
|
runUpdateMiddleware(S);
|
|
882
|
+
|
|
883
|
+
notify({
|
|
884
|
+
doc: docChanged,
|
|
885
|
+
selection: selChanged,
|
|
886
|
+
hover: false,
|
|
887
|
+
ui: uiChanged,
|
|
888
|
+
mode: modeChanged,
|
|
889
|
+
});
|
|
909
890
|
});
|
|
910
891
|
|
|
911
892
|
// Register session dispatch — lightweight path for selection/hover/ui changes
|
|
@@ -934,12 +915,6 @@ setUpdateSessionFn(function _updateSession(/** @type {any} */ patch) {
|
|
|
934
915
|
uiChanged &&
|
|
935
916
|
(prev.ui?.leftTab !== session.ui?.leftTab || prev.ui?.settingsTab !== session.ui?.settingsTab);
|
|
936
917
|
|
|
937
|
-
try {
|
|
938
|
-
renderToolbar();
|
|
939
|
-
} catch (e) {
|
|
940
|
-
console.error("renderToolbar error:", e);
|
|
941
|
-
}
|
|
942
|
-
|
|
943
918
|
if (canvasUiChanged) {
|
|
944
919
|
try {
|
|
945
920
|
renderCanvas();
|
|
@@ -955,22 +930,10 @@ setUpdateSessionFn(function _updateSession(/** @type {any} */ patch) {
|
|
|
955
930
|
updateActivePanelHeaders();
|
|
956
931
|
}
|
|
957
932
|
|
|
958
|
-
if (selChanged || uiChanged) {
|
|
959
|
-
safeRenderRightPanel();
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
try {
|
|
963
|
-
renderOverlays();
|
|
964
|
-
} catch (e) {
|
|
965
|
-
console.error("renderOverlays error:", e);
|
|
966
|
-
}
|
|
967
|
-
try {
|
|
968
|
-
renderStatusbar(S);
|
|
969
|
-
} catch (e) {
|
|
970
|
-
console.error("renderStatusbar error:", e);
|
|
971
|
-
}
|
|
972
|
-
|
|
973
933
|
runPostRenderHooks(doc.document, prev.selection);
|
|
934
|
+
|
|
935
|
+
const hoverChanged = prev.hover !== session.hover;
|
|
936
|
+
notify({ doc: false, selection: selChanged, hover: hoverChanged, ui: uiChanged, mode: false });
|
|
974
937
|
});
|
|
975
938
|
|
|
976
939
|
// Register post-render hook for pseudo-state preview
|
|
@@ -1084,86 +1047,6 @@ if (_openParam) {
|
|
|
1084
1047
|
|
|
1085
1048
|
// ─── Media helpers ────────────────────────────────────────────────────────────
|
|
1086
1049
|
|
|
1087
|
-
/**
|
|
1088
|
-
* Classify $media entries into size breakpoints (get a canvas each) and feature queries (rendered
|
|
1089
|
-
* as toolbar toggles).
|
|
1090
|
-
*
|
|
1091
|
-
* @param {any} mediaDef
|
|
1092
|
-
*/
|
|
1093
|
-
function parseMediaEntries(mediaDef) {
|
|
1094
|
-
if (!mediaDef) return { sizeBreakpoints: [], featureQueries: [], baseWidth: 320 };
|
|
1095
|
-
const sizes = [],
|
|
1096
|
-
features = [];
|
|
1097
|
-
let baseWidth = 320;
|
|
1098
|
-
for (const [name, query] of Object.entries(mediaDef)) {
|
|
1099
|
-
if (name === "--") {
|
|
1100
|
-
const wm = String(query).match(/^(\d+)\s*px$/);
|
|
1101
|
-
baseWidth = wm ? parseFloat(wm[1]) : 320;
|
|
1102
|
-
continue;
|
|
1103
|
-
}
|
|
1104
|
-
const minMatch = query.match(/min-width:\s*([\d.]+)px/);
|
|
1105
|
-
const maxMatch = query.match(/max-width:\s*([\d.]+)px/);
|
|
1106
|
-
if (minMatch) sizes.push({ name, query, width: parseFloat(minMatch[1]), type: "min" });
|
|
1107
|
-
else if (maxMatch) sizes.push({ name, query, width: parseFloat(maxMatch[1]), type: "max" });
|
|
1108
|
-
else features.push({ name, query });
|
|
1109
|
-
}
|
|
1110
|
-
sizes.sort((a, b) => (a.type === "min" ? a.width - b.width : b.width - a.width));
|
|
1111
|
-
return { sizeBreakpoints: sizes, featureQueries: features, baseWidth };
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
/**
|
|
1115
|
-
* Compute which named breakpoints are active at a given canvas width. For min-width canvases: all
|
|
1116
|
-
* breakpoints with min-width <= canvasWidth are active. For max-width canvases: all breakpoints
|
|
1117
|
-
* with max-width >= canvasWidth are active.
|
|
1118
|
-
*
|
|
1119
|
-
* @param {any} sizeBreakpoints
|
|
1120
|
-
* @param {any} canvasWidth
|
|
1121
|
-
*/
|
|
1122
|
-
function activeBreakpointsForWidth(sizeBreakpoints, canvasWidth) {
|
|
1123
|
-
const active = new Set();
|
|
1124
|
-
for (const bp of sizeBreakpoints) {
|
|
1125
|
-
if (bp.type === "min" && canvasWidth >= bp.width) active.add(bp.name);
|
|
1126
|
-
else if (bp.type === "max" && canvasWidth <= bp.width) active.add(bp.name);
|
|
1127
|
-
}
|
|
1128
|
-
return active;
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
/**
|
|
1132
|
-
* Apply styles to a canvas element, including active media overrides. Base (flat) styles applied
|
|
1133
|
-
* first, then matching media overrides in source order.
|
|
1134
|
-
*
|
|
1135
|
-
* @param {any} el
|
|
1136
|
-
* @param {any} styleDef
|
|
1137
|
-
* @param {any} activeBreakpoints
|
|
1138
|
-
* @param {any} featureToggles
|
|
1139
|
-
*/
|
|
1140
|
-
function applyCanvasStyle(el, styleDef, activeBreakpoints, featureToggles) {
|
|
1141
|
-
if (!styleDef || typeof styleDef !== "object") return;
|
|
1142
|
-
for (const [prop, val] of Object.entries(styleDef)) {
|
|
1143
|
-
if (typeof val === "string" || typeof val === "number") {
|
|
1144
|
-
try {
|
|
1145
|
-
if (prop.startsWith("--")) el.style.setProperty(prop, String(val));
|
|
1146
|
-
else /** @type {any} */ (el.style)[prop] = val;
|
|
1147
|
-
} catch {}
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
for (const [key, val] of Object.entries(styleDef)) {
|
|
1151
|
-
if (!key.startsWith("@") || typeof val !== "object") continue;
|
|
1152
|
-
const mediaName = key.slice(1);
|
|
1153
|
-
if (mediaName === "--") continue; // skip base canvas width key
|
|
1154
|
-
if (activeBreakpoints.has(mediaName) || featureToggles[mediaName]) {
|
|
1155
|
-
for (const [prop, v] of Object.entries(/** @type {any} */ (val))) {
|
|
1156
|
-
if (typeof v === "string" || typeof v === "number") {
|
|
1157
|
-
try {
|
|
1158
|
-
if (prop.startsWith("--")) el.style.setProperty(prop, String(v));
|
|
1159
|
-
else /** @type {any} */ (el.style)[prop] = v;
|
|
1160
|
-
} catch {}
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
1050
|
/**
|
|
1168
1051
|
* After a runtime render, apply active media overrides as inline styles so they beat the base
|
|
1169
1052
|
* inline styles the runtime already set. The runtime uses @media CSS rules for overrides, but those
|
|
@@ -1174,26 +1057,13 @@ function applyCanvasStyle(el, styleDef, activeBreakpoints, featureToggles) {
|
|
|
1174
1057
|
*/
|
|
1175
1058
|
function applyCanvasMediaOverrides(canvasEl, activeBreakpoints) {
|
|
1176
1059
|
if (!activeBreakpoints.size) return;
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
if (!node?.style) continue;
|
|
1182
|
-
for (const [key, val] of Object.entries(node.style)) {
|
|
1183
|
-
if (!key.startsWith("@") || typeof val !== "object") continue;
|
|
1184
|
-
const mediaName = key.slice(1);
|
|
1185
|
-
if (mediaName === "--") continue;
|
|
1186
|
-
if (!activeBreakpoints.has(mediaName)) continue;
|
|
1187
|
-
for (const [prop, v] of Object.entries(/** @type {any} */ (val))) {
|
|
1188
|
-
if (typeof v === "string" || typeof v === "number") {
|
|
1189
|
-
try {
|
|
1190
|
-
if (prop.startsWith("--")) el.style.setProperty(prop, String(v));
|
|
1191
|
-
else /** @type {any} */ (el.style)[prop] = v;
|
|
1192
|
-
} catch {}
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1060
|
+
const docMedia = getEffectiveMedia(S.document.$media || {});
|
|
1061
|
+
const validBreakpoints = new Set();
|
|
1062
|
+
for (const name of activeBreakpoints) {
|
|
1063
|
+
if (docMedia[name]) validBreakpoints.add(name);
|
|
1196
1064
|
}
|
|
1065
|
+
const overrides = collectMediaOverrides(document.styleSheets, validBreakpoints);
|
|
1066
|
+
applyOverridesToCanvas(canvasEl, overrides);
|
|
1197
1067
|
}
|
|
1198
1068
|
|
|
1199
1069
|
// ─── Canvas ───────────────────────────────────────────────────────────────────
|
|
@@ -1926,7 +1796,6 @@ function renderCanvasNode(node, path, parent, activeBreakpoints, featureToggles)
|
|
|
1926
1796
|
*
|
|
1927
1797
|
* @type {any}
|
|
1928
1798
|
*/
|
|
1929
|
-
let lastDragInput = null;
|
|
1930
1799
|
|
|
1931
1800
|
/**
|
|
1932
1801
|
* Register all canvas elements in a panel as DnD drop targets.
|
|
@@ -1946,12 +1815,12 @@ function registerPanelDnD(panel) {
|
|
|
1946
1815
|
for (const p of canvasPanels) p.overlayClk.style.pointerEvents = "none";
|
|
1947
1816
|
},
|
|
1948
1817
|
onDrag({ location }) {
|
|
1949
|
-
lastDragInput = location.current.input;
|
|
1818
|
+
view.lastDragInput = location.current.input;
|
|
1950
1819
|
},
|
|
1951
1820
|
onDrop() {
|
|
1952
1821
|
// Hide all drop lines
|
|
1953
1822
|
for (const p of canvasPanels) p.dropLine.style.display = "none";
|
|
1954
|
-
lastDragInput = null;
|
|
1823
|
+
view.lastDragInput = null;
|
|
1955
1824
|
for (const el of canvas.querySelectorAll("*")) {
|
|
1956
1825
|
/** @type {any} */ (el).style.pointerEvents = "none";
|
|
1957
1826
|
}
|
|
@@ -2006,8 +1875,8 @@ function registerPanelDnD(panel) {
|
|
|
2006
1875
|
*/
|
|
2007
1876
|
function getCanvasDropInstruction(el, elPath, isVoid) {
|
|
2008
1877
|
const rect = el.getBoundingClientRect();
|
|
2009
|
-
if (!lastDragInput) return null;
|
|
2010
|
-
const y = lastDragInput.clientY;
|
|
1878
|
+
if (!view.lastDragInput) return null;
|
|
1879
|
+
const y = view.lastDragInput.clientY;
|
|
2011
1880
|
const relY = (y - rect.top) / rect.height;
|
|
2012
1881
|
|
|
2013
1882
|
if (elPath.length === 0) return { type: "make-child" };
|
|
@@ -2127,15 +1996,10 @@ function onBarMousedown(e) {
|
|
|
2127
1996
|
e.preventDefault();
|
|
2128
1997
|
}
|
|
2129
1998
|
|
|
2130
|
-
/**
|
|
2131
|
-
* Saved selection range for format button mousedown→click flow
|
|
2132
|
-
*
|
|
2133
|
-
* @type {any}
|
|
2134
|
-
*/
|
|
2135
|
-
let savedRange = null;
|
|
1999
|
+
/** Saved selection range for format button mousedown→click flow */
|
|
2136
2000
|
function captureSelectionRange() {
|
|
2137
2001
|
const sel = window.getSelection();
|
|
2138
|
-
if (sel && sel.rangeCount) savedRange = sel.getRangeAt(0).cloneRange();
|
|
2002
|
+
if (sel && sel.rangeCount) view.savedRange = sel.getRangeAt(0).cloneRange();
|
|
2139
2003
|
}
|
|
2140
2004
|
|
|
2141
2005
|
/**
|
|
@@ -2146,16 +2010,16 @@ function onFormatClick(e, action) {
|
|
|
2146
2010
|
e.stopPropagation();
|
|
2147
2011
|
if (action.command === "link") {
|
|
2148
2012
|
showLinkPopover(e.target.closest("sp-action-button"));
|
|
2149
|
-
} else if (savedRange) {
|
|
2013
|
+
} else if (view.savedRange) {
|
|
2150
2014
|
const sel = /** @type {any} */ (window.getSelection());
|
|
2151
|
-
const anchor = savedRange.startContainer;
|
|
2015
|
+
const anchor = view.savedRange.startContainer;
|
|
2152
2016
|
const editableRoot = (
|
|
2153
2017
|
anchor?.nodeType === Node.ELEMENT_NODE ? anchor : anchor?.parentElement
|
|
2154
2018
|
)?.closest("[contenteditable]");
|
|
2155
2019
|
if (editableRoot) {
|
|
2156
2020
|
editableRoot.focus();
|
|
2157
2021
|
sel.removeAllRanges();
|
|
2158
|
-
sel.addRange(savedRange);
|
|
2022
|
+
sel.addRange(view.savedRange);
|
|
2159
2023
|
applyInlineFormat(action);
|
|
2160
2024
|
}
|
|
2161
2025
|
}
|
|
@@ -3683,7 +3547,7 @@ function registerLayersDnD() {
|
|
|
3683
3547
|
},
|
|
3684
3548
|
onDragStart() {
|
|
3685
3549
|
row.classList.add("dragging");
|
|
3686
|
-
layerDragSourceHeight = row.offsetHeight;
|
|
3550
|
+
view.layerDragSourceHeight = row.offsetHeight;
|
|
3687
3551
|
},
|
|
3688
3552
|
onDrop() {
|
|
3689
3553
|
row.classList.remove("dragging");
|
|
@@ -3787,8 +3651,6 @@ function registerComponentsDnD() {
|
|
|
3787
3651
|
}
|
|
3788
3652
|
|
|
3789
3653
|
/** @type {any} */
|
|
3790
|
-
let _currentDropTargetRow = null;
|
|
3791
|
-
let layerDragSourceHeight = 0;
|
|
3792
3654
|
|
|
3793
3655
|
/**
|
|
3794
3656
|
* @param {any} rowEl
|
|
@@ -3799,8 +3661,8 @@ function showLayerDropGap(rowEl, data, container) {
|
|
|
3799
3661
|
const instruction = extractInstruction(data);
|
|
3800
3662
|
|
|
3801
3663
|
// Clear previous drop-target highlight
|
|
3802
|
-
if (_currentDropTargetRow && _currentDropTargetRow !== rowEl) {
|
|
3803
|
-
_currentDropTargetRow.classList.remove("drop-target");
|
|
3664
|
+
if (view._currentDropTargetRow && view._currentDropTargetRow !== rowEl) {
|
|
3665
|
+
view._currentDropTargetRow.classList.remove("drop-target");
|
|
3804
3666
|
}
|
|
3805
3667
|
|
|
3806
3668
|
if (!instruction || instruction.type === "instruction-blocked") {
|
|
@@ -3811,17 +3673,17 @@ function showLayerDropGap(rowEl, data, container) {
|
|
|
3811
3673
|
if (instruction.type === "make-child") {
|
|
3812
3674
|
clearLayerDropGap(container);
|
|
3813
3675
|
rowEl.classList.add("drop-target");
|
|
3814
|
-
_currentDropTargetRow = rowEl;
|
|
3676
|
+
view._currentDropTargetRow = rowEl;
|
|
3815
3677
|
return;
|
|
3816
3678
|
}
|
|
3817
3679
|
|
|
3818
3680
|
rowEl.classList.remove("drop-target");
|
|
3819
|
-
_currentDropTargetRow = rowEl;
|
|
3681
|
+
view._currentDropTargetRow = rowEl;
|
|
3820
3682
|
|
|
3821
3683
|
// Shift rows to create gap
|
|
3822
3684
|
const rows = Array.from(container.querySelectorAll(".layers-tree .layer-row"));
|
|
3823
3685
|
const targetIdx = rows.indexOf(rowEl);
|
|
3824
|
-
const gap = layerDragSourceHeight;
|
|
3686
|
+
const gap = view.layerDragSourceHeight;
|
|
3825
3687
|
|
|
3826
3688
|
for (let i = 0; i < rows.length; i++) {
|
|
3827
3689
|
if (rows[i].classList.contains("dragging")) continue;
|
|
@@ -3835,9 +3697,9 @@ function showLayerDropGap(rowEl, data, container) {
|
|
|
3835
3697
|
|
|
3836
3698
|
/** @param {any} container */
|
|
3837
3699
|
function clearLayerDropGap(container) {
|
|
3838
|
-
if (_currentDropTargetRow) {
|
|
3839
|
-
_currentDropTargetRow.classList.remove("drop-target");
|
|
3840
|
-
_currentDropTargetRow = null;
|
|
3700
|
+
if (view._currentDropTargetRow) {
|
|
3701
|
+
view._currentDropTargetRow.classList.remove("drop-target");
|
|
3702
|
+
view._currentDropTargetRow = null;
|
|
3841
3703
|
}
|
|
3842
3704
|
const rows = container.querySelectorAll(".layers-tree .layer-row");
|
|
3843
3705
|
for (const r of rows) r.style.transform = "";
|
|
@@ -3850,25 +3712,22 @@ function clearLayerDropGap(container) {
|
|
|
3850
3712
|
* @param {string | null} [media]
|
|
3851
3713
|
*/
|
|
3852
3714
|
function selectStylebookTag(tag, media) {
|
|
3853
|
-
|
|
3854
|
-
...S,
|
|
3715
|
+
updateSession({
|
|
3855
3716
|
selection: [],
|
|
3856
3717
|
ui: {
|
|
3857
|
-
...S.ui,
|
|
3858
3718
|
stylebookSelection: tag,
|
|
3859
3719
|
rightTab: "style",
|
|
3860
3720
|
activeSelector: `& ${tag}`,
|
|
3861
3721
|
...(media !== undefined ? { activeMedia: media } : {}),
|
|
3862
3722
|
},
|
|
3863
|
-
};
|
|
3723
|
+
});
|
|
3864
3724
|
renderStylebookOverlays();
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
}
|
|
3725
|
+
requestAnimationFrame(() => {
|
|
3726
|
+
if (canvasPanels.length > 0) {
|
|
3727
|
+
const el = findStylebookEl(canvasPanels[0].canvas, tag);
|
|
3728
|
+
if (el) el.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
3729
|
+
}
|
|
3730
|
+
});
|
|
3872
3731
|
}
|
|
3873
3732
|
|
|
3874
3733
|
function renderStylebookLayersTemplate() {
|
|
@@ -4121,18 +3980,18 @@ const unsafeTags = new Set(["script", "style", "link", "iframe", "object", "embe
|
|
|
4121
3980
|
function renderElementsTemplate() {
|
|
4122
3981
|
const categories = Object.entries(webdata.elements).map(
|
|
4123
3982
|
(/** @type {any} */ [category, elements]) => {
|
|
4124
|
-
const filtered = elementsFilter
|
|
4125
|
-
? elements.filter((/** @type {any} */ e) => e.tag.includes(elementsFilter))
|
|
3983
|
+
const filtered = view.elementsFilter
|
|
3984
|
+
? elements.filter((/** @type {any} */ e) => e.tag.includes(view.elementsFilter))
|
|
4126
3985
|
: elements;
|
|
4127
3986
|
if (filtered.length === 0) return nothing;
|
|
4128
3987
|
|
|
4129
3988
|
return html`
|
|
4130
3989
|
<sp-accordion-item
|
|
4131
3990
|
label=${category}
|
|
4132
|
-
?open=${!elementsCollapsed.has(category)}
|
|
3991
|
+
?open=${!view.elementsCollapsed.has(category)}
|
|
4133
3992
|
@sp-accordion-item-toggle=${(/** @type {any} */ e) => {
|
|
4134
|
-
if (e.target.open) elementsCollapsed.delete(category);
|
|
4135
|
-
else elementsCollapsed.add(category);
|
|
3993
|
+
if (e.target.open) view.elementsCollapsed.delete(category);
|
|
3994
|
+
else view.elementsCollapsed.add(category);
|
|
4136
3995
|
}}
|
|
4137
3996
|
>
|
|
4138
3997
|
${filtered.map((/** @type {any} */ { tag }) => {
|
|
@@ -4184,7 +4043,7 @@ function renderElementsTemplate() {
|
|
|
4184
4043
|
.filter((/** @type {any} */ c) => c.source !== "npm" || enabledTags.has(c.tagName))
|
|
4185
4044
|
.filter(
|
|
4186
4045
|
(/** @type {any} */ c) =>
|
|
4187
|
-
!elementsFilter || c.tagName.toLowerCase().includes(elementsFilter),
|
|
4046
|
+
!view.elementsFilter || c.tagName.toLowerCase().includes(view.elementsFilter),
|
|
4188
4047
|
)
|
|
4189
4048
|
: [];
|
|
4190
4049
|
|
|
@@ -4193,10 +4052,10 @@ function renderElementsTemplate() {
|
|
|
4193
4052
|
? html`
|
|
4194
4053
|
<sp-accordion-item
|
|
4195
4054
|
label="Components"
|
|
4196
|
-
?open=${!elementsCollapsed.has("Components")}
|
|
4055
|
+
?open=${!view.elementsCollapsed.has("Components")}
|
|
4197
4056
|
@sp-accordion-item-toggle=${(/** @type {any} */ e) => {
|
|
4198
|
-
if (e.target.open) elementsCollapsed.delete("Components");
|
|
4199
|
-
else elementsCollapsed.add("Components");
|
|
4057
|
+
if (e.target.open) view.elementsCollapsed.delete("Components");
|
|
4058
|
+
else view.elementsCollapsed.add("Components");
|
|
4200
4059
|
}}
|
|
4201
4060
|
>
|
|
4202
4061
|
<div class="components-section">
|
|
@@ -4242,9 +4101,9 @@ function renderElementsTemplate() {
|
|
|
4242
4101
|
<sp-search
|
|
4243
4102
|
size="s"
|
|
4244
4103
|
placeholder="Filter elements…"
|
|
4245
|
-
value=${elementsFilter}
|
|
4104
|
+
value=${view.elementsFilter}
|
|
4246
4105
|
@input=${(/** @type {any} */ e) => {
|
|
4247
|
-
elementsFilter = e.target.value.toLowerCase();
|
|
4106
|
+
view.elementsFilter = e.target.value.toLowerCase();
|
|
4248
4107
|
renderLeftPanel();
|
|
4249
4108
|
}}
|
|
4250
4109
|
></sp-search>
|
|
@@ -4283,7 +4142,6 @@ function registerElementsDnD() {
|
|
|
4283
4142
|
// ─── Stylebook ───────────────────────────────────────────────────────────────
|
|
4284
4143
|
|
|
4285
4144
|
/** Map from rendered stylebook DOM elements to their tag names */
|
|
4286
|
-
let stylebookElToTag = new WeakMap();
|
|
4287
4145
|
|
|
4288
4146
|
/**
|
|
4289
4147
|
* Build a DOM element tree from a stylebook-meta.json entry. Applies any existing tag-scoped styles
|
|
@@ -4431,7 +4289,7 @@ function renderSettings() {
|
|
|
4431
4289
|
}
|
|
4432
4290
|
|
|
4433
4291
|
// Stylebook tab — existing behavior
|
|
4434
|
-
stylebookElToTag = new WeakMap();
|
|
4292
|
+
view.stylebookElToTag = new WeakMap();
|
|
4435
4293
|
const rootStyle = getEffectiveStyle(S.document.style);
|
|
4436
4294
|
const filter = (S.ui.stylebookFilter || "").toLowerCase();
|
|
4437
4295
|
const customizedOnly = S.ui.stylebookCustomizedOnly;
|
|
@@ -4626,12 +4484,12 @@ function renderStylebookElementsIntoCanvas(
|
|
|
4626
4484
|
class="element-card"
|
|
4627
4485
|
${ref((card) => {
|
|
4628
4486
|
if (!card) return;
|
|
4629
|
-
stylebookElToTag.set(card, entry.tag);
|
|
4487
|
+
view.stylebookElToTag.set(card, entry.tag);
|
|
4630
4488
|
elToPath.set(card, ["__sb", entry.tag]);
|
|
4631
4489
|
for (const child of el.querySelectorAll("*")) {
|
|
4632
4490
|
const tag = child.tagName.toLowerCase();
|
|
4633
|
-
if (!stylebookElToTag.has(child)) {
|
|
4634
|
-
stylebookElToTag.set(child, tag);
|
|
4491
|
+
if (!view.stylebookElToTag.has(child)) {
|
|
4492
|
+
view.stylebookElToTag.set(child, tag);
|
|
4635
4493
|
elToPath.set(child, ["__sb", tag]);
|
|
4636
4494
|
}
|
|
4637
4495
|
}
|
|
@@ -4673,7 +4531,7 @@ function renderStylebookElementsIntoCanvas(
|
|
|
4673
4531
|
style="display:inline-flex;width:auto"
|
|
4674
4532
|
${ref((card) => {
|
|
4675
4533
|
if (!card) return;
|
|
4676
|
-
stylebookElToTag.set(card, comp.tagName);
|
|
4534
|
+
view.stylebookElToTag.set(card, comp.tagName);
|
|
4677
4535
|
elToPath.set(card, ["__sb", comp.tagName]);
|
|
4678
4536
|
})}
|
|
4679
4537
|
>
|
|
@@ -5154,7 +5012,8 @@ function createUnitInput(initialValue, { onChange, size = "s" } = {}) {
|
|
|
5154
5012
|
}
|
|
5155
5013
|
|
|
5156
5014
|
/**
|
|
5157
|
-
* Click handler for stylebook canvas — selects elements via the elToPath/stylebookElToTag
|
|
5015
|
+
* Click handler for stylebook canvas — selects elements via the elToPath/view.stylebookElToTag
|
|
5016
|
+
* mapping
|
|
5158
5017
|
*
|
|
5159
5018
|
* @param {any} panel
|
|
5160
5019
|
*/
|
|
@@ -5175,7 +5034,7 @@ function registerStylebookPanelEvents(panel) {
|
|
|
5175
5034
|
if (!canvas.contains(el) || el === canvas) continue;
|
|
5176
5035
|
let cur = /** @type {any} */ (el);
|
|
5177
5036
|
while (cur && cur !== canvas) {
|
|
5178
|
-
const tag = stylebookElToTag.get(cur);
|
|
5037
|
+
const tag = view.stylebookElToTag.get(cur);
|
|
5179
5038
|
if (tag) {
|
|
5180
5039
|
const newMedia = panel.mediaName === "base" ? null : (panel.mediaName ?? null);
|
|
5181
5040
|
selectStylebookTag(tag, newMedia);
|
|
@@ -5203,7 +5062,7 @@ function registerStylebookPanelEvents(panel) {
|
|
|
5203
5062
|
if (!canvas.contains(el) || el === canvas) continue;
|
|
5204
5063
|
let cur = /** @type {any} */ (el);
|
|
5205
5064
|
while (cur && cur !== canvas) {
|
|
5206
|
-
const tag = stylebookElToTag.get(cur);
|
|
5065
|
+
const tag = view.stylebookElToTag.get(cur);
|
|
5207
5066
|
if (tag) {
|
|
5208
5067
|
hoverTag = tag;
|
|
5209
5068
|
break;
|
|
@@ -5273,7 +5132,7 @@ function renderStylebookOverlays() {
|
|
|
5273
5132
|
/** Find a stylebook element by tag in the canvas */
|
|
5274
5133
|
function findStylebookEl(/** @type {any} */ canvasEl, /** @type {any} */ tag) {
|
|
5275
5134
|
for (const child of canvasEl.querySelectorAll("*")) {
|
|
5276
|
-
if (stylebookElToTag.get(child) === tag) return child;
|
|
5135
|
+
if (view.stylebookElToTag.get(child) === tag) return child;
|
|
5277
5136
|
}
|
|
5278
5137
|
return null;
|
|
5279
5138
|
}
|
|
@@ -5571,11 +5430,7 @@ function propertiesSidebarTemplate() {
|
|
|
5571
5430
|
|
|
5572
5431
|
function toggleSection(/** @type {any} */ key) {
|
|
5573
5432
|
const current = isSectionOpen(key);
|
|
5574
|
-
S
|
|
5575
|
-
...S,
|
|
5576
|
-
ui: { ...S.ui, inspectorSections: { ...S.ui.inspectorSections, [key]: !current } },
|
|
5577
|
-
};
|
|
5578
|
-
renderRightPanel();
|
|
5433
|
+
updateUi("inspectorSections", { ...S.ui.inspectorSections, [key]: !current });
|
|
5579
5434
|
}
|
|
5580
5435
|
|
|
5581
5436
|
// ── Build section templates ─────────────────────────────────────────
|
|
@@ -6271,8 +6126,6 @@ function renderCustomAttrsFieldsTemplate(
|
|
|
6271
6126
|
}
|
|
6272
6127
|
|
|
6273
6128
|
/** Media breakpoint fields template */
|
|
6274
|
-
let showAddBreakpointForm = false;
|
|
6275
|
-
let addBreakpointPreview = "";
|
|
6276
6129
|
|
|
6277
6130
|
function renderMediaFieldsTemplate(/** @type {any} */ node) {
|
|
6278
6131
|
const media = node.$media || {};
|
|
@@ -6308,14 +6161,14 @@ function renderMediaFieldsTemplate(/** @type {any} */ node) {
|
|
|
6308
6161
|
<div>
|
|
6309
6162
|
<span
|
|
6310
6163
|
class="kv-add"
|
|
6311
|
-
style=${showAddBreakpointForm ? "display:none" : ""}
|
|
6164
|
+
style=${view.showAddBreakpointForm ? "display:none" : ""}
|
|
6312
6165
|
@click=${(/** @type {any} */ _e) => {
|
|
6313
|
-
showAddBreakpointForm = true;
|
|
6166
|
+
view.showAddBreakpointForm = true;
|
|
6314
6167
|
renderRightPanel();
|
|
6315
6168
|
}}
|
|
6316
6169
|
>+ Add breakpoint</span
|
|
6317
6170
|
>
|
|
6318
|
-
${showAddBreakpointForm
|
|
6171
|
+
${view.showAddBreakpointForm
|
|
6319
6172
|
? html`
|
|
6320
6173
|
<div style="margin-top:4px">
|
|
6321
6174
|
<div style="display:flex;gap:4px;margin-bottom:3px;align-items:center">
|
|
@@ -6324,13 +6177,13 @@ function renderMediaFieldsTemplate(/** @type {any} */ node) {
|
|
|
6324
6177
|
placeholder="Name (e.g. Tablet)"
|
|
6325
6178
|
style="flex:1"
|
|
6326
6179
|
@input=${(/** @type {any} */ e) => {
|
|
6327
|
-
addBreakpointPreview = friendlyNameToMedia(e.target.value) || "";
|
|
6180
|
+
view.addBreakpointPreview = friendlyNameToMedia(e.target.value) || "";
|
|
6328
6181
|
renderRightPanel();
|
|
6329
6182
|
}}
|
|
6330
6183
|
/>
|
|
6331
6184
|
<span
|
|
6332
6185
|
style="font-size:10px;color:var(--fg-dim);font-family:'SF Mono','Fira Code',monospace;white-space:nowrap"
|
|
6333
|
-
>${addBreakpointPreview}</span
|
|
6186
|
+
>${view.addBreakpointPreview}</span
|
|
6334
6187
|
>
|
|
6335
6188
|
</div>
|
|
6336
6189
|
<div style="display:flex;gap:4px;margin-bottom:3px;align-items:center">
|
|
@@ -6346,8 +6199,8 @@ function renderMediaFieldsTemplate(/** @type {any} */ node) {
|
|
|
6346
6199
|
const queryVal = wrap.querySelector(".add-bp-query")?.value?.trim();
|
|
6347
6200
|
const key = friendlyNameToMedia(nameVal);
|
|
6348
6201
|
if (key && queryVal) {
|
|
6349
|
-
showAddBreakpointForm = false;
|
|
6350
|
-
addBreakpointPreview = "";
|
|
6202
|
+
view.showAddBreakpointForm = false;
|
|
6203
|
+
view.addBreakpointPreview = "";
|
|
6351
6204
|
update(updateMedia(S, key, queryVal));
|
|
6352
6205
|
}
|
|
6353
6206
|
}}
|
|
@@ -6358,8 +6211,8 @@ function renderMediaFieldsTemplate(/** @type {any} */ node) {
|
|
|
6358
6211
|
class="kv-add"
|
|
6359
6212
|
style="padding:2px 10px;cursor:pointer;color:var(--fg-dim)"
|
|
6360
6213
|
@click=${() => {
|
|
6361
|
-
showAddBreakpointForm = false;
|
|
6362
|
-
addBreakpointPreview = "";
|
|
6214
|
+
view.showAddBreakpointForm = false;
|
|
6215
|
+
view.addBreakpointPreview = "";
|
|
6363
6216
|
renderRightPanel();
|
|
6364
6217
|
}}
|
|
6365
6218
|
>
|
|
@@ -6868,14 +6721,7 @@ function renderShorthandRow(
|
|
|
6868
6721
|
quiet
|
|
6869
6722
|
@click=${(/** @type {any} */ e) => {
|
|
6870
6723
|
e.stopPropagation();
|
|
6871
|
-
S
|
|
6872
|
-
...S,
|
|
6873
|
-
ui: {
|
|
6874
|
-
...S.ui,
|
|
6875
|
-
styleShorthands: { ...S.ui.styleShorthands, [shortProp]: !isExpanded },
|
|
6876
|
-
},
|
|
6877
|
-
};
|
|
6878
|
-
renderRightPanel();
|
|
6724
|
+
updateUi("styleShorthands", { ...S.ui.styleShorthands, [shortProp]: !isExpanded });
|
|
6879
6725
|
}}
|
|
6880
6726
|
>
|
|
6881
6727
|
${isExpanded
|
|
@@ -7181,10 +7027,7 @@ function styleSidebarTemplate(
|
|
|
7181
7027
|
label=${sec.label}
|
|
7182
7028
|
.open=${isOpen}
|
|
7183
7029
|
@sp-accordion-item-toggle=${(/** @type {any} */ e) => {
|
|
7184
|
-
S
|
|
7185
|
-
...S,
|
|
7186
|
-
ui: { ...S.ui, styleSections: { ...S.ui.styleSections, [sec.key]: e.target.open } },
|
|
7187
|
-
};
|
|
7030
|
+
updateUi("styleSections", { ...S.ui.styleSections, [sec.key]: e.target.open });
|
|
7188
7031
|
}}
|
|
7189
7032
|
>
|
|
7190
7033
|
${sectionActiveProps.length > 0
|
|
@@ -7225,10 +7068,7 @@ function styleSidebarTemplate(
|
|
|
7225
7068
|
label="Custom"
|
|
7226
7069
|
.open=${customIsOpen}
|
|
7227
7070
|
@sp-accordion-item-toggle=${(/** @type {any} */ e) => {
|
|
7228
|
-
S
|
|
7229
|
-
...S,
|
|
7230
|
-
ui: { ...S.ui, styleSections: { ...S.ui.styleSections, other: e.target.open } },
|
|
7231
|
-
};
|
|
7071
|
+
updateUi("styleSections", { ...S.ui.styleSections, other: e.target.open });
|
|
7232
7072
|
}}
|
|
7233
7073
|
>
|
|
7234
7074
|
<div>
|
|
@@ -7679,10 +7519,9 @@ function getFunctionBody(/** @type {any} */ editing) {
|
|
|
7679
7519
|
}
|
|
7680
7520
|
|
|
7681
7521
|
// Register Monaco JS completion provider for state scope variables (once)
|
|
7682
|
-
let _completionRegistered = false;
|
|
7683
7522
|
function registerFunctionCompletions() {
|
|
7684
|
-
if (_completionRegistered) return;
|
|
7685
|
-
_completionRegistered = true;
|
|
7523
|
+
if (view._completionRegistered) return;
|
|
7524
|
+
view._completionRegistered = true;
|
|
7686
7525
|
monaco.languages.registerCompletionItemProvider("javascript", {
|
|
7687
7526
|
triggerCharacters: ["."],
|
|
7688
7527
|
provideCompletionItems(model, position) {
|
|
@@ -7816,13 +7655,12 @@ initShortcuts(() => ({
|
|
|
7816
7655
|
// ─── Autosave (registered as update middleware) ──────────────────────────────
|
|
7817
7656
|
|
|
7818
7657
|
/** @type {any} */
|
|
7819
|
-
let autosaveTimer;
|
|
7820
7658
|
const AUTO_SAVE_DELAY = 2000;
|
|
7821
7659
|
|
|
7822
7660
|
function scheduleAutosave() {
|
|
7823
7661
|
if (!S.fileHandle || !S.dirty) return;
|
|
7824
|
-
clearTimeout(autosaveTimer);
|
|
7825
|
-
autosaveTimer = setTimeout(async () => {
|
|
7662
|
+
clearTimeout(view.autosaveTimer);
|
|
7663
|
+
view.autosaveTimer = setTimeout(async () => {
|
|
7826
7664
|
if (S.fileHandle && S.dirty && "createWritable" in S.fileHandle) {
|
|
7827
7665
|
try {
|
|
7828
7666
|
const writable = await S.fileHandle.createWritable();
|