@pyreon/zero 0.12.14 → 0.13.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/lib/client.js +1 -1
- package/lib/client.js.map +1 -1
- package/lib/index.js +37 -10
- package/lib/index.js.map +1 -1
- package/lib/link.js +11 -4
- package/lib/link.js.map +1 -1
- package/lib/server.js +27 -2
- package/lib/server.js.map +1 -1
- package/lib/theme.js +27 -7
- package/lib/theme.js.map +1 -1
- package/lib/types/config.d.ts +7 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/index.d.ts +13 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/link.d.ts.map +1 -1
- package/lib/types/server.d.ts +14 -0
- package/lib/types/server.d.ts.map +1 -1
- package/lib/types/theme.d.ts +6 -1
- package/lib/types/theme.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/client.ts +5 -1
- package/src/isr.ts +34 -2
- package/src/link.tsx +18 -5
- package/src/theme.tsx +33 -11
- package/src/types.ts +7 -0
package/lib/theme.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { onMount
|
|
1
|
+
import { onMount } from "@pyreon/core";
|
|
2
2
|
import { effect, signal } from "@pyreon/reactivity";
|
|
3
3
|
|
|
4
4
|
//#region ../../core/core/lib/jsx-runtime.js
|
|
@@ -55,6 +55,18 @@ const jsxs = jsx;
|
|
|
55
55
|
const STORAGE_KEY = "zero-theme";
|
|
56
56
|
/** Reactive theme signal. */
|
|
57
57
|
const theme = signal("system");
|
|
58
|
+
/**
|
|
59
|
+
* Reactive signal tracking the OS color-scheme preference. Updated by the
|
|
60
|
+
* `matchMedia('(prefers-color-scheme: dark)').change` event registered in
|
|
61
|
+
* `initTheme`. Components reading `resolvedTheme()` subscribe to BOTH
|
|
62
|
+
* `theme` and this signal, so a user toggling dark mode at the OS level
|
|
63
|
+
* re-renders everything reactively — not just the `<html data-theme>`
|
|
64
|
+
* attribute.
|
|
65
|
+
*
|
|
66
|
+
* SSR default is `_ssrDefault` (mutable via `setSSRThemeDefault`) so the
|
|
67
|
+
* server-rendered theme can differ from the client's OS preference.
|
|
68
|
+
*/
|
|
69
|
+
const _osPrefersDark = signal(false);
|
|
58
70
|
/** SSR fallback when system preference can't be detected. Default: 'light'. */
|
|
59
71
|
let _ssrDefault = "light";
|
|
60
72
|
/**
|
|
@@ -64,12 +76,17 @@ let _ssrDefault = "light";
|
|
|
64
76
|
function setSSRThemeDefault(value) {
|
|
65
77
|
_ssrDefault = value;
|
|
66
78
|
}
|
|
67
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Reactive read of the resolved theme. Subscribes to `theme` (explicit
|
|
81
|
+
* user choice) and — when `theme === 'system'` — to `_osPrefersDark`
|
|
82
|
+
* (OS color-scheme preference). Components using `resolvedTheme()`
|
|
83
|
+
* inside JSX / effects / computeds re-render when either changes.
|
|
84
|
+
*/
|
|
68
85
|
function resolvedTheme() {
|
|
69
86
|
const t = theme();
|
|
70
87
|
if (t === "system") {
|
|
71
88
|
if (typeof window === "undefined") return _ssrDefault;
|
|
72
|
-
return
|
|
89
|
+
return _osPrefersDark() ? "dark" : "light";
|
|
73
90
|
}
|
|
74
91
|
return t;
|
|
75
92
|
}
|
|
@@ -99,18 +116,21 @@ function initTheme() {
|
|
|
99
116
|
} catch {}
|
|
100
117
|
document.documentElement.dataset.theme = resolvedTheme();
|
|
101
118
|
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
102
|
-
|
|
103
|
-
|
|
119
|
+
_osPrefersDark.set(mq.matches);
|
|
120
|
+
function onChange(e) {
|
|
121
|
+
_osPrefersDark.set(e.matches);
|
|
104
122
|
}
|
|
105
123
|
mq.addEventListener("change", onChange);
|
|
106
|
-
onUnmount(() => mq.removeEventListener("change", onChange));
|
|
107
124
|
const dispose = effect(() => {
|
|
108
125
|
const mode = resolvedTheme();
|
|
109
126
|
document.documentElement.dataset.theme = mode;
|
|
110
127
|
const faviconLinks = document.querySelectorAll("[data-favicon-theme]");
|
|
111
128
|
for (const link of faviconLinks) link.media = link.dataset.faviconTheme === mode ? "" : "not all";
|
|
112
129
|
});
|
|
113
|
-
|
|
130
|
+
return () => {
|
|
131
|
+
mq.removeEventListener("change", onChange);
|
|
132
|
+
dispose?.dispose();
|
|
133
|
+
};
|
|
114
134
|
});
|
|
115
135
|
}
|
|
116
136
|
/**
|
package/lib/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","names":[],"sources":["../../../core/core/lib/jsx-runtime.js","../src/theme.tsx"],"sourcesContent":["//#region src/h.ts\n/** Marker for fragment nodes — renders children without a wrapper element */\nconst Fragment = Symbol(\"Pyreon.Fragment\");\n/**\n* Hyperscript function — the compiled output of JSX.\n* `<div class=\"x\">hello</div>` → `h(\"div\", { class: \"x\" }, \"hello\")`\n*\n* Generic on P so TypeScript validates props match the component's signature\n* at the call site, then stores the result in the loosely-typed VNode.\n*/\n/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */\nconst EMPTY_PROPS = {};\nfunction h(type, props, ...children) {\n\treturn {\n\t\ttype,\n\t\tprops: props ?? EMPTY_PROPS,\n\t\tchildren: normalizeChildren(children),\n\t\tkey: props?.key ?? null\n\t};\n}\nfunction normalizeChildren(children) {\n\tfor (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);\n\treturn children;\n}\nfunction flattenChildren(children) {\n\tconst result = [];\n\tfor (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));\n\telse result.push(child);\n\treturn result;\n}\n\n//#endregion\n//#region src/jsx-runtime.ts\n/**\n* JSX automatic runtime.\n*\n* When tsconfig has `\"jsxImportSource\": \"@pyreon/core\"`, the TS/bundler compiler\n* rewrites JSX to imports from this file automatically:\n* <div class=\"x\" /> → jsx(\"div\", { class: \"x\" })\n*/\nfunction jsx(type, props, key) {\n\tconst { children, ...rest } = props;\n\tconst propsWithKey = key != null ? {\n\t\t...rest,\n\t\tkey\n\t} : rest;\n\tif (typeof type === \"function\") return h(type, children !== void 0 ? {\n\t\t...propsWithKey,\n\t\tchildren\n\t} : propsWithKey);\n\treturn h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);\n}\nconst jsxs = jsx;\n\n//#endregion\nexport { Fragment, jsx, jsxs };\n//# sourceMappingURL=jsx-runtime.js.map","import type { VNodeChild } from '@pyreon/core'\nimport { onMount, onUnmount } from '@pyreon/core'\nimport { effect, signal } from '@pyreon/reactivity'\n\n// ─── Theme system ───────────────────────────────────────────────────────────\n//\n// Provides dark/light/system theme support with:\n// - System preference detection via matchMedia\n// - Persistent preference via localStorage\n// - No flash of wrong theme (inline script in HTML)\n// - Reactive theme signal for components\n\nexport type Theme = 'light' | 'dark' | 'system'\n\nconst STORAGE_KEY = 'zero-theme'\n\n/** Reactive theme signal. */\nexport const theme = signal<Theme>('system')\n\n/** SSR fallback when system preference can't be detected. Default: 'light'. */\nlet _ssrDefault: 'light' | 'dark' = 'light'\n\n/**\n * Set the default theme for SSR (when `matchMedia` is unavailable).\n * Call once at server startup before rendering.\n */\nexport function setSSRThemeDefault(value: 'light' | 'dark'): void {\n _ssrDefault = value\n}\n\n/** Computed resolved theme (what's actually applied). */\nexport function resolvedTheme(): 'light' | 'dark' {\n const t = theme()\n if (t === 'system') {\n if (typeof window === 'undefined') return _ssrDefault\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n }\n return t\n}\n\n/** Toggle between light and dark. */\nexport function toggleTheme() {\n const current = resolvedTheme()\n setTheme(current === 'dark' ? 'light' : 'dark')\n}\n\n/** Set theme explicitly. */\nexport function setTheme(t: Theme) {\n theme.set(t)\n if (typeof document !== 'undefined') {\n document.documentElement.dataset.theme = resolvedTheme()\n try {\n localStorage.setItem(STORAGE_KEY, t)\n } catch {\n // localStorage may not be available (SSR, private browsing)\n }\n }\n}\n\n/**\n * Initialize the theme system. Call once in your app entry or layout.\n * Reads from localStorage, listens for system preference changes.\n */\nexport function initTheme() {\n onMount(() => {\n // Read persisted preference\n try {\n const stored = localStorage.getItem(STORAGE_KEY) as Theme | null\n if (stored === 'light' || stored === 'dark' || stored === 'system') {\n theme.set(stored)\n }\n } catch {\n // localStorage may not be available\n }\n\n // Apply to document\n document.documentElement.dataset.theme = resolvedTheme()\n\n // Watch for system preference changes\n const mq = window.matchMedia('(prefers-color-scheme: dark)')\n function onChange() {\n if (theme() === 'system') {\n document.documentElement.dataset.theme = resolvedTheme()\n }\n }\n mq.addEventListener('change', onChange)\n onUnmount(() => mq.removeEventListener('change', onChange))\n\n // Re-apply when theme signal changes — updates data-theme + favicons\n const dispose = effect(() => {\n const mode = resolvedTheme()\n document.documentElement.dataset.theme = mode\n\n // Swap favicon variants (if dual-variant favicons are present)\n const faviconLinks = document.querySelectorAll<HTMLLinkElement>('[data-favicon-theme]')\n for (const link of faviconLinks) {\n link.media = link.dataset.faviconTheme === mode ? '' : 'not all'\n }\n })\n if (dispose) onUnmount(() => dispose.dispose())\n\n return undefined\n })\n}\n\n/**\n * Theme toggle button component.\n *\n * @example\n * import { ThemeToggle } from \"@pyreon/zero/theme\"\n * <ThemeToggle />\n */\nexport function ThemeToggle(props: { class?: string; style?: string }): VNodeChild {\n initTheme()\n\n return (\n <button\n class={props.class}\n style={props.style}\n onClick={toggleTheme}\n aria-label=\"Toggle theme\"\n title=\"Toggle theme\"\n type=\"button\"\n >\n {() =>\n resolvedTheme() === 'dark' ? (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"5\" />\n <line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\" />\n <line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\" />\n <line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\" />\n <line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\" />\n <line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\" />\n <line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\" />\n <line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\" />\n <line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\" />\n </svg>\n ) : (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z\" />\n </svg>\n )\n }\n </button>\n )\n}\n\n/**\n * Inline script to prevent flash of wrong theme.\n * Include this in your index.html <head> BEFORE any stylesheets.\n *\n * @example\n * // index.html\n * <head>\n * <script>{themeScript}</script>\n * ...\n * </head>\n */\nexport const themeScript = `(function(){try{var t=localStorage.getItem(\"${STORAGE_KEY}\");var r=t===\"light\"?\"light\":t===\"dark\"?\"dark\":window.matchMedia(\"(prefers-color-scheme:dark)\").matches?\"dark\":\"light\";document.documentElement.dataset.theme=r;document.querySelectorAll(\"[data-favicon-theme]\").forEach(function(l){l.media=l.dataset.faviconTheme===r?\"\":\"not all\"})}catch(e){}})()`\n"],"mappings":";;;;;;;;;;;;AAWA,MAAM,cAAc,EAAE;AACtB,SAAS,EAAE,MAAM,OAAO,GAAG,UAAU;AACpC,QAAO;EACN;EACA,OAAO,SAAS;EAChB,UAAU,kBAAkB,SAAS;EACrC,KAAK,OAAO,OAAO;EACnB;;AAEF,SAAS,kBAAkB,UAAU;AACpC,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,IAAK,KAAI,MAAM,QAAQ,SAAS,GAAG,CAAE,QAAO,gBAAgB,SAAS;AAC1G,QAAO;;AAER,SAAS,gBAAgB,UAAU;CAClC,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,SAAS,SAAU,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,KAAK,GAAG,gBAAgB,MAAM,CAAC;KACzF,QAAO,KAAK,MAAM;AACvB,QAAO;;;;;;;;;AAYR,SAAS,IAAI,MAAM,OAAO,KAAK;CAC9B,MAAM,EAAE,UAAU,GAAG,SAAS;CAC9B,MAAM,eAAe,OAAO,OAAO;EAClC,GAAG;EACH;EACA,GAAG;AACJ,KAAI,OAAO,SAAS,WAAY,QAAO,EAAE,MAAM,aAAa,KAAK,IAAI;EACpE,GAAG;EACH;EACA,GAAG,aAAa;AACjB,QAAO,EAAE,MAAM,cAAc,GAAG,aAAa,KAAK,IAAI,EAAE,GAAG,MAAM,QAAQ,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC;;AAE5G,MAAM,OAAO;;;;ACtCb,MAAM,cAAc;;AAGpB,MAAa,QAAQ,OAAc,SAAS;;AAG5C,IAAI,cAAgC;;;;;AAMpC,SAAgB,mBAAmB,OAA+B;AAChE,eAAc;;;AAIhB,SAAgB,gBAAkC;CAChD,MAAM,IAAI,OAAO;AACjB,KAAI,MAAM,UAAU;AAClB,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO,OAAO,WAAW,+BAA+B,CAAC,UAAU,SAAS;;AAE9E,QAAO;;;AAIT,SAAgB,cAAc;AAE5B,UADgB,eAAe,KACV,SAAS,UAAU,OAAO;;;AAIjD,SAAgB,SAAS,GAAU;AACjC,OAAM,IAAI,EAAE;AACZ,KAAI,OAAO,aAAa,aAAa;AACnC,WAAS,gBAAgB,QAAQ,QAAQ,eAAe;AACxD,MAAI;AACF,gBAAa,QAAQ,aAAa,EAAE;UAC9B;;;;;;;AAUZ,SAAgB,YAAY;AAC1B,eAAc;AAEZ,MAAI;GACF,MAAM,SAAS,aAAa,QAAQ,YAAY;AAChD,OAAI,WAAW,WAAW,WAAW,UAAU,WAAW,SACxD,OAAM,IAAI,OAAO;UAEb;AAKR,WAAS,gBAAgB,QAAQ,QAAQ,eAAe;EAGxD,MAAM,KAAK,OAAO,WAAW,+BAA+B;EAC5D,SAAS,WAAW;AAClB,OAAI,OAAO,KAAK,SACd,UAAS,gBAAgB,QAAQ,QAAQ,eAAe;;AAG5D,KAAG,iBAAiB,UAAU,SAAS;AACvC,kBAAgB,GAAG,oBAAoB,UAAU,SAAS,CAAC;EAG3D,MAAM,UAAU,aAAa;GAC3B,MAAM,OAAO,eAAe;AAC5B,YAAS,gBAAgB,QAAQ,QAAQ;GAGzC,MAAM,eAAe,SAAS,iBAAkC,uBAAuB;AACvF,QAAK,MAAM,QAAQ,aACjB,MAAK,QAAQ,KAAK,QAAQ,iBAAiB,OAAO,KAAK;IAEzD;AACF,MAAI,QAAS,iBAAgB,QAAQ,SAAS,CAAC;GAG/C;;;;;;;;;AAUJ,SAAgB,YAAY,OAAuD;AACjF,YAAW;AAEX,QACE,oBAAC,UAAD;EACE,OAAO,MAAM;EACb,OAAO,MAAM;EACb,SAAS;EACT,cAAW;EACX,OAAM;EACN,MAAK;kBAGH,eAAe,KAAK,SAClB,qBAAC,OAAD;GACE,OAAM;GACN,QAAO;GACP,SAAQ;GACR,MAAK;GACL,QAAO;GACP,gBAAa;GACb,kBAAe;GACf,mBAAgB;GAChB,eAAY;aATd;IAWE,oBAAC,UAAD;KAAQ,IAAG;KAAK,IAAG;KAAK,GAAE;KAAM;IAChC,oBAAC,QAAD;KAAM,IAAG;KAAK,IAAG;KAAI,IAAG;KAAK,IAAG;KAAM;IACtC,oBAAC,QAAD;KAAM,IAAG;KAAK,IAAG;KAAK,IAAG;KAAK,IAAG;KAAO;IACxC,oBAAC,QAAD;KAAM,IAAG;KAAO,IAAG;KAAO,IAAG;KAAO,IAAG;KAAS;IAChD,oBAAC,QAAD;KAAM,IAAG;KAAQ,IAAG;KAAQ,IAAG;KAAQ,IAAG;KAAU;IACpD,oBAAC,QAAD;KAAM,IAAG;KAAI,IAAG;KAAK,IAAG;KAAI,IAAG;KAAO;IACtC,oBAAC,QAAD;KAAM,IAAG;KAAK,IAAG;KAAK,IAAG;KAAK,IAAG;KAAO;IACxC,oBAAC,QAAD;KAAM,IAAG;KAAO,IAAG;KAAQ,IAAG;KAAO,IAAG;KAAU;IAClD,oBAAC,QAAD;KAAM,IAAG;KAAQ,IAAG;KAAO,IAAG;KAAQ,IAAG;KAAS;IAC9C;OAEN,oBAAC,OAAD;GACE,OAAM;GACN,QAAO;GACP,SAAQ;GACR,MAAK;GACL,QAAO;GACP,gBAAa;GACb,kBAAe;GACf,mBAAgB;GAChB,eAAY;aAEZ,oBAAC,QAAD,EAAM,GAAE,mDAAoD;GACxD;EAGH;;;;;;;;;;;;;AAeb,MAAa,cAAc,+CAA+C,YAAY"}
|
|
1
|
+
{"version":3,"file":"theme.js","names":[],"sources":["../../../core/core/lib/jsx-runtime.js","../src/theme.tsx"],"sourcesContent":["//#region src/h.ts\n/** Marker for fragment nodes — renders children without a wrapper element */\nconst Fragment = Symbol(\"Pyreon.Fragment\");\n/**\n* Hyperscript function — the compiled output of JSX.\n* `<div class=\"x\">hello</div>` → `h(\"div\", { class: \"x\" }, \"hello\")`\n*\n* Generic on P so TypeScript validates props match the component's signature\n* at the call site, then stores the result in the loosely-typed VNode.\n*/\n/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */\nconst EMPTY_PROPS = {};\nfunction h(type, props, ...children) {\n\treturn {\n\t\ttype,\n\t\tprops: props ?? EMPTY_PROPS,\n\t\tchildren: normalizeChildren(children),\n\t\tkey: props?.key ?? null\n\t};\n}\nfunction normalizeChildren(children) {\n\tfor (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);\n\treturn children;\n}\nfunction flattenChildren(children) {\n\tconst result = [];\n\tfor (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));\n\telse result.push(child);\n\treturn result;\n}\n\n//#endregion\n//#region src/jsx-runtime.ts\n/**\n* JSX automatic runtime.\n*\n* When tsconfig has `\"jsxImportSource\": \"@pyreon/core\"`, the TS/bundler compiler\n* rewrites JSX to imports from this file automatically:\n* <div class=\"x\" /> → jsx(\"div\", { class: \"x\" })\n*/\nfunction jsx(type, props, key) {\n\tconst { children, ...rest } = props;\n\tconst propsWithKey = key != null ? {\n\t\t...rest,\n\t\tkey\n\t} : rest;\n\tif (typeof type === \"function\") return h(type, children !== void 0 ? {\n\t\t...propsWithKey,\n\t\tchildren\n\t} : propsWithKey);\n\treturn h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);\n}\nconst jsxs = jsx;\n\n//#endregion\nexport { Fragment, jsx, jsxs };\n//# sourceMappingURL=jsx-runtime.js.map","import type { VNodeChild } from '@pyreon/core'\nimport { onMount } from '@pyreon/core'\nimport { effect, signal } from '@pyreon/reactivity'\n\n// ─── Theme system ───────────────────────────────────────────────────────────\n//\n// Provides dark/light/system theme support with:\n// - System preference detection via matchMedia\n// - Persistent preference via localStorage\n// - No flash of wrong theme (inline script in HTML)\n// - Reactive theme signal for components\n\nexport type Theme = 'light' | 'dark' | 'system'\n\nconst STORAGE_KEY = 'zero-theme'\n\n/** Reactive theme signal. */\nexport const theme = signal<Theme>('system')\n\n/**\n * Reactive signal tracking the OS color-scheme preference. Updated by the\n * `matchMedia('(prefers-color-scheme: dark)').change` event registered in\n * `initTheme`. Components reading `resolvedTheme()` subscribe to BOTH\n * `theme` and this signal, so a user toggling dark mode at the OS level\n * re-renders everything reactively — not just the `<html data-theme>`\n * attribute.\n *\n * SSR default is `_ssrDefault` (mutable via `setSSRThemeDefault`) so the\n * server-rendered theme can differ from the client's OS preference.\n */\nconst _osPrefersDark = signal<boolean>(false)\n\n/** SSR fallback when system preference can't be detected. Default: 'light'. */\nlet _ssrDefault: 'light' | 'dark' = 'light'\n\n/**\n * Set the default theme for SSR (when `matchMedia` is unavailable).\n * Call once at server startup before rendering.\n */\nexport function setSSRThemeDefault(value: 'light' | 'dark'): void {\n _ssrDefault = value\n}\n\n/**\n * Reactive read of the resolved theme. Subscribes to `theme` (explicit\n * user choice) and — when `theme === 'system'` — to `_osPrefersDark`\n * (OS color-scheme preference). Components using `resolvedTheme()`\n * inside JSX / effects / computeds re-render when either changes.\n */\nexport function resolvedTheme(): 'light' | 'dark' {\n const t = theme()\n if (t === 'system') {\n if (typeof window === 'undefined') return _ssrDefault\n return _osPrefersDark() ? 'dark' : 'light'\n }\n return t\n}\n\n/** Toggle between light and dark. */\nexport function toggleTheme() {\n const current = resolvedTheme()\n setTheme(current === 'dark' ? 'light' : 'dark')\n}\n\n/** Set theme explicitly. */\nexport function setTheme(t: Theme) {\n theme.set(t)\n if (typeof document !== 'undefined') {\n document.documentElement.dataset.theme = resolvedTheme()\n try {\n localStorage.setItem(STORAGE_KEY, t)\n } catch {\n // localStorage may not be available (SSR, private browsing)\n }\n }\n}\n\n/**\n * Initialize the theme system. Call once in your app entry or layout.\n * Reads from localStorage, listens for system preference changes.\n */\nexport function initTheme() {\n onMount(() => {\n // Read persisted preference\n try {\n const stored = localStorage.getItem(STORAGE_KEY) as Theme | null\n if (stored === 'light' || stored === 'dark' || stored === 'system') {\n theme.set(stored)\n }\n } catch {\n // localStorage may not be available\n }\n\n // Apply to document\n document.documentElement.dataset.theme = resolvedTheme()\n\n // Watch for system preference changes. Seed the signal from the\n // current media-query state, then update reactively on each OS\n // preference flip. Components reading `resolvedTheme()` pick up the\n // change automatically (they subscribe to `_osPrefersDark` when\n // `theme === 'system'`).\n const mq = window.matchMedia('(prefers-color-scheme: dark)')\n _osPrefersDark.set(mq.matches)\n function onChange(e: MediaQueryListEvent) {\n _osPrefersDark.set(e.matches)\n }\n mq.addEventListener('change', onChange)\n\n // Re-apply when theme signal changes — updates data-theme + favicons\n const dispose = effect(() => {\n const mode = resolvedTheme()\n document.documentElement.dataset.theme = mode\n\n // Swap favicon variants (if dual-variant favicons are present)\n const faviconLinks = document.querySelectorAll<HTMLLinkElement>('[data-favicon-theme]')\n for (const link of faviconLinks) {\n link.media = link.dataset.faviconTheme === mode ? '' : 'not all'\n }\n })\n\n return () => {\n mq.removeEventListener('change', onChange)\n dispose?.dispose()\n }\n })\n}\n\n/**\n * Theme toggle button component.\n *\n * @example\n * import { ThemeToggle } from \"@pyreon/zero/theme\"\n * <ThemeToggle />\n */\nexport function ThemeToggle(props: { class?: string; style?: string }): VNodeChild {\n initTheme()\n\n return (\n <button\n class={props.class}\n style={props.style}\n onClick={toggleTheme}\n aria-label=\"Toggle theme\"\n title=\"Toggle theme\"\n type=\"button\"\n >\n {() =>\n resolvedTheme() === 'dark' ? (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"5\" />\n <line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\" />\n <line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\" />\n <line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\" />\n <line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\" />\n <line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\" />\n <line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\" />\n <line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\" />\n <line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\" />\n </svg>\n ) : (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z\" />\n </svg>\n )\n }\n </button>\n )\n}\n\n/**\n * Inline script to prevent flash of wrong theme.\n * Include this in your index.html <head> BEFORE any stylesheets.\n *\n * @example\n * // index.html\n * <head>\n * <script>{themeScript}</script>\n * ...\n * </head>\n */\nexport const themeScript = `(function(){try{var t=localStorage.getItem(\"${STORAGE_KEY}\");var r=t===\"light\"?\"light\":t===\"dark\"?\"dark\":window.matchMedia(\"(prefers-color-scheme:dark)\").matches?\"dark\":\"light\";document.documentElement.dataset.theme=r;document.querySelectorAll(\"[data-favicon-theme]\").forEach(function(l){l.media=l.dataset.faviconTheme===r?\"\":\"not all\"})}catch(e){}})()`\n"],"mappings":"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"}
|
package/lib/types/config.d.ts
CHANGED
|
@@ -5,6 +5,13 @@ type RenderMode = 'ssr' | 'ssg' | 'spa' | 'isr';
|
|
|
5
5
|
interface ISRConfig {
|
|
6
6
|
/** Revalidation interval in seconds. */
|
|
7
7
|
revalidate: number;
|
|
8
|
+
/**
|
|
9
|
+
* Maximum number of distinct URL paths to keep in the in-memory cache.
|
|
10
|
+
* Oldest-first LRU eviction once the cap is reached. Default: `1000`.
|
|
11
|
+
* Set higher for SSG-heavy sites, lower for routes with unbounded URL
|
|
12
|
+
* space (e.g. `/user/:id` where `:id` is free-form).
|
|
13
|
+
*/
|
|
14
|
+
maxEntries?: number;
|
|
8
15
|
}
|
|
9
16
|
interface ZeroConfig {
|
|
10
17
|
/** Default rendering mode. Default: "ssr" */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config2.d.ts","names":[],"sources":["../../../src/types.ts","../../../src/config.ts"],"mappings":";;;KA6CY,UAAA;AAAA,UAEK,SAAA;
|
|
1
|
+
{"version":3,"file":"config2.d.ts","names":[],"sources":["../../../src/types.ts","../../../src/config.ts"],"mappings":";;;KA6CY,UAAA;AAAA,UAEK,SAAA;EA2CF;EAzCb,UAAA;EA4CI;;;;;AC9EN;EDyCE,UAAA;AAAA;AAAA,UAKe,UAAA;EC9CoB;EDgDnC,IAAA,GAAO,UAAA;EChDyC;EDmDhD,IAAA,GAAO,MAAA;ECnDmD;EDsD1D,GAAA;ICjD2B,wCDmDzB,IAAA;EAAA;ECjDa;EDqDf,GAAA;ICrDC,wDDuDC,KAAA,gCAAqC,OAAA;EAAA;ECvDuC;ED2D9E,GAAA,GAAM,SAAA;EC5DN;ED+DA,OAAA;EC9DU;EDiEV,IAAA;ECjEoE;EDoEpE,UAAA,GAAa,UAAA;ECpEiE;EDuE9E,IAAA;AAAA;;;;;;;AAhDF;;;;;AAEA;;;;iBChCgB,YAAA,CAAa,MAAA,EAAQ,UAAA,GAAa,UAAA;AD8ClD;AAAA,iBCzCgB,aAAA,CACd,UAAA,GAAY,UAAA,GACX,QAAA,CAAS,IAAA,CAAK,UAAA,2CAAqD,UAAA"}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -454,7 +454,12 @@ declare const theme: _pyreon_reactivity0.Signal<Theme>;
|
|
|
454
454
|
* Call once at server startup before rendering.
|
|
455
455
|
*/
|
|
456
456
|
declare function setSSRThemeDefault(value: 'light' | 'dark'): void;
|
|
457
|
-
/**
|
|
457
|
+
/**
|
|
458
|
+
* Reactive read of the resolved theme. Subscribes to `theme` (explicit
|
|
459
|
+
* user choice) and — when `theme === 'system'` — to `_osPrefersDark`
|
|
460
|
+
* (OS color-scheme preference). Components using `resolvedTheme()`
|
|
461
|
+
* inside JSX / effects / computeds re-render when either changes.
|
|
462
|
+
*/
|
|
458
463
|
declare function resolvedTheme(): 'light' | 'dark';
|
|
459
464
|
/** Toggle between light and dark. */
|
|
460
465
|
declare function toggleTheme(): void;
|
|
@@ -528,6 +533,13 @@ type RenderMode = 'ssr' | 'ssg' | 'spa' | 'isr';
|
|
|
528
533
|
interface ISRConfig {
|
|
529
534
|
/** Revalidation interval in seconds. */
|
|
530
535
|
revalidate: number;
|
|
536
|
+
/**
|
|
537
|
+
* Maximum number of distinct URL paths to keep in the in-memory cache.
|
|
538
|
+
* Oldest-first LRU eviction once the cap is reached. Default: `1000`.
|
|
539
|
+
* Set higher for SSG-heavy sites, lower for routes with unbounded URL
|
|
540
|
+
* space (e.g. `/user/:id` where `:id` is free-form).
|
|
541
|
+
*/
|
|
542
|
+
maxEntries?: number;
|
|
531
543
|
}
|
|
532
544
|
interface ZeroConfig {
|
|
533
545
|
/** Default rendering mode. Default: "ssr" */
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/image-plugin.ts","../../../src/image.tsx","../../../src/link.tsx","../../../src/script.tsx","../../../src/i18n-routing.ts","../../../src/meta.tsx","../../../src/theme.tsx","../../../src/types.ts","../../../src/index.ts"],"mappings":";;;;;;;;UAgHiB,YAAA;EE/EA;EFiFf,IAAA;EEjFyB;EFmFzB,MAAA;AAAA;;;UCpGe,UAAA;;EAEf,GAAA;;EAEA,GAAA;;EAEA,KAAA;ED0F2B;ECxF3B,MAAA;ED0FA;ECxFA,KAAA;;EAEA,MAAA,YAAkB,WAAA;;EAElB,OAAA,GAAU,YAAA;EAde;EAgBzB,OAAA;EAFsB;EAItB,QAAA;EAdA;EAgBA,WAAA;EAZA;EAcA,KAAA;EAVA;EAYA,KAAA;EAVA;EAYA,GAAA;EAVA;EAYA,QAAA;EARA;;;;;EAcA,GAAA;AAAA;AAAA,UAGe,WAAA;EACf,GAAA;EACA,KAAA;AAAA;;;AAgBF;;;;;;;;;;;iBAAgB,KAAA,CAAM,KAAA,EAAO,UAAA,GAAa,UAAA;;;UC1DzB,SAAA;;EAEf,IAAA;;EAEA,QAAA;;EAEA,KAAA;;EAEA,WAAA;EF2F2B;EEzF3B,gBAAA;EF2FA;EEzFA,QAAA;;EAEA,QAAA;;EAEA,KAAA;EDbyB;ECezB,YAAA;EDDsB;ECGtB,OAAA,KAAY,CAAA,EAAG,UAAA;AAAA;;UAIA,eAAA;EACf,IAAA;EACA,GAAA,EAAiD,aAAA,CAArB,GAAA,CAAI,iBAAA;EAChC,OAAA,GAAU,CAAA,EAAG,UAAA;EACb,YAAA;EACA,YAAA;EACA,QAAA;EACA,aAAA;EDRA;ECUA,KAAA;EACA,KAAA;EACA,MAAA;EACA,GAAA;EACA,YAAA;EACA,QAAA;AAAA;ADEF;AAAA,UCEiB,aAAA;;EAEf,GAAA,EAAiD,aAAA,CAArB,GAAA,CAAI,iBAAA;EDF3B;ECIL,WAAA,GAAc,CAAA,EAAG,UAAA;EDYE;ECVnB,gBAAA;EDUkD;ECRlD,gBAAA;EDQoB;ECNpB,QAAA;EDMkD;ECJlD,aAAA;;EAEA,OAAA;AAAA;AAxDF;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/image-plugin.ts","../../../src/image.tsx","../../../src/link.tsx","../../../src/script.tsx","../../../src/i18n-routing.ts","../../../src/meta.tsx","../../../src/theme.tsx","../../../src/types.ts","../../../src/index.ts"],"mappings":"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"}
|
package/lib/types/link.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link2.d.ts","names":[],"sources":["../../../src/link.tsx"],"mappings":";;;UAaiB,SAAA;;EAEf,IAAA;EAFe;EAIf,QAAA;;EAEA,KAAA;EAJA;EAMA,WAAA;EAFA;EAIA,gBAAA;EAAA;EAEA,QAAA;EAEA;EAAA,QAAA;EAIA;EAFA,KAAA;EAIe;EAFf,YAAA;EAEyB;EAAzB,OAAA,KAAY,CAAA,EAAG,UAAA;AAAA;;UAIA,eAAA;EACf,IAAA;EACA,GAAA,EAAiD,aAAA,CAArB,GAAA,CAAI,iBAAA;EAChC,OAAA,GAAU,CAAA,EAAG,UAAA;EACb,YAAA;EACA,YAAA;EACA,QAAA;EACA,aAAA;EALG;EAOH,KAAA;EACA,KAAA;EACA,MAAA;EACA,GAAA;EACA,YAAA;EACA,QAAA;AAAA;;UAIe,aAAA;EARf;EAUA,GAAA,EAAiD,aAAA,CAArB,GAAA,CAAI,iBAAA;EARhC;EAUA,WAAA,GAAc,CAAA,EAAG,UAAA;EARjB;EAUA,gBAAA;EAVQ;EAYR,gBAAA;EAR4B;EAU5B,QAAA;EARgC;EAUhC,aAAA;EARiB;EAUjB,OAAA;AAAA;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"link2.d.ts","names":[],"sources":["../../../src/link.tsx"],"mappings":";;;UAaiB,SAAA;;EAEf,IAAA;EAFe;EAIf,QAAA;;EAEA,KAAA;EAJA;EAMA,WAAA;EAFA;EAIA,gBAAA;EAAA;EAEA,QAAA;EAEA;EAAA,QAAA;EAIA;EAFA,KAAA;EAIe;EAFf,YAAA;EAEyB;EAAzB,OAAA,KAAY,CAAA,EAAG,UAAA;AAAA;;UAIA,eAAA;EACf,IAAA;EACA,GAAA,EAAiD,aAAA,CAArB,GAAA,CAAI,iBAAA;EAChC,OAAA,GAAU,CAAA,EAAG,UAAA;EACb,YAAA;EACA,YAAA;EACA,QAAA;EACA,aAAA;EALG;EAOH,KAAA;EACA,KAAA;EACA,MAAA;EACA,GAAA;EACA,YAAA;EACA,QAAA;AAAA;;UAIe,aAAA;EARf;EAUA,GAAA,EAAiD,aAAA,CAArB,GAAA,CAAI,iBAAA;EARhC;EAUA,WAAA,GAAc,CAAA,EAAG,UAAA;EARjB;EAUA,gBAAA;EAVQ;EAYR,gBAAA;EAR4B;EAU5B,QAAA;EARgC;EAUhC,aAAA;EARiB;EAUjB,OAAA;AAAA;;;;;;;;;iBAuDc,aAAA,CAAc,IAAA;;;;;AAA9B;;;;;AAoBA;;;;;;;iBAAgB,OAAA,CAAQ,KAAA,EAAO,SAAA,GAAY,aAAA;;AAiH3C;;;;;;;;;;;AA8BA;;;;;;;;;;;;;;;;;;;;;;;iBA9BgB,UAAA,CAAW,SAAA,GAAY,KAAA,EAAO,eAAA,YAA2B,KAAA,EAAO,SAAA;;;;;;;;cA8BnE,IAAA,GAAI,KAAA,EA9B+D,SAAA"}
|
package/lib/types/server.d.ts
CHANGED
|
@@ -66,6 +66,13 @@ type RenderMode = 'ssr' | 'ssg' | 'spa' | 'isr';
|
|
|
66
66
|
interface ISRConfig {
|
|
67
67
|
/** Revalidation interval in seconds. */
|
|
68
68
|
revalidate: number;
|
|
69
|
+
/**
|
|
70
|
+
* Maximum number of distinct URL paths to keep in the in-memory cache.
|
|
71
|
+
* Oldest-first LRU eviction once the cap is reached. Default: `1000`.
|
|
72
|
+
* Set higher for SSG-heavy sites, lower for routes with unbounded URL
|
|
73
|
+
* space (e.g. `/user/:id` where `:id` is free-form).
|
|
74
|
+
*/
|
|
75
|
+
maxEntries?: number;
|
|
69
76
|
}
|
|
70
77
|
interface ZeroConfig {
|
|
71
78
|
/** Default rendering mode. Default: "ssr" */
|
|
@@ -288,6 +295,13 @@ declare function scanRouteFiles(routesDir: string): Promise<string[]>;
|
|
|
288
295
|
*
|
|
289
296
|
* Wraps an SSR handler and caches responses per URL path.
|
|
290
297
|
* Serves stale content immediately while revalidating in the background.
|
|
298
|
+
*
|
|
299
|
+
* Bounded by `config.maxEntries` (default: 1000) with LRU eviction. The
|
|
300
|
+
* `Map` preserves insertion order, so re-inserting an entry on every
|
|
301
|
+
* serve (touching it) keeps the LRU order correct. Without the cap,
|
|
302
|
+
* unbounded URL spaces like `/user/:id` would grow cache memory without
|
|
303
|
+
* limit over the server's lifetime — a real leak in long-running
|
|
304
|
+
* deployments.
|
|
291
305
|
*/
|
|
292
306
|
declare function createISRHandler(handler: (req: Request) => Promise<Response>, config: ISRConfig): (req: Request) => Promise<Response>;
|
|
293
307
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server2.d.ts","names":[],"sources":["../../../src/app.ts","../../../src/api-routes.ts","../../../src/types.ts","../../../src/entry-server.ts","../../../src/config.ts","../../../src/fs-router.ts","../../../src/isr.ts","../../../src/adapters/bun.ts","../../../src/adapters/cloudflare.ts","../../../src/adapters/netlify.ts","../../../src/adapters/node.ts","../../../src/adapters/static.ts","../../../src/adapters/vercel.ts","../../../src/adapters/index.ts","../../../src/not-found.ts","../../../src/middleware.ts","../../../src/vite-plugin.ts","../../../src/favicon.ts","../../../src/seo.ts","../../../src/og-image.ts","../../../src/ai.ts","../../../src/i18n-routing.ts"],"mappings":";;;;;;;UAQiB,gBAAA;;EAEf,MAAA,EAAQ,WAAA;;EAGR,UAAA;;EAGA,GAAA;EARe;EAWf,MAAA,GAAS,WAAA;;EAGT,cAAA,GAAiB,WAAA;AAAA;;;;;;iBAQH,SAAA,CAAU,OAAA,EAAS,gBAAA;aAAgB,aAAA,CAAA,KAAA;;;;;;UCtBlC,UAAA;;EAEf,OAAA,EAAS,OAAA;;EAET,GAAA,EAAK,GAAA;EDJU;ECMf,IAAA;;EAEA,MAAA,EAAQ,MAAA;EDGC;ECDT,OAAA,EAAS,OAAA;AAAA;;KAIC,UAAA,IAAc,GAAA,EAAK,UAAA,KAAe,QAAA,GAAW,OAAA,CAAQ,QAAA;;UAGhD,cAAA;EACf,GAAA,GAAM,UAAA;EACN,IAAA,GAAO,UAAA;EACP,GAAA,GAAM,UAAA;EACN,KAAA,GAAQ,UAAA;EACR,MAAA,GAAS,UAAA;EACT,IAAA,GAAO,UAAA;EACP,OAAA,GAAU,UAAA;AAAA;;UAIK,aAAA;EDNkB;ECQjC,OAAA;;EAEA,MAAA,EAAQ,cAAA;AAAA;;;KCKE,UAAA;AAAA,UAEK,SAAA;;EAEf,UAAA;AAAA;AAAA,UAKe,UAAA
|
|
1
|
+
{"version":3,"file":"server2.d.ts","names":[],"sources":["../../../src/app.ts","../../../src/api-routes.ts","../../../src/types.ts","../../../src/entry-server.ts","../../../src/config.ts","../../../src/fs-router.ts","../../../src/isr.ts","../../../src/adapters/bun.ts","../../../src/adapters/cloudflare.ts","../../../src/adapters/netlify.ts","../../../src/adapters/node.ts","../../../src/adapters/static.ts","../../../src/adapters/vercel.ts","../../../src/adapters/index.ts","../../../src/not-found.ts","../../../src/middleware.ts","../../../src/vite-plugin.ts","../../../src/favicon.ts","../../../src/seo.ts","../../../src/og-image.ts","../../../src/ai.ts","../../../src/i18n-routing.ts"],"mappings":"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"}
|
package/lib/types/theme.d.ts
CHANGED
|
@@ -10,7 +10,12 @@ declare const theme: _pyreon_reactivity0.Signal<Theme>;
|
|
|
10
10
|
* Call once at server startup before rendering.
|
|
11
11
|
*/
|
|
12
12
|
declare function setSSRThemeDefault(value: 'light' | 'dark'): void;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Reactive read of the resolved theme. Subscribes to `theme` (explicit
|
|
15
|
+
* user choice) and — when `theme === 'system'` — to `_osPrefersDark`
|
|
16
|
+
* (OS color-scheme preference). Components using `resolvedTheme()`
|
|
17
|
+
* inside JSX / effects / computeds re-render when either changes.
|
|
18
|
+
*/
|
|
14
19
|
declare function resolvedTheme(): 'light' | 'dark';
|
|
15
20
|
/** Toggle between light and dark. */
|
|
16
21
|
declare function toggleTheme(): void;
|
package/lib/types/theme.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme2.d.ts","names":[],"sources":["../../../src/theme.tsx"],"mappings":";;;;KAYY,KAAA;;cAKC,KAAA,EAAK,mBAAA,CAAA,MAAA,CAAA,KAAA;AALlB;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"theme2.d.ts","names":[],"sources":["../../../src/theme.tsx"],"mappings":";;;;KAYY,KAAA;;cAKC,KAAA,EAAK,mBAAA,CAAA,MAAA,CAAA,KAAA;AALlB;;;;AAAA,iBA2BgB,kBAAA,CAAmB,KAAA;AAtBnC;;;;;AAsBA;AAtBA,iBAgCgB,aAAA,CAAA;;iBAUA,WAAA,CAAA;;iBAMA,QAAA,CAAS,CAAA,EAAG,KAAA;;;;;iBAgBZ,SAAA,CAAA;;;;;AAhBhB;;;iBAqEgB,WAAA,CAAY,KAAA;EAAS,KAAA;EAAgB,KAAA;AAAA,IAAmB,UAAA;;;;AAAxE;;;;;;;;cAkEa,WAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/zero",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Pyreon Zero — zero-config full-stack framework powered by Pyreon and Vite",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Vit Bokisch",
|
|
@@ -166,18 +166,18 @@
|
|
|
166
166
|
"lint": "oxlint ."
|
|
167
167
|
},
|
|
168
168
|
"dependencies": {
|
|
169
|
-
"@pyreon/core": "^0.
|
|
170
|
-
"@pyreon/head": "^0.
|
|
171
|
-
"@pyreon/meta": "^0.
|
|
172
|
-
"@pyreon/router": "^0.
|
|
173
|
-
"@pyreon/runtime-dom": "^0.
|
|
174
|
-
"@pyreon/runtime-server": "^0.
|
|
175
|
-
"@pyreon/server": "^0.
|
|
176
|
-
"@pyreon/vite-plugin": "^0.
|
|
169
|
+
"@pyreon/core": "^0.13.0",
|
|
170
|
+
"@pyreon/head": "^0.13.0",
|
|
171
|
+
"@pyreon/meta": "^0.13.0",
|
|
172
|
+
"@pyreon/router": "^0.13.0",
|
|
173
|
+
"@pyreon/runtime-dom": "^0.13.0",
|
|
174
|
+
"@pyreon/runtime-server": "^0.13.0",
|
|
175
|
+
"@pyreon/server": "^0.13.0",
|
|
176
|
+
"@pyreon/vite-plugin": "^0.13.0",
|
|
177
177
|
"vite": "^8.0.0"
|
|
178
178
|
},
|
|
179
179
|
"peerDependencies": {
|
|
180
|
-
"@pyreon/reactivity": "^0.
|
|
180
|
+
"@pyreon/reactivity": "^0.13.0",
|
|
181
181
|
"sharp": "^0.33.0"
|
|
182
182
|
},
|
|
183
183
|
"peerDependenciesMeta": {
|
package/src/client.ts
CHANGED
|
@@ -85,7 +85,11 @@ export function startClient(options: StartClientOptions) {
|
|
|
85
85
|
const vnode = h(App, null)
|
|
86
86
|
|
|
87
87
|
// ── Mount vs hydrate ───────────────────────────────────────────────────────
|
|
88
|
-
|
|
88
|
+
// Ignore comment nodes (Vite injects <!--app-html-->) — only real DOM
|
|
89
|
+
// elements or text nodes count as SSR content worth hydrating.
|
|
90
|
+
const hasSSRContent = Array.from(container.childNodes).some(
|
|
91
|
+
(n) => n.nodeType === 1 || (n.nodeType === 3 && n.textContent!.trim().length > 0),
|
|
92
|
+
)
|
|
89
93
|
const cleanup = hasSSRContent ? hydrateRoot(container, vnode) : mount(vnode, container)
|
|
90
94
|
|
|
91
95
|
// ── Loader run (SPA cold-start path) ───────────────────────────────────────
|
package/src/isr.ts
CHANGED
|
@@ -13,6 +13,13 @@ interface CacheEntry {
|
|
|
13
13
|
*
|
|
14
14
|
* Wraps an SSR handler and caches responses per URL path.
|
|
15
15
|
* Serves stale content immediately while revalidating in the background.
|
|
16
|
+
*
|
|
17
|
+
* Bounded by `config.maxEntries` (default: 1000) with LRU eviction. The
|
|
18
|
+
* `Map` preserves insertion order, so re-inserting an entry on every
|
|
19
|
+
* serve (touching it) keeps the LRU order correct. Without the cap,
|
|
20
|
+
* unbounded URL spaces like `/user/:id` would grow cache memory without
|
|
21
|
+
* limit over the server's lifetime — a real leak in long-running
|
|
22
|
+
* deployments.
|
|
16
23
|
*/
|
|
17
24
|
export function createISRHandler(
|
|
18
25
|
handler: (req: Request) => Promise<Response>,
|
|
@@ -21,6 +28,28 @@ export function createISRHandler(
|
|
|
21
28
|
const cache = new Map<string, CacheEntry>()
|
|
22
29
|
const revalidating = new Set<string>()
|
|
23
30
|
const revalidateMs = config.revalidate * 1000
|
|
31
|
+
const maxEntries = Math.max(1, config.maxEntries ?? 1000)
|
|
32
|
+
|
|
33
|
+
function set(key: string, entry: CacheEntry): void {
|
|
34
|
+
// LRU: re-inserting moves the key to the newest position. Then if we're
|
|
35
|
+
// over the cap, drop the oldest (first in iteration order).
|
|
36
|
+
if (cache.has(key)) cache.delete(key)
|
|
37
|
+
cache.set(key, entry)
|
|
38
|
+
while (cache.size > maxEntries) {
|
|
39
|
+
const oldest = cache.keys().next().value
|
|
40
|
+
if (oldest === undefined) break
|
|
41
|
+
cache.delete(oldest)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function touch(key: string): CacheEntry | undefined {
|
|
46
|
+
const entry = cache.get(key)
|
|
47
|
+
if (entry !== undefined) {
|
|
48
|
+
cache.delete(key)
|
|
49
|
+
cache.set(key, entry)
|
|
50
|
+
}
|
|
51
|
+
return entry
|
|
52
|
+
}
|
|
24
53
|
|
|
25
54
|
async function revalidate(url: URL) {
|
|
26
55
|
const key = url.pathname
|
|
@@ -36,7 +65,7 @@ export function createISRHandler(
|
|
|
36
65
|
headers[k] = v
|
|
37
66
|
})
|
|
38
67
|
|
|
39
|
-
|
|
68
|
+
set(key, { html, headers, timestamp: Date.now() })
|
|
40
69
|
} catch {
|
|
41
70
|
// Revalidation failed — stale cache entry remains valid
|
|
42
71
|
} finally {
|
|
@@ -52,7 +81,10 @@ export function createISRHandler(
|
|
|
52
81
|
|
|
53
82
|
const url = new URL(req.url)
|
|
54
83
|
const key = url.pathname
|
|
55
|
-
|
|
84
|
+
// `touch` moves the entry to the newest LRU position on read so
|
|
85
|
+
// hot paths survive eviction even when the cap is small. `get`
|
|
86
|
+
// wouldn't update ordering.
|
|
87
|
+
const entry = touch(key)
|
|
56
88
|
|
|
57
89
|
if (entry) {
|
|
58
90
|
const age = Date.now() - entry.timestamp
|
package/src/link.tsx
CHANGED
|
@@ -71,34 +71,47 @@ export interface UseLinkReturn {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const MAX_PREFETCH_CACHE = 200
|
|
74
|
-
|
|
74
|
+
// Maps href → list of <link> elements injected into <head>. When the
|
|
75
|
+
// cache evicts an href (FIFO at MAX_PREFETCH_CACHE), the matching <link>
|
|
76
|
+
// elements must be removed too — otherwise head bloats unboundedly
|
|
77
|
+
// across long SPA sessions (every Link interaction added 2 <link> nodes
|
|
78
|
+
// with no cleanup).
|
|
79
|
+
const prefetched = new Map<string, Element[]>()
|
|
75
80
|
|
|
76
81
|
function doPrefetch(href: string) {
|
|
77
82
|
// Prefetch only fires from browser-mounted Link interactions (hover /
|
|
78
83
|
// click intent). Explicit guard documents the SSR-safety contract.
|
|
79
84
|
if (typeof document === 'undefined') return
|
|
80
85
|
if (prefetched.has(href)) return
|
|
81
|
-
// Evict oldest entries when cache is full
|
|
86
|
+
// Evict oldest entries when cache is full — AND remove their DOM nodes.
|
|
82
87
|
if (prefetched.size >= MAX_PREFETCH_CACHE) {
|
|
83
|
-
const
|
|
84
|
-
if (
|
|
88
|
+
const firstEntry = prefetched.entries().next().value
|
|
89
|
+
if (firstEntry) {
|
|
90
|
+
const [oldestHref, oldestLinks] = firstEntry
|
|
91
|
+
for (const link of oldestLinks) link.remove()
|
|
92
|
+
prefetched.delete(oldestHref)
|
|
93
|
+
}
|
|
85
94
|
}
|
|
86
|
-
prefetched.add(href)
|
|
87
95
|
|
|
96
|
+
const injected: Element[] = []
|
|
88
97
|
const docLink = document.createElement('link')
|
|
89
98
|
docLink.rel = 'prefetch'
|
|
90
99
|
docLink.href = href
|
|
91
100
|
docLink.as = 'document'
|
|
92
101
|
document.head.appendChild(docLink)
|
|
102
|
+
injected.push(docLink)
|
|
93
103
|
|
|
94
104
|
try {
|
|
95
105
|
const chunkHint = document.createElement('link')
|
|
96
106
|
chunkHint.rel = 'modulepreload'
|
|
97
107
|
chunkHint.href = href
|
|
98
108
|
document.head.appendChild(chunkHint)
|
|
109
|
+
injected.push(chunkHint)
|
|
99
110
|
} catch {
|
|
100
111
|
// modulepreload is a hint, not critical
|
|
101
112
|
}
|
|
113
|
+
|
|
114
|
+
prefetched.set(href, injected)
|
|
102
115
|
}
|
|
103
116
|
|
|
104
117
|
/**
|
package/src/theme.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VNodeChild } from '@pyreon/core'
|
|
2
|
-
import { onMount
|
|
2
|
+
import { onMount } from '@pyreon/core'
|
|
3
3
|
import { effect, signal } from '@pyreon/reactivity'
|
|
4
4
|
|
|
5
5
|
// ─── Theme system ───────────────────────────────────────────────────────────
|
|
@@ -17,6 +17,19 @@ const STORAGE_KEY = 'zero-theme'
|
|
|
17
17
|
/** Reactive theme signal. */
|
|
18
18
|
export const theme = signal<Theme>('system')
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Reactive signal tracking the OS color-scheme preference. Updated by the
|
|
22
|
+
* `matchMedia('(prefers-color-scheme: dark)').change` event registered in
|
|
23
|
+
* `initTheme`. Components reading `resolvedTheme()` subscribe to BOTH
|
|
24
|
+
* `theme` and this signal, so a user toggling dark mode at the OS level
|
|
25
|
+
* re-renders everything reactively — not just the `<html data-theme>`
|
|
26
|
+
* attribute.
|
|
27
|
+
*
|
|
28
|
+
* SSR default is `_ssrDefault` (mutable via `setSSRThemeDefault`) so the
|
|
29
|
+
* server-rendered theme can differ from the client's OS preference.
|
|
30
|
+
*/
|
|
31
|
+
const _osPrefersDark = signal<boolean>(false)
|
|
32
|
+
|
|
20
33
|
/** SSR fallback when system preference can't be detected. Default: 'light'. */
|
|
21
34
|
let _ssrDefault: 'light' | 'dark' = 'light'
|
|
22
35
|
|
|
@@ -28,12 +41,17 @@ export function setSSRThemeDefault(value: 'light' | 'dark'): void {
|
|
|
28
41
|
_ssrDefault = value
|
|
29
42
|
}
|
|
30
43
|
|
|
31
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Reactive read of the resolved theme. Subscribes to `theme` (explicit
|
|
46
|
+
* user choice) and — when `theme === 'system'` — to `_osPrefersDark`
|
|
47
|
+
* (OS color-scheme preference). Components using `resolvedTheme()`
|
|
48
|
+
* inside JSX / effects / computeds re-render when either changes.
|
|
49
|
+
*/
|
|
32
50
|
export function resolvedTheme(): 'light' | 'dark' {
|
|
33
51
|
const t = theme()
|
|
34
52
|
if (t === 'system') {
|
|
35
53
|
if (typeof window === 'undefined') return _ssrDefault
|
|
36
|
-
return
|
|
54
|
+
return _osPrefersDark() ? 'dark' : 'light'
|
|
37
55
|
}
|
|
38
56
|
return t
|
|
39
57
|
}
|
|
@@ -76,15 +94,17 @@ export function initTheme() {
|
|
|
76
94
|
// Apply to document
|
|
77
95
|
document.documentElement.dataset.theme = resolvedTheme()
|
|
78
96
|
|
|
79
|
-
// Watch for system preference changes
|
|
97
|
+
// Watch for system preference changes. Seed the signal from the
|
|
98
|
+
// current media-query state, then update reactively on each OS
|
|
99
|
+
// preference flip. Components reading `resolvedTheme()` pick up the
|
|
100
|
+
// change automatically (they subscribe to `_osPrefersDark` when
|
|
101
|
+
// `theme === 'system'`).
|
|
80
102
|
const mq = window.matchMedia('(prefers-color-scheme: dark)')
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
103
|
+
_osPrefersDark.set(mq.matches)
|
|
104
|
+
function onChange(e: MediaQueryListEvent) {
|
|
105
|
+
_osPrefersDark.set(e.matches)
|
|
85
106
|
}
|
|
86
107
|
mq.addEventListener('change', onChange)
|
|
87
|
-
onUnmount(() => mq.removeEventListener('change', onChange))
|
|
88
108
|
|
|
89
109
|
// Re-apply when theme signal changes — updates data-theme + favicons
|
|
90
110
|
const dispose = effect(() => {
|
|
@@ -97,9 +117,11 @@ export function initTheme() {
|
|
|
97
117
|
link.media = link.dataset.faviconTheme === mode ? '' : 'not all'
|
|
98
118
|
}
|
|
99
119
|
})
|
|
100
|
-
if (dispose) onUnmount(() => dispose.dispose())
|
|
101
120
|
|
|
102
|
-
return
|
|
121
|
+
return () => {
|
|
122
|
+
mq.removeEventListener('change', onChange)
|
|
123
|
+
dispose?.dispose()
|
|
124
|
+
}
|
|
103
125
|
})
|
|
104
126
|
}
|
|
105
127
|
|
package/src/types.ts
CHANGED
|
@@ -48,6 +48,13 @@ export type RenderMode = 'ssr' | 'ssg' | 'spa' | 'isr'
|
|
|
48
48
|
export interface ISRConfig {
|
|
49
49
|
/** Revalidation interval in seconds. */
|
|
50
50
|
revalidate: number
|
|
51
|
+
/**
|
|
52
|
+
* Maximum number of distinct URL paths to keep in the in-memory cache.
|
|
53
|
+
* Oldest-first LRU eviction once the cap is reached. Default: `1000`.
|
|
54
|
+
* Set higher for SSG-heavy sites, lower for routes with unbounded URL
|
|
55
|
+
* space (e.g. `/user/:id` where `:id` is free-form).
|
|
56
|
+
*/
|
|
57
|
+
maxEntries?: number
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
// ─── Zero config ─────────────────────────────────────────────────────────────
|