@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,204 +0,0 @@
|
|
|
1
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
|
|
4
|
-
//#region src/cli/dev/island-canvas-bootstrap.ts
|
|
5
|
-
const CACHE_DIR = ".tk-dev-cache";
|
|
6
|
-
const BOOTSTRAP_FILE = "island-canvas-bootstrap.js";
|
|
7
|
-
const BOOTSTRAP_SOURCE = `import RefreshRuntime from "/@react-refresh";
|
|
8
|
-
import { hydrateIslands, unmountIslands } from "@homepages/template-kit/island-runtime";
|
|
9
|
-
import { createElement, useLayoutEffect } from "react";
|
|
10
|
-
|
|
11
|
-
// React Refresh preamble. @vitejs/plugin-react compiles every client component
|
|
12
|
-
// to assert this ran and throws "can't detect preamble" otherwise, so any page
|
|
13
|
-
// that was not built by Vite's own index-html transform must supply it.
|
|
14
|
-
//
|
|
15
|
-
// It lives HERE, in the bootstrap, rather than in the page that loads the
|
|
16
|
-
// bootstrap, because the two canvas surfaces reach islands by different routes:
|
|
17
|
-
// the server-rendered ?canvas=1 page emits the preamble itself (section-page.ts)
|
|
18
|
-
// before this script, but the shared-kernel srcdoc canvas is assembled by
|
|
19
|
-
// canvas-core, whose CanvasAssets port carries stylesheets, an island map and
|
|
20
|
-
// ONE host script — it has no channel for a dev-only inline prelude, and adding
|
|
21
|
-
// one would push a Vite-specific concern into a kernel the app also ships.
|
|
22
|
-
// Emitting it from the one module both surfaces already load covers both.
|
|
23
|
-
//
|
|
24
|
-
// Guarded so the server-rendered page, which already installed it, does not
|
|
25
|
-
// re-enter injectIntoGlobalHook.
|
|
26
|
-
if (!window.__vite_plugin_react_preamble_installed__) {
|
|
27
|
-
RefreshRuntime.injectIntoGlobalHook(window);
|
|
28
|
-
window.$RefreshReg$ = () => {};
|
|
29
|
-
window.$RefreshSig$ = () => (type) => type;
|
|
30
|
-
window.__vite_plugin_react_preamble_installed__ = true;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const SHIELD_CLASS = "tr-canvas-shield";
|
|
34
|
-
const LIVE_ATTR = "data-tr-live";
|
|
35
|
-
|
|
36
|
-
const modules = import.meta.glob("/templates/**/*.{tsx,jsx}");
|
|
37
|
-
const map = window.__TR_ISLAND_MAP || {};
|
|
38
|
-
|
|
39
|
-
// Per-island hydration-commit signal, keyed by the \`editor\` object THIS load()
|
|
40
|
-
// call clones for that island — never by island key. A section rendering N of
|
|
41
|
-
// one island calls load() N times; keying by key would let the last call's
|
|
42
|
-
// commit gate every handle, un-shielding N-1 of them before their own root has
|
|
43
|
-
// actually committed.
|
|
44
|
-
const commitOf = new WeakMap();
|
|
45
|
-
|
|
46
|
-
// Wrap the loaded default export so it reports its own hydration commit.
|
|
47
|
-
// Renders no DOM of its own (the tree still matches the SSR markup exactly),
|
|
48
|
-
// and useLayoutEffect fires after the commit but before paint, so the canvas
|
|
49
|
-
// never shows an unshielded frame.
|
|
50
|
-
function withCommitSignal(component, signalCommit) {
|
|
51
|
-
return function IslandCommitSignal(props) {
|
|
52
|
-
useLayoutEffect(signalCommit, []);
|
|
53
|
-
return createElement(component, props);
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function load(key) {
|
|
58
|
-
const url = map[key];
|
|
59
|
-
const importer = url ? modules[url] : undefined;
|
|
60
|
-
if (!importer) return Promise.reject(new Error("template-kit dev: no island module for " + key));
|
|
61
|
-
const mod = await importer();
|
|
62
|
-
|
|
63
|
-
let signalCommit;
|
|
64
|
-
const committed = new Promise((resolve) => { signalCommit = resolve; });
|
|
65
|
-
const editor = mod.editor ? { ...mod.editor } : undefined;
|
|
66
|
-
if (editor) commitOf.set(editor, { committed, signalCommit });
|
|
67
|
-
|
|
68
|
-
return { ...mod, editor, default: withCommitSignal(mod.default, signalCommit) };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function makeShield(doc) {
|
|
72
|
-
const shield = doc.createElement("div");
|
|
73
|
-
shield.className = SHIELD_CLASS;
|
|
74
|
-
shield.setAttribute("aria-hidden", "true");
|
|
75
|
-
return shield;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// "fill-self": surface made position:relative, shield appended as its last
|
|
79
|
-
// child (unit cards). "fill-parent" (map canvas, slider viewport): the
|
|
80
|
-
// shield is an inset:0 sibling after the surface, so the surface's PARENT is
|
|
81
|
-
// made position:relative instead — otherwise the shield escapes to the
|
|
82
|
-
// initial containing block and covers the whole canvas. Idempotent in both
|
|
83
|
-
// modes.
|
|
84
|
-
function installShield(surface, mode) {
|
|
85
|
-
const doc = surface.ownerDocument;
|
|
86
|
-
const win = doc.defaultView;
|
|
87
|
-
if (mode === "fill-self") {
|
|
88
|
-
const pos = win ? win.getComputedStyle(surface).position : "";
|
|
89
|
-
if (!pos || pos === "static") surface.style.position = "relative";
|
|
90
|
-
if (Array.from(surface.children).some((c) => c.classList.contains(SHIELD_CLASS))) return;
|
|
91
|
-
surface.appendChild(makeShield(doc));
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const parent = surface.parentElement;
|
|
95
|
-
if (parent) {
|
|
96
|
-
const pos = win ? win.getComputedStyle(parent).position : "";
|
|
97
|
-
if (!pos || pos === "static") parent.style.position = "relative";
|
|
98
|
-
}
|
|
99
|
-
const next = surface.nextElementSibling;
|
|
100
|
-
if (next && next.classList.contains(SHIELD_CLASS)) return;
|
|
101
|
-
surface.insertAdjacentElement("afterend", makeShield(doc));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function shieldHandle(handle) {
|
|
105
|
-
const editor = handle.editor;
|
|
106
|
-
if (!editor || !editor.live) return;
|
|
107
|
-
const surfaces = editor.liveSurface ? editor.liveSurface(handle.element) : [handle.element];
|
|
108
|
-
const mode = editor.shieldMode || "fill-parent";
|
|
109
|
-
for (const surface of surfaces) installShield(surface, mode);
|
|
110
|
-
// Stamped for island-inspect.ts's read-only panel — not read by any hydration logic.
|
|
111
|
-
handle.element.setAttribute("data-tr-island-live", "true");
|
|
112
|
-
handle.element.setAttribute("data-tr-shield-mode", mode);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Every TOP-LEVEL island marker under root, excluding nested ones (a marker
|
|
116
|
-
// inside another marker is hydrated by its parent island's own React root —
|
|
117
|
-
// see hydrateIslands' own filter in island-runtime; this mirrors it so the
|
|
118
|
-
// inspector never double-reports or mis-marks a nested child).
|
|
119
|
-
function topLevelMarkers(root) {
|
|
120
|
-
return Array.from(root.querySelectorAll("[data-tr-island]")).filter(
|
|
121
|
-
(el) => !el.parentElement || !el.parentElement.closest("[data-tr-island]"),
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
let styleInstalled = false;
|
|
126
|
-
function ensureShieldStyle() {
|
|
127
|
-
if (styleInstalled || document.getElementById("tr-canvas-shield-style")) return;
|
|
128
|
-
styleInstalled = true;
|
|
129
|
-
const style = document.createElement("style");
|
|
130
|
-
style.id = "tr-canvas-shield-style";
|
|
131
|
-
style.textContent =
|
|
132
|
-
"." + SHIELD_CLASS + "{position:absolute;inset:0;z-index:1;cursor:pointer;background:transparent;}" +
|
|
133
|
-
"[" + LIVE_ATTR + "] ." + SHIELD_CLASS + "{display:none;}";
|
|
134
|
-
document.head.appendChild(style);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Hydrate every live island under \`root\`, install its shield(s), and mark every
|
|
138
|
-
// top-level island (live or not) with data-tr-island-live for the inspector.
|
|
139
|
-
async function hydrateRoot(root) {
|
|
140
|
-
ensureShieldStyle();
|
|
141
|
-
const before = new Set(topLevelMarkers(root));
|
|
142
|
-
|
|
143
|
-
const handles = await hydrateIslands({
|
|
144
|
-
root,
|
|
145
|
-
load,
|
|
146
|
-
shouldHydrate: (ctx) => (ctx.editor ? ctx.editor.live === true : false),
|
|
147
|
-
applyEditorProps: true,
|
|
148
|
-
onError: (error, ctx) => {
|
|
149
|
-
console.error("template-kit dev: canvas island failed to hydrate:", ctx.key, error);
|
|
150
|
-
// Settle its commit: a failed island never signals one, and the wait
|
|
151
|
-
// below must not stall the rest of this root's shields on it.
|
|
152
|
-
if (ctx.editor) { const c = commitOf.get(ctx.editor); if (c) c.signalCommit(); }
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// hydrateRoot (React's) flushes on a scheduler task, so hydrateIslands
|
|
157
|
-
// returns before React has committed. Shielding here would mutate a
|
|
158
|
-
// not-yet-hydrated tree: in fill-self mode the shield lands INSIDE a
|
|
159
|
-
// React-owned surface, and React then discards the whole SSR tree and
|
|
160
|
-
// client-renders, wiping shield and inline position both. Waiting on the
|
|
161
|
-
// real commit — not a task-turn guess — is what makes the mutation stick.
|
|
162
|
-
await Promise.all(
|
|
163
|
-
handles
|
|
164
|
-
.map((h) => (h.editor ? commitOf.get(h.editor) : undefined))
|
|
165
|
-
.filter((c) => c !== undefined)
|
|
166
|
-
.map((c) => c.committed),
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
for (const handle of handles) {
|
|
170
|
-
shieldHandle(handle);
|
|
171
|
-
before.delete(handle.element);
|
|
172
|
-
}
|
|
173
|
-
// Whatever's left in \`before\` is a top-level island that did not pass
|
|
174
|
-
// shouldHydrate (editor.live !== true, or no editor at all) — static by its
|
|
175
|
-
// own contract; mark it so for the inspector.
|
|
176
|
-
for (const el of before) el.setAttribute("data-tr-island-live", "false");
|
|
177
|
-
|
|
178
|
-
return handles;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function unmountRoot(root) {
|
|
182
|
-
unmountIslands(root);
|
|
183
|
-
root.querySelectorAll("." + SHIELD_CLASS).forEach((s) => s.remove());
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
window.__trCanvasIslands = { hydrateRoot, unmountRoot };
|
|
187
|
-
void hydrateRoot(document.body);
|
|
188
|
-
`;
|
|
189
|
-
/**
|
|
190
|
-
* Write the shared canvas bootstrap into the workspace cache dir and return
|
|
191
|
-
* the URL the canvas page loads it from. Same mechanics as
|
|
192
|
-
* writeIslandBootstrap: lives under the root so Vite serves + transforms it,
|
|
193
|
-
* reached via Vite's `/@fs/` prefix.
|
|
194
|
-
*/
|
|
195
|
-
async function writeIslandCanvasBootstrap(root) {
|
|
196
|
-
const dir = join(root, CACHE_DIR);
|
|
197
|
-
await mkdir(dir, { recursive: true });
|
|
198
|
-
const abs = join(dir, BOOTSTRAP_FILE);
|
|
199
|
-
await writeFile(abs, BOOTSTRAP_SOURCE, "utf8");
|
|
200
|
-
return `/@fs/${abs}`;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
//#endregion
|
|
204
|
-
export { writeIslandCanvasBootstrap };
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { islandKey } from "../../islands/detect.js";
|
|
2
|
-
import { findSectionIslands } from "../../islands/discover.js";
|
|
3
|
-
import { basename, extname, relative, sep } from "node:path";
|
|
4
|
-
|
|
5
|
-
//#region src/cli/dev/island-map.ts
|
|
6
|
-
/**
|
|
7
|
-
* Derive an island key from a client component's absolute path, relative to the
|
|
8
|
-
* workspace's `templates/` dir: `<templateFolder>/<section>:<ComponentName>`.
|
|
9
|
-
* A component name is the file basename. Returns null for a path that is not a
|
|
10
|
-
* `templates/<folder>/sections/<section>/…` component.
|
|
11
|
-
*/
|
|
12
|
-
function islandKeyForFile(templatesDir, absFile) {
|
|
13
|
-
const rel = relative(templatesDir, absFile);
|
|
14
|
-
if (rel.startsWith("..")) return null;
|
|
15
|
-
const parts = rel.split(sep);
|
|
16
|
-
if (parts.length < 4 || parts[1] !== "sections") return null;
|
|
17
|
-
return islandKey(`${parts[0]}/${parts[2]}`, basename(absFile, extname(absFile)));
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* The map the browser bootstrap reads: island key → the module's root-relative
|
|
21
|
-
* URL (what Vite serves it at, and what `import.meta.glob("/templates/**")` keys
|
|
22
|
-
* it by). Empty when the section has no islands.
|
|
23
|
-
*/
|
|
24
|
-
async function buildSectionIslandMap(root, templatesDir, sectionDir) {
|
|
25
|
-
const map = {};
|
|
26
|
-
for (const file of await findSectionIslands(sectionDir)) {
|
|
27
|
-
const key = islandKeyForFile(templatesDir, file);
|
|
28
|
-
if (!key) continue;
|
|
29
|
-
map[key] = "/" + relative(root, file).split(sep).join("/");
|
|
30
|
-
}
|
|
31
|
-
return map;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
//#endregion
|
|
35
|
-
export { buildSectionIslandMap, islandKeyForFile };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { wrapClientModuleMagic } from "../../islands/wrap.js";
|
|
2
|
-
import { islandKeyForFile } from "./island-map.js";
|
|
3
|
-
import { extname, join, sep } from "node:path";
|
|
4
|
-
|
|
5
|
-
//#region src/cli/dev/island-transform.ts
|
|
6
|
-
const COMPONENT_EXTS = /* @__PURE__ */ new Set([".tsx", ".jsx"]);
|
|
7
|
-
function islandTransformPlugin(opts) {
|
|
8
|
-
const templatesDir = join(opts.root, "templates");
|
|
9
|
-
const templatesPrefix = templatesDir + sep;
|
|
10
|
-
return {
|
|
11
|
-
name: "template-kit:island-transform",
|
|
12
|
-
enforce: "pre",
|
|
13
|
-
transform(code, id, options) {
|
|
14
|
-
if (!options?.ssr) return null;
|
|
15
|
-
const file = id.split("?", 1)[0] ?? id;
|
|
16
|
-
if (!file.startsWith(templatesPrefix)) return null;
|
|
17
|
-
if (!COMPONENT_EXTS.has(extname(file))) return null;
|
|
18
|
-
const key = islandKeyForFile(templatesDir, file);
|
|
19
|
-
if (!key) return null;
|
|
20
|
-
const s = wrapClientModuleMagic(code, key);
|
|
21
|
-
if (s === null) return null;
|
|
22
|
-
return {
|
|
23
|
-
code: s.toString(),
|
|
24
|
-
map: s.generateMap({ hires: true })
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
//#endregion
|
|
31
|
-
export { islandTransformPlugin };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { TemplateManifest } from "../../schema/manifest.js";
|
|
2
|
-
import { discoverSections } from "./discover.js";
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
4
|
-
|
|
5
|
-
//#region src/cli/dev/manifest-instances.ts
|
|
6
|
-
function selectManifestInstances(sections, manifestSections) {
|
|
7
|
-
const out = [];
|
|
8
|
-
for (const inst of manifestSections) {
|
|
9
|
-
const info = sections.find((s) => s.name === inst.section);
|
|
10
|
-
if (!info) continue;
|
|
11
|
-
out.push({
|
|
12
|
-
instanceId: inst.instance_id,
|
|
13
|
-
section: inst.section,
|
|
14
|
-
sectionDir: info.dir,
|
|
15
|
-
fixture: "typical",
|
|
16
|
-
options: inst.options
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
return out;
|
|
20
|
-
}
|
|
21
|
-
async function resolveManifestInstances(template) {
|
|
22
|
-
const manifest = TemplateManifest.parse(JSON.parse(await readFile(template.manifestPath, "utf8")));
|
|
23
|
-
return selectManifestInstances(await discoverSections(template.dir), manifest.sections);
|
|
24
|
-
}
|
|
25
|
-
/** The single manifest instance with this id, or null (author WIP / unknown id). */
|
|
26
|
-
async function findManifestInstance(template, instanceId) {
|
|
27
|
-
return (await resolveManifestInstances(template)).find((i) => i.instanceId === instanceId) ?? null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
//#endregion
|
|
31
|
-
export { findManifestInstance, resolveManifestInstances, selectManifestInstances };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { loadSectionBundle, renderSectionHtml } from "../../ssr.js";
|
|
2
|
-
import { applyContentOverride } from "./content-override.js";
|
|
3
|
-
import { projectSlotSchema } from "./slot-schema.js";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
|
|
6
|
-
//#region src/cli/dev/render-section.ts
|
|
7
|
-
async function renderSection(vite, req) {
|
|
8
|
-
const load = (dir, file) => vite.ssrLoadModule(join(dir, file));
|
|
9
|
-
const { Renderer, invariantFixtures, schemaSlots } = await loadSectionBundle(req.sectionDir, load);
|
|
10
|
-
const fx = invariantFixtures.find((f) => f.id === req.fixture);
|
|
11
|
-
if (!fx) throw new Error(`fixture "${req.fixture}" not found (have: ${invariantFixtures.map((r) => r.id).join(", ")})`);
|
|
12
|
-
const props = applyContentOverride(fx.props, req.override);
|
|
13
|
-
return {
|
|
14
|
-
html: renderSectionHtml(Renderer, props),
|
|
15
|
-
resolvedProps: props,
|
|
16
|
-
fixtureLabel: fx.label,
|
|
17
|
-
slotSchema: projectSlotSchema(schemaSlots),
|
|
18
|
-
schemaSlots,
|
|
19
|
-
nullCorpus: invariantFixtures.filter((f) => f.id.startsWith("null_")).map((f) => f.id)
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
//#endregion
|
|
24
|
-
export { renderSection };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
//#region src/cli/dev/screenshot-target.ts
|
|
2
|
-
function resolveScreenshotPath(t) {
|
|
3
|
-
if (!t.template) return {
|
|
4
|
-
ok: false,
|
|
5
|
-
error: "screenshot requires a template"
|
|
6
|
-
};
|
|
7
|
-
const hasSection = Boolean(t.section);
|
|
8
|
-
if (hasSection !== Boolean(t.fixture)) return {
|
|
9
|
-
ok: false,
|
|
10
|
-
error: "provide section and fixture together for a section screenshot, or neither for a full-template screenshot"
|
|
11
|
-
};
|
|
12
|
-
const enc = encodeURIComponent;
|
|
13
|
-
if (hasSection) return {
|
|
14
|
-
ok: true,
|
|
15
|
-
path: `/sections/${enc(t.template)}/${enc(t.section)}/${enc(t.fixture)}`
|
|
16
|
-
};
|
|
17
|
-
return {
|
|
18
|
-
ok: true,
|
|
19
|
-
path: `/template/${enc(t.template)}`
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
//#endregion
|
|
24
|
-
export { resolveScreenshotPath };
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
//#region src/cli/dev/section-page.ts
|
|
2
|
-
function wrapSectionHtml(opts) {
|
|
3
|
-
const t = encodeURIComponent(opts.template);
|
|
4
|
-
const s = encodeURIComponent(opts.section);
|
|
5
|
-
const v = encodeURIComponent(opts.cssRev);
|
|
6
|
-
return `<!doctype html>
|
|
7
|
-
<html lang="en">
|
|
8
|
-
<head>
|
|
9
|
-
<meta charset="utf-8" />
|
|
10
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
11
|
-
<title>Section Preview</title>
|
|
12
|
-
<link rel="stylesheet" href="/runtime/base.css?v=${v}" />
|
|
13
|
-
<link rel="stylesheet" href="/runtime/template.css?template=${t}&v=${v}" />
|
|
14
|
-
<style>html, body { margin: 0; padding: 0; background: #fff; }</style>
|
|
15
|
-
</head>
|
|
16
|
-
<body>
|
|
17
|
-
<div id="section-host">${opts.sectionHtml}</div>${islandBootstrap(opts.islands, opts.bootstrapUrl)}
|
|
18
|
-
<script>${HMR_CLIENT_JS}<\/script>${diagnosticsBanner(opts.section, t, s)}
|
|
19
|
-
</body>
|
|
20
|
-
</html>`;
|
|
21
|
-
}
|
|
22
|
-
function diagnosticsBanner(section, template, encodedSection) {
|
|
23
|
-
if (section === "") return "";
|
|
24
|
-
return `
|
|
25
|
-
<script>${diagnosticsClientJs(template, encodedSection)}<\/script>`;
|
|
26
|
-
}
|
|
27
|
-
function islandBootstrap(islands, bootstrapUrl) {
|
|
28
|
-
if (Object.keys(islands).length === 0) return "";
|
|
29
|
-
const mapJson = JSON.stringify(islands).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
|
|
30
|
-
return `
|
|
31
|
-
${REACT_REFRESH_PREAMBLE}
|
|
32
|
-
<script>window.__TR_ISLAND_MAP = ${mapJson};<\/script>
|
|
33
|
-
<script type="module" src="${bootstrapUrl}"><\/script>`;
|
|
34
|
-
}
|
|
35
|
-
const REACT_REFRESH_PREAMBLE = `<script type="module">
|
|
36
|
-
import RefreshRuntime from "/@react-refresh";
|
|
37
|
-
RefreshRuntime.injectIntoGlobalHook(window);
|
|
38
|
-
window.$RefreshReg$ = () => {};
|
|
39
|
-
window.$RefreshSig$ = () => (type) => type;
|
|
40
|
-
window.__vite_plugin_react_preamble_installed__ = true;
|
|
41
|
-
<\/script>`;
|
|
42
|
-
const HMR_CLIENT_JS = `
|
|
43
|
-
(function () {
|
|
44
|
-
try {
|
|
45
|
-
var src = new EventSource("/__hmr");
|
|
46
|
-
src.addEventListener("section:changed", function () { window.location.reload(); });
|
|
47
|
-
src.addEventListener("tailwind:changed", function () {
|
|
48
|
-
var link = document.querySelector('link[href*="/runtime/template.css"]');
|
|
49
|
-
if (link) {
|
|
50
|
-
var href = link.getAttribute("href");
|
|
51
|
-
var base = href.split("&v=")[0];
|
|
52
|
-
link.setAttribute("href", base + "&v=" + Date.now());
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
} catch (e) { /* dev-only; ignore */ }
|
|
56
|
-
})();
|
|
57
|
-
`.trim();
|
|
58
|
-
function diagnosticsClientJs(template, section) {
|
|
59
|
-
return `
|
|
60
|
-
(function () {
|
|
61
|
-
function render(violations) {
|
|
62
|
-
var banner = document.createElement("div");
|
|
63
|
-
banner.setAttribute("data-diagnostics-banner", "");
|
|
64
|
-
banner.style.cssText = "position:sticky;top:0;z-index:9999;background:#fee2e2;color:#7f1d1d;" +
|
|
65
|
-
"font:13px/1.4 monospace;padding:8px 12px;border-bottom:1px solid #fca5a5;";
|
|
66
|
-
var dismiss = document.createElement("button");
|
|
67
|
-
dismiss.textContent = "dismiss";
|
|
68
|
-
dismiss.style.cssText = "float:right;cursor:pointer;";
|
|
69
|
-
dismiss.onclick = function () { banner.remove(); };
|
|
70
|
-
var text = document.createElement("pre");
|
|
71
|
-
text.style.cssText = "margin:0;white-space:pre-wrap;";
|
|
72
|
-
text.textContent = violations.map(function (v) {
|
|
73
|
-
var loc = v.file ? " (" + v.file + (v.line ? ":" + v.line : "") + ")" : "";
|
|
74
|
-
return "[" + v.rule + "] " + v.message + loc;
|
|
75
|
-
}).join("\\n");
|
|
76
|
-
banner.appendChild(dismiss);
|
|
77
|
-
banner.appendChild(text);
|
|
78
|
-
document.body.insertBefore(banner, document.body.firstChild);
|
|
79
|
-
}
|
|
80
|
-
fetch("/api/diagnostics?template=${template}§ion=${section}")
|
|
81
|
-
.then(function (r) { return r.json(); })
|
|
82
|
-
.then(function (body) {
|
|
83
|
-
if (body.available && body.violations && body.violations.length > 0) render(body.violations);
|
|
84
|
-
})
|
|
85
|
-
.catch(function () { /* dev-only; ignore */ });
|
|
86
|
-
})();
|
|
87
|
-
`.trim();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
//#endregion
|
|
91
|
-
export { wrapSectionHtml };
|