@voltro/web 0.51.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,29 +1,30 @@
1
- import { t as e } from "./globalContext-d4A-ugDg.js";
1
+ import { t as e } from "./globalContext-AuflFFmy.js";
2
2
  import { AppClientsContext as t, useAppClient as n } from "./hooks.js";
3
- import { a as r, c as i, i as a, l as o, o as s, r as c, s as l, u } from "./frameworkBoot-CV_o2tIk.js";
4
- import { a as d, c as f, i as p, l as m, o as h, u as g } from "./defaultFallbacks-B4Ak-R6R.js";
5
- import { a as _, i as ee, n as te, r as ne, t as re } from "./mount-nudb4UCl.js";
6
- import { c as ie, d as ae, h as oe, l as se, p as ce, u as le } from "./routerState-DAT472IC.js";
7
- import { A as ue, B as de, C as fe, D as pe, E as me, F as he, G as ge, H as _e, I as v, K as y, L as b, M as x, N as S, O as C, P as w, R as T, S as E, T as D, U as O, V as k, W as A, _ as j, a as M, b as N, c as P, d as F, f as I, g as ve, h as ye, i as be, j as xe, k as Se, l as Ce, m as we, n as Te, o as Ee, p as De, q as Oe, r as ke, s as Ae, t as je, u as Me, v as Ne, w as Pe, x as Fe, y as Ie, z as Le } from "./serverContext-38JTbYPa.js";
8
- import { Component as Re, Suspense as ze, createElement as L, use as Be, useCallback as Ve, useContext as He, useSyncExternalStore as Ue } from "react";
9
- import { Fragment as R, jsx as z, jsxs as B } from "react/jsx-runtime";
3
+ import { a as r, c as i, i as a, l as o, o as s, r as c, s as l, u } from "./frameworkBoot-CnE9vzLQ.js";
4
+ import { a as d, c as f, i as p, l as m, o as h, u as g } from "./defaultFallbacks-SQ45vAhz.js";
5
+ import { getIslandComponent as _, hydrateIslandsOnPage as v, island as y } from "./islands.js";
6
+ import { c as b, d as x, f as S, g as C, l as w, m as T } from "./routerState-Cr6fTbka.js";
7
+ import { mount as E, noticeIslandsShipTheFullBundle as ee } from "./mount.js";
8
+ import { A as te, B as ne, C as re, D as ie, E as ae, F as oe, G as se, H as ce, I as le, K as ue, L as de, M as fe, N as pe, O as me, P as he, R as ge, S as _e, T as ve, U as ye, V as be, W as D, _ as O, a as k, b as A, c as j, d as M, f as N, g as xe, h as Se, i as Ce, j as we, k as Te, l as Ee, m as De, n as Oe, o as ke, p as Ae, q as je, r as Me, s as Ne, t as Pe, u as Fe, v as Ie, w as Le, x as Re, y as ze, z as Be } from "./serverContext-BwzZ6Q7d.js";
9
+ import { Component as Ve, Suspense as He, createElement as P, use as Ue, useCallback as We, useContext as Ge, useEffect as Ke, useSyncExternalStore as qe } from "react";
10
+ import { Fragment as F, jsx as I, jsxs as L } from "react/jsx-runtime";
10
11
  export * from "@voltro/client";
11
12
  export * from "@voltro/ui";
12
13
  //#region src/await.tsx
13
- var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PURE__ */ z(ze, {
14
+ var R = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PURE__ */ I(He, {
14
15
  fallback: t,
15
- children: /* @__PURE__ */ z(Ke, {
16
+ children: /* @__PURE__ */ I(Ye, {
16
17
  errorFallback: r,
17
- children: /* @__PURE__ */ z(Ge, {
18
+ children: /* @__PURE__ */ I(Je, {
18
19
  value: e,
19
20
  errorFallback: r ?? null,
20
21
  children: n
21
22
  })
22
23
  })
23
- }), V = ({ body: e }) => /* @__PURE__ */ z("script", { dangerouslySetInnerHTML: { __html: e } }), Ge = ({ value: e, errorFallback: t, children: n }) => {
24
- let r = Be(e), i = le(e), a = oe(r);
25
- return a === void 0 ? /* @__PURE__ */ B(R, { children: [i === void 0 ? null : /* @__PURE__ */ z(V, { body: ae(i, r) }), n(r)] }) : /* @__PURE__ */ B(R, { children: [i === void 0 ? null : /* @__PURE__ */ z(V, { body: se(i, a) }), t] });
26
- }, Ke = class extends Re {
24
+ }), z = ({ body: e }) => /* @__PURE__ */ I("script", { dangerouslySetInnerHTML: { __html: e } }), Je = ({ value: e, errorFallback: t, children: n }) => {
25
+ let r = Ue(e), i = x(e), a = C(r);
26
+ return a === void 0 ? /* @__PURE__ */ L(F, { children: [i === void 0 ? null : /* @__PURE__ */ I(z, { body: S(i, r) }), n(r)] }) : /* @__PURE__ */ L(F, { children: [i === void 0 ? null : /* @__PURE__ */ I(z, { body: w(i, a) }), t] });
27
+ }, Ye = class extends Ve {
27
28
  state = { error: void 0 };
28
29
  static getDerivedStateFromError(e) {
29
30
  return { error: e };
@@ -31,7 +32,7 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
31
32
  render() {
32
33
  return this.state.error === void 0 ? this.props.children : this.props.errorFallback ?? null;
33
34
  }
34
- }, H = ({ src: e }) => e, U = e("imageConfig", { loader: H }), qe = ({ loader: e, children: t }) => L(U.Provider, { value: { loader: e } }, t), W = [
35
+ }, Xe = (e) => typeof e == "object" && !!e && typeof e.src == "string", B = ({ src: e }) => e, V = e("imageConfig", { loader: B }), Ze = ({ loader: e, children: t }) => P(V.Provider, { value: { loader: e } }, t), H = [
35
36
  640,
36
37
  750,
37
38
  828,
@@ -40,8 +41,8 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
40
41
  1920,
41
42
  2048,
42
43
  3840
43
- ], Je = (e, t, n, r) => {
44
- let i = n !== void 0 && !r ? Array.from(new Set(W.filter((e) => e <= n * 2).concat(n))).sort((e, t) => e - t) : [...W];
44
+ ], Qe = (e, t, n, r) => {
45
+ let i = n !== void 0 && !r ? Array.from(new Set(H.filter((e) => e <= n * 2).concat(n))).sort((e, t) => e - t) : [...H];
45
46
  return {
46
47
  srcSet: i.map((n) => `${e({
47
48
  src: t,
@@ -52,43 +53,153 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
52
53
  width: i[i.length - 1]
53
54
  })
54
55
  };
55
- }, Ye = ({ src: e, alt: t, width: n, height: r, fill: i = !1, sizes: a, priority: o = !1, loader: s, placeholder: c = "empty", blurDataURL: l, style: u, ...d }) => {
56
- let f = He(U).loader, p = s ?? f;
57
- !i && (n === void 0 || r === void 0) && typeof console < "u" && console.warn(`<Image src="${e}"> needs both width and height (or fill) to reserve layout space and avoid CLS.`);
58
- let { srcSet: m, fallback: h } = Je(p, e, n, i), g = c === "blur" && l ? {
59
- backgroundImage: `url(${l})`,
56
+ }, $e = ({ src: e, alt: t, width: n, height: r, fill: i = !1, sizes: a, priority: o = !1, loader: s, quality: c, placeholder: l, blurDataURL: u, style: d, ...f }) => {
57
+ let p = Ge(V).loader, m = s ?? p, h = c === void 0 ? m : (e) => m({
58
+ ...e,
59
+ quality: c
60
+ }), g = Xe(e) ? e : void 0, _ = g === void 0 ? e : g.src, v = n ?? (g !== void 0 && g.width > 0 ? g.width : void 0), y = r ?? (g !== void 0 && g.height > 0 ? g.height : void 0), b = u ?? (g !== void 0 && g.blurDataURL !== "" ? g.blurDataURL : void 0), x = l ?? (b !== void 0 && g !== void 0 ? "blur" : "empty");
61
+ !i && (v === void 0 || y === void 0) && typeof console < "u" && console.warn(`<Image src="${_}"> needs both width and height (or fill) to reserve layout space and avoid CLS.`);
62
+ let { srcSet: S, fallback: C } = g !== void 0 && g.srcSet !== "" ? {
63
+ srcSet: g.srcSet,
64
+ fallback: g.src
65
+ } : Qe(h, _, v, i), w = x === "blur" && b ? {
66
+ backgroundImage: `url(${b})`,
60
67
  backgroundSize: "cover",
61
68
  backgroundPosition: "center"
62
- } : {}, _ = i ? {
69
+ } : {}, T = i ? {
63
70
  position: "absolute",
64
71
  inset: 0,
65
72
  height: "100%",
66
73
  width: "100%",
67
74
  objectFit: "cover"
68
- } : {};
69
- return L("img", {
70
- src: h,
71
- srcSet: m,
75
+ } : {}, E = P("img", {
76
+ src: C,
77
+ srcSet: S === "" ? void 0 : S,
72
78
  sizes: a ?? (i ? "100vw" : void 0),
73
79
  alt: t,
74
80
  ...i ? {} : {
75
- width: n,
76
- height: r
81
+ width: v,
82
+ height: y
77
83
  },
78
84
  loading: o ? "eager" : "lazy",
79
85
  decoding: "async",
80
86
  ...o ? { fetchPriority: "high" } : {},
81
87
  style: {
82
- ...g,
83
- ..._,
84
- ...u
88
+ ...w,
89
+ ...T,
90
+ ...d
85
91
  },
86
- ...d
92
+ ...f
87
93
  });
88
- }, Xe = ({ to: e, children: t, className: n }) => L("a", {
94
+ return g !== void 0 && g.sources.length > 0 ? P("picture", null, ...g.sources.map((e) => P("source", {
95
+ key: e.type,
96
+ type: e.type,
97
+ srcSet: e.srcSet,
98
+ sizes: a ?? (i ? "100vw" : void 0)
99
+ })), E) : E;
100
+ }, et = Symbol.for("@voltro/web/script:registry"), U = () => {
101
+ let e = globalThis;
102
+ return e[et] ??= /* @__PURE__ */ new Map();
103
+ }, tt = () => {
104
+ U().clear();
105
+ }, W = (e, t, n) => {
106
+ e.status = t, e.error = n;
107
+ let r = e.listeners.splice(0);
108
+ for (let e of r) t === "loaded" ? e.onLoad?.() : e.onError?.(n);
109
+ }, G = (e, t) => {
110
+ let n = U(), r = n.get(t);
111
+ if (r !== void 0) {
112
+ if (r.status === "loaded" || r.status === "error") {
113
+ let t = !1;
114
+ return queueMicrotask(() => {
115
+ t || (r.status === "loaded" ? e.onLoad?.() : e.onError?.(r.error));
116
+ }), () => {
117
+ t = !0;
118
+ };
119
+ }
120
+ let t = {
121
+ onLoad: e.onLoad,
122
+ onError: e.onError
123
+ };
124
+ return r.listeners.push(t), () => {
125
+ let e = r.listeners.indexOf(t);
126
+ e !== -1 && r.listeners.splice(e, 1);
127
+ };
128
+ }
129
+ let i = {
130
+ status: "loading",
131
+ listeners: []
132
+ };
133
+ n.set(t, i);
134
+ let a = document.createElement("script"), o = e.nonce ?? document.querySelector("script[nonce]")?.nonce;
135
+ o !== void 0 && o !== "" && (a.nonce = o), e.id !== void 0 && (a.id = e.id);
136
+ for (let [t, n] of Object.entries(e.attributes ?? {})) a.setAttribute(t, n);
137
+ if (e.src !== void 0) {
138
+ a.addEventListener("load", () => {
139
+ W(i, "loaded");
140
+ }), a.addEventListener("error", (e) => {
141
+ W(i, "error", e);
142
+ });
143
+ let t = {
144
+ onLoad: e.onLoad,
145
+ onError: e.onError
146
+ };
147
+ return i.listeners.push(t), a.src = e.src, document.body.appendChild(a), () => {
148
+ let e = i.listeners.indexOf(t);
149
+ e !== -1 && i.listeners.splice(e, 1);
150
+ };
151
+ }
152
+ a.textContent = e.children ?? "";
153
+ try {
154
+ document.body.appendChild(a), W(i, "loaded"), e.onLoad?.();
155
+ } catch (t) {
156
+ W(i, "error", t), e.onError?.(t);
157
+ }
158
+ }, nt = (e) => {
159
+ let t = globalThis;
160
+ if (typeof t.requestIdleCallback == "function") {
161
+ let n = t.requestIdleCallback(e);
162
+ return () => t.cancelIdleCallback?.(n);
163
+ }
164
+ let n = setTimeout(e, 0);
165
+ return () => clearTimeout(n);
166
+ }, rt = ({ src: e, children: t, id: n, strategy: r = "afterInteractive", onLoad: i, onError: a, nonce: o, attributes: s }) => (Ke(() => {
167
+ if (e === void 0 && (t === void 0 || t === "")) {
168
+ console.warn("<Script> needs either src or inline children — rendered nothing.");
169
+ return;
170
+ }
171
+ if (e === void 0 && n === void 0) {
172
+ console.error("<Script> with inline children requires an `id` (the dedupe key). Script not injected.");
173
+ return;
174
+ }
175
+ let c = e ?? `inline:${n}`, l = {
176
+ ...e === void 0 ? {} : { src: e },
177
+ ...t === void 0 ? {} : { children: t },
178
+ ...n === void 0 ? {} : { id: n },
179
+ ...i ? { onLoad: i } : {},
180
+ ...a ? { onError: a } : {},
181
+ ...o === void 0 ? {} : { nonce: o },
182
+ ...s === void 0 ? {} : { attributes: s }
183
+ };
184
+ if (r === "lazyOnload") {
185
+ let e, t = nt(() => {
186
+ e = G(l, c);
187
+ });
188
+ return () => {
189
+ t(), e?.();
190
+ };
191
+ }
192
+ return G(l, c);
193
+ }, []), null), it = (e) => e.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""), at = (e) => {
194
+ let t = `--font-${it(e)}`;
195
+ return {
196
+ variable: t,
197
+ fontFamily: `var(${t})`
198
+ };
199
+ }, ot = ({ to: e, children: t, className: n }) => P("a", {
89
200
  href: e,
90
201
  className: n
91
- }, t), Ze = {
202
+ }, t), st = {
92
203
  position: "sticky",
93
204
  top: 0,
94
205
  zIndex: 10,
@@ -99,13 +210,13 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
99
210
  padding: "1rem 1.5rem",
100
211
  borderBottom: "1px solid var(--voltro-blog-border, rgba(127,127,127,0.2))",
101
212
  backdropFilter: "blur(8px)"
102
- }, Qe = {
213
+ }, ct = {
103
214
  maxWidth: "48rem",
104
215
  margin: "0 auto",
105
216
  padding: "2rem 1.5rem",
106
217
  width: "100%"
107
- }, $e = (e) => {
108
- let { brand: t, topNav: n, children: r, pathname: i, footer: a, breadcrumbs: o, headerRight: s } = e, c = e.Link ?? Xe, l = L("nav", {
218
+ }, lt = (e) => {
219
+ let { brand: t, topNav: n, children: r, pathname: i, footer: a, breadcrumbs: o, headerRight: s } = e, c = e.Link ?? ot, l = P("nav", {
109
220
  className: "voltro-blog-nav",
110
221
  style: {
111
222
  display: "flex",
@@ -114,20 +225,20 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
114
225
  }
115
226
  }, ...n.map((e) => {
116
227
  let t = i === e.href;
117
- return L(c, {
228
+ return P(c, {
118
229
  key: e.href,
119
230
  to: e.href,
120
231
  className: t ? "voltro-blog-nav-link is-active" : "voltro-blog-nav-link",
121
232
  children: e.label
122
233
  });
123
- })), u = L("header", {
234
+ })), u = P("header", {
124
235
  className: "voltro-blog-header",
125
- style: Ze
126
- }, L("div", { className: "voltro-blog-brand" }, t), s ? L("div", { style: {
236
+ style: st
237
+ }, P("div", { className: "voltro-blog-brand" }, t), s ? P("div", { style: {
127
238
  display: "flex",
128
239
  gap: "1rem",
129
240
  alignItems: "center"
130
- } }, l, s) : l), d = o && o.length > 0 ? L("nav", {
241
+ } }, l, s) : l), d = o && o.length > 0 ? P("nav", {
131
242
  className: "voltro-blog-breadcrumbs",
132
243
  "aria-label": "Breadcrumb",
133
244
  style: {
@@ -138,19 +249,19 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
138
249
  gap: "0.5rem"
139
250
  }
140
251
  }, ...o.flatMap((e, t) => {
141
- let n = t === o.length - 1, r = e.href && !n ? L(c, {
252
+ let n = t === o.length - 1, r = e.href && !n ? P(c, {
142
253
  key: `c${t}`,
143
254
  to: e.href,
144
255
  children: e.label
145
- }) : L("span", {
256
+ }) : P("span", {
146
257
  key: `c${t}`,
147
258
  "aria-current": n ? "page" : void 0
148
259
  }, e.label);
149
- return n ? [r] : [r, L("span", { key: `s${t}` }, "/")];
150
- })) : null, f = L("main", {
260
+ return n ? [r] : [r, P("span", { key: `s${t}` }, "/")];
261
+ })) : null, f = P("main", {
151
262
  className: "voltro-blog-main",
152
- style: Qe
153
- }, d, r), p = a ? L("footer", {
263
+ style: ct
264
+ }, d, r), p = a ? P("footer", {
154
265
  className: "voltro-blog-footer",
155
266
  style: {
156
267
  maxWidth: "48rem",
@@ -159,32 +270,32 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
159
270
  borderTop: "1px solid var(--voltro-blog-border, rgba(127,127,127,0.2))"
160
271
  }
161
272
  }, a) : null;
162
- return L("div", { className: "voltro-blog-layout" }, u, f, p);
163
- }, G = (e) => {
273
+ return P("div", { className: "voltro-blog-layout" }, u, f, p);
274
+ }, K = (e) => {
164
275
  if (e === "" || e === "/") return "/";
165
276
  let t = e.startsWith("/") ? e : `/${e}`;
166
277
  return t.endsWith("/") ? t.slice(0, -1) : t;
167
- }, K = (e, t) => {
168
- let n = e.endsWith("/") ? e.slice(0, -1) : e, r = G(t);
278
+ }, q = (e, t) => {
279
+ let n = e.endsWith("/") ? e.slice(0, -1) : e, r = K(t);
169
280
  return r === "/" ? `${n}/` : `${n}${r}`;
170
- }, q = (e, t, n) => {
171
- let r = G(e);
281
+ }, J = (e, t, n) => {
282
+ let r = K(e);
172
283
  return t === n ? r : r === "/" ? `/${t}` : `/${t}${r}`;
173
- }, J = (e, t) => K(e, t), et = (e) => {
174
- let { siteUrl: t, path: n, locale: r, locales: i, defaultLocale: a, xDefault: o = !0 } = e, s = K(t, q(n, r, a)), c = i.map((e) => ({
284
+ }, ut = (e, t) => q(e, t), dt = (e) => {
285
+ let { siteUrl: t, path: n, locale: r, locales: i, defaultLocale: a, xDefault: o = !0 } = e, s = q(t, J(n, r, a)), c = i.map((e) => ({
175
286
  rel: "alternate",
176
287
  hreflang: e,
177
- href: K(t, q(n, e, a))
288
+ href: q(t, J(n, e, a))
178
289
  }));
179
290
  return o && c.push({
180
291
  rel: "alternate",
181
292
  hreflang: "x-default",
182
- href: K(t, q(n, a, a))
293
+ href: q(t, J(n, a, a))
183
294
  }), {
184
295
  canonical: s,
185
296
  links: c
186
297
  };
187
- }, Y = "voltro:theme", tt = 31536e3, nt = () => {
298
+ }, Y = "voltro:theme", ft = 31536e3, pt = () => {
188
299
  if (typeof document > "u") return "system";
189
300
  try {
190
301
  let e = document.cookie.match(/(?:^|;\s*)voltro:theme=([^;]*)/), t = e?.[1] === void 0 ? "" : decodeURIComponent(e[1]);
@@ -192,17 +303,17 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
192
303
  } catch {
193
304
  return "system";
194
305
  }
195
- }, rt = () => {
306
+ }, mt = () => {
196
307
  if (typeof window > "u" || !window.matchMedia) return !1;
197
308
  try {
198
309
  return window.matchMedia("(prefers-color-scheme: dark)").matches;
199
310
  } catch {
200
311
  return !1;
201
312
  }
202
- }, X = (e) => e === "system" ? rt() ? "dark" : "light" : e, Z = 0, Q = /* @__PURE__ */ new Set(), $ = () => {
313
+ }, X = (e) => e === "system" ? mt() ? "dark" : "light" : e, Z = 0, Q = /* @__PURE__ */ new Set(), $ = () => {
203
314
  Z++;
204
315
  for (let e of Q) e();
205
- }, it = (e) => {
316
+ }, ht = (e) => {
206
317
  Q.add(e);
207
318
  let t, n = () => $();
208
319
  if (typeof window < "u" && window.matchMedia) try {
@@ -214,21 +325,21 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
214
325
  t?.removeEventListener("change", n);
215
326
  } catch {}
216
327
  };
217
- }, at = () => {
218
- let e = nt();
328
+ }, gt = () => {
329
+ let e = pt();
219
330
  return `${Z}:${e}:${X(e)}`;
220
- }, ot = () => "0:system:light", st = () => {
221
- let [, e, t] = Ue(it, at, ot).split(":");
331
+ }, _t = () => "0:system:light", vt = () => {
332
+ let [, e, t] = qe(ht, gt, _t).split(":");
222
333
  return {
223
334
  theme: e,
224
335
  resolvedTheme: t,
225
- setTheme: Ve((e) => {
336
+ setTheme: We((e) => {
226
337
  if (typeof document < "u") try {
227
- document.cookie = e === "system" ? `${Y}=; path=/; max-age=0; SameSite=Lax` : `${Y}=${e}; path=/; max-age=${tt}; SameSite=Lax`, document.documentElement.classList.toggle("dark", X(e) === "dark");
338
+ document.cookie = e === "system" ? `${Y}=; path=/; max-age=0; SameSite=Lax` : `${Y}=${e}; path=/; max-age=${ft}; SameSite=Lax`, document.documentElement.classList.toggle("dark", X(e) === "dark");
228
339
  } catch {}
229
340
  $();
230
341
  }, [])
231
342
  };
232
- }, ct = "framework-web";
343
+ }, yt = "framework-web";
233
344
  //#endregion
234
- export { t as AppClientsContext, We as Await, $e as BlogLayout, p as FallbackStringsProvider, Ye as Image, qe as ImageConfigProvider, Ee as Link, Ae as LoaderCache, P as LoaderDataContext, Ce as NO_LOADER_DATA, i as NavigationIndicator, Le as NotFoundError, Me as PAGE_SLOT_ATTR, F as PageSlot, I as PlainLink, De as RENDER_MODES, o as ReconnectContext, de as RedirectError, we as Router, ye as RouterContext, je as ServerRequestContext, Te as ServerRequestProvider, Y as THEME_COOKIE, ct as WEB_NAME, J as canonicalUrl, ve as compileRoute, d as defaultFallbackStrings, ie as defer, j as externalUrl, Ne as findNotFound, c as formatPrintf, ne as getIslandComponent, ge as getRouteSnapshot, f as getStatuses, ee as hydrateIslandsOnPage, a as installBrowserConsoleBridge, r as installServerLogRelay, ce as isDeferredLoaderResult, k as isNotFound, _e as isRedirect, _ as island, K as joinUrl, Ie as lazyPageRoute, N as loaderCacheKey, q as localizedPath, Fe as matchRoute, re as mount, G as normalizePath, O as notFound, te as noticeIslandsShipTheFullBundle, E as pageRoute, ke as parseCookieHeader, H as passthroughImageLoader, fe as preloadRouteModule, m as pushStatus, A as redirect, s as registerClientTrace, Pe as renderRouterProviderTree, D as resolveAnchorNavigation, me as resolveMeta, pe as segmentLoaderKey, et as seoAlternates, y as setRouteSnapshot, C as sortRoutesByPriority, Oe as subscribeRouteSnapshot, g as subscribeStatuses, l as subscribeTraceErrors, n as useAppClient, Se as useBlocker, h as useFallbackStrings, ue as useLoaderData, xe as useLocation, x as useNavigate, S as useOptionalLoaderData, w as useParams, he as usePrefetch, u as useReconnect, be as useSearchParams, M as useServerRequest, v as useSetSearchParams, st as useTheme, b as withHash, T as withQuery };
345
+ export { t as AppClientsContext, R as Await, lt as BlogLayout, p as FallbackStringsProvider, $e as Image, Ze as ImageConfigProvider, Me as Link, Ce as LoaderCache, k as LoaderDataContext, ke as NO_LOADER_DATA, i as NavigationIndicator, Be as NotFoundError, Ne as PAGE_SLOT_ATTR, j as PageSlot, Ee as PlainLink, Fe as RENDER_MODES, o as ReconnectContext, ne as RedirectError, M as Router, N as RouterContext, rt as Script, Y as THEME_COOKIE, yt as WEB_NAME, ut as canonicalUrl, Ae as compileRoute, le as decodeSearchParams, d as defaultFallbackStrings, b as defer, de as encodeSearchParams, De as externalUrl, Se as findNotFound, c as formatPrintf, _ as getIslandComponent, se as getRouteSnapshot, f as getStatuses, v as hydrateIslandsOnPage, a as installBrowserConsoleBridge, r as installServerLogRelay, T as isDeferredLoaderResult, be as isNotFound, ce as isRedirect, y as island, q as joinUrl, xe as lazyPageRoute, O as loaderCacheKey, at as localFont, J as localizedPath, Ie as matchRoute, E as mount, K as normalizePath, ye as notFound, ee as noticeIslandsShipTheFullBundle, ze as pageRoute, Pe as parseCookieHeader, B as passthroughImageLoader, A as preloadRouteModule, m as pushStatus, D as redirect, s as registerClientTrace, Re as renderRouterProviderTree, tt as resetScriptRegistryForTest, _e as resolveAnchorNavigation, re as resolveMeta, ge as searchParamsToObject, Le as segmentLoaderKey, dt as seoAlternates, ue as setRouteSnapshot, ve as sortRoutesByPriority, je as subscribeRouteSnapshot, g as subscribeStatuses, l as subscribeTraceErrors, n as useAppClient, ae as useBlocker, h as useFallbackStrings, ie as useLoaderData, me as useLocation, Te as useNavigate, te as useOptionalLoaderData, we as useParams, fe as usePrefetch, u as useReconnect, Oe as useSearchParams, pe as useSetSearchParams, vt as useTheme, he as withHash, oe as withQuery };
@@ -0,0 +1,66 @@
1
+ import { ComponentType } from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * Look up a registered island Component by name. Returns undefined if
6
+ * the name isn't registered (typically means the user forgot to import
7
+ * the island file in this bundle).
8
+ */
9
+ export declare const getIslandComponent: (name: string) => ComponentType<unknown> | undefined;
10
+
11
+ /**
12
+ * Client-side runtime: scan the document for `[data-voltro-island]`
13
+ * markers and schedule each for hydration per its strategy. Called by the
14
+ * per-page islands entry, and by `@voltro/web/mount` when an islands page
15
+ * is reached through the full app bundle (SPA navigation). Idempotent —
16
+ * running twice is a no-op (we mark elements as visited).
17
+ */
18
+ export declare const hydrateIslandsOnPage: (options?: HydrateIslandsOptions) => void;
19
+
20
+ export declare interface HydrateIslandsOptions {
21
+ /** Wrap every island root — the per-page islands entry of a page whose
22
+ * islands use framework hooks passes a `<VoltroRuntimeProvider>` here so
23
+ * a `useSubscription` island gets a live runtime. Purely presentational
24
+ * entries pass nothing and never load the client core. */
25
+ readonly wrap?: (children: ReactNode) => ReactNode;
26
+ }
27
+
28
+ export declare type HydrateStrategy =
29
+ /** Hydrate as soon as the client runtime mounts (after main script load). */
30
+ 'load'
31
+ /** Hydrate when the browser is idle (via `requestIdleCallback`, with a
32
+ * setTimeout fallback for browsers that lack it). */
33
+ | 'idle'
34
+ /** Hydrate when the element scrolls into the viewport (IntersectionObserver). */
35
+ | 'visible'
36
+ /** Hydrate on the first pointer / keyboard interaction with the element. */
37
+ | 'interaction'
38
+ /** Never hydrate. Useful for fully-static islands (e.g. SSR-only data
39
+ * display that never changes). */
40
+ | 'never'
41
+ /** CLIENT-ONLY: the server renders an empty placeholder (never the
42
+ * component — a browser-only lib touching `window` in render would
43
+ * crash the SSR pass), and the client mounts fresh with `createRoot`
44
+ * instead of hydrating. Astro's `client:only`. */
45
+ | 'only';
46
+
47
+ /**
48
+ * Wrap a Component as an island. The returned Component renders the
49
+ * inner content wrapped in a marker `<div data-voltro-island>` that
50
+ * carries the island's name + props + hydrate strategy. The same
51
+ * call also registers the Component under its name so the client
52
+ * runtime can find it when hydrating.
53
+ */
54
+ export declare const island: <P extends Record<string, unknown>>(Component: ComponentType<P>, options: IslandOptions) => ComponentType<P>;
55
+
56
+ export declare interface IslandOptions {
57
+ /** Stable id of this island. Must be unique within an app. The framework
58
+ * uses it to match the server-rendered marker with the client-side
59
+ * Component. */
60
+ readonly name: string;
61
+ /** When the client runtime should hydrate this island. Defaults to
62
+ * `visible` — matches Astro's default and is the best perf/UX balance. */
63
+ readonly hydrate?: HydrateStrategy;
64
+ }
65
+
66
+ export { }
@@ -0,0 +1,60 @@
1
+ import { createElement as e } from "react";
2
+ import { createRoot as t, hydrateRoot as n } from "react-dom/client";
3
+ //#region src/islands.tsx
4
+ var r = /* @__PURE__ */ new Map(), i = (t, n) => {
5
+ r.set(n.name, t);
6
+ let i = n.hydrate ?? "visible", a = (r) => e("div", {
7
+ "data-voltro-island": "",
8
+ "data-island-name": n.name,
9
+ "data-island-hydrate": i,
10
+ "data-island-props": o(r, n.name)
11
+ }, i === "only" ? null : e(t, r));
12
+ return a.displayName = `Island(${n.name})`, a;
13
+ }, a = (e) => r.get(e), o = (e, t) => {
14
+ if (process.env.NODE_ENV !== "production" && typeof e == "object" && e) for (let [n, r] of Object.entries(e)) {
15
+ let e = typeof r == "function" ? "a function" : r instanceof Date ? "a Date (arrives as an ISO string)" : r instanceof Map || r instanceof Set ? "a Map/Set (arrives as {})" : void 0;
16
+ e !== void 0 && console.warn(`[voltro] island "${t}" prop "${n}" is ${e} — island props cross an HTML attribute as JSON. Pass a JSON shape (string/number/boolean/array/plain object) and reconstruct richer types inside the island.`);
17
+ }
18
+ return JSON.stringify(e ?? {}).replace(/</g, "\\u003c");
19
+ }, s = (e) => {
20
+ if (!e) return {};
21
+ try {
22
+ return JSON.parse(e);
23
+ } catch {
24
+ return {};
25
+ }
26
+ }, c = (i) => {
27
+ let a = document.querySelectorAll("[data-voltro-island]:not([data-voltro-hydrated])");
28
+ for (let o of a) {
29
+ let a = o.dataset.islandName ?? "", c = r.get(a);
30
+ if (!c) {
31
+ console.warn(`[voltro] island "${a}" referenced in DOM but not registered. Did the island file get imported in this bundle?`);
32
+ continue;
33
+ }
34
+ let l = s(o.dataset.islandProps ?? null), u = o.dataset.islandHydrate ?? "visible";
35
+ o.setAttribute("data-voltro-hydrated", "pending");
36
+ let d = () => {
37
+ if (o.getAttribute("data-voltro-hydrated") === "done") return;
38
+ o.setAttribute("data-voltro-hydrated", "done");
39
+ let r = i?.wrap === void 0 ? e(c, l) : i.wrap(e(c, l));
40
+ u === "only" ? t(o).render(r) : n(o, r);
41
+ };
42
+ if (u === "load" || u === "only") d();
43
+ else if (u === "idle") {
44
+ let e = globalThis.requestIdleCallback;
45
+ e ? e(d) : setTimeout(d, 0);
46
+ } else if (u === "visible") {
47
+ let e = new IntersectionObserver((t) => {
48
+ t.some((e) => e.isIntersecting) && (e.disconnect(), d());
49
+ }, { rootMargin: "64px" });
50
+ e.observe(o);
51
+ } else if (u === "interaction") {
52
+ let e = () => {
53
+ o.removeEventListener("pointerdown", e), o.removeEventListener("keydown", e), d();
54
+ };
55
+ o.addEventListener("pointerdown", e, { passive: !0 }), o.addEventListener("keydown", e);
56
+ }
57
+ }
58
+ };
59
+ //#endregion
60
+ export { a as getIslandComponent, c as hydrateIslandsOnPage, i as island };
package/dist/mount.js CHANGED
@@ -1,2 +1,37 @@
1
- import { n as e, t } from "./mount-nudb4UCl.js";
2
- export { t as mount, e as noticeIslandsShipTheFullBundle };
1
+ import { t as e } from "./frameworkBoot-CnE9vzLQ.js";
2
+ import { hydrateIslandsOnPage as t } from "./islands.js";
3
+ import { o as n, r, t as i } from "./routerState-Cr6fTbka.js";
4
+ import { StrictMode as a } from "react";
5
+ import { createRoot as o, hydrateRoot as s } from "react-dom/client";
6
+ import { applyPreloadSeeds as c, applyStoreSeeds as l } from "@voltro/client";
7
+ import { jsx as u } from "react/jsx-runtime";
8
+ //#region src/mount.tsx
9
+ var d = () => !1, f = "__voltroIslandsBundleNoticeShown", p = (e) => {
10
+ if (!e) return;
11
+ let t = globalThis;
12
+ t[f] !== !0 && (t[f] = !0, console.info("[voltro] islands mode: hydration is scoped to this page's islands, but the JS payload is NOT reduced — the full app bundle is still downloaded and evaluated. Islands buy CPU, not bytes, today. See the \"Render modes\" docs page."));
13
+ }, m = (e) => `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}/ws/${e}`, h = (f, h) => {
14
+ let g = document.getElementById(h.rootId ?? "root");
15
+ if (!g) throw Error(`@voltro/web: no #${h.rootId ?? "root"} element in the document`);
16
+ let _ = Object.entries(h.apis).map(([e, t]) => ({
17
+ name: e,
18
+ group: t.group,
19
+ descriptors: t.descriptors ?? {},
20
+ wsUrl: t.wsUrl ?? m(e),
21
+ headers: t.headers
22
+ })), v = document.getElementById(i), y = r(v?.textContent, window.location.pathname), b = y !== null && g.children.length > 0, x = document.querySelector("meta[name=\"voltro-interactive\"]")?.getAttribute("content") ?? "full";
23
+ if (x === "none") return;
24
+ if (x === "islands") {
25
+ p(d()), t();
26
+ return;
27
+ }
28
+ b && n(y), l(y?.storeSeeds), c(y?.preloadSeeds);
29
+ let S = /* @__PURE__ */ u(a, { children: /* @__PURE__ */ u(e, {
30
+ App: f,
31
+ apis: _,
32
+ ...h.Devtools ? { Devtools: h.Devtools } : {}
33
+ }) });
34
+ b ? s(g, S) : o(g).render(S);
35
+ };
36
+ //#endregion
37
+ export { h as mount, p as noticeIslandsShipTheFullBundle };
@@ -55,7 +55,9 @@ var e = /* @__PURE__ */ RegExp("\\u2028", "g"), t = /* @__PURE__ */ RegExp("\\u2
55
55
  }, x = (e) => {
56
56
  let { page: t, renderMode: n, interactive: r, layoutShell: i } = e;
57
57
  if (i === "artefact") throw Error(`[voltro] a layout in "${t}"'s chain uses defer() in its loader, but this page's SSR layout shell is PRERENDERED at build time into a static HTML file. defer() streams values in AFTER the shell, and a file has no "after" — the <Await> fallback would be frozen into the artefact forever. Drop defer() from the layout loader and return the values directly (the shell then prerenders as before), or give the layout per-request data so the page is served on demand.`);
58
- if (!(n === "ssr" || n === "spa" && i === "stream")) throw Error(`[voltro] "${t}" uses defer() in its loader but has renderMode: '${n}'. defer() streams values in AFTER the shell, which only a per-request response can do — '${n}' produces a stored HTML artefact with no "after". Set \`export const renderMode = 'ssr'\` on this page, or drop defer() and return the values directly.`);
58
+ let a = e.ppr === !0 && n === "isr";
59
+ if (e.ppr === !0 && n !== "isr") throw Error(`[voltro] "${t}" exports ppr = true with renderMode: '${n}'. Partial prerendering caches a SHELL and appends per-request holes, which needs the isr serve path — a '${n}' ${n === "static" ? "file is served by any static host with no way to append holes" : "page already streams per request, ppr adds nothing"}. ` + (n === "static" ? "Set `export const renderMode = 'isr'` (a long revalidate gives the same cache behaviour)." : "Drop the ppr export."));
60
+ if (!(n === "ssr" || n === "spa" && i === "stream") && !a) throw Error(`[voltro] "${t}" uses defer() in its loader but has renderMode: '${n}'. defer() streams values in AFTER the shell, which only a per-request response can do — '${n}' produces a stored HTML artefact with no "after". Set \`export const renderMode = 'ssr'\` on this page, add \`export const ppr = true\` to an isr page (partial prerendering: cached shell + per-request holes), or drop defer() and return the values directly.`);
59
61
  if (r !== "full") throw Error(`[voltro] "${t}" uses defer() in its loader but has interactive: '${r}'. ` + (r === "none" ? "Revealing a streamed <Suspense> boundary requires React's inline reveal scripts, and interactive: 'none' ships no JS at all — the <Await> fallback would be permanent. " : "interactive: 'islands' never hydrates the page's React root, so nothing consumes the streamed values and the <Await> fallback would be permanent. ") + "Remove the `interactive` export (defaults to 'full'), or drop defer() and return the values directly.");
60
62
  }, S = "__voltro_state__", C = (e) => {
61
63
  let t = Object.keys(e.segmentLoaderData ?? {}).map((e) => Number(e)).filter((e) => Number.isInteger(e)).sort((e, t) => e - t), n = e.deferredPageIds !== void 0, r = e.deferredSegmentIds !== void 0 && Object.keys(e.deferredSegmentIds).length > 0;
@@ -112,4 +114,4 @@ var e = /* @__PURE__ */ RegExp("\\u2028", "g"), t = /* @__PURE__ */ RegExp("\\u2
112
114
  k = e;
113
115
  }, j = () => k;
114
116
  //#endregion
115
- export { n as _, w as a, i as c, m as d, o as f, p as g, y as h, j as i, h as l, b as m, C as n, A as o, a as p, D as r, x as s, S as t, l as u };
117
+ export { p as _, w as a, i as c, l as d, m as f, y as g, b as h, j as i, h as l, a as m, C as n, A as o, o as p, D as r, x as s, S as t, u, n as v };