@homepages/template-kit 0.8.1-dev-20260718224903 → 0.9.0-dev-20260719224319
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/CHANGELOG.md +61 -1
- package/README.md +2 -2
- package/dist/canvas-core/chrome-css.d.ts +24 -0
- package/dist/canvas-core/chrome-css.js +403 -0
- package/dist/canvas-core/chrome.d.ts +49 -0
- package/dist/canvas-core/chrome.js +147 -0
- package/dist/canvas-core/frame.d.ts +20 -0
- package/dist/canvas-core/frame.js +23 -0
- package/dist/canvas-core/hidden-tabs.d.ts +16 -0
- package/dist/canvas-core/hidden-tabs.js +84 -0
- package/dist/canvas-core/resolve-target.js +55 -0
- package/dist/canvas-core/scroll.d.ts +10 -0
- package/dist/canvas-core/scroll.js +15 -0
- package/dist/canvas-core/section-dom.d.ts +6 -0
- package/dist/canvas-core/section-dom.js +43 -0
- package/dist/canvas-core/srcdoc.d.ts +8 -0
- package/dist/canvas-core/srcdoc.js +77 -0
- package/dist/canvas-core/types.d.ts +76 -0
- package/dist/canvas-core.d.ts +9 -0
- package/dist/canvas-core.js +9 -0
- package/dist/cli/check/css.js +2 -2
- package/dist/cli/check/loader.js +1 -1
- package/dist/cli/check/stages/deps.js +1 -1
- package/dist/cli/check/stages/render.js +3 -2
- package/dist/cli/check/stages/size.js +2 -2
- package/dist/cli/check/stages/tree.js +1 -1
- package/dist/cli/check/stages/validate/index.js +1 -1
- package/dist/cli/check/stages/validate/nav-contract.js +4 -3
- package/dist/cli/check/stages/validate/orchestrator.js +1 -1
- package/dist/cli/check/workspace.js +2 -2
- package/dist/cli/dev/build-css.js +1 -1
- package/dist/cli/dev/discover.js +2 -2
- package/dist/cli/dev/inspect.js +1 -1
- package/dist/cli/dev/island-bootstrap.js +1 -1
- package/dist/cli/dev/island-canvas-bootstrap.js +37 -5
- package/dist/cli/dev/section-page.js +1 -1
- package/dist/cli/dev/server.js +12 -5
- package/dist/cli/dev/tailwind.js +1 -1
- package/dist/cli/dev/tsconfig-paths-plugin.js +1 -1
- package/dist/cli/dev/workspace.js +2 -2
- package/dist/cli/link/index.js +1 -1
- package/dist/cli/link/overlay.js +1 -1
- package/dist/cli/new/emit.js +1 -1
- package/dist/cli/new/index.js +1 -1
- package/dist/cli/new/scaffold/template/sections/hero/fixtures.ts +4 -4
- package/dist/cli/new/scaffold-assets.js +2 -2
- package/dist/cli/pack/collect.js +1 -1
- package/dist/cli/pack/guards.js +1 -1
- package/dist/cli/pack/index.js +1 -1
- package/dist/cli/theme/generate.js +1 -1
- package/dist/cli/theme/load-theme.js +1 -1
- package/dist/dev-client/assets/index-CJa9G1Na.css +1 -0
- package/dist/dev-client/assets/index-C_1atZs4.js +450 -0
- package/dist/dev-client/index.html +2 -2
- package/dist/fixtures/sample-property.d.ts +4 -7
- package/dist/fixtures/sample-property.js +41 -97
- package/dist/fixtures/scenario.d.ts +1 -1
- package/dist/fixtures/scenarios/for-rent-condo.js +24 -44
- package/dist/fixtures/scenarios/luxury-multi-unit.js +1 -1
- package/dist/fixtures/scenarios/sparse-single-family.js +14 -26
- package/dist/fixtures.d.ts +2 -2
- package/dist/fixtures.js +1 -2
- package/dist/islands/client-directive.d.ts +7 -0
- package/dist/{eslint/is-client-file.js → islands/client-directive.js} +6 -3
- package/dist/islands/detect.d.ts +1 -1
- package/dist/islands/detect.js +1 -1
- package/dist/islands/discover.js +1 -1
- package/dist/islands/esbuild-plugin.js +1 -1
- package/dist/islands/wrap.js +1 -1
- package/dist/manifest.json +940 -0
- package/dist/media/pack.d.ts +49 -0
- package/dist/media/pack.js +69 -0
- package/dist/media/resolve-fixture-media.js +73 -0
- package/dist/media/resolve-media.js +195 -0
- package/dist/package.js +1 -1
- package/dist/rules.d.ts +176 -0
- package/dist/rules.js +209 -0
- package/dist/schema/property-facts.d.ts +2 -2
- package/dist/ssr.d.ts +14 -2
- package/dist/ssr.js +28 -13
- package/dist/tokens.css +21 -0
- package/guide/INDEX.md +2 -2
- package/guide/check.md +5 -5
- package/guide/dev.md +39 -30
- package/guide/eslint.md +13 -10
- package/guide/llms.txt +4 -3
- package/guide/quickstart.md +1 -1
- package/guide/recipes/image-slot-crop.md +6 -6
- package/guide/recipes/pick-a-scenario.md +13 -5
- package/guide/rules/INDEX.md +3 -2
- package/guide/schema-system.md +36 -12
- package/guide/upgrading.md +18 -2
- package/package.json +8 -4
- package/tsconfig.json +1 -1
- package/dist/dev-client/assets/index-3Gn34X_P.js +0 -50
- package/dist/dev-client/assets/index-DxQeiHfu.css +0 -1
- package/dist/eslint/is-client-file.d.ts +0 -4
- package/dist/eslint/rules/image-bare-needs-reason.js +0 -43
- package/dist/eslint/rules/no-client-directive-in-contract.js +0 -31
- package/dist/eslint/rules/no-client-runtime-in-server.js +0 -103
- package/dist/eslint/rules/no-css-import-from-render-path.js +0 -29
- package/dist/eslint/rules/no-hex.js +0 -188
- package/dist/eslint/rules/no-inline-style.js +0 -27
- package/dist/eslint/rules/no-nondeterminism.js +0 -48
- package/dist/eslint/rules/no-raw-element.js +0 -38
- package/dist/eslint/rules/props-from-schema.js +0 -37
- package/dist/eslint/rules/require-island-editor.js +0 -74
- package/dist/eslint/rules/serializable-island-props.js +0 -112
- package/dist/eslint/rules/slot-marker-literal.js +0 -38
- package/dist/eslint.d.ts +0 -6
- package/dist/eslint.js +0 -80
- package/dist/rules/registry.js +0 -16
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
//#region src/canvas-core/chrome.ts
|
|
2
|
+
/** How far outside the target the ring sits, in CSS px. With a 2px border-box
|
|
3
|
+
* border, offset = 1 centers the stroke on the element's edge (1px outside,
|
|
4
|
+
* 1px overlapping inside) so the ring reads as flush. */
|
|
5
|
+
const RING_OFFSET = 1;
|
|
6
|
+
/** Inset of the section title pill from the target's left edge, in CSS px. */
|
|
7
|
+
const LABEL_LEFT_INDENT = 12;
|
|
8
|
+
/**
|
|
9
|
+
* Ring geometry in document space: shift by scroll, inflate by `offset`.
|
|
10
|
+
*
|
|
11
|
+
* `containerWidth` clamps the horizontal edges. A section flush with both page
|
|
12
|
+
* edges would otherwise inflate `offset` px past each one and grow the
|
|
13
|
+
* document's horizontal scroll extent. Omitting it means unclamped: the app's
|
|
14
|
+
* overlay is wider than its page card and never overflows, so clamping it would
|
|
15
|
+
* silently shift every full-bleed ring. A consumer whose overlay is page-width
|
|
16
|
+
* opts in by passing one.
|
|
17
|
+
*
|
|
18
|
+
* Absence — not a sentinel value — is what selects the unclamped branch. A
|
|
19
|
+
* numeric stand-in for "unbounded" would make NaN (plausible out of a detached
|
|
20
|
+
* document's clientWidth arithmetic) take the clamped branch and yield NaN
|
|
21
|
+
* geometry, and would let Number.MAX_SAFE_INTEGER quietly enable the left floor.
|
|
22
|
+
*/
|
|
23
|
+
function ringBox(rect, scroll, offset, containerWidth) {
|
|
24
|
+
const rawLeft = rect.left + scroll.x - offset;
|
|
25
|
+
const rawRight = rawLeft + rect.width + 2 * offset;
|
|
26
|
+
const left = containerWidth === void 0 ? rawLeft : Math.max(0, rawLeft);
|
|
27
|
+
const right = containerWidth === void 0 ? rawRight : Math.min(containerWidth, rawRight);
|
|
28
|
+
return {
|
|
29
|
+
top: rect.top + scroll.y - offset,
|
|
30
|
+
left,
|
|
31
|
+
width: Math.max(0, right - left),
|
|
32
|
+
height: rect.height + 2 * offset
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Whether an element has a box a ring can actually wrap. */
|
|
36
|
+
function hasMeasurableRingBox(el) {
|
|
37
|
+
const rect = measureRingRect(el);
|
|
38
|
+
return rect.width > 0 && rect.height > 0;
|
|
39
|
+
}
|
|
40
|
+
function measureRingRect(el) {
|
|
41
|
+
const rect = el.getBoundingClientRect();
|
|
42
|
+
if (rect.width > 0 && rect.height > 0) return rect;
|
|
43
|
+
let top = Infinity;
|
|
44
|
+
let left = Infinity;
|
|
45
|
+
let right = -Infinity;
|
|
46
|
+
let bottom = -Infinity;
|
|
47
|
+
let found = false;
|
|
48
|
+
for (const child of Array.from(el.children)) {
|
|
49
|
+
const childRect = measureRingRect(child);
|
|
50
|
+
if (childRect.width <= 0 || childRect.height <= 0) continue;
|
|
51
|
+
found = true;
|
|
52
|
+
top = Math.min(top, childRect.top);
|
|
53
|
+
left = Math.min(left, childRect.left);
|
|
54
|
+
right = Math.max(right, childRect.right);
|
|
55
|
+
bottom = Math.max(bottom, childRect.bottom);
|
|
56
|
+
}
|
|
57
|
+
if (!found) return rect;
|
|
58
|
+
return new DOMRect(left, top, right - left, bottom - top);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Move a ring in #we-chrome-overlay to sit `offset` px outside `target`.
|
|
62
|
+
*
|
|
63
|
+
* `kind` flips a data attribute so CSS can pick a color (gold for sections and
|
|
64
|
+
* slots). The hover ring leaves it unset and uses its own selector.
|
|
65
|
+
*/
|
|
66
|
+
function positionRing(ring, target, offset, kind, containerWidth) {
|
|
67
|
+
if (!ring) return;
|
|
68
|
+
if (!target) {
|
|
69
|
+
ring.removeAttribute("data-active");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const win = target.ownerDocument.defaultView;
|
|
73
|
+
if (!win) return;
|
|
74
|
+
const box = ringBox(measureRingRect(target), {
|
|
75
|
+
x: win.scrollX,
|
|
76
|
+
y: win.scrollY
|
|
77
|
+
}, offset, containerWidth);
|
|
78
|
+
ring.style.top = `${box.top}px`;
|
|
79
|
+
ring.style.left = `${box.left}px`;
|
|
80
|
+
ring.style.width = `${box.width}px`;
|
|
81
|
+
ring.style.height = `${box.height}px`;
|
|
82
|
+
if (kind) ring.setAttribute("data-kind", kind);
|
|
83
|
+
ring.setAttribute("data-active", "true");
|
|
84
|
+
}
|
|
85
|
+
function applySelectionKind(ring, kind) {
|
|
86
|
+
ring.removeAttribute("data-kind");
|
|
87
|
+
requestAnimationFrame(() => {
|
|
88
|
+
requestAnimationFrame(() => {
|
|
89
|
+
ring.setAttribute("data-kind", kind);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function clearRing(ring) {
|
|
94
|
+
if (!ring) return;
|
|
95
|
+
ring.removeAttribute("data-active");
|
|
96
|
+
ring.removeAttribute("data-kind");
|
|
97
|
+
}
|
|
98
|
+
function positionLabel(label, target, text) {
|
|
99
|
+
if (!label) return;
|
|
100
|
+
if (!target || !text) {
|
|
101
|
+
clearLabel(label);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const win = target.ownerDocument.defaultView;
|
|
105
|
+
if (!win) return;
|
|
106
|
+
const rect = measureRingRect(target);
|
|
107
|
+
const wasActive = label.getAttribute("data-active") === "true";
|
|
108
|
+
const textChanged = label.textContent !== text;
|
|
109
|
+
label.textContent = text;
|
|
110
|
+
label.style.top = `${rect.top + win.scrollY}px`;
|
|
111
|
+
label.style.left = `${rect.left + win.scrollX + 12}px`;
|
|
112
|
+
if (wasActive && textChanged) {
|
|
113
|
+
label.removeAttribute("data-active");
|
|
114
|
+
label.offsetWidth;
|
|
115
|
+
}
|
|
116
|
+
label.setAttribute("data-active", "true");
|
|
117
|
+
}
|
|
118
|
+
function clearLabel(label) {
|
|
119
|
+
if (!label) return;
|
|
120
|
+
label.removeAttribute("data-active");
|
|
121
|
+
label.textContent = "";
|
|
122
|
+
}
|
|
123
|
+
function cssEscape(value) {
|
|
124
|
+
if (typeof CSS !== "undefined" && CSS.escape) return CSS.escape(value);
|
|
125
|
+
return value.replace(/[^a-zA-Z0-9_-]/g, (c) => `\\${c}`);
|
|
126
|
+
}
|
|
127
|
+
function resolveVisibleSlotEl(scope, slotId, markers) {
|
|
128
|
+
const nodes = scope.querySelectorAll(`[${markers.slotId}="${cssEscape(slotId)}"]`);
|
|
129
|
+
for (const el of Array.from(nodes)) if (hasMeasurableRingBox(el)) return el;
|
|
130
|
+
return nodes[0] ?? null;
|
|
131
|
+
}
|
|
132
|
+
function resolveItemEl(slotEl, selection, markers) {
|
|
133
|
+
if (!selection || selection.kind !== "slot" || selection.item_index == null) return null;
|
|
134
|
+
return slotEl?.querySelector(`[${markers.slotItem}="${cssEscape(String(selection.item_index))}"]`) ?? null;
|
|
135
|
+
}
|
|
136
|
+
function resolveSelectionEl(doc, selection, markers) {
|
|
137
|
+
if (!selection) return null;
|
|
138
|
+
const sec = doc.querySelector(`[${markers.sectionInstanceId}="${cssEscape(selection.instance_id)}"]`);
|
|
139
|
+
if (!sec) return null;
|
|
140
|
+
if (selection.kind === "section") return sec;
|
|
141
|
+
const node = resolveVisibleSlotEl(sec, selection.slot_id, markers);
|
|
142
|
+
if (!node) return null;
|
|
143
|
+
return resolveItemEl(node, selection, markers) ?? node.closest(`[${markers.slotGroup}]`) ?? node;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
export { LABEL_LEFT_INDENT, RING_OFFSET, applySelectionKind, clearLabel, clearRing, cssEscape, hasMeasurableRingBox, measureRingRect, positionLabel, positionRing, resolveItemEl, resolveSelectionEl, resolveVisibleSlotEl, ringBox };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CanvasFrameDeps, CanvasSectionEntry, CanvasSelection, CanvasTarget } from "./types.js";
|
|
2
|
+
//#region src/canvas-core/frame.d.ts
|
|
3
|
+
interface CanvasFrame {
|
|
4
|
+
srcdoc(): string;
|
|
5
|
+
buildSectionWrapper(entry: CanvasSectionEntry, doc: Document): HTMLElement;
|
|
6
|
+
buildErrorPlaceholder(entry: CanvasSectionEntry, doc: Document): HTMLElement;
|
|
7
|
+
resolveTarget(hit: HTMLElement | null, sections: CanvasSectionEntry[]): CanvasTarget | null;
|
|
8
|
+
localizeSectionAssets(html: string): string;
|
|
9
|
+
/** The DOM node a selection points at: item, then slot group, then slot —
|
|
10
|
+
* the same order the selection ring targets. */
|
|
11
|
+
resolveSelectionEl(doc: Document, selection: CanvasSelection | null): HTMLElement | null;
|
|
12
|
+
/** The painting copy of a slot, for sections with responsive duplicate DOM. */
|
|
13
|
+
resolveVisibleSlotEl(scope: ParentNode, slotId: string): HTMLElement | null;
|
|
14
|
+
/** The selected collection item within an already-resolved slot element. */
|
|
15
|
+
resolveItemEl(slotEl: HTMLElement | null, selection: CanvasSelection | null): HTMLElement | null;
|
|
16
|
+
}
|
|
17
|
+
/** Bind the frame to one consumer's markers, asset URLs and editability rule. */
|
|
18
|
+
declare function createCanvasFrame(deps: CanvasFrameDeps): CanvasFrame;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { CanvasFrame, createCanvasFrame };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { resolveItemEl, resolveSelectionEl, resolveVisibleSlotEl } from "./chrome.js";
|
|
2
|
+
import { resolveCanvasTarget } from "./resolve-target.js";
|
|
3
|
+
import { buildErrorPlaceholder, buildSectionWrapper } from "./section-dom.js";
|
|
4
|
+
import { buildSrcdoc, localizeSectionAssets } from "./srcdoc.js";
|
|
5
|
+
|
|
6
|
+
//#region src/canvas-core/frame.ts
|
|
7
|
+
/** Bind the frame to one consumer's markers, asset URLs and editability rule. */
|
|
8
|
+
function createCanvasFrame(deps) {
|
|
9
|
+
const localize = (html) => localizeSectionAssets(html, deps.assets.basePath);
|
|
10
|
+
return {
|
|
11
|
+
srcdoc: () => buildSrcdoc(deps.assets, deps.markers),
|
|
12
|
+
buildSectionWrapper: (entry, doc) => buildSectionWrapper(entry, doc, deps.markers, localize),
|
|
13
|
+
buildErrorPlaceholder,
|
|
14
|
+
resolveTarget: (hit, sections) => resolveCanvasTarget(hit, sections, deps),
|
|
15
|
+
localizeSectionAssets: localize,
|
|
16
|
+
resolveSelectionEl: (doc, selection) => resolveSelectionEl(doc, selection, deps.markers),
|
|
17
|
+
resolveVisibleSlotEl: (scope, slotId) => resolveVisibleSlotEl(scope, slotId, deps.markers),
|
|
18
|
+
resolveItemEl: (slotEl, selection) => resolveItemEl(slotEl, selection, deps.markers)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { createCanvasFrame };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/canvas-core/hidden-tabs.d.ts
|
|
2
|
+
declare const WE_TAB_STEP = 42;
|
|
3
|
+
declare const TAB_TUCK = 16;
|
|
4
|
+
interface TabAnchor {
|
|
5
|
+
idx: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
interface HiddenTabSpec {
|
|
9
|
+
instanceId: string;
|
|
10
|
+
label: string;
|
|
11
|
+
}
|
|
12
|
+
declare function placeTabs(anchors: TabAnchor[], step: number): Record<number, number>;
|
|
13
|
+
declare function buildHiddenTab(doc: Document, instanceId: string, label: string, onReveal: () => void): HTMLButtonElement;
|
|
14
|
+
declare function reconcileHiddenTabs(container: HTMLElement, doc: Document, specs: HiddenTabSpec[], onReveal: (instanceId: string) => void): HTMLButtonElement[];
|
|
15
|
+
//#endregion
|
|
16
|
+
export { HiddenTabSpec, TAB_TUCK, TabAnchor, WE_TAB_STEP, buildHiddenTab, placeTabs, reconcileHiddenTabs };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
//#region src/canvas-core/hidden-tabs.ts
|
|
2
|
+
const WE_TAB_STEP = 42;
|
|
3
|
+
const TAB_TUCK = 16;
|
|
4
|
+
function placeTabs(anchors, step) {
|
|
5
|
+
const clusters = [];
|
|
6
|
+
for (const a of anchors) {
|
|
7
|
+
clusters.push({
|
|
8
|
+
sum: a.y,
|
|
9
|
+
n: 1,
|
|
10
|
+
items: [a]
|
|
11
|
+
});
|
|
12
|
+
while (clusters.length > 1) {
|
|
13
|
+
const b = clusters[clusters.length - 1];
|
|
14
|
+
const p = clusters[clusters.length - 2];
|
|
15
|
+
if (!b || !p) break;
|
|
16
|
+
if (b.sum / b.n - (b.n - 1) / 2 * step - (p.sum / p.n + (p.n - 1) / 2 * step) < step) clusters.splice(clusters.length - 2, 2, {
|
|
17
|
+
sum: p.sum + b.sum,
|
|
18
|
+
n: p.n + b.n,
|
|
19
|
+
items: p.items.concat(b.items)
|
|
20
|
+
});
|
|
21
|
+
else break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const out = {};
|
|
25
|
+
for (const c of clusters) {
|
|
26
|
+
const top = c.sum / c.n - (c.n - 1) / 2 * step;
|
|
27
|
+
c.items.forEach((it, i) => {
|
|
28
|
+
out[it.idx] = top + i * step;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
const SVG_WRAP = (cls, inner) => `<svg class="${cls}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${inner}</svg>`;
|
|
34
|
+
const EYE_OFF_SVG = SVG_WRAP("we-htab-eye-off", "<path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\"/><path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\"/><path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\"/><path d=\"m2 2 20 20\"/>");
|
|
35
|
+
const EYE_SVG = SVG_WRAP("we-htab-eye-on", "<path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>");
|
|
36
|
+
const revealHandlers = /* @__PURE__ */ new WeakMap();
|
|
37
|
+
function buildHiddenTab(doc, instanceId, label, onReveal) {
|
|
38
|
+
const btn = doc.createElement("button");
|
|
39
|
+
btn.type = "button";
|
|
40
|
+
btn.className = "we-htab";
|
|
41
|
+
btn.dataset.hiddenTab = instanceId;
|
|
42
|
+
btn.title = `Show ${label}`;
|
|
43
|
+
btn.setAttribute("aria-label", `Show ${label}`);
|
|
44
|
+
btn.innerHTML = `<span class="we-htab-eye">${EYE_OFF_SVG}${EYE_SVG}</span><span class="we-htab-name"></span>`;
|
|
45
|
+
const nameEl = btn.querySelector(".we-htab-name");
|
|
46
|
+
if (nameEl) nameEl.textContent = label;
|
|
47
|
+
revealHandlers.set(btn, onReveal);
|
|
48
|
+
btn.addEventListener("click", (event) => {
|
|
49
|
+
event.stopPropagation();
|
|
50
|
+
revealHandlers.get(btn)?.();
|
|
51
|
+
});
|
|
52
|
+
return btn;
|
|
53
|
+
}
|
|
54
|
+
function reconcileHiddenTabs(container, doc, specs, onReveal) {
|
|
55
|
+
const existing = /* @__PURE__ */ new Map();
|
|
56
|
+
container.querySelectorAll(".we-htab").forEach((el) => {
|
|
57
|
+
const id = el.dataset.hiddenTab;
|
|
58
|
+
if (id) existing.set(id, el);
|
|
59
|
+
});
|
|
60
|
+
const keep = /* @__PURE__ */ new Set();
|
|
61
|
+
const live = [];
|
|
62
|
+
for (const spec of specs) {
|
|
63
|
+
let el = existing.get(spec.instanceId);
|
|
64
|
+
if (!el) {
|
|
65
|
+
el = buildHiddenTab(doc, spec.instanceId, spec.label, () => onReveal(spec.instanceId));
|
|
66
|
+
container.appendChild(el);
|
|
67
|
+
} else {
|
|
68
|
+
const nameEl = el.querySelector(".we-htab-name");
|
|
69
|
+
if (nameEl && nameEl.textContent !== spec.label) nameEl.textContent = spec.label;
|
|
70
|
+
el.title = `Show ${spec.label}`;
|
|
71
|
+
el.setAttribute("aria-label", `Show ${spec.label}`);
|
|
72
|
+
revealHandlers.set(el, () => onReveal(spec.instanceId));
|
|
73
|
+
}
|
|
74
|
+
keep.add(spec.instanceId);
|
|
75
|
+
live.push(el);
|
|
76
|
+
}
|
|
77
|
+
existing.forEach((el, id) => {
|
|
78
|
+
if (!keep.has(id)) el.remove();
|
|
79
|
+
});
|
|
80
|
+
return live;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
export { TAB_TUCK, WE_TAB_STEP, buildHiddenTab, placeTabs, reconcileHiddenTabs };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/canvas-core/resolve-target.ts
|
|
2
|
+
function firstEditableGroupMemberId(groupEl, instanceId, deps) {
|
|
3
|
+
for (const el of Array.from(groupEl.querySelectorAll(`[${deps.markers.slotId}]`))) {
|
|
4
|
+
const id = el.getAttribute(deps.markers.slotId);
|
|
5
|
+
if (id && deps.isSlotEditable(instanceId, id)) return id;
|
|
6
|
+
}
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
function resolveCanvasTarget(hit, sections, deps) {
|
|
10
|
+
if (!hit) return null;
|
|
11
|
+
const sectionEl = hit.closest(`[${deps.markers.sectionInstanceId}]`);
|
|
12
|
+
const instanceId = sectionEl?.getAttribute(deps.markers.sectionInstanceId);
|
|
13
|
+
if (!sectionEl || !instanceId) return null;
|
|
14
|
+
const section = sections.find((s) => s.instance_id === instanceId);
|
|
15
|
+
const sectionTarget = {
|
|
16
|
+
selection: {
|
|
17
|
+
kind: "section",
|
|
18
|
+
instance_id: instanceId
|
|
19
|
+
},
|
|
20
|
+
element: sectionEl
|
|
21
|
+
};
|
|
22
|
+
if (!section) return sectionTarget;
|
|
23
|
+
const groupEl = hit.closest(`[${deps.markers.slotGroup}]`);
|
|
24
|
+
if (groupEl && sectionEl.contains(groupEl)) {
|
|
25
|
+
const repId = firstEditableGroupMemberId(groupEl, instanceId, deps);
|
|
26
|
+
if (!repId) return sectionTarget;
|
|
27
|
+
return {
|
|
28
|
+
selection: {
|
|
29
|
+
kind: "slot",
|
|
30
|
+
instance_id: instanceId,
|
|
31
|
+
slot_id: repId
|
|
32
|
+
},
|
|
33
|
+
element: groupEl
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const slotEl = hit.closest(`[${deps.markers.slotId}]`);
|
|
37
|
+
const slotId = slotEl?.getAttribute(deps.markers.slotId);
|
|
38
|
+
if (!slotEl || !slotId) return sectionTarget;
|
|
39
|
+
if (!deps.isSlotEditable(instanceId, slotId)) return sectionTarget;
|
|
40
|
+
const itemEl = hit.closest(`[${deps.markers.slotItem}]`);
|
|
41
|
+
const rawItem = itemEl ? Number(itemEl.getAttribute(deps.markers.slotItem)) : NaN;
|
|
42
|
+
const itemIndex = Number.isInteger(rawItem) ? rawItem : void 0;
|
|
43
|
+
return {
|
|
44
|
+
selection: {
|
|
45
|
+
kind: "slot",
|
|
46
|
+
instance_id: instanceId,
|
|
47
|
+
slot_id: slotId,
|
|
48
|
+
...itemIndex !== void 0 ? { item_index: itemIndex } : {}
|
|
49
|
+
},
|
|
50
|
+
element: itemEl ?? slotEl
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { resolveCanvasTarget };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/canvas-core/scroll.d.ts
|
|
2
|
+
declare const SCROLL_MARGIN_PX = 24;
|
|
3
|
+
interface ScrollRect {
|
|
4
|
+
top: number;
|
|
5
|
+
bottom: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
declare function computeScrollTop(rect: ScrollRect, viewportH: number, scrollY: number, margin: number): number | null;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { SCROLL_MARGIN_PX, ScrollRect, computeScrollTop };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/canvas-core/scroll.ts
|
|
2
|
+
const SCROLL_MARGIN_PX = 24;
|
|
3
|
+
function computeScrollTop(rect, viewportH, scrollY, margin) {
|
|
4
|
+
if (rect.height + 2 * margin <= viewportH) {
|
|
5
|
+
if (rect.top >= margin && rect.bottom <= viewportH - margin) return null;
|
|
6
|
+
if (rect.top < margin) return Math.max(0, scrollY + rect.top - margin);
|
|
7
|
+
return Math.max(0, scrollY + rect.bottom - (viewportH - margin));
|
|
8
|
+
}
|
|
9
|
+
const target = Math.max(0, scrollY + rect.top - margin);
|
|
10
|
+
if (Math.abs(target - scrollY) < 1) return null;
|
|
11
|
+
return target;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { SCROLL_MARGIN_PX, computeScrollTop };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CanvasSectionEntry } from "./types.js";
|
|
2
|
+
//#region src/canvas-core/section-dom.d.ts
|
|
3
|
+
declare function sectionLabel(entry: CanvasSectionEntry): string;
|
|
4
|
+
declare function hashHtml(html: string | null): string;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { hashHtml, sectionLabel };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/canvas-core/section-dom.ts
|
|
2
|
+
function sectionLabel(entry) {
|
|
3
|
+
if (entry.section_display_name) return entry.section_display_name;
|
|
4
|
+
return entry.section_key.split("-").map((p) => p ? p[0].toUpperCase() + p.slice(1) : p).join(" ");
|
|
5
|
+
}
|
|
6
|
+
function hashHtml(html) {
|
|
7
|
+
if (!html) return "null";
|
|
8
|
+
let h = 2166136261;
|
|
9
|
+
for (let i = 0; i < html.length; i++) {
|
|
10
|
+
h ^= html.charCodeAt(i);
|
|
11
|
+
h = Math.imul(h, 16777619);
|
|
12
|
+
}
|
|
13
|
+
return (h >>> 0).toString(16);
|
|
14
|
+
}
|
|
15
|
+
function buildErrorPlaceholder(entry, doc) {
|
|
16
|
+
const card = doc.createElement("div");
|
|
17
|
+
card.className = "we-render-error";
|
|
18
|
+
const title = doc.createElement("p");
|
|
19
|
+
title.className = "we-render-error__title";
|
|
20
|
+
title.textContent = "Couldn’t render this section.";
|
|
21
|
+
const detail = doc.createElement("p");
|
|
22
|
+
detail.className = "we-render-error__detail";
|
|
23
|
+
detail.textContent = entry.render_error?.message ?? "Unknown render error.";
|
|
24
|
+
card.appendChild(title);
|
|
25
|
+
card.appendChild(detail);
|
|
26
|
+
return card;
|
|
27
|
+
}
|
|
28
|
+
function buildSectionWrapper(entry, doc, markers, localize) {
|
|
29
|
+
const wrapper = doc.createElement("div");
|
|
30
|
+
wrapper.setAttribute(markers.sectionInstanceId, entry.instance_id);
|
|
31
|
+
wrapper.setAttribute("data-section-label", sectionLabel(entry));
|
|
32
|
+
wrapper.dataset.svId = entry.section_version_id;
|
|
33
|
+
wrapper.dataset.htmlHash = hashHtml(entry.html);
|
|
34
|
+
const body = doc.createElement("div");
|
|
35
|
+
body.className = "we-section-body";
|
|
36
|
+
if (entry.render_error || entry.html === null) body.appendChild(buildErrorPlaceholder(entry, doc));
|
|
37
|
+
else body.innerHTML = localize(entry.html);
|
|
38
|
+
wrapper.appendChild(body);
|
|
39
|
+
return wrapper;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { buildErrorPlaceholder, buildSectionWrapper, hashHtml, sectionLabel };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CanvasAssets, MarkerAttrs } from "./types.js";
|
|
2
|
+
//#region src/canvas-core/srcdoc.d.ts
|
|
3
|
+
declare function localizeSectionAssets(html: string, basePath: string): string;
|
|
4
|
+
declare function buildSrcdoc(assets: CanvasAssets, markers: MarkerAttrs): string;
|
|
5
|
+
declare function buildSrcdocError(): string;
|
|
6
|
+
declare function isCanvasScaffoldReady(doc: Document | null | undefined): boolean;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { buildSrcdoc, buildSrcdocError, isCanvasScaffoldReady, localizeSectionAssets };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { buildChromeCss } from "./chrome-css.js";
|
|
2
|
+
|
|
3
|
+
//#region src/canvas-core/srcdoc.ts
|
|
4
|
+
function jsonForScript(value) {
|
|
5
|
+
return JSON.stringify(value).replaceAll("<", "\\u003c").replaceAll(">", "\\u003e").replaceAll("&", "\\u0026");
|
|
6
|
+
}
|
|
7
|
+
function islandHead(assets) {
|
|
8
|
+
if (Object.keys(assets.islandMap).length === 0) return "";
|
|
9
|
+
if (Object.keys(assets.importMap).length === 0 && !assets.hostResolvesOwnImports) {
|
|
10
|
+
console.error("canvas: this template version has islands but no import map, so nothing can resolve their React — sections render statically. Republish the template to emit the vendor.");
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
const host = assets.hostScriptSrc ? `
|
|
14
|
+
<script id="tr-island-host" type="module" src="${assets.hostScriptSrc}"><\/script>` : "";
|
|
15
|
+
return `${Object.keys(assets.importMap).length === 0 ? "" : `
|
|
16
|
+
<script type="importmap">${jsonForScript({ imports: assets.importMap })}<\/script>`}
|
|
17
|
+
<script>window.__TR_ISLAND_MAP=${jsonForScript(assets.islandMap)};<\/script>
|
|
18
|
+
<!-- id is the contract the host's readiness gate keys off — it waits on THIS
|
|
19
|
+
element's load event, not a timeout, so a slow cold first load still
|
|
20
|
+
activates without a refresh. -->${host}`;
|
|
21
|
+
}
|
|
22
|
+
function localizeSectionAssets(html, basePath) {
|
|
23
|
+
return html.replaceAll("/section-assets/", `${basePath}runtime/section-asset/`);
|
|
24
|
+
}
|
|
25
|
+
function buildSrcdoc(assets, markers) {
|
|
26
|
+
const links = assets.stylesheets.map((href) => `<link rel="stylesheet" href="${href}">`).join("");
|
|
27
|
+
return `<!doctype html>
|
|
28
|
+
<html>
|
|
29
|
+
<head>
|
|
30
|
+
<meta charset="utf-8">
|
|
31
|
+
<base href="${assets.basePath}">
|
|
32
|
+
${links}${islandHead(assets)}
|
|
33
|
+
<style>${buildChromeCss(markers)}</style>
|
|
34
|
+
</head>
|
|
35
|
+
<body>
|
|
36
|
+
<div id="we-zoom">
|
|
37
|
+
<div id="we-page"></div>
|
|
38
|
+
</div>
|
|
39
|
+
<div id="we-chrome-overlay" aria-hidden="true">
|
|
40
|
+
<div class="we-chrome-ring we-chrome-ring--hover"></div>
|
|
41
|
+
<div class="we-chrome-ring we-chrome-ring--selection"></div>
|
|
42
|
+
<div class="we-chrome-label"></div>
|
|
43
|
+
</div>
|
|
44
|
+
<div id="we-htabs"></div>
|
|
45
|
+
</body>
|
|
46
|
+
</html>`;
|
|
47
|
+
}
|
|
48
|
+
function buildSrcdocError() {
|
|
49
|
+
return `<!doctype html>
|
|
50
|
+
<html>
|
|
51
|
+
<head>
|
|
52
|
+
<meta charset="utf-8">
|
|
53
|
+
<style>
|
|
54
|
+
body { margin: 0; font-family: ui-sans-serif, system-ui, sans-serif; }
|
|
55
|
+
.we-assets-error {
|
|
56
|
+
margin: 40px; padding: 24px 28px; border-radius: 8px;
|
|
57
|
+
border: 1px solid #e6c0c0; background: #fdf4f4; color: #7a2e2e;
|
|
58
|
+
font-size: 14px; line-height: 1.5; max-width: 520px;
|
|
59
|
+
}
|
|
60
|
+
.we-assets-error strong { display: block; margin-bottom: 6px; font-size: 15px; }
|
|
61
|
+
</style>
|
|
62
|
+
</head>
|
|
63
|
+
<body>
|
|
64
|
+
<div class="we-assets-error" role="alert">
|
|
65
|
+
<strong>Template assets unavailable</strong>
|
|
66
|
+
This template has no published static-assets binding. Re-publish
|
|
67
|
+
the template registry, then reload the editor.
|
|
68
|
+
</div>
|
|
69
|
+
</body>
|
|
70
|
+
</html>`;
|
|
71
|
+
}
|
|
72
|
+
function isCanvasScaffoldReady(doc) {
|
|
73
|
+
return !!doc?.getElementById("we-page");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { buildSrcdoc, buildSrcdocError, isCanvasScaffoldReady, localizeSectionAssets };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//#region src/canvas-core/types.d.ts
|
|
2
|
+
/** Marker attribute names the frame stamps and reads. Injected because each
|
|
3
|
+
* consuming repo owns its own generated copy of the marker contract. */
|
|
4
|
+
interface MarkerAttrs {
|
|
5
|
+
sectionInstanceId: string;
|
|
6
|
+
slotId: string;
|
|
7
|
+
slotGroup: string;
|
|
8
|
+
slotItem: string;
|
|
9
|
+
}
|
|
10
|
+
/** Everything the frame needs to resolve a URL. The app derives this from its
|
|
11
|
+
* published static-asset binding; a dev harness derives it from its own server. */
|
|
12
|
+
interface CanvasAssets {
|
|
13
|
+
/** Prefix for every same-origin URL the frame emits, e.g. "/app/" or "/". */
|
|
14
|
+
basePath: string;
|
|
15
|
+
/** Stylesheet hrefs, emitted in order. Already absolute or base-relative. */
|
|
16
|
+
stylesheets: string[];
|
|
17
|
+
/** Bare-specifier -> URL, emitted as an import map. Empty means no islands. */
|
|
18
|
+
importMap: Record<string, string>;
|
|
19
|
+
/** Island key -> module URL, emitted as window.__TR_ISLAND_MAP. */
|
|
20
|
+
islandMap: Record<string, string>;
|
|
21
|
+
/** The island host module, or null to emit no host. */
|
|
22
|
+
hostScriptSrc: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* True when the host module resolves its own bare specifiers — a build-time
|
|
25
|
+
* transform (a Vite dev server, say) having already rewritten every import
|
|
26
|
+
* including `react`. Such a consumer needs no import map, so an empty
|
|
27
|
+
* `importMap` is correct rather than broken.
|
|
28
|
+
*
|
|
29
|
+
* Defaults to false, which keeps the strict gate: for a host that DOES carry
|
|
30
|
+
* bare specifiers, an empty import map means its `import "react"` cannot
|
|
31
|
+
* resolve, and emitting no host at all beats emitting one that throws.
|
|
32
|
+
*/
|
|
33
|
+
hostResolvesOwnImports?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** The subset of a rendered section the frame needs: exactly the fields the frame
|
|
36
|
+
* reads, and no more. Field names mirror the consumer's own entry shape, so a
|
|
37
|
+
* richer entry type satisfies this structurally and is passed unconverted. */
|
|
38
|
+
interface CanvasSectionEntry {
|
|
39
|
+
instance_id: string;
|
|
40
|
+
section_version_id: string;
|
|
41
|
+
section_key: string;
|
|
42
|
+
section_display_name?: string | null;
|
|
43
|
+
html: string | null;
|
|
44
|
+
render_error?: {
|
|
45
|
+
code: string;
|
|
46
|
+
message: string;
|
|
47
|
+
} | null;
|
|
48
|
+
}
|
|
49
|
+
/** A resolved canvas selection. A discriminated union rather than flat optionals
|
|
50
|
+
* so a slot selection structurally always carries its slot_id. */
|
|
51
|
+
type CanvasSelection = {
|
|
52
|
+
kind: "section";
|
|
53
|
+
instance_id: string;
|
|
54
|
+
} | {
|
|
55
|
+
kind: "slot";
|
|
56
|
+
instance_id: string;
|
|
57
|
+
slot_id: string;
|
|
58
|
+
/** For collection slots: the item the user clicked (the slotItem index). */
|
|
59
|
+
item_index?: number;
|
|
60
|
+
};
|
|
61
|
+
interface CanvasTarget {
|
|
62
|
+
selection: CanvasSelection;
|
|
63
|
+
element: HTMLElement;
|
|
64
|
+
}
|
|
65
|
+
/** The frame's injected dependencies. */
|
|
66
|
+
interface CanvasFrameDeps {
|
|
67
|
+
markers: MarkerAttrs;
|
|
68
|
+
assets: CanvasAssets;
|
|
69
|
+
/** True when a slot may be selected. Inverted out of the kernel so it does not
|
|
70
|
+
* pull in a consumer's slot-editor registry. Keyed on the section INSTANCE id,
|
|
71
|
+
* not the section key: two instances of one key can pin different section
|
|
72
|
+
* versions, so the key alone does not determine a slot's schema. */
|
|
73
|
+
isSlotEditable: (sectionInstanceId: string, slotId: string) => boolean;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { CanvasAssets, CanvasFrameDeps, CanvasSectionEntry, CanvasSelection, CanvasTarget, MarkerAttrs };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CanvasAssets, CanvasFrameDeps, CanvasSectionEntry, CanvasSelection, CanvasTarget, MarkerAttrs } from "./canvas-core/types.js";
|
|
2
|
+
import { LABEL_LEFT_INDENT, RING_OFFSET, RingRect, applySelectionKind, clearLabel, clearRing, cssEscape, hasMeasurableRingBox, measureRingRect, positionLabel, positionRing, ringBox } from "./canvas-core/chrome.js";
|
|
3
|
+
import { HOST_INJECTED_PROPERTIES, buildChromeCss } from "./canvas-core/chrome-css.js";
|
|
4
|
+
import { CanvasFrame, createCanvasFrame } from "./canvas-core/frame.js";
|
|
5
|
+
import { HiddenTabSpec, TAB_TUCK, TabAnchor, WE_TAB_STEP, buildHiddenTab, placeTabs, reconcileHiddenTabs } from "./canvas-core/hidden-tabs.js";
|
|
6
|
+
import { SCROLL_MARGIN_PX, ScrollRect, computeScrollTop } from "./canvas-core/scroll.js";
|
|
7
|
+
import { hashHtml, sectionLabel } from "./canvas-core/section-dom.js";
|
|
8
|
+
import { buildSrcdoc, buildSrcdocError, isCanvasScaffoldReady, localizeSectionAssets } from "./canvas-core/srcdoc.js";
|
|
9
|
+
export { type CanvasAssets, type CanvasFrame, type CanvasFrameDeps, type CanvasSectionEntry, type CanvasSelection, type CanvasTarget, HOST_INJECTED_PROPERTIES, type HiddenTabSpec, LABEL_LEFT_INDENT, type MarkerAttrs, RING_OFFSET, type RingRect, SCROLL_MARGIN_PX, type ScrollRect, TAB_TUCK, type TabAnchor, WE_TAB_STEP, applySelectionKind, buildChromeCss, buildHiddenTab, buildSrcdoc, buildSrcdocError, clearLabel, clearRing, computeScrollTop, createCanvasFrame, cssEscape, hasMeasurableRingBox, hashHtml, isCanvasScaffoldReady, localizeSectionAssets, measureRingRect, placeTabs, positionLabel, positionRing, reconcileHiddenTabs, ringBox, sectionLabel };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { LABEL_LEFT_INDENT, RING_OFFSET, applySelectionKind, clearLabel, clearRing, cssEscape, hasMeasurableRingBox, measureRingRect, positionLabel, positionRing, ringBox } from "./canvas-core/chrome.js";
|
|
2
|
+
import { TAB_TUCK, WE_TAB_STEP, buildHiddenTab, placeTabs, reconcileHiddenTabs } from "./canvas-core/hidden-tabs.js";
|
|
3
|
+
import { HOST_INJECTED_PROPERTIES, buildChromeCss } from "./canvas-core/chrome-css.js";
|
|
4
|
+
import { hashHtml, sectionLabel } from "./canvas-core/section-dom.js";
|
|
5
|
+
import { buildSrcdoc, buildSrcdocError, isCanvasScaffoldReady, localizeSectionAssets } from "./canvas-core/srcdoc.js";
|
|
6
|
+
import { createCanvasFrame } from "./canvas-core/frame.js";
|
|
7
|
+
import { SCROLL_MARGIN_PX, computeScrollTop } from "./canvas-core/scroll.js";
|
|
8
|
+
|
|
9
|
+
export { HOST_INJECTED_PROPERTIES, LABEL_LEFT_INDENT, RING_OFFSET, SCROLL_MARGIN_PX, TAB_TUCK, WE_TAB_STEP, applySelectionKind, buildChromeCss, buildHiddenTab, buildSrcdoc, buildSrcdocError, clearLabel, clearRing, computeScrollTop, createCanvasFrame, cssEscape, hasMeasurableRingBox, hashHtml, isCanvasScaffoldReady, localizeSectionAssets, measureRingRect, placeTabs, positionLabel, positionRing, reconcileHiddenTabs, ringBox, sectionLabel };
|
package/dist/cli/check/css.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { loadEsbuild } from "./resolve-tool.js";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
2
|
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
5
|
|
|
6
6
|
//#region src/cli/check/css.ts
|
|
7
7
|
/**
|
package/dist/cli/check/loader.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { loadEsbuild } from "./resolve-tool.js";
|
|
2
2
|
import { ASSET_LOADERS, ASSET_NAMES } from "./css.js";
|
|
3
|
-
import { join, relative } from "node:path";
|
|
4
3
|
import { mkdir, rm, stat } from "node:fs/promises";
|
|
4
|
+
import { join, relative } from "node:path";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CHECK_CONFIG } from "../config.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { promisify } from "node:util";
|
|
5
4
|
import { readFile, readdir, realpath, stat } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
6
|
import { execFile } from "node:child_process";
|
|
7
7
|
|
|
8
8
|
//#region src/cli/check/stages/deps.ts
|