@homepages/template-kit 0.9.0-dev-20260719224319 → 0.9.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/CHANGELOG.md +29 -59
- package/README.md +14 -4
- package/dist/contracts/fill-treatments.d.ts +23 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/islands/discover.js +1 -1
- package/dist/islands/esbuild-plugin.js +1 -1
- package/dist/islands/wrap.d.ts +9 -1
- package/dist/media/resolve-fixture-media.d.ts +22 -0
- package/dist/package.js +1 -1
- package/dist/schema/resolve-section-ref.d.ts +4 -0
- package/dist/schema/rows.d.ts +9 -0
- package/dist/schema/section-nav.d.ts +5 -1
- package/dist/schema/slot-types.d.ts +1 -1
- package/dist/ssr.d.ts +7 -2
- package/dist/ssr.js +6 -2
- package/guide/INDEX.md +5 -0
- package/guide/check.md +1 -0
- package/guide/dev.md +1 -0
- package/guide/llms.txt +11 -3
- package/guide/upgrading.md +12 -8
- package/package.json +4 -16
- package/dist/canvas-core/chrome-css.d.ts +0 -24
- package/dist/canvas-core/chrome-css.js +0 -403
- package/dist/canvas-core/chrome.d.ts +0 -49
- package/dist/canvas-core/chrome.js +0 -147
- package/dist/canvas-core/frame.d.ts +0 -20
- package/dist/canvas-core/frame.js +0 -23
- package/dist/canvas-core/hidden-tabs.d.ts +0 -16
- package/dist/canvas-core/hidden-tabs.js +0 -84
- package/dist/canvas-core/resolve-target.js +0 -55
- package/dist/canvas-core/scroll.d.ts +0 -10
- package/dist/canvas-core/scroll.js +0 -15
- package/dist/canvas-core/section-dom.d.ts +0 -6
- package/dist/canvas-core/section-dom.js +0 -43
- package/dist/canvas-core/srcdoc.d.ts +0 -8
- package/dist/canvas-core/srcdoc.js +0 -77
- package/dist/canvas-core/types.d.ts +0 -76
- package/dist/canvas-core.d.ts +0 -9
- package/dist/canvas-core.js +0 -9
- package/dist/cli/check/config.js +0 -41
- package/dist/cli/check/css.js +0 -131
- package/dist/cli/check/diagnostics.js +0 -37
- package/dist/cli/check/index.js +0 -94
- package/dist/cli/check/loader.js +0 -149
- package/dist/cli/check/paths.js +0 -15
- package/dist/cli/check/relativize.js +0 -18
- package/dist/cli/check/render-invariants.js +0 -24
- package/dist/cli/check/resolve-tool.js +0 -38
- package/dist/cli/check/section-assets.js +0 -58
- package/dist/cli/check/stages/deps.js +0 -337
- package/dist/cli/check/stages/lint.js +0 -46
- package/dist/cli/check/stages/render.js +0 -98
- package/dist/cli/check/stages/size.js +0 -274
- package/dist/cli/check/stages/tree.js +0 -206
- package/dist/cli/check/stages/typecheck.js +0 -46
- package/dist/cli/check/stages/validate/catalog-exhaustiveness.js +0 -18
- package/dist/cli/check/stages/validate/facts.js +0 -19
- package/dist/cli/check/stages/validate/formatter-contract.js +0 -14
- package/dist/cli/check/stages/validate/group-contract.js +0 -21
- package/dist/cli/check/stages/validate/index.js +0 -66
- package/dist/cli/check/stages/validate/list-scalar-contract.js +0 -22
- package/dist/cli/check/stages/validate/nav-contract.js +0 -93
- package/dist/cli/check/stages/validate/nested-slot-contract.js +0 -12
- package/dist/cli/check/stages/validate/object-list-contract.js +0 -31
- package/dist/cli/check/stages/validate/orchestrator.js +0 -241
- package/dist/cli/check/stages/validate/produced-by-contract.js +0 -18
- package/dist/cli/check/stages/validate/row-contract.js +0 -31
- package/dist/cli/check/stages/validate/select-contract.js +0 -13
- package/dist/cli/check/stages/validate/source-contract.js +0 -21
- package/dist/cli/check/stages/validate/variant-contract.js +0 -15
- package/dist/cli/check/workspace.js +0 -99
- package/dist/cli/dev/build-css.js +0 -97
- package/dist/cli/dev/catalog.js +0 -35
- package/dist/cli/dev/compose-template.js +0 -39
- package/dist/cli/dev/content-override.js +0 -58
- package/dist/cli/dev/diagnostics.js +0 -68
- package/dist/cli/dev/discover.js +0 -35
- package/dist/cli/dev/fill-state.js +0 -77
- package/dist/cli/dev/index.js +0 -42
- package/dist/cli/dev/inspect.js +0 -38
- package/dist/cli/dev/island-bootstrap.js +0 -38
- package/dist/cli/dev/island-canvas-bootstrap.js +0 -204
- package/dist/cli/dev/island-map.js +0 -35
- package/dist/cli/dev/island-transform.js +0 -31
- package/dist/cli/dev/manifest-instances.js +0 -31
- package/dist/cli/dev/render-section.js +0 -24
- package/dist/cli/dev/screenshot-target.js +0 -24
- package/dist/cli/dev/section-page.js +0 -91
- package/dist/cli/dev/server.js +0 -511
- package/dist/cli/dev/slot-schema.js +0 -12
- package/dist/cli/dev/structure-summary.js +0 -119
- package/dist/cli/dev/tailwind.js +0 -32
- package/dist/cli/dev/tsconfig-paths-plugin.js +0 -90
- package/dist/cli/dev/vite-server.js +0 -39
- package/dist/cli/dev/workspace.js +0 -63
- package/dist/cli/link/index.js +0 -74
- package/dist/cli/link/overlay.js +0 -59
- package/dist/cli/link/watch.js +0 -25
- package/dist/cli/new/emit.js +0 -48
- package/dist/cli/new/index.js +0 -69
- package/dist/cli/new/scaffold/section/_Renderer.tsx +0 -20
- package/dist/cli/new/scaffold/section/_fill-spec.ts +0 -18
- package/dist/cli/new/scaffold/section/_fixtures.ts +0 -13
- package/dist/cli/new/scaffold/section/_schema.ts +0 -24
- package/dist/cli/new/scaffold/template/_manifest.json +0 -9
- package/dist/cli/new/scaffold/template/sections/hero/ExpandableText.tsx +0 -45
- package/dist/cli/new/scaffold/template/sections/hero/Renderer.tsx +0 -40
- package/dist/cli/new/scaffold/template/sections/hero/components/Feature.tsx +0 -14
- package/dist/cli/new/scaffold/template/sections/hero/fill-spec.ts +0 -29
- package/dist/cli/new/scaffold/template/sections/hero/fixtures.ts +0 -41
- package/dist/cli/new/scaffold/template/sections/hero/schema.ts +0 -60
- package/dist/cli/new/scaffold/template/theme.css +0 -24
- package/dist/cli/new/scaffold/template/theme.ts +0 -27
- package/dist/cli/new/scaffold-assets.js +0 -20
- package/dist/cli/pack/collect.js +0 -44
- package/dist/cli/pack/guards.js +0 -57
- package/dist/cli/pack/index.js +0 -66
- package/dist/cli/pack/manifest.js +0 -15
- package/dist/cli/pack/zip.js +0 -86
- package/dist/cli/theme/generate.js +0 -43
- package/dist/cli/theme/index.js +0 -33
- package/dist/cli/theme/load-theme.js +0 -69
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -138
- package/dist/dev-client/assets/index-CJa9G1Na.css +0 -1
- package/dist/dev-client/assets/index-C_1atZs4.js +0 -450
- package/dist/dev-client/index.html +0 -13
- package/dist/tokens.css +0 -21
|
@@ -1,84 +0,0 @@
|
|
|
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 };
|
|
@@ -1,55 +0,0 @@
|
|
|
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 };
|
|
@@ -1,10 +0,0 @@
|
|
|
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 };
|
|
@@ -1,15 +0,0 @@
|
|
|
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 };
|
|
@@ -1,6 +0,0 @@
|
|
|
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 };
|
|
@@ -1,43 +0,0 @@
|
|
|
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 };
|
|
@@ -1,8 +0,0 @@
|
|
|
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 };
|
|
@@ -1,77 +0,0 @@
|
|
|
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 };
|
|
@@ -1,76 +0,0 @@
|
|
|
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 };
|
package/dist/canvas-core.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
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 };
|
package/dist/canvas-core.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
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/config.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
//#region src/cli/check/config.ts
|
|
2
|
-
const CHECK_CONFIG = {
|
|
3
|
-
size: {
|
|
4
|
-
/** Gzipped bytes of a section's renderer bundle, React excluded. */
|
|
5
|
-
rendererBundleGzip: 50 * 1024,
|
|
6
|
-
/** Gzipped bytes of a section's stylesheet, including CSS pulled in from packages. */
|
|
7
|
-
sectionCssGzip: 50 * 1024,
|
|
8
|
-
/** Gzipped bytes of a section's largest island (browser) bundle, React excluded. */
|
|
9
|
-
islandBundleGzip: 50 * 1024,
|
|
10
|
-
/** Raw bytes of a section's static assets (svg/images/fonts). RAW, not gzip — images/fonts are already compressed. */
|
|
11
|
-
assets: 250 * 1024
|
|
12
|
-
},
|
|
13
|
-
audit: {
|
|
14
|
-
/** A vulnerability at or above this severity fails the check. */
|
|
15
|
-
failOn: ["high", "critical"] },
|
|
16
|
-
/**
|
|
17
|
-
* A package whose license is not on this list fails the check. A missing
|
|
18
|
-
* license field, or a bespoke "SEE LICENSE IN …", is a denial — not a pass.
|
|
19
|
-
*/
|
|
20
|
-
licenseAllowlist: [
|
|
21
|
-
"MIT",
|
|
22
|
-
"ISC",
|
|
23
|
-
"Apache-2.0",
|
|
24
|
-
"BSD-2-Clause",
|
|
25
|
-
"BSD-3-Clause",
|
|
26
|
-
"0BSD",
|
|
27
|
-
"Unlicense",
|
|
28
|
-
"CC0-1.0"
|
|
29
|
-
],
|
|
30
|
-
/**
|
|
31
|
-
* The license gate walks the *shipped* dependency graph of every third-party
|
|
32
|
-
* package a template pulls in — this is the first-party exception to that.
|
|
33
|
-
* The kit itself is `UNLICENSED` by design (it is not published for reuse
|
|
34
|
-
* outside this platform) and every workspace depends on it, so without this
|
|
35
|
-
* exemption the gate would deny the kit on a stock, correct workspace.
|
|
36
|
-
*/
|
|
37
|
-
licenseExemptions: ["@homepages/template-kit"]
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
//#endregion
|
|
41
|
-
export { CHECK_CONFIG };
|
package/dist/cli/check/css.js
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { loadEsbuild } from "./resolve-tool.js";
|
|
2
|
-
import { readdir } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
|
-
|
|
6
|
-
//#region src/cli/check/css.ts
|
|
7
|
-
/**
|
|
8
|
-
* Every `.css` file anywhere in a section folder (the folder is free-form —
|
|
9
|
-
* an author may nest CSS under components/, enhancers/, wherever), in
|
|
10
|
-
* published order: `styles.css` first (the conventional root-level home),
|
|
11
|
-
* then every other file sorted by path. `snapshots/` and `node_modules/` are
|
|
12
|
-
* skipped — generated or not authored, never hand-CSS.
|
|
13
|
-
*/
|
|
14
|
-
async function sectionCssFiles(dir) {
|
|
15
|
-
if (!existsSync(dir)) return [];
|
|
16
|
-
const found = [];
|
|
17
|
-
const walk = async (d) => {
|
|
18
|
-
for (const entry of await readdir(d, { withFileTypes: true })) {
|
|
19
|
-
const full = join(d, entry.name);
|
|
20
|
-
if (entry.isDirectory()) {
|
|
21
|
-
if (entry.name === "snapshots" || entry.name === "node_modules") continue;
|
|
22
|
-
await walk(full);
|
|
23
|
-
} else if (entry.isFile() && entry.name.endsWith(".css")) found.push(full);
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
await walk(dir);
|
|
27
|
-
const own = join(dir, "styles.css");
|
|
28
|
-
const rest = found.filter((f) => f !== own).sort();
|
|
29
|
-
return (existsSync(own) ? [own] : []).concat(rest);
|
|
30
|
-
}
|
|
31
|
-
const ASSET_LOADERS = {
|
|
32
|
-
".svg": "file",
|
|
33
|
-
".png": "file",
|
|
34
|
-
".jpg": "file",
|
|
35
|
-
".jpeg": "file",
|
|
36
|
-
".gif": "file",
|
|
37
|
-
".webp": "file",
|
|
38
|
-
".avif": "file",
|
|
39
|
-
".ico": "file",
|
|
40
|
-
".woff": "file",
|
|
41
|
-
".woff2": "file",
|
|
42
|
-
".ttf": "file",
|
|
43
|
-
".otf": "file",
|
|
44
|
-
".eot": "file",
|
|
45
|
-
".mp4": "file",
|
|
46
|
-
".webm": "file",
|
|
47
|
-
".mov": "file",
|
|
48
|
-
".mp3": "file",
|
|
49
|
-
".wav": "file",
|
|
50
|
-
".pdf": "file",
|
|
51
|
-
".zip": "file"
|
|
52
|
-
};
|
|
53
|
-
const ASSET_PUBLIC_PATH = "/section-assets";
|
|
54
|
-
const ASSET_NAMES = "[name]-[hash]";
|
|
55
|
-
/**
|
|
56
|
-
* A section's third-party package CSS — discovered by the bundler, not
|
|
57
|
-
* declared. An author writes `import "swiper/css"` in Renderer.tsx exactly
|
|
58
|
-
* as in React; this runs a CSS-only esbuild pass rooted at Renderer.tsx and
|
|
59
|
-
* returns the emitted stylesheet (empty string if there is none).
|
|
60
|
-
*
|
|
61
|
-
* A relative CSS import in the render path is a lint error
|
|
62
|
-
* (`no-css-import-from-render-path`, already enforced by ESLint) — this pass
|
|
63
|
-
* does not re-implement that rejection, it only has to not crash on one.
|
|
64
|
-
*
|
|
65
|
-
* `platform: "neutral"` defaults `mainFields` to `[]`, which cannot resolve a
|
|
66
|
-
* package that ships only a CJS `main` (no `exports` map) — `mainFields`
|
|
67
|
-
* is set explicitly so such a package still resolves to its ESM `module`
|
|
68
|
-
* build where one exists.
|
|
69
|
-
*/
|
|
70
|
-
async function compileSectionPackageCss(workspaceRoot, sectionDir) {
|
|
71
|
-
const renderer = join(sectionDir, "Renderer.tsx");
|
|
72
|
-
if (!existsSync(renderer)) return "";
|
|
73
|
-
const { build } = await loadEsbuild(workspaceRoot);
|
|
74
|
-
const css = (await build({
|
|
75
|
-
entryPoints: [renderer],
|
|
76
|
-
bundle: true,
|
|
77
|
-
write: false,
|
|
78
|
-
minify: true,
|
|
79
|
-
outdir: join(workspaceRoot, "node_modules", ".template-kit", "check-css"),
|
|
80
|
-
format: "esm",
|
|
81
|
-
target: "es2022",
|
|
82
|
-
platform: "neutral",
|
|
83
|
-
mainFields: ["module", "main"],
|
|
84
|
-
jsx: "automatic",
|
|
85
|
-
external: [
|
|
86
|
-
"react",
|
|
87
|
-
"react-dom",
|
|
88
|
-
"react/jsx-runtime"
|
|
89
|
-
],
|
|
90
|
-
loader: { ...ASSET_LOADERS },
|
|
91
|
-
publicPath: ASSET_PUBLIC_PATH,
|
|
92
|
-
assetNames: ASSET_NAMES,
|
|
93
|
-
absWorkingDir: workspaceRoot,
|
|
94
|
-
logLevel: "silent"
|
|
95
|
-
})).outputFiles?.find((f) => f.path.endsWith(".css"));
|
|
96
|
-
return css ? css.text : "";
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* The 1-based line of the first top-level `@import`, or `undefined` if there
|
|
100
|
-
* is none. Comment-aware: an `@import` mentioned inside a CSS block comment
|
|
101
|
-
* is prose (e.g. a header warning authors not to write one), not a rule — a
|
|
102
|
-
* naive line-regex would false-fire on it.
|
|
103
|
-
*/
|
|
104
|
-
function findImportLine(css) {
|
|
105
|
-
const lines = css.split("\n");
|
|
106
|
-
let inComment = false;
|
|
107
|
-
for (let i = 0; i < lines.length; i++) {
|
|
108
|
-
let line = lines[i];
|
|
109
|
-
if (inComment) {
|
|
110
|
-
const close = line.indexOf("*/");
|
|
111
|
-
if (close === -1) continue;
|
|
112
|
-
line = line.slice(close + 2);
|
|
113
|
-
inComment = false;
|
|
114
|
-
}
|
|
115
|
-
for (;;) {
|
|
116
|
-
const open = line.indexOf("/*");
|
|
117
|
-
if (open === -1) break;
|
|
118
|
-
const close = line.indexOf("*/", open + 2);
|
|
119
|
-
if (close === -1) {
|
|
120
|
-
line = line.slice(0, open);
|
|
121
|
-
inComment = true;
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
line = line.slice(0, open) + line.slice(close + 2);
|
|
125
|
-
}
|
|
126
|
-
if (/^\s*@import\b/.test(line)) return i + 1;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
//#endregion
|
|
131
|
-
export { ASSET_LOADERS, ASSET_NAMES, ASSET_PUBLIC_PATH, compileSectionPackageCss, findImportLine, sectionCssFiles };
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
//#region src/cli/check/diagnostics.ts
|
|
2
|
-
function location(d) {
|
|
3
|
-
if (!d.file) return "";
|
|
4
|
-
return d.line === void 0 ? d.file : `${d.file}:${d.line}`;
|
|
5
|
-
}
|
|
6
|
-
function formatOne(d) {
|
|
7
|
-
const where = location(d);
|
|
8
|
-
return `${where ? ` ${where}\n` : ""} [${d.ruleId}] ${d.message}\n fix: ${d.fix}\n`;
|
|
9
|
-
}
|
|
10
|
-
function formatHuman(report) {
|
|
11
|
-
const parts = [];
|
|
12
|
-
if (report.linkedKit !== void 0) {
|
|
13
|
-
const { kitVersion, linkedFrom, pin } = report.linkedKit;
|
|
14
|
-
parts.push(`⚠ linked kit ${kitVersion} from ${linkedFrom} — your pin is ${pin}.\n`);
|
|
15
|
-
parts.push(" This result does not reflect your pin. Run `template-kit unlink` before merging.\n");
|
|
16
|
-
}
|
|
17
|
-
for (const [key, t] of Object.entries(report.templates)) {
|
|
18
|
-
if (t.ok) {
|
|
19
|
-
parts.push(`✓ ${key}\n`);
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
parts.push(`✗ ${key} — ${String(t.diagnostics.length)} problem(s)\n`);
|
|
23
|
-
for (const d of t.diagnostics) parts.push(formatOne(d));
|
|
24
|
-
}
|
|
25
|
-
if (!report.workspace.ok) {
|
|
26
|
-
parts.push(`✗ workspace — ${String(report.workspace.diagnostics.length)} problem(s)\n`);
|
|
27
|
-
for (const d of report.workspace.diagnostics) parts.push(formatOne(d));
|
|
28
|
-
}
|
|
29
|
-
if (report.ok) parts.push("check passed\n");
|
|
30
|
-
return parts.join("");
|
|
31
|
-
}
|
|
32
|
-
function toJson(report) {
|
|
33
|
-
return JSON.stringify(report, null, 2);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
//#endregion
|
|
37
|
-
export { formatHuman, toJson };
|