@voltro/web 0.50.1 → 0.52.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,10 +1,11 @@
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";
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 ee, island as te } from "./islands.js";
6
+ import { c as ne, d as re, h as ie, l as ae, p as oe, u as se } from "./routerState-DAT472IC.js";
7
+ import { mount as ce, noticeIslandsShipTheFullBundle as le } from "./mount.js";
8
+ 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-CzmZZwuQ.js";
8
9
  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
10
  import { Fragment as R, jsx as z, jsxs as B } from "react/jsx-runtime";
10
11
  export * from "@voltro/client";
@@ -21,8 +22,8 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
21
22
  })
22
23
  })
23
24
  }), 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] });
25
+ let r = Be(e), i = se(e), a = ie(r);
26
+ return a === void 0 ? /* @__PURE__ */ B(R, { children: [i === void 0 ? null : /* @__PURE__ */ z(V, { body: re(i, r) }), n(r)] }) : /* @__PURE__ */ B(R, { children: [i === void 0 ? null : /* @__PURE__ */ z(V, { body: ae(i, a) }), t] });
26
27
  }, Ke = class extends Re {
27
28
  state = { error: void 0 };
28
29
  static getDerivedStateFromError(e) {
@@ -231,4 +232,4 @@ var We = ({ value: e, fallback: t, children: n, errorFallback: r }) => /* @__PUR
231
232
  };
232
233
  }, ct = "framework-web";
233
234
  //#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 };
235
+ export { t as AppClientsContext, We as Await, $e as BlogLayout, p as FallbackStringsProvider, Ye as Image, qe as ImageConfigProvider, ke as Link, be as LoaderCache, M as LoaderDataContext, Ee as NO_LOADER_DATA, i as NavigationIndicator, Le as NotFoundError, Ae as PAGE_SLOT_ATTR, P as PageSlot, Ce as PlainLink, Me as RENDER_MODES, o as ReconnectContext, de as RedirectError, F as Router, I as RouterContext, Y as THEME_COOKIE, ct as WEB_NAME, J as canonicalUrl, De as compileRoute, v as decodeSearchParams, d as defaultFallbackStrings, ne as defer, b as encodeSearchParams, we as externalUrl, ye as findNotFound, c as formatPrintf, _ as getIslandComponent, ge as getRouteSnapshot, f as getStatuses, ee as hydrateIslandsOnPage, a as installBrowserConsoleBridge, r as installServerLogRelay, oe as isDeferredLoaderResult, k as isNotFound, _e as isRedirect, te as island, K as joinUrl, ve as lazyPageRoute, j as loaderCacheKey, q as localizedPath, Ne as matchRoute, ce as mount, G as normalizePath, O as notFound, le as noticeIslandsShipTheFullBundle, Ie as pageRoute, je as parseCookieHeader, H as passthroughImageLoader, N as preloadRouteModule, m as pushStatus, A as redirect, s as registerClientTrace, Fe as renderRouterProviderTree, E as resolveAnchorNavigation, fe as resolveMeta, T as searchParamsToObject, Pe as segmentLoaderKey, et as seoAlternates, y as setRouteSnapshot, D as sortRoutesByPriority, Oe as subscribeRouteSnapshot, g as subscribeStatuses, l as subscribeTraceErrors, n as useAppClient, me as useBlocker, h as useFallbackStrings, pe as useLoaderData, C as useLocation, Se as useNavigate, ue as useOptionalLoaderData, xe as useParams, x as usePrefetch, u as useReconnect, Te as useSearchParams, S as useSetSearchParams, st as useTheme, w as withHash, he 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-DAT472IC.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 };