@jxsuite/studio 0.23.2 → 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 +2230 -714
- 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} +109 -84
- 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} +35 -23
- 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,3 +1,5 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/// <reference lib="dom.iterable" />
|
|
1
3
|
/**
|
|
2
4
|
* Stylebook panel — renders the Stylebook mode canvas (element catalog with per-file style
|
|
3
5
|
* defaults). Extracted from studio.js Phase 4e.
|
|
@@ -16,64 +18,65 @@ import {
|
|
|
16
18
|
canvasPanels,
|
|
17
19
|
elToPath,
|
|
18
20
|
projectState,
|
|
19
|
-
} from "../store
|
|
20
|
-
import { activeTab } from "../workspace/workspace
|
|
21
|
-
import { view } from "../view
|
|
21
|
+
} from "../store";
|
|
22
|
+
import { activeTab } from "../workspace/workspace";
|
|
23
|
+
import { view } from "../view";
|
|
22
24
|
import { defineElement, setSkipServerFunctions } from "@jxsuite/runtime";
|
|
23
|
-
import { componentRegistry } from "../files/components
|
|
24
|
-
import { getEffectiveStyle, getEffectiveMedia } from "../site-context
|
|
25
|
-
import { parseMediaEntries, activeBreakpointsForWidth } from "../utils/canvas-media
|
|
26
|
-
import { mediaDisplayName } from "./shared
|
|
27
|
-
import { panToCanvasEl } from "../canvas/canvas-utils
|
|
25
|
+
import { componentRegistry } from "../files/components";
|
|
26
|
+
import { getEffectiveStyle, getEffectiveMedia } from "../site-context";
|
|
27
|
+
import { parseMediaEntries, activeBreakpointsForWidth } from "../utils/canvas-media";
|
|
28
|
+
import { mediaDisplayName } from "./shared";
|
|
29
|
+
import { panToCanvasEl } from "../canvas/canvas-utils";
|
|
28
30
|
import stylebookMeta from "../../data/stylebook-meta.json";
|
|
29
31
|
|
|
30
|
-
export
|
|
32
|
+
export interface StylebookEntry {
|
|
33
|
+
tag: string;
|
|
34
|
+
text?: string;
|
|
35
|
+
attributes?: Record<string, string>;
|
|
36
|
+
style?: string;
|
|
37
|
+
children?: StylebookEntry[];
|
|
38
|
+
}
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
interface StylebookPanel {
|
|
41
|
+
mediaName: string | null;
|
|
42
|
+
element: HTMLElement | null;
|
|
43
|
+
canvas: HTMLElement;
|
|
44
|
+
overlay: HTMLElement;
|
|
45
|
+
overlayClk: HTMLElement;
|
|
46
|
+
viewport: HTMLElement | null;
|
|
47
|
+
scrollContainer: HTMLElement | null;
|
|
48
|
+
dropLine: HTMLElement | null;
|
|
49
|
+
_width: number | null;
|
|
50
|
+
_lastHoverTag?: string | null;
|
|
51
|
+
}
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
interface StylebookCtx {
|
|
54
|
+
canvasPanelTemplate: (
|
|
55
|
+
mediaName: string | null,
|
|
56
|
+
label: string | null,
|
|
57
|
+
fullWidth: boolean,
|
|
58
|
+
width?: number | null,
|
|
59
|
+
) => { tpl: import("lit-html").TemplateResult; panel: any };
|
|
60
|
+
applyTransform: () => void;
|
|
61
|
+
observeCenterUntilStable: () => void;
|
|
62
|
+
renderZoomIndicator: () => void;
|
|
63
|
+
updateActivePanelHeaders: () => void;
|
|
64
|
+
overlayBoxDescriptor: (
|
|
65
|
+
el: Element,
|
|
66
|
+
type: string,
|
|
67
|
+
panel: any,
|
|
68
|
+
) => { cls: string; top: string; left: string; width: string; height: string };
|
|
69
|
+
effectiveZoom: () => number;
|
|
70
|
+
}
|
|
56
71
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
* updateActivePanelHeaders: Function;
|
|
64
|
-
* overlayBoxDescriptor: Function;
|
|
65
|
-
* effectiveZoom: Function;
|
|
66
|
-
* }} StylebookCtx
|
|
67
|
-
*/
|
|
72
|
+
interface ComponentEntry {
|
|
73
|
+
source?: string;
|
|
74
|
+
tagName: string;
|
|
75
|
+
path?: string;
|
|
76
|
+
props?: Array<{ name: string; default?: string }>;
|
|
77
|
+
}
|
|
68
78
|
|
|
69
|
-
|
|
70
|
-
* @typedef {{
|
|
71
|
-
* source?: string;
|
|
72
|
-
* tagName: string;
|
|
73
|
-
* path?: string;
|
|
74
|
-
* props?: Array<{ name: string; default?: string }>;
|
|
75
|
-
* }} ComponentEntry
|
|
76
|
-
*/
|
|
79
|
+
export { stylebookMeta };
|
|
77
80
|
|
|
78
81
|
/**
|
|
79
82
|
* Resolve a nested tag path in a style object. e.g., "table th" → style["table"]["th"]
|
|
@@ -82,23 +85,22 @@ export { stylebookMeta };
|
|
|
82
85
|
* @param {string} tagPath
|
|
83
86
|
* @returns {Record<string, unknown> | null}
|
|
84
87
|
*/
|
|
85
|
-
function _resolveNestedStyle(style, tagPath) {
|
|
88
|
+
function _resolveNestedStyle(style: Record<string, unknown>, tagPath: string) {
|
|
86
89
|
const parts = tagPath.split(" ");
|
|
87
90
|
let obj = style;
|
|
88
91
|
for (const part of parts) {
|
|
89
92
|
if (!obj || typeof obj !== "object") return null;
|
|
90
|
-
obj =
|
|
93
|
+
obj = obj[part] as Record<string, unknown>;
|
|
91
94
|
}
|
|
92
|
-
return obj && typeof obj === "object" ?
|
|
95
|
+
return obj && typeof obj === "object" ? (obj as Record<string, unknown>) : null;
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
let _ctx = null;
|
|
98
|
+
let _ctx: StylebookCtx | null = null;
|
|
97
99
|
|
|
98
100
|
/** Lookup: tag → entry from stylebookMeta (built once) */
|
|
99
101
|
const _entryByTag = new Map();
|
|
100
102
|
for (const section of stylebookMeta.$sections) {
|
|
101
|
-
for (const entry of
|
|
103
|
+
for (const entry of section.elements as StylebookEntry[]) {
|
|
102
104
|
_entryByTag.set(entry.tag, entry);
|
|
103
105
|
}
|
|
104
106
|
}
|
|
@@ -108,7 +110,7 @@ for (const section of stylebookMeta.$sections) {
|
|
|
108
110
|
*
|
|
109
111
|
* @param {StylebookCtx} ctx
|
|
110
112
|
*/
|
|
111
|
-
export function renderStylebookMode(ctx) {
|
|
113
|
+
export function renderStylebookMode(ctx: StylebookCtx) {
|
|
112
114
|
_ctx = ctx;
|
|
113
115
|
|
|
114
116
|
// Stylebook mode — element catalog only
|
|
@@ -123,8 +125,8 @@ export function renderStylebookMode(ctx) {
|
|
|
123
125
|
);
|
|
124
126
|
const hasMedia = sizeBreakpoints.length > 0;
|
|
125
127
|
|
|
126
|
-
const onFilterInput = (
|
|
127
|
-
updateUi("stylebookFilter",
|
|
128
|
+
const onFilterInput = (e: Event) => {
|
|
129
|
+
updateUi("stylebookFilter", (e.target as HTMLInputElement).value);
|
|
128
130
|
};
|
|
129
131
|
|
|
130
132
|
const onCustomizedToggle = () => {
|
|
@@ -145,7 +147,10 @@ export function renderStylebookMode(ctx) {
|
|
|
145
147
|
@input=${onFilterInput}
|
|
146
148
|
/>
|
|
147
149
|
<button
|
|
148
|
-
class=${classMap({
|
|
150
|
+
class=${classMap({
|
|
151
|
+
"tb-toggle": true,
|
|
152
|
+
active: !!tab?.session.ui.stylebookCustomizedOnly,
|
|
153
|
+
})}
|
|
149
154
|
@click=${onCustomizedToggle}
|
|
150
155
|
>
|
|
151
156
|
Customized
|
|
@@ -154,7 +159,7 @@ export function renderStylebookMode(ctx) {
|
|
|
154
159
|
</div>
|
|
155
160
|
`;
|
|
156
161
|
|
|
157
|
-
|
|
162
|
+
(canvasWrap as HTMLElement).style.overflow = "hidden";
|
|
158
163
|
|
|
159
164
|
/** @type {{ name: string; displayName: string; width: number; activeSet: Set<string> }[]} */
|
|
160
165
|
const allPanelDefs = [];
|
|
@@ -175,10 +180,7 @@ export function renderStylebookMode(ctx) {
|
|
|
175
180
|
}
|
|
176
181
|
}
|
|
177
182
|
|
|
178
|
-
const renderIntoPanel = (
|
|
179
|
-
/** @type {StylebookPanel} */ panel,
|
|
180
|
-
/** @type {Set<string>} */ activeBreakpoints,
|
|
181
|
-
) => {
|
|
183
|
+
const renderIntoPanel = (panel: StylebookPanel, activeBreakpoints: Set<string>) => {
|
|
182
184
|
panel.canvas.classList.add("sb-canvas");
|
|
183
185
|
renderStylebookElementsIntoCanvas(
|
|
184
186
|
panel.canvas,
|
|
@@ -188,7 +190,7 @@ export function renderStylebookMode(ctx) {
|
|
|
188
190
|
activeBreakpoints,
|
|
189
191
|
);
|
|
190
192
|
for (const child of panel.canvas.querySelectorAll("*")) {
|
|
191
|
-
|
|
193
|
+
(child as HTMLElement).style.pointerEvents = "none";
|
|
192
194
|
}
|
|
193
195
|
registerStylebookPanelEvents(panel);
|
|
194
196
|
};
|
|
@@ -211,7 +213,7 @@ export function renderStylebookMode(ctx) {
|
|
|
211
213
|
!hasBaseWidth,
|
|
212
214
|
hasBaseWidth ? baseWidth : undefined,
|
|
213
215
|
);
|
|
214
|
-
panelEntries = [{ tpl: entry.tpl, panel: entry.panel, activeSet: new Set() }];
|
|
216
|
+
panelEntries = [{ tpl: entry.tpl, panel: entry.panel, activeSet: new Set<string>() }];
|
|
215
217
|
} else {
|
|
216
218
|
panelEntries = allPanelDefs.map((def) => {
|
|
217
219
|
const label = `${def.displayName} (${def.width}px)`;
|
|
@@ -227,7 +229,7 @@ export function renderStylebookMode(ctx) {
|
|
|
227
229
|
class="panzoom-wrap"
|
|
228
230
|
style="transform-origin:0 0;padding-top:40px"
|
|
229
231
|
${ref((el) => {
|
|
230
|
-
if (el) view.panzoomWrap =
|
|
232
|
+
if (el) view.panzoomWrap = el as HTMLDivElement;
|
|
231
233
|
})}
|
|
232
234
|
>
|
|
233
235
|
${panelEntries.map((e) => e.tpl)}
|
|
@@ -266,15 +268,15 @@ export function refreshStylebookStyles() {
|
|
|
266
268
|
|
|
267
269
|
const { sizeBreakpoints } = parseMediaEntries(getEffectiveMedia(tab.doc.document?.$media));
|
|
268
270
|
const activeBreakpoints = panel.mediaName
|
|
269
|
-
? activeBreakpointsForWidth(sizeBreakpoints,
|
|
270
|
-
: new Set();
|
|
271
|
+
? activeBreakpointsForWidth(sizeBreakpoints, panel._width as number)
|
|
272
|
+
: new Set<string>();
|
|
271
273
|
|
|
272
274
|
// Re-apply styles to each element in the canvas
|
|
273
275
|
const allEls = canvas.querySelectorAll("*");
|
|
274
276
|
for (const el of allEls) {
|
|
275
277
|
const tag = view.stylebookElToTag.get(el);
|
|
276
278
|
if (!tag) continue;
|
|
277
|
-
const htmlEl =
|
|
279
|
+
const htmlEl = el as HTMLElement;
|
|
278
280
|
// Determine if it's a compound selector (e.g. "ul li") or simple tag
|
|
279
281
|
const parts = tag.split(" ");
|
|
280
282
|
const leafTag = parts[parts.length - 1];
|
|
@@ -289,27 +291,21 @@ export function refreshStylebookStyles() {
|
|
|
289
291
|
for (const [prop, val] of Object.entries(tagStyle)) {
|
|
290
292
|
if (typeof val === "string" || typeof val === "number") {
|
|
291
293
|
try {
|
|
292
|
-
|
|
293
|
-
/** @type {unknown} */ (htmlEl.style)
|
|
294
|
-
)[prop] = val;
|
|
294
|
+
(htmlEl.style as unknown as Record<string, string | number>)[prop] = val;
|
|
295
295
|
} catch {}
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
// Media overrides nested in tag style
|
|
299
299
|
if (activeBreakpoints.size > 0) {
|
|
300
300
|
for (const [key, val] of Object.entries(tagStyle)) {
|
|
301
|
-
if (!key.startsWith("@") || typeof val !== "object") continue;
|
|
301
|
+
if (!key.startsWith("@") || typeof val !== "object" || val === null) continue;
|
|
302
302
|
const mediaName = key.slice(1);
|
|
303
303
|
if (mediaName === "--") continue;
|
|
304
304
|
if (activeBreakpoints.has(mediaName)) {
|
|
305
|
-
for (const [prop, v] of Object.entries(
|
|
306
|
-
/** @type {Record<string, unknown>} */ (val),
|
|
307
|
-
)) {
|
|
305
|
+
for (const [prop, v] of Object.entries(val as Record<string, unknown>)) {
|
|
308
306
|
if (typeof v === "string" || typeof v === "number") {
|
|
309
307
|
try {
|
|
310
|
-
|
|
311
|
-
/** @type {unknown} */ (htmlEl.style)
|
|
312
|
-
)[prop] = v;
|
|
308
|
+
(htmlEl.style as unknown as Record<string, string | number>)[prop] = v;
|
|
313
309
|
} catch {}
|
|
314
310
|
}
|
|
315
311
|
}
|
|
@@ -320,7 +316,7 @@ export function refreshStylebookStyles() {
|
|
|
320
316
|
// Top-level @media keys
|
|
321
317
|
if (activeBreakpoints.size > 0) {
|
|
322
318
|
for (const [key, val] of Object.entries(rootStyle)) {
|
|
323
|
-
if (!key.startsWith("@") || typeof val !== "object") continue;
|
|
319
|
+
if (!key.startsWith("@") || typeof val !== "object" || val === null) continue;
|
|
324
320
|
const mediaName = key.slice(1);
|
|
325
321
|
if (mediaName === "--") continue;
|
|
326
322
|
if (activeBreakpoints.has(mediaName)) {
|
|
@@ -332,9 +328,7 @@ export function refreshStylebookStyles() {
|
|
|
332
328
|
for (const [prop, v] of Object.entries(mediaTagStyle)) {
|
|
333
329
|
if (typeof v === "string" || typeof v === "number") {
|
|
334
330
|
try {
|
|
335
|
-
|
|
336
|
-
/** @type {unknown} */ (htmlEl.style)
|
|
337
|
-
)[prop] = v;
|
|
331
|
+
(htmlEl.style as unknown as Record<string, string | number>)[prop] = v;
|
|
338
332
|
} catch {}
|
|
339
333
|
}
|
|
340
334
|
}
|
|
@@ -354,7 +348,7 @@ export function refreshStylebookStyles() {
|
|
|
354
348
|
* @param {string} tag
|
|
355
349
|
* @param {string | null} [media]
|
|
356
350
|
*/
|
|
357
|
-
export function selectStylebookTag(tag, media, { panCanvas = false } = {}) {
|
|
351
|
+
export function selectStylebookTag(tag: string, media?: string | null, { panCanvas = false } = {}) {
|
|
358
352
|
updateSession({
|
|
359
353
|
selection: [],
|
|
360
354
|
ui: {
|
|
@@ -380,7 +374,7 @@ export function renderStylebookOverlays() {
|
|
|
380
374
|
const selectedTag = activeTab.value?.session.ui.stylebookSelection;
|
|
381
375
|
|
|
382
376
|
for (const panel of canvasPanels) {
|
|
383
|
-
const hoverTag =
|
|
377
|
+
const hoverTag = (panel as StylebookPanel)._lastHoverTag;
|
|
384
378
|
/**
|
|
385
379
|
* @type {{
|
|
386
380
|
* cls: string;
|
|
@@ -436,7 +430,12 @@ export function renderStylebookOverlays() {
|
|
|
436
430
|
* @param {Set<string> | null} activeBreakpoints
|
|
437
431
|
* @param {string | null} [parentTag]
|
|
438
432
|
*/
|
|
439
|
-
export function buildStylebookElement(
|
|
433
|
+
export function buildStylebookElement(
|
|
434
|
+
entry: StylebookEntry,
|
|
435
|
+
rootStyle: Record<string, unknown>,
|
|
436
|
+
activeBreakpoints: Set<string> | null,
|
|
437
|
+
parentTag: string | null = null,
|
|
438
|
+
) {
|
|
440
439
|
const el = document.createElement(entry.tag);
|
|
441
440
|
if (entry.text) el.textContent = entry.text;
|
|
442
441
|
if (entry.attributes) {
|
|
@@ -455,24 +454,21 @@ export function buildStylebookElement(entry, rootStyle, activeBreakpoints, paren
|
|
|
455
454
|
for (const [prop, val] of Object.entries(tagStyle)) {
|
|
456
455
|
if (typeof val === "string" || typeof val === "number") {
|
|
457
456
|
try {
|
|
458
|
-
|
|
459
|
-
val;
|
|
457
|
+
(el.style as unknown as Record<string, string | number>)[prop] = val;
|
|
460
458
|
} catch {}
|
|
461
459
|
}
|
|
462
460
|
}
|
|
463
461
|
if (activeBreakpoints) {
|
|
464
462
|
// Check media overrides nested inside the tag style (selector wraps media)
|
|
465
463
|
for (const [key, val] of Object.entries(tagStyle)) {
|
|
466
|
-
if (!key.startsWith("@") || typeof val !== "object") continue;
|
|
464
|
+
if (!key.startsWith("@") || typeof val !== "object" || val === null) continue;
|
|
467
465
|
const mediaName = key.slice(1);
|
|
468
466
|
if (mediaName === "--") continue;
|
|
469
467
|
if (activeBreakpoints.has(mediaName)) {
|
|
470
|
-
for (const [prop, v] of Object.entries(
|
|
468
|
+
for (const [prop, v] of Object.entries(val as Record<string, unknown>)) {
|
|
471
469
|
if (typeof v === "string" || typeof v === "number") {
|
|
472
470
|
try {
|
|
473
|
-
|
|
474
|
-
prop
|
|
475
|
-
] = v;
|
|
471
|
+
(el.style as unknown as Record<string, string | number>)[prop] = v;
|
|
476
472
|
} catch {}
|
|
477
473
|
}
|
|
478
474
|
}
|
|
@@ -484,21 +480,16 @@ export function buildStylebookElement(entry, rootStyle, activeBreakpoints, paren
|
|
|
484
480
|
if (activeBreakpoints) {
|
|
485
481
|
const tagPath = compoundTag || entry.tag;
|
|
486
482
|
for (const [key, val] of Object.entries(rootStyle)) {
|
|
487
|
-
if (!key.startsWith("@") || typeof val !== "object") continue;
|
|
483
|
+
if (!key.startsWith("@") || typeof val !== "object" || val === null) continue;
|
|
488
484
|
const mediaName = key.slice(1);
|
|
489
485
|
if (mediaName === "--") continue;
|
|
490
486
|
if (activeBreakpoints.has(mediaName)) {
|
|
491
|
-
const mediaTagStyle = _resolveNestedStyle(
|
|
492
|
-
/** @type {Record<string, unknown>} */ (val),
|
|
493
|
-
tagPath,
|
|
494
|
-
);
|
|
487
|
+
const mediaTagStyle = _resolveNestedStyle(val as Record<string, unknown>, tagPath);
|
|
495
488
|
if (mediaTagStyle && typeof mediaTagStyle === "object") {
|
|
496
489
|
for (const [prop, v] of Object.entries(mediaTagStyle)) {
|
|
497
490
|
if (typeof v === "string" || typeof v === "number") {
|
|
498
491
|
try {
|
|
499
|
-
|
|
500
|
-
prop
|
|
501
|
-
] = v;
|
|
492
|
+
(el.style as unknown as Record<string, string | number>)[prop] = v;
|
|
502
493
|
} catch {}
|
|
503
494
|
}
|
|
504
495
|
}
|
|
@@ -520,7 +511,7 @@ export function buildStylebookElement(entry, rootStyle, activeBreakpoints, paren
|
|
|
520
511
|
* @param {ComponentEntry} comp
|
|
521
512
|
* @returns {Promise<HTMLElement>}
|
|
522
513
|
*/
|
|
523
|
-
export async function renderComponentPreview(comp) {
|
|
514
|
+
export async function renderComponentPreview(comp: ComponentEntry) {
|
|
524
515
|
setSkipServerFunctions(true);
|
|
525
516
|
try {
|
|
526
517
|
if (comp.source === "npm") {
|
|
@@ -543,14 +534,14 @@ export async function renderComponentPreview(comp) {
|
|
|
543
534
|
}
|
|
544
535
|
}
|
|
545
536
|
return el;
|
|
546
|
-
} catch (
|
|
537
|
+
} catch (e) {
|
|
547
538
|
console.warn("Component preview failed:", comp.tagName, e);
|
|
548
539
|
return _componentFallback(comp.tagName);
|
|
549
540
|
}
|
|
550
541
|
}
|
|
551
542
|
|
|
552
543
|
/** @param {string} tagName */
|
|
553
|
-
function _componentFallback(tagName) {
|
|
544
|
+
function _componentFallback(tagName: string) {
|
|
554
545
|
const fallback = document.createElement("div");
|
|
555
546
|
fallback.style.cssText =
|
|
556
547
|
"padding:12px;border:1px dashed var(--border);border-radius:4px;color:var(--fg-dim)";
|
|
@@ -562,12 +553,12 @@ function _componentFallback(tagName) {
|
|
|
562
553
|
* @param {Record<string, unknown>} rootStyle
|
|
563
554
|
* @param {string} tag
|
|
564
555
|
*/
|
|
565
|
-
function hasTagStyle(rootStyle, tag) {
|
|
556
|
+
function hasTagStyle(rootStyle: Record<string, unknown>, tag: string) {
|
|
566
557
|
const s = _resolveNestedStyle(rootStyle, tag);
|
|
567
558
|
if (s && typeof s === "object" && Object.keys(s).length > 0) return true;
|
|
568
559
|
for (const [key, val] of Object.entries(rootStyle)) {
|
|
569
|
-
if (!key.startsWith("@") || typeof val !== "object") continue;
|
|
570
|
-
const ms = _resolveNestedStyle(
|
|
560
|
+
if (!key.startsWith("@") || typeof val !== "object" || val === null) continue;
|
|
561
|
+
const ms = _resolveNestedStyle(val as Record<string, unknown>, tag);
|
|
571
562
|
if (ms && typeof ms === "object" && Object.keys(ms).length > 0) return true;
|
|
572
563
|
}
|
|
573
564
|
return false;
|
|
@@ -581,11 +572,11 @@ function hasTagStyle(rootStyle, tag) {
|
|
|
581
572
|
* @param {Set<string> | null} activeBreakpoints
|
|
582
573
|
*/
|
|
583
574
|
export function renderStylebookElementsIntoCanvas(
|
|
584
|
-
canvasEl,
|
|
585
|
-
rootStyle,
|
|
586
|
-
filter,
|
|
587
|
-
customizedOnly,
|
|
588
|
-
activeBreakpoints,
|
|
575
|
+
canvasEl: HTMLElement,
|
|
576
|
+
rootStyle: Record<string, unknown>,
|
|
577
|
+
filter: string,
|
|
578
|
+
customizedOnly: boolean | undefined,
|
|
579
|
+
activeBreakpoints: Set<string> | null,
|
|
589
580
|
) {
|
|
590
581
|
for (const [k, v] of Object.entries(rootStyle)) {
|
|
591
582
|
if (k.startsWith("--") && (typeof v === "string" || typeof v === "number")) {
|
|
@@ -593,23 +584,22 @@ export function renderStylebookElementsIntoCanvas(
|
|
|
593
584
|
}
|
|
594
585
|
}
|
|
595
586
|
|
|
596
|
-
|
|
597
|
-
const sectionTemplates = [];
|
|
587
|
+
const sectionTemplates: import("lit-html").TemplateResult[] = [];
|
|
598
588
|
|
|
599
589
|
for (const section of stylebookMeta.$sections) {
|
|
600
|
-
let entries =
|
|
590
|
+
let entries = section.elements as StylebookEntry[];
|
|
601
591
|
if (filter) {
|
|
602
592
|
entries = entries.filter(
|
|
603
|
-
(
|
|
593
|
+
(e: StylebookEntry) =>
|
|
604
594
|
e.tag.includes(filter) || section.label.toLowerCase().includes(filter),
|
|
605
595
|
);
|
|
606
596
|
}
|
|
607
597
|
if (customizedOnly) {
|
|
608
|
-
entries = entries.filter((
|
|
598
|
+
entries = entries.filter((e: StylebookEntry) => hasTagStyle(rootStyle, e.tag));
|
|
609
599
|
}
|
|
610
600
|
if (entries.length === 0) continue;
|
|
611
601
|
|
|
612
|
-
const cardTemplates = entries.map((
|
|
602
|
+
const cardTemplates = entries.map((entry: StylebookEntry) => {
|
|
613
603
|
const el = buildStylebookElement(entry, rootStyle, activeBreakpoints);
|
|
614
604
|
return html`
|
|
615
605
|
<div
|
|
@@ -654,15 +644,12 @@ export function renderStylebookElementsIntoCanvas(
|
|
|
654
644
|
if (componentRegistry.length > 0) {
|
|
655
645
|
let comps = componentRegistry;
|
|
656
646
|
if (filter)
|
|
657
|
-
comps = comps.filter((
|
|
658
|
-
c.tagName.toLowerCase().includes(filter),
|
|
659
|
-
);
|
|
647
|
+
comps = comps.filter((c: ComponentEntry) => c.tagName.toLowerCase().includes(filter));
|
|
660
648
|
if (customizedOnly)
|
|
661
|
-
comps = comps.filter((
|
|
649
|
+
comps = comps.filter((c: ComponentEntry) => hasTagStyle(rootStyle, c.tagName));
|
|
662
650
|
if (comps.length > 0) {
|
|
663
|
-
const compCards = comps.map((
|
|
664
|
-
|
|
665
|
-
let previewEl = null;
|
|
651
|
+
const compCards = comps.map((comp: ComponentEntry) => {
|
|
652
|
+
let previewEl: HTMLDivElement | null = null;
|
|
666
653
|
const cardTpl = html`
|
|
667
654
|
<div
|
|
668
655
|
class="element-card"
|
|
@@ -676,7 +663,7 @@ export function renderStylebookElementsIntoCanvas(
|
|
|
676
663
|
<div
|
|
677
664
|
class="element-card-preview"
|
|
678
665
|
${ref((c) => {
|
|
679
|
-
if (c) previewEl =
|
|
666
|
+
if (c) previewEl = c as HTMLDivElement;
|
|
680
667
|
})}
|
|
681
668
|
></div>
|
|
682
669
|
<div class="element-card-label"><${comp.tagName}></div>
|
|
@@ -718,20 +705,20 @@ export function renderStylebookElementsIntoCanvas(
|
|
|
718
705
|
*
|
|
719
706
|
* @param {StylebookPanel} panel
|
|
720
707
|
*/
|
|
721
|
-
function registerStylebookPanelEvents(panel) {
|
|
708
|
+
function registerStylebookPanelEvents(panel: StylebookPanel) {
|
|
722
709
|
const { canvas, overlayClk } = panel;
|
|
723
710
|
|
|
724
|
-
overlayClk.addEventListener("click", (
|
|
711
|
+
overlayClk.addEventListener("click", (e: MouseEvent) => {
|
|
725
712
|
const els = canvas.querySelectorAll("*");
|
|
726
|
-
for (const el of els)
|
|
713
|
+
for (const el of els) (el as HTMLElement).style.pointerEvents = "auto";
|
|
727
714
|
overlayClk.style.display = "none";
|
|
728
715
|
const elements = document.elementsFromPoint(e.clientX, e.clientY);
|
|
729
716
|
overlayClk.style.display = "";
|
|
730
|
-
for (const el of els)
|
|
717
|
+
for (const el of els) (el as HTMLElement).style.pointerEvents = "none";
|
|
731
718
|
|
|
732
719
|
for (const el of elements) {
|
|
733
720
|
if (!canvas.contains(el) || el === canvas) continue;
|
|
734
|
-
let cur =
|
|
721
|
+
let cur = el as Element | null;
|
|
735
722
|
while (cur && cur !== canvas) {
|
|
736
723
|
const tag = view.stylebookElToTag.get(cur);
|
|
737
724
|
if (tag) {
|
|
@@ -747,18 +734,18 @@ function registerStylebookPanelEvents(panel) {
|
|
|
747
734
|
renderStylebookOverlays();
|
|
748
735
|
});
|
|
749
736
|
|
|
750
|
-
overlayClk.addEventListener("mousemove", (
|
|
737
|
+
overlayClk.addEventListener("mousemove", (e: MouseEvent) => {
|
|
751
738
|
const els = canvas.querySelectorAll("*");
|
|
752
|
-
for (const el of els)
|
|
739
|
+
for (const el of els) (el as HTMLElement).style.pointerEvents = "auto";
|
|
753
740
|
overlayClk.style.display = "none";
|
|
754
741
|
const elements = document.elementsFromPoint(e.clientX, e.clientY);
|
|
755
742
|
overlayClk.style.display = "";
|
|
756
|
-
for (const el of els)
|
|
743
|
+
for (const el of els) (el as HTMLElement).style.pointerEvents = "none";
|
|
757
744
|
|
|
758
745
|
let hoverTag = null;
|
|
759
746
|
for (const el of elements) {
|
|
760
747
|
if (!canvas.contains(el) || el === canvas) continue;
|
|
761
|
-
let cur =
|
|
748
|
+
let cur = el as Element | null;
|
|
762
749
|
while (cur && cur !== canvas) {
|
|
763
750
|
const tag = view.stylebookElToTag.get(cur);
|
|
764
751
|
if (tag) {
|
|
@@ -778,9 +765,9 @@ function registerStylebookPanelEvents(panel) {
|
|
|
778
765
|
}
|
|
779
766
|
|
|
780
767
|
/** Find a stylebook element by tag in the canvas */
|
|
781
|
-
function findStylebookEl(
|
|
768
|
+
function findStylebookEl(canvasEl: HTMLElement, tag: string) {
|
|
782
769
|
for (const child of canvasEl.querySelectorAll("*")) {
|
|
783
|
-
if (view.stylebookElToTag.get(child) === tag) return
|
|
770
|
+
if (view.stylebookElToTag.get(child) === tag) return child as HTMLElement;
|
|
784
771
|
}
|
|
785
772
|
return null;
|
|
786
773
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
/**
|
|
2
3
|
* Tab strip — renders open tabs above the canvas area.
|
|
3
4
|
*
|
|
@@ -8,24 +9,21 @@
|
|
|
8
9
|
import { html, render as litRender, nothing } from "lit-html";
|
|
9
10
|
import { classMap } from "lit-html/directives/class-map.js";
|
|
10
11
|
import { repeat } from "lit-html/directives/repeat.js";
|
|
11
|
-
import { effect, effectScope } from "../reactivity
|
|
12
|
-
import { workspace, activateTab, closeTab } from "../workspace/workspace
|
|
13
|
-
import {
|
|
12
|
+
import { effect, effectScope } from "../reactivity";
|
|
13
|
+
import { workspace, activateTab, closeTab } from "../workspace/workspace";
|
|
14
|
+
import type { Tab } from "../tabs/tab";
|
|
15
|
+
import { showConfirmDialog } from "../ui/layers";
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
let _host: HTMLElement | null = null;
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
let _host = null;
|
|
19
|
-
|
|
20
|
-
/** @type {import("@vue/reactivity").EffectScope | null} */
|
|
21
|
-
let _scope = null;
|
|
19
|
+
let _scope: import("@vue/reactivity").EffectScope | null = null;
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
22
|
* Mount the tab strip into the given host element.
|
|
25
23
|
*
|
|
26
24
|
* @param {HTMLElement} host
|
|
27
25
|
*/
|
|
28
|
-
export function mount(host) {
|
|
26
|
+
export function mount(host: HTMLElement) {
|
|
29
27
|
_host = host;
|
|
30
28
|
_scope = effectScope();
|
|
31
29
|
_scope.run(() => {
|
|
@@ -71,7 +69,7 @@ function render() {
|
|
|
71
69
|
<div
|
|
72
70
|
class=${classMap({ "tab-strip-tab": true, active: isActive })}
|
|
73
71
|
@click=${() => activateTab(id)}
|
|
74
|
-
@auxclick=${(
|
|
72
|
+
@auxclick=${(e: MouseEvent) => {
|
|
75
73
|
if (e.button === 1) {
|
|
76
74
|
e.preventDefault();
|
|
77
75
|
requestClose(id);
|
|
@@ -83,7 +81,7 @@ function render() {
|
|
|
83
81
|
${isDirty ? html`<span class="tab-strip-dirty">●</span>` : nothing}
|
|
84
82
|
<button
|
|
85
83
|
class="tab-strip-close"
|
|
86
|
-
@click=${(
|
|
84
|
+
@click=${(e: Event) => {
|
|
87
85
|
e.stopPropagation();
|
|
88
86
|
requestClose(id);
|
|
89
87
|
}}
|
|
@@ -106,7 +104,7 @@ function render() {
|
|
|
106
104
|
* @param {Tab} tab
|
|
107
105
|
* @returns {string}
|
|
108
106
|
*/
|
|
109
|
-
function tabLabel(tab) {
|
|
107
|
+
function tabLabel(tab: Tab) {
|
|
110
108
|
const path = tab.documentPath;
|
|
111
109
|
if (!path) return "Untitled";
|
|
112
110
|
const parts = path.split("/");
|
|
@@ -118,7 +116,7 @@ function tabLabel(tab) {
|
|
|
118
116
|
*
|
|
119
117
|
* @param {string} id
|
|
120
118
|
*/
|
|
121
|
-
async function requestClose(id) {
|
|
119
|
+
async function requestClose(id: string) {
|
|
122
120
|
const tab = workspace.tabs.get(id);
|
|
123
121
|
if (!tab) return;
|
|
124
122
|
if (tab.doc.dirty) {
|