@takazudo/zfb 2.22.1 → 3.0.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/README.md +5 -9
- package/dist/config.d.ts +62 -19
- package/dist/config.js +27 -6
- package/dist/config.js.map +1 -1
- package/dist/content.d.ts +8 -22
- package/dist/content.js +6 -28
- package/dist/content.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/island-boundary.d.ts +4 -0
- package/dist/island-boundary.js +42 -0
- package/dist/island-boundary.js.map +1 -0
- package/dist/island.d.ts +2 -118
- package/dist/island.js +4 -284
- package/dist/island.js.map +1 -1
- package/dist/jsx-types.d.ts +2 -38
- package/dist/jsx-types.js +3 -10
- package/dist/jsx-types.js.map +1 -1
- package/dist/plugins.d.ts +40 -0
- package/dist/plugins.js.map +1 -1
- package/dist/runtime.d.ts +23 -77
- package/dist/runtime.js +149 -320
- package/dist/runtime.js.map +1 -1
- package/dist/zudo-react/client.d.ts +3 -0
- package/dist/zudo-react/client.js +3 -0
- package/dist/zudo-react/client.js.map +1 -0
- package/dist/zudo-react/description.d.ts +16 -0
- package/dist/zudo-react/description.js +64 -0
- package/dist/zudo-react/description.js.map +1 -0
- package/dist/zudo-react/dom-bindings.d.ts +13 -0
- package/dist/zudo-react/dom-bindings.js +58 -0
- package/dist/zudo-react/dom-bindings.js.map +1 -0
- package/dist/zudo-react/escape.d.ts +2 -0
- package/dist/zudo-react/escape.js +7 -0
- package/dist/zudo-react/escape.js.map +1 -0
- package/dist/zudo-react/forms.d.ts +29 -0
- package/dist/zudo-react/forms.js +371 -0
- package/dist/zudo-react/forms.js.map +1 -0
- package/dist/zudo-react/hydrate.d.ts +4 -0
- package/dist/zudo-react/hydrate.js +909 -0
- package/dist/zudo-react/hydrate.js.map +1 -0
- package/dist/zudo-react/index.d.ts +47 -0
- package/dist/zudo-react/index.js +13 -0
- package/dist/zudo-react/index.js.map +1 -0
- package/dist/zudo-react/island-root-type.d.ts +1 -0
- package/dist/zudo-react/island-root-type.js +2 -0
- package/dist/zudo-react/island-root-type.js.map +1 -0
- package/dist/zudo-react/jsx-dev-runtime.d.ts +8 -0
- package/dist/zudo-react/jsx-dev-runtime.js +6 -0
- package/dist/zudo-react/jsx-dev-runtime.js.map +1 -0
- package/dist/zudo-react/jsx-runtime.d.ts +5 -0
- package/dist/zudo-react/jsx-runtime.js +7 -0
- package/dist/zudo-react/jsx-runtime.js.map +1 -0
- package/dist/zudo-react/jsx-types.d.ts +203 -0
- package/dist/zudo-react/jsx-types.js +2 -0
- package/dist/zudo-react/jsx-types.js.map +1 -0
- package/dist/zudo-react/props-transport.d.ts +2 -0
- package/dist/zudo-react/props-transport.js +95 -0
- package/dist/zudo-react/props-transport.js.map +1 -0
- package/dist/zudo-react/reactive-types.d.ts +8 -0
- package/dist/zudo-react/reactive-types.js +2 -0
- package/dist/zudo-react/reactive-types.js.map +1 -0
- package/dist/zudo-react/reactive.d.ts +20 -0
- package/dist/zudo-react/reactive.js +176 -0
- package/dist/zudo-react/reactive.js.map +1 -0
- package/dist/zudo-react/render-html.d.ts +3 -0
- package/dist/zudo-react/render-html.js +537 -0
- package/dist/zudo-react/render-html.js.map +1 -0
- package/dist/zudo-react/root.d.ts +20 -0
- package/dist/zudo-react/root.js +74 -0
- package/dist/zudo-react/root.js.map +1 -0
- package/dist/zudo-react/scheduler.d.ts +12 -0
- package/dist/zudo-react/scheduler.js +113 -0
- package/dist/zudo-react/scheduler.js.map +1 -0
- package/dist/zudo-react/scope.d.ts +42 -0
- package/dist/zudo-react/scope.js +220 -0
- package/dist/zudo-react/scope.js.map +1 -0
- package/dist/zudo-react/server.d.ts +15 -0
- package/dist/zudo-react/server.js +11 -0
- package/dist/zudo-react/server.js.map +1 -0
- package/dist/zudo-react/structure.d.ts +14 -0
- package/dist/zudo-react/structure.js +35 -0
- package/dist/zudo-react/structure.js.map +1 -0
- package/package.json +28 -24
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["// Hydration scheduling helper consumed by the hydration runtime (Sub 3).\n//\n// Sub 3 owns the hydration runtime that walks the DOM, finds elements\n// marked with `data-zfb-island`, and dispatches each one through this\n// helper to decide *when* to fire the actual hydrate() call. The helper\n// itself does not know how to hydrate — it only schedules the supplied\n// `fire` callback.\n//\n// The branching matches the `When` union exactly:\n// \"visible\" → IntersectionObserver, threshold 0.0, hydrate on first\n// intersection, then disconnect.\n// \"idle\" → requestIdleCallback if available, otherwise setTimeout(0).\n// \"media\" → matchMedia(target's data-media), hydrate when the query\n// first matches (now or on a later change event), then\n// remove the listener.\n// \"load\" → immediate, synchronous fire.\n//\n// Anything else is treated as \"load\" (with a console.warn in development).\n// The helper is environment-tolerant: callers can run it in jsdom /\n// happy-dom or bare Node, and the absence of `IntersectionObserver` /\n// `requestIdleCallback` / `matchMedia` is handled gracefully.\n\nimport { resolveWhen, type When } from \"./types.js\";\n\n/**\n * Subset of the global object that this module touches. Cast once at the\n * module top so individual scheduler functions don't repeat the inline\n * widening.\n */\ntype SchedulerGlobal = typeof globalThis & {\n requestIdleCallback?: (\n cb: (deadline: { didTimeout: boolean; timeRemaining: () => number }) => void,\n options?: { timeout?: number },\n ) => number;\n cancelIdleCallback?: (handle: number) => void;\n IntersectionObserver?: typeof IntersectionObserver;\n matchMedia?: typeof matchMedia;\n};\n\nconst g = globalThis as SchedulerGlobal;\n\n/**\n * Internal variant of `scheduleHydrate` that also reports whether the fire\n * callback was invoked synchronously. Unexported — call sites in this module\n * use this to decide whether to register a `pendingCancels` entry.\n */\nfunction scheduleHydrateInternal(\n target: Element,\n when: When | string | undefined,\n fire: () => void,\n): { fired: boolean; cancel: () => void } {\n const resolved = resolveWhen(when);\n\n if (resolved === \"load\") {\n fire();\n return { fired: true, cancel: noop };\n }\n\n if (resolved === \"idle\") {\n return { fired: false, cancel: scheduleIdle(fire) };\n }\n\n if (resolved === \"media\") {\n return scheduleMedia(target, fire);\n }\n\n // \"visible\"\n return scheduleVisible(target, fire);\n}\n\n/**\n * Schedule a hydration `fire` callback for `target` according to `when`.\n *\n * Returns a `cancel` function that aborts the scheduling if it has not\n * fired yet. After firing, calling `cancel` is a no-op. If the helper\n * cannot find the relevant browser API (e.g. running in pure Node with no\n * polyfill), it falls back to firing synchronously so server-side smoke\n * tests still observe the call.\n */\nexport function scheduleHydrate(\n target: Element,\n when: When | string | undefined,\n fire: () => void,\n): () => void {\n return scheduleHydrateInternal(target, when, fire).cancel;\n}\n\nfunction noop(): void {\n // intentionally empty\n}\n\n/**\n * Build a one-shot gate around `fn`. The returned `run` invokes `fn`\n * exactly once provided `cancel` has not been called first; `cancel`\n * marks the gate as cancelled (later `run` invocations become no-ops)\n * and reports whether the gate had already fired.\n */\nfunction oneShot(fn: () => void): {\n run: () => void;\n cancel: () => boolean;\n} {\n let fired = false;\n let cancelled = false;\n return {\n run(): void {\n if (cancelled || fired) return;\n fired = true;\n fn();\n },\n cancel(): boolean {\n if (fired) return true;\n cancelled = true;\n return false;\n },\n };\n}\n\nfunction scheduleIdle(fire: () => void): () => void {\n const gate = oneShot(fire);\n\n if (typeof g.requestIdleCallback === \"function\") {\n const handle = g.requestIdleCallback(gate.run);\n return () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n if (typeof g.cancelIdleCallback === \"function\") g.cancelIdleCallback(handle);\n };\n }\n\n const handle = setTimeout(gate.run, 0);\n return () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n clearTimeout(handle);\n };\n}\n\nfunction scheduleVisible(\n target: Element,\n fire: () => void,\n): { fired: boolean; cancel: () => void } {\n const Observer = g.IntersectionObserver;\n\n // No IntersectionObserver (e.g. very old browsers, bare Node) — fail\n // open and hydrate immediately so the island is at least functional.\n if (typeof Observer !== \"function\") {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const gate = oneShot(fire);\n const observer = new Observer(\n (entries, obs) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n obs.disconnect();\n gate.run();\n return;\n }\n }\n },\n { threshold: 0 },\n );\n\n observer.observe(target);\n\n return {\n fired: false,\n cancel: () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n observer.disconnect();\n },\n };\n}\n\nfunction scheduleMedia(target: Element, fire: () => void): { fired: boolean; cancel: () => void } {\n const query = target.getAttribute(\"data-media\");\n\n // No matchMedia API (e.g. bare Node, very old browser) or missing/empty\n // query — fail open and hydrate immediately so the island is at least\n // functional.\n if (typeof g.matchMedia !== \"function\" || !query) {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const mql = g.matchMedia(query);\n\n // Already matches — fire synchronously (no pending listener needed).\n if (mql.matches) {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const gate = oneShot(fire);\n\n let removeListener = noop;\n\n // Listen for the first change event where the query matches.\n // We do NOT use `{once:true}` because we must ignore un-match events\n // (e.g. viewport widens back above breakpoint) and only fire on the\n // first match event — `{once:true}` would consume any change, including\n // un-match changes.\n const handler = (e: MediaQueryListEvent): void => {\n if (!e.matches) return; // ignore un-match changes\n removeListener();\n gate.run();\n };\n\n // Modern browsers expose the EventTarget API on MediaQueryList; older\n // Safari (<14) only has the deprecated addListener/removeListener pair\n // and throws on addEventListener. Prefer modern, fall back to legacy,\n // and fail open when neither exists (mirrors the missing-matchMedia case).\n if (typeof mql.addEventListener === \"function\") {\n mql.addEventListener(\"change\", handler);\n removeListener = () => mql.removeEventListener(\"change\", handler);\n } else if (typeof mql.addListener === \"function\") {\n mql.addListener(handler);\n removeListener = () => mql.removeListener(handler);\n } else {\n fire();\n return { fired: true, cancel: noop };\n }\n\n return {\n fired: false,\n cancel: () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n removeListener();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// mountIslands — DOM walk + dynamic-import dispatcher.\n//\n// `mountIslands` is the entry point the generated `islands-runtime-<hash>.js`\n// bundle calls at script load time. It walks the DOM for the two island\n// markers emitted by the server-side hydration step and the `<Island>`\n// JSX wrapper:\n//\n// 1. `[data-zfb-island]` — SSR'd islands. We `hydrate()` (Preact) /\n// `hydrateRoot()` (React) against the existing server-rendered\n// DOM, gated by `scheduleHydrate(when)`.\n//\n// 2. `[data-zfb-island-skip-ssr]` — SSR-skip islands. The server\n// emitted no markup for these, so we `render()` (Preact) /\n// `createRoot().render()` (React). Skipping hydrate for this case\n// avoids the hydrate-mismatch warnings React/Preact would emit\n// against an empty DOM container.\n//\n// The per-island bundles each export a `mount(props, element, mode)`\n// function (see zfb_islands::render_island_entry_source). The\n// framework-specific glue lives inside that bundle, so this runtime is\n// framework-agnostic.\n//\n// ## Module-level singleton\n//\n// Dynamic imports of the same URL are cached by the JS runtime, so\n// \"switching pages\" (in an SPA shell) reuses the loaded bundle for free.\n// We keep an extra in-memory dedup map keyed by element so an island is\n// never mounted twice (e.g. on hot-reload / repeat-mount scenarios).\n// ---------------------------------------------------------------------------\n\n/**\n * The shape of the default export each per-island bundle ships.\n *\n * `mode === \"hydrate\"` is used for SSR'd islands, `\"render\"` for\n * SSR-skip islands.\n */\ntype IslandMount = (\n props: Record<string, unknown>,\n element: Element,\n mode: \"hydrate\" | \"render\",\n) => void;\n\ntype IslandUnmount = (element: Element) => void;\n\ninterface IslandModule {\n mount?: IslandMount;\n default?: IslandMount;\n unmount?: IslandUnmount;\n}\n\n/**\n * Map of `componentName → island descriptor` baked into the runtime entry.\n *\n * Two descriptor shapes are accepted so the same `mountIslands` runtime\n * handles both bundling strategies the build emits:\n *\n * 1. `string` — a per-island bundle URL. The runtime fetches it via\n * dynamic `import()` and reads `mount` / `default` off the loaded\n * module. Used by the per-island bundling path\n * (`bundle_per_island` / `render_runtime_entry_source`).\n *\n * 2. `IslandModule` — an inline module-shaped object whose `mount` (or\n * `default`) is called directly. Used by the shared-bundle path\n * (`render_shared_bundle_entry_source`): every island's source code\n * is already in the same bundle, so the synthesised entry can hand\n * the runtime the constructed mount functions inline without a\n * second HTTP fetch. This preserves the one-request shared-bundle\n * contract while giving up nothing on hydration semantics\n * (zudolab/zudo-doc#1355 wave 6).\n */\nexport type IslandManifestValue = string | IslandModule;\nexport type IslandManifest = Readonly<Record<string, IslandManifestValue>>;\n\n// data-zfb-transition-persist marker attribute — the client-router's persist\n// contract. Mirrored from client-router/swap-functions.ts: that package owns the\n// body swap (lifting persisted nodes into the incoming body), this package owns\n// island mount/unmount. Both must agree on the literal string. See the port\n// spec at packages/zfb-runtime/docs/client-router/port-spec.md §12.3.\nconst PERSIST_ATTR = \"data-zfb-transition-persist\";\n\n// Cross-package \"needs-remount\" flag set by client-router/swap-functions.ts on a\n// persisted island whose props changed across a body swap. Mirrored literal (same\n// cross-package contract as PERSIST_ATTR above — both packages must agree on the\n// string). Consumed by clearMountedForRemount(). See #1389.\nconst ISLAND_REMOUNT_ATTR = \"data-zfb-island-remount\";\n\n/**\n * Public DOM signal written after an island's mount function returns.\n *\n * State table (the marker is observational only and is never a mount guard):\n *\n * - initial: absent; `mountIslands` / `mountNewIslands` strip a marker that is\n * stale relative to this module instance's `mounted` map before scheduling.\n * - deferred idle / visible / media: absent while the scheduler is waiting.\n * - importing: absent while the URL module is in `pending`.\n * - mounted via URL: `scheduleMount`'s URL success handler writes it only after\n * `fn(propsForMount, element, mode)` returns, alongside the `mounted` entry.\n * - mounted via inline module: `fireInlineMount` writes it only after\n * `fn(props, element, mode)` returns, alongside the `mounted` entry.\n * - missing manifest entry: absent; `scheduleMount` returns without writing.\n * - no `mount` export: absent; both manifest paths return without writing.\n * - synchronous mount throw: absent; the `mounted` entry is not written, so a\n * later walk can retry the element.\n * - rejected import: absent; the URL rejection handler clears `pending` and\n * any defensive `mounted` entry.\n * - detached during import: absent; the URL success handler clears `pending`\n * and returns before calling mount.\n * - unmounted (discarded): `unmountIslands` clears the marker and `mounted`\n * entry in `finally`, even when the unmount thunk throws.\n * - unmounted (persisted-lifted): retained together with the `mounted` entry;\n * `unmountIslands` skips elements whose persist id exists in the incoming body.\n * - props-changed remount: `clearMountedForRemount` clears the marker and map\n * entry in `finally`, then the forced mount writes it again after mount returns.\n * - dev hot-swap over a marked DOM: a fresh module's `mountIslands` strips the\n * stale marker before scheduling, then writes it after its own mount returns.\n */\nexport const ISLAND_MOUNTED_ATTR = \"data-zfb-island-mounted\";\n\n// WeakMap<Element, unmount thunk> — replaces the old WeakSet.\n// Value is a per-element function that calls the bundle's unmount(element)\n// (or a noop if the bundle does not expose one). Used by unmountIslands()\n// to fire framework lifecycle cleanups before a body swap.\nconst mounted = new WeakMap<Element, () => void>();\n// Elements for which the nested-island self-wrap warning has already been\n// emitted. Guards against repeated warn spam across re-walks (e.g. SPA swaps).\nconst warnedNested = new WeakSet<Element>();\n// Elements with an in-flight dynamic import that has not yet resolved.\n// Two concurrent `mountIslands` invocations (or two `scheduleMount`\n// calls hitting the same element through different code paths) could\n// otherwise both pass the `mounted` guard and both spawn an\n// `importIsland(url)` -> `fn()` chain, double-mounting the component.\n// Adding the element to `pending` synchronously, before the import is\n// fired, closes that window; the entry is removed in both the success\n// (after `mounted.set`) and failure branches.\nconst pending = new WeakSet<Element>();\n\n// Module-level captured manifest — set by the first `mountIslands` call and reused by\n// `mountNewIslands()` so the client-router does not need to know the manifest directly.\n// Named technical cause (W1B §12.1): the router lives in @takazudo/zfb-runtime; the\n// islands manifest lives in @takazudo/zfb. Passing the manifest through the swap event\n// would require widening the event API or threading manifest into router options. The\n// captured-manifest pattern keeps the package boundary clean.\nlet capturedManifest: IslandManifest | null = null;\n\n// Map of element → cancel-function for deferred-hydration islands\n// (data-when=\"idle\"|\"visible\"|\"media\").\n// Populated in scheduleMount; consulted on `zfb:before-swap` so deferred fires do not run\n// against orphan elements after a body swap. (W1B §12.5)\nconst pendingCancels = new Map<Element, () => void>();\n\n/**\n * Walk the DOM and mount every `[data-zfb-island]` / `[data-zfb-island-skip-ssr]`\n * element using `manifest`.\n *\n * No-op when `document` is undefined (SSR, edge runtime). Safe to call\n * multiple times: each element is mounted at most once thanks to the\n * `mounted` WeakSet guard.\n *\n * The manifest is captured at module level so `mountNewIslands()` can re-use\n * it after an SPA body swap without needing the caller to re-supply it.\n */\nexport function mountIslands(manifest: IslandManifest): void {\n if (typeof document === \"undefined\") return;\n\n // Capture the manifest for post-swap re-walks via mountNewIslands().\n capturedManifest = manifest;\n\n const ssrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island]\");\n for (const el of Array.from(ssrIslands)) {\n stripStaleMountedMarker(el);\n // Skip the empty-skeleton case left behind when the server-side\n // rewriter has not run yet (data-zfb-island=\"\" with no component\n // name). The hydration emit step is expected to fill this in\n // before the page reaches the browser; if it didn't, we cannot\n // dispatch.\n const name = el.getAttribute(\"data-zfb-island\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, \"hydrate\");\n }\n\n const skipSsrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island-skip-ssr]\");\n for (const el of Array.from(skipSsrIslands)) {\n stripStaleMountedMarker(el);\n const name = el.getAttribute(\"data-zfb-island-skip-ssr\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, \"render\");\n }\n}\n\n/**\n * Re-walk the current document body and mount any new island markers introduced\n * by an SPA body swap. Uses the manifest captured by the previous `mountIslands`\n * call — no manifest arg required.\n *\n * The caller (client-router `router.ts`) invokes this after `swap()` + `runScripts()`\n * and before dispatching `zfb:page-load`, per W1B §12.2 contract.\n *\n * No-op when called before `mountIslands` (capturedManifest is null) or when\n * `document` is undefined.\n */\nexport function mountNewIslands(): void {\n if (typeof document === \"undefined\") return;\n if (capturedManifest === null) return;\n\n const manifest = capturedManifest;\n\n const ssrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island]\");\n for (const el of Array.from(ssrIslands)) {\n stripStaleMountedMarker(el);\n const name = el.getAttribute(\"data-zfb-island\");\n if (!name) continue;\n // A persisted island whose props changed across the body swap is flagged\n // for remount by swap-functions.swapBodyElement. Clear its surviving mounted\n // entry BEFORE scheduleMount's already-mounted guard so it re-mounts fresh\n // with the refreshed data-props. No-op for every other element.\n const forceRemount = clearMountedForRemount(el);\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, \"hydrate\", { force: forceRemount });\n }\n\n const skipSsrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island-skip-ssr]\");\n for (const el of Array.from(skipSsrIslands)) {\n stripStaleMountedMarker(el);\n const name = el.getAttribute(\"data-zfb-island-skip-ssr\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, \"render\");\n }\n}\n\n/**\n * Consume the cross-package \"needs-remount\" signal for the persist-props hybrid\n * path (port-spec §12.3.1 hybrid case / §12.3.2). When a persisted island's\n * props differ from the incoming markup, `swapBodyElement` refreshes the\n * surviving element's `data-props` and marks it with `ISLAND_REMOUNT_ATTR`.\n * That attribute is the ONLY channel that crosses the zfb-runtime → zfb package\n * boundary — the `mounted` map is module-private to this file, so a shared\n * in-memory \"needs-remount\" queue between the two packages is impossible; the\n * live DOM node carrying the flag IS the queue.\n *\n * On a flagged mounted element: fire the old instance's unmount thunk (so its\n * useEffect/framework cleanups run against the still-connected node), drop the\n * `mounted` entry so `scheduleMount`'s guard no longer short-circuits, strip the\n * flag, and ask the caller to force the replacement mount through immediately\n * instead of re-entering any deferred scheduler. This keeps a deferred persisted\n * island from blanking while it waits for idle/visible/media to fire again.\n *\n * On a flagged element whose URL import is still pending, leave the flag in\n * place. The already-running import's success handler consumes it after the\n * module resolves and re-reads `data-props` at that point, so a props refresh\n * that happened during the import wins without starting a duplicate import.\n *\n * A no-op for elements without the flag (the common case: fresh markers and\n * props-unchanged persisted islands).\n *\n * Scope: only the `[data-zfb-island]` (hydrated) loop calls this, mirroring the\n * writer side — swapBodyElement sets the flag only for `newTarget.matches(\n * \"[data-zfb-island]\")`, never for skip-ssr islands.\n */\nfunction clearMountedForRemount(el: Element): boolean {\n if (!el.hasAttribute(ISLAND_REMOUNT_ATTR)) return false;\n if (pending.has(el)) return false;\n\n const thunk = mounted.get(el);\n if (thunk) {\n try {\n thunk();\n } finally {\n mounted.delete(el);\n el.removeAttribute(ISLAND_MOUNTED_ATTR);\n el.removeAttribute(ISLAND_REMOUNT_ATTR);\n }\n return true;\n }\n el.removeAttribute(ISLAND_MOUNTED_ATTR);\n el.removeAttribute(ISLAND_REMOUNT_ATTR);\n return false;\n}\n\nfunction stripStaleMountedMarker(el: Element): void {\n if (!mounted.has(el)) el.removeAttribute(ISLAND_MOUNTED_ATTR);\n}\n\n/**\n * Cancel deferred-hydration callbacks for all islands in the old body before a\n * swap. Prevents idle / visibility callbacks from running against orphan elements\n * after `swapBodyElement` removes them from the live document. (W1B §12.5)\n *\n * Call this on `zfb:before-swap` (or equivalently, in the router's swap sequence\n * before `swap()` mutates the DOM). Fire-and-forget; safe to call if nothing is\n * pending.\n */\nexport function cancelPendingIslands(): void {\n for (const [el, cancel] of pendingCancels) {\n cancel();\n pendingCancels.delete(el);\n }\n}\n\n/**\n * Warn (once per element, dev-only) when an island marker element is found\n * nested inside another island marker. Self-wrapping an island — emitting a\n * `data-zfb-island` or `data-zfb-island-skip-ssr` container *inside* another\n * island component's render output — mis-hydrates because the runtime will\n * try to mount both the outer and inner islands independently. The outer\n * island's framework instance owns the inner DOM, so a second `hydrate()` /\n * `render()` call against the inner element races with the outer render and\n * produces undefined behaviour.\n *\n * The fix is to author the inner component bare (no `<Island>` in its own\n * render output) and apply the `<Island when=\"...\">` wrapper at the call site.\n */\nfunction warnIfNestedIsland(el: Element, componentName: string): void {\n if (typeof process === \"undefined\" || !process.env || process.env[\"NODE_ENV\"] === \"production\") {\n return;\n }\n if (warnedNested.has(el)) return;\n const parent = el.parentElement;\n if (!parent || typeof parent.closest !== \"function\") return;\n const ancestor = parent.closest(\"[data-zfb-island],[data-zfb-island-skip-ssr]\");\n if (!ancestor) return;\n warnedNested.add(el);\n // eslint-disable-next-line no-console\n console.warn(\n `[zfb] Island \"${componentName}\" is nested inside another island marker. ` +\n `Self-wrapping an island mis-hydrates: the outer framework instance owns ` +\n `the inner DOM, causing a conflicting mount. ` +\n `Fix: author \"${componentName}\" bare (remove <Island> from its own render output) ` +\n `and apply <Island when=\"...\"> at the call site instead.`,\n );\n}\n\nfunction scheduleMount(\n manifest: IslandManifest,\n element: Element,\n componentName: string,\n mode: \"hydrate\" | \"render\",\n options: { force?: boolean } = {},\n): void {\n // Skip elements already mounted OR currently importing — the latter\n // prevents two concurrent `mountIslands` calls from each firing a\n // separate dynamic import for the same element.\n if (mounted.has(element) || pending.has(element)) return;\n\n const entry = manifest[componentName];\n if (entry == null) {\n if (typeof process !== \"undefined\" && process.env && process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[zfb] no island manifest entry for component \"${componentName}\" — ` +\n `the runtime manifest is out of sync with the rendered HTML.`,\n );\n }\n return;\n }\n\n const when = element.getAttribute(\"data-when\") ?? undefined;\n\n // Two manifest shapes:\n //\n // - `string` (per-island bundle URL): fetch via dynamic `import()`\n // and call `mount` / `default` on the resolved module.\n // - `IslandModule` (inline descriptor): the shared-bundle path has\n // already imported every island's source into the same bundle and\n // constructed a mount function for it. Skip the dynamic import\n // and call the supplied function directly.\n if (typeof entry !== \"string\") {\n fireInlineMount(element, entry, mode, options);\n return;\n }\n\n const url: string = entry;\n\n const fire = (): void => {\n // Re-check both guards in case `fire` is invoked from a deferred\n // scheduler (rIC/rAF/visibility) after a sibling caller already\n // mounted or started importing for this element.\n if (mounted.has(element) || pending.has(element)) return;\n\n // When the deferred fire actually runs, the cancel handle is no longer\n // needed — remove it so pendingCancels doesn't hold stale entries.\n pendingCancels.delete(element);\n\n // Lazy props parse: read and parse data-props only now that we know we\n // are actually going to mount this island. For deferred strategies\n // (media, visible, idle) this avoids JSON.parse work at boot time for\n // islands that may never hydrate (e.g. media query never matches).\n const props = readProps(element);\n\n // Mark as pending BEFORE firing the import so any concurrent\n // `mountIslands` invocation that arrives during the await window\n // is short-circuited by `scheduleMount`'s guard.\n pending.add(element);\n\n // Dynamic-import is cached by the JS runtime, so repeat hits for\n // the same URL share the resolved module — module-level\n // singletons are fine.\n //\n // We move the element from `pending` to `mounted` only on the\n // success path so a failed import (e.g. transient network blip\n // in dev) doesn't permanently block a retry of the same element.\n let started: Promise<IslandModule>;\n try {\n started = importIsland(url);\n } catch (err) {\n // Some implementations of dynamic-import wrappers can throw\n // synchronously (e.g. URL parsing errors). Treat the same as\n // an async rejection.\n pending.delete(element);\n // eslint-disable-next-line no-console\n console.error(`[zfb] failed to start dynamic import for ${url}`, err);\n return;\n }\n started.then(\n (mod) => {\n const fn = mod.mount ?? mod.default;\n if (typeof fn !== \"function\") {\n pending.delete(element);\n if (\n typeof process !== \"undefined\" &&\n process.env &&\n process.env[\"NODE_ENV\"] !== \"production\"\n ) {\n // eslint-disable-next-line no-console\n console.warn(`[zfb] island bundle at ${url} did not export mount() or default()`);\n }\n return;\n }\n // Stale-mount race guard: if the element was detached while the\n // dynamic import was in-flight (e.g. a body swap happened), skip\n // mounting — the element is no longer in the live document and\n // its useEffect listeners would never receive a cleanup call.\n if (!element.isConnected) {\n pending.delete(element);\n return;\n }\n const shouldRefreshProps = element.hasAttribute(ISLAND_REMOUNT_ATTR);\n const propsForMount = shouldRefreshProps ? readProps(element) : props;\n if (shouldRefreshProps) element.removeAttribute(ISLAND_REMOUNT_ATTR);\n const unmountThunk = mod.unmount\n ? () => mod.unmount!(element)\n : () => {\n // noop — bundle does not expose unmount\n };\n try {\n fn(propsForMount, element, mode);\n mounted.set(element, unmountThunk);\n element.setAttribute(ISLAND_MOUNTED_ATTR, \"\");\n } finally {\n pending.delete(element);\n }\n },\n (err: unknown) => {\n // Surface the error in dev so the user notices, then clear\n // both guards so a later retry (e.g. another scheduleHydrate\n // fire) can attempt the import again.\n pending.delete(element);\n mounted.delete(element);\n // eslint-disable-next-line no-console\n console.error(`[zfb] failed to load island bundle ${url}`, err);\n },\n );\n };\n\n if (mode === \"render\") {\n // SSR-skip islands ignore data-when: there is nothing to defer\n // hydration of, just an empty container we paint into. Mount\n // immediately so the user sees output.\n fire();\n return;\n }\n\n if (options.force) {\n fire();\n return;\n }\n\n const { fired, cancel } = scheduleHydrateInternal(element, when, fire);\n // Track deferred-hydration cancel handle so cancelPendingIslands() can abort\n // idle / visibility callbacks before a body swap. (W1B §12.5)\n // Only register when the scheduler did NOT fire synchronously — a synchronous\n // fire means the island is already handling its import and there is no\n // deferred callback to cancel. Registering noop after a sync fire would leave\n // a stale pendingCancels entry for an already-handled element. (#743)\n if (when && when !== \"load\" && !fired) {\n pendingCancels.set(element, cancel);\n }\n}\n\n/**\n * Run the mount step for the inline-module manifest shape used by the\n * shared-bundle path. The module is already in memory (it was imported\n * into the bundle at build time), so there is no async window to\n * coordinate around — we just call `mount` / `default` directly,\n * gated by the same `data-when` semantics as the URL path.\n */\nfunction fireInlineMount(\n element: Element,\n mod: IslandModule,\n mode: \"hydrate\" | \"render\",\n options: { force?: boolean } = {},\n): void {\n const fn = mod.mount ?? mod.default;\n if (typeof fn !== \"function\") {\n if (typeof process !== \"undefined\" && process.env && process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\"[zfb] inline island manifest entry did not export mount() or default()\");\n }\n return;\n }\n\n const fire = (): void => {\n // Re-check the guard in case `fire` is invoked from a deferred\n // scheduler (rIC/rAF/visibility) after a sibling caller already\n // mounted this element.\n if (mounted.has(element)) return;\n // When the deferred fire actually runs, the cancel handle is no longer\n // needed — remove it so pendingCancels doesn't hold stale entries.\n pendingCancels.delete(element);\n // Stale-mount race guard for deferred inline mounts: skip if the element\n // was detached (e.g. body swap) while the idle/visible callback was queued.\n if (!element.isConnected) return;\n // Lazy props parse: read and parse data-props only at mount time.\n // For deferred strategies (media, visible, idle) this avoids JSON.parse\n // work at boot time for islands that may never hydrate.\n const props = readProps(element);\n const unmountThunk = mod.unmount\n ? () => mod.unmount!(element)\n : () => {\n // noop — inline module does not expose unmount\n };\n fn(props, element, mode);\n mounted.set(element, unmountThunk);\n element.setAttribute(ISLAND_MOUNTED_ATTR, \"\");\n };\n\n if (mode === \"render\") {\n fire();\n return;\n }\n\n if (options.force) {\n fire();\n return;\n }\n\n const when = element.getAttribute(\"data-when\") ?? undefined;\n const { fired, cancel } = scheduleHydrateInternal(element, when, fire);\n // Track deferred-hydration cancel handle so cancelPendingIslands() can abort\n // idle / visibility callbacks before a body swap. (W1B §12.5)\n // Only register when the scheduler did NOT fire synchronously — a synchronous\n // fire means the island is already handling its mount and there is no\n // deferred callback to cancel. Registering noop after a sync fire would leave\n // a stale pendingCancels entry for an already-handled element. (#743)\n if (when && when !== \"load\" && !fired) {\n pendingCancels.set(element, cancel);\n }\n}\n\n/**\n * Unmount the mounted islands within `root` (default: `document.body`) that will\n * NOT survive the body swap.\n *\n * Walks `root` for `[data-zfb-island]` and `[data-zfb-island-skip-ssr]` elements,\n * looks up each element's unmount thunk in the `mounted` WeakMap, calls it (which\n * triggers `render(null, element)` for Preact or `root.unmount()` for React), and\n * removes the entry from the map so `mountNewIslands()` can re-mount later.\n *\n * Call this before `swapBodyElement(...)` so the OLD body's islands receive proper\n * framework lifecycle cleanup (useEffect teardowns, etc.) before being discarded.\n *\n * When `incomingBody` is supplied (the client-router passes the parsed incoming\n * document body), any island whose `data-zfb-transition-persist` id matches a\n * marker in that body is DELIBERATELY SKIPPED: swapBodyElement will physically\n * lift the node into the new body, so its component instance and internal state\n * must survive — unmounting it here would empty the container before the lift and\n * defeat the persist contract (issue #1389). Omit `incomingBody` (or pass null)\n * to unmount everything, the pre-#1389 behavior.\n *\n * No-op for elements not in the `mounted` map (e.g. never-mounted or already cleaned up).\n */\nexport function unmountIslands(\n root: ParentNode = document.body,\n incomingBody?: ParentNode | null,\n): void {\n const selector = \"[data-zfb-island],[data-zfb-island-skip-ssr]\";\n // Persist ids that `swapBodyElement` will physically LIFT from the old body\n // into the incoming body — an old marker survives iff the incoming body has a\n // marker with the same `data-zfb-transition-persist` id. Those DOM nodes are\n // moved, not discarded, so their component instance and internal state MUST\n // survive the swap: skip their framework unmount here or the persist contract\n // preserves nothing (port-spec §12.3.1 case (a) / issue #1389). A persisted\n // island whose props changed is skipped here too — its refreshed remount runs\n // later in mountNewIslands via the `data-zfb-island-remount` flag (see\n // `clearMountedForRemount`) swapBodyElement sets. With no incoming body (a\n // call outside a swap) nothing is preserved, so the walk is byte-identical to\n // the pre-#1389 behavior.\n const preservedPersistIds = collectPersistIds(incomingBody);\n const elements = root.querySelectorAll<HTMLElement>(selector);\n for (const el of Array.from(elements)) {\n const persistId = el.getAttribute(PERSIST_ATTR);\n if (persistId !== null && preservedPersistIds.has(persistId)) continue;\n const thunk = mounted.get(el);\n try {\n thunk?.();\n } finally {\n mounted.delete(el);\n el.removeAttribute(ISLAND_MOUNTED_ATTR);\n }\n }\n}\n\n/**\n * Collect the `data-zfb-transition-persist` ids present in the incoming body so\n * `unmountIslands` can tell which old-body islands `swapBodyElement` will lift\n * (and therefore must be left mounted). Returns an empty set when no incoming\n * body is supplied.\n */\nfunction collectPersistIds(incomingBody?: ParentNode | null): Set<string> {\n const ids = new Set<string>();\n if (!incomingBody) return ids;\n for (const el of incomingBody.querySelectorAll(`[${PERSIST_ATTR}]`)) {\n const id = el.getAttribute(PERSIST_ATTR);\n if (id !== null) ids.add(id);\n }\n return ids;\n}\n\nfunction readProps(element: Element): Record<string, unknown> {\n const raw = element.getAttribute(\"data-props\");\n if (!raw) return {};\n try {\n const parsed = JSON.parse(raw) as unknown;\n // Reject arrays explicitly: `typeof [] === \"object\"` is true but\n // an array is not a valid props bag, and passing it through would\n // mean the component receives index-keyed values where it\n // expected a record. Fall through to the empty-object default\n // instead of forwarding a malformed shape.\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // fall through\n }\n return {};\n}\n\n/**\n * Indirection so tests can stub the dynamic import without intercepting\n * the global `import()`. In production this is a thin wrapper over\n * native `import(url)`.\n */\nlet importImpl: (url: string) => Promise<IslandModule> = (url) =>\n // Modern bundlers (esbuild, Vite, Rollup, webpack) preserve a plain\n // `import(<dynamic>)` call when the argument isn't a static literal,\n // so we no longer need the `new Function(...)` indirection — which\n // also failed under strict CSPs that disallow `unsafe-eval`.\n import(/* @vite-ignore */ /* webpackIgnore: true */ url) as Promise<IslandModule>;\n\nfunction importIsland(url: string): Promise<IslandModule> {\n return importImpl(url);\n}\n\n/**\n * Test-only seam. Replace the module dynamic-import with a fake.\n * Returns the previous implementation so tests can restore it.\n */\nexport function __setIslandImporterForTests(\n impl: (url: string) => Promise<IslandModule>,\n): (url: string) => Promise<IslandModule> {\n const prev = importImpl;\n importImpl = impl;\n return prev;\n}\n\n/**\n * Test-only seam. Returns whether the given element has an entry in the\n * module-private `pendingCancels` Map. Used to assert that a synchronous\n * scheduler fire does not leave a stale entry behind. (#743)\n */\nexport function __hasPendingCancelForTests(element: Element): boolean {\n return pendingCancels.has(element);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["// Hydration scheduling helper consumed by the hydration runtime (Sub 3).\n//\n// Sub 3 owns the hydration runtime that walks the DOM, finds elements\n// marked with `data-zfb-island`, and dispatches each one through this\n// helper to decide *when* to fire the actual hydrate() call. The helper\n// itself does not know how to hydrate — it only schedules the supplied\n// `fire` callback.\n//\n// The branching matches the `When` union exactly:\n// \"visible\" → IntersectionObserver, threshold 0.0, hydrate on first\n// intersection, then disconnect.\n// \"idle\" → requestIdleCallback if available, otherwise setTimeout(0).\n// \"media\" → matchMedia(target's data-media), hydrate when the query\n// first matches (now or on a later change event), then\n// remove the listener.\n// \"load\" → immediate, synchronous fire.\n//\n// Anything else is treated as \"load\" (with a console.warn in development).\n// The helper is environment-tolerant: callers can run it in jsdom /\n// happy-dom or bare Node, and the absence of `IntersectionObserver` /\n// `requestIdleCallback` / `matchMedia` is handled gracefully.\n\nimport { resolveWhen, type When } from \"./types.js\";\nimport { ROOT_KEY, type RootHandle } from \"./zudo-react/root.js\";\nimport { parseProps as parseOwnedProps } from \"./zudo-react/props-transport.js\";\n\n/**\n * Subset of the global object that this module touches. Cast once at the\n * module top so individual scheduler functions don't repeat the inline\n * widening.\n */\ntype SchedulerGlobal = typeof globalThis & {\n requestIdleCallback?: (\n cb: (deadline: { didTimeout: boolean; timeRemaining: () => number }) => void,\n options?: { timeout?: number },\n ) => number;\n cancelIdleCallback?: (handle: number) => void;\n IntersectionObserver?: typeof IntersectionObserver;\n matchMedia?: typeof matchMedia;\n};\n\nconst g = globalThis as SchedulerGlobal;\n\n/**\n * Internal variant of `scheduleHydrate` that also reports whether the fire\n * callback was invoked synchronously. Unexported — call sites in this module\n * use this to decide whether to register a `pendingCancels` entry.\n */\nfunction scheduleHydrateInternal(\n target: Element,\n when: When | string | undefined,\n fire: () => void,\n): { fired: boolean; cancel: () => void } {\n const resolved = resolveWhen(when);\n\n if (resolved === \"load\") {\n fire();\n return { fired: true, cancel: noop };\n }\n\n if (resolved === \"idle\") {\n return { fired: false, cancel: scheduleIdle(fire) };\n }\n\n if (resolved === \"media\") {\n return scheduleMedia(target, fire);\n }\n\n // \"visible\"\n return scheduleVisible(target, fire);\n}\n\n/**\n * Schedule a hydration `fire` callback for `target` according to `when`.\n *\n * Returns a `cancel` function that aborts the scheduling if it has not\n * fired yet. After firing, calling `cancel` is a no-op. If the helper\n * cannot find the relevant browser API (e.g. running in pure Node with no\n * polyfill), it falls back to firing synchronously so server-side smoke\n * tests still observe the call.\n */\nexport function scheduleHydrate(\n target: Element,\n when: When | string | undefined,\n fire: () => void,\n): () => void {\n return scheduleHydrateInternal(target, when, fire).cancel;\n}\n\nfunction noop(): void {\n // intentionally empty\n}\n\n/**\n * Build a one-shot gate around `fn`. The returned `run` invokes `fn`\n * exactly once provided `cancel` has not been called first; `cancel`\n * marks the gate as cancelled (later `run` invocations become no-ops)\n * and reports whether the gate had already fired.\n */\nfunction oneShot(fn: () => void): {\n run: () => void;\n cancel: () => boolean;\n} {\n let fired = false;\n let cancelled = false;\n return {\n run(): void {\n if (cancelled || fired) return;\n fired = true;\n fn();\n },\n cancel(): boolean {\n if (fired) return true;\n cancelled = true;\n return false;\n },\n };\n}\n\nfunction scheduleIdle(fire: () => void): () => void {\n const gate = oneShot(fire);\n\n if (typeof g.requestIdleCallback === \"function\") {\n const handle = g.requestIdleCallback(gate.run);\n return () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n if (typeof g.cancelIdleCallback === \"function\") g.cancelIdleCallback(handle);\n };\n }\n\n const handle = setTimeout(gate.run, 0);\n return () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n clearTimeout(handle);\n };\n}\n\nfunction scheduleVisible(\n target: Element,\n fire: () => void,\n): { fired: boolean; cancel: () => void } {\n const Observer = g.IntersectionObserver;\n\n // No IntersectionObserver (e.g. very old browsers, bare Node) — fail\n // open and hydrate immediately so the island is at least functional.\n if (typeof Observer !== \"function\") {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const gate = oneShot(fire);\n const observer = new Observer(\n (entries, obs) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n obs.disconnect();\n gate.run();\n return;\n }\n }\n },\n { threshold: 0 },\n );\n\n observer.observe(target);\n\n return {\n fired: false,\n cancel: () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n observer.disconnect();\n },\n };\n}\n\nfunction scheduleMedia(target: Element, fire: () => void): { fired: boolean; cancel: () => void } {\n const query = target.getAttribute(\"data-media\");\n\n // No matchMedia API (e.g. bare Node, very old browser) or missing/empty\n // query — fail open and hydrate immediately so the island is at least\n // functional.\n if (typeof g.matchMedia !== \"function\" || !query) {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const mql = g.matchMedia(query);\n\n // Already matches — fire synchronously (no pending listener needed).\n if (mql.matches) {\n fire();\n return { fired: true, cancel: noop };\n }\n\n const gate = oneShot(fire);\n\n let removeListener = noop;\n\n // Listen for the first change event where the query matches.\n // We do NOT use `{once:true}` because we must ignore un-match events\n // (e.g. viewport widens back above breakpoint) and only fire on the\n // first match event — `{once:true}` would consume any change, including\n // un-match changes.\n const handler = (e: MediaQueryListEvent): void => {\n if (!e.matches) return; // ignore un-match changes\n removeListener();\n gate.run();\n };\n\n // Modern browsers expose the EventTarget API on MediaQueryList; older\n // Safari (<14) only has the deprecated addListener/removeListener pair\n // and throws on addEventListener. Prefer modern, fall back to legacy,\n // and fail open when neither exists (mirrors the missing-matchMedia case).\n if (typeof mql.addEventListener === \"function\") {\n mql.addEventListener(\"change\", handler);\n removeListener = () => mql.removeEventListener(\"change\", handler);\n } else if (typeof mql.addListener === \"function\") {\n mql.addListener(handler);\n removeListener = () => mql.removeListener(handler);\n } else {\n fire();\n return { fired: true, cancel: noop };\n }\n\n return {\n fired: false,\n cancel: () => {\n const alreadyFired = gate.cancel();\n if (alreadyFired) return;\n removeListener();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// mountIslands — DOM walk + dynamic-import dispatcher.\n//\n// `mountIslands` is the entry point the generated `islands-runtime-<hash>.js`\n// bundle calls at script load time. It walks the DOM for the two island\n// markers emitted by the server-side hydration step and the `<Island>`\n// JSX wrapper:\n//\n// 1. `[data-zfb-island]` — adopt server-rendered owned DOM.\n// 2. `[data-zfb-island-skip-ssr]` — mount over the fallback when scheduled.\n//\n// The generated shared bundle supplies strict identity and a RootHandle.\n// ---------------------------------------------------------------------------\n\n/**\n * The mount function supplied by a shared-bundle island module.\n *\n * `mode === \"hydrate\"` is used for SSR'd islands, `\"render\"` for\n * SSR-skip islands.\n */\ntype IslandMount = (\n props: Record<string, unknown>,\n element: Element,\n mode: \"hydrate\" | \"render\",\n) => RootHandle | null;\n\ninterface IslandModule {\n identity: { component: string; build: string };\n mount: IslandMount;\n}\n\n/**\n * Map of `componentName → island descriptor` baked into the runtime entry.\n *\n * Each manifest value is an inline module with `mount` or `default`.\n * The shared bundle imports island sources at build time.\n */\nexport type IslandManifestValue = IslandModule;\nexport type IslandManifest = Readonly<Record<string, IslandManifestValue>>;\n\n// data-zfb-transition-persist marker attribute — the client-router's persist\n// contract. Mirrored from client-router/swap-functions.ts: that package owns the\n// body swap (lifting persisted nodes into the incoming body), this package owns\n// island mount/unmount. Both must agree on the literal string. See the port\n// spec at packages/zfb-runtime/docs/client-router/port-spec.md §12.3.\nconst PERSIST_ATTR = \"data-zfb-transition-persist\";\n\n// Cross-package \"needs-remount\" flag set by client-router/swap-functions.ts on a\n// persisted island whose props changed across a body swap. Mirrored literal (same\n// cross-package contract as PERSIST_ATTR above — both packages must agree on the\n// string). Consumed by clearMountedForRemount(). See #1389.\nconst ISLAND_REMOUNT_ATTR = \"data-zfb-island-remount\";\n\n/**\n * Public observation marker; the symbol handle is the live-root guard.\n *\n * State table:\n * - initial/deferred/missing entry/failed mount: marker and handle absent;\n * - successful mount: both present;\n * - discarded root: disposal leaves DOM for the body swap, then clears both;\n * - unchanged persisted root: both survive with the same DOM node;\n * - changed persisted root: dispose, clear, then mount in render mode;\n * - bundle re-import: dispose the old symbol handle before render mode replaces it.\n */\nexport const ISLAND_MOUNTED_ATTR = \"data-zfb-island-mounted\";\nconst COMPOSITION_KEY = Symbol.for(\"@takazudo/zfb/zudo-react/composition-v1\");\nconst TRACKER_KEY = Symbol.for(\"@takazudo/zfb/zudo-react/composition-tracker-v1\");\n\n// A fresh bundle instance replaces roots installed by a previous instance.\n// Ordinary repeat scans in the same instance keep their live handles.\nconst owned = new WeakSet<Element>();\nfunction rootHandle(element: Element): RootHandle | undefined {\n return (element as unknown as Record<symbol, RootHandle | undefined>)[ROOT_KEY];\n}\nfunction setRootHandle(element: Element, handle: RootHandle | undefined): void {\n const target = element as unknown as Record<symbol, RootHandle | undefined>;\n if (handle) target[ROOT_KEY] = handle;\n else delete target[ROOT_KEY];\n}\nfunction reportIslandError(element: Element, phase: string, error: unknown): void {\n const name =\n element.getAttribute(\"data-zfb-island\") ??\n element.getAttribute(\"data-zfb-island-skip-ssr\") ??\n \"unknown\";\n try {\n console.error(`[zfb] island \"${name}\" ${phase} failed`, error);\n } catch {\n // A broken reporter must not stop other roots.\n }\n}\nfunction disposeIsland(element: Element, phase: string): void {\n const handle = rootHandle(element);\n try {\n handle?.dispose();\n } catch (error) {\n reportIslandError(element, phase, error);\n } finally {\n if (rootHandle(element) === handle) setRootHandle(element, undefined);\n element.removeAttribute(ISLAND_MOUNTED_ATTR);\n }\n}\nfunction installCompositionTracker(doc: Document): void {\n const target = doc as unknown as Record<symbol, (() => void) | undefined>;\n if (target[TRACKER_KEY]) return;\n const set = (event: Event, value: \"active\" | \"idle\") => {\n if (event.target instanceof Element) {\n (event.target as unknown as Record<symbol, string>)[COMPOSITION_KEY] = value;\n }\n };\n const start = (event: Event) => set(event, \"active\");\n const end = (event: Event) => set(event, \"idle\");\n const input = (event: Event) => {\n if ((event as InputEvent).isComposing) set(event, \"active\");\n };\n doc.addEventListener(\"compositionstart\", start, true);\n doc.addEventListener(\"compositionend\", end, true);\n doc.addEventListener(\"input\", input, true);\n doc.addEventListener(\"blur\", end, true);\n target[TRACKER_KEY] = () => {\n doc.removeEventListener(\"compositionstart\", start, true);\n doc.removeEventListener(\"compositionend\", end, true);\n doc.removeEventListener(\"input\", input, true);\n doc.removeEventListener(\"blur\", end, true);\n delete target[TRACKER_KEY];\n };\n}\n\n// Elements for which the nested-island self-wrap warning has already been\n// emitted. Guards against repeated warn spam across re-walks (e.g. SPA swaps).\nconst warnedNested = new WeakSet<Element>();\n// Module-level captured manifest — set by the first `mountIslands` call and reused by\n// `mountNewIslands()` so the client-router does not need to know the manifest directly.\n// Named technical cause (W1B §12.1): the router lives in @takazudo/zfb-runtime; the\n// islands manifest lives in @takazudo/zfb. Passing the manifest through the swap event\n// would require widening the event API or threading manifest into router options. The\n// captured-manifest pattern keeps the package boundary clean.\nlet capturedManifest: IslandManifest | null = null;\n\n// Map of element → cancel-function for deferred-hydration islands\n// (data-when=\"idle\"|\"visible\"|\"media\").\n// Populated in scheduleMount; consulted on `zfb:before-swap` so deferred fires do not run\n// against orphan elements after a body swap. (W1B §12.5)\nconst pendingCancels = new Map<Element, () => void>();\n\n/**\n * Walk the DOM and mount every `[data-zfb-island]` / `[data-zfb-island-skip-ssr]`\n * element using `manifest`.\n *\n * No-op when `document` is undefined (SSR, edge runtime). Safe to call\n * multiple times: each element is mounted at most once thanks to the\n * symbol-handle guard.\n *\n * The manifest is captured at module level so `mountNewIslands()` can re-use\n * it after an SPA body swap without needing the caller to re-supply it.\n */\nexport function mountIslands(manifest: IslandManifest): void {\n if (typeof document === \"undefined\") return;\n\n // Capture the manifest for post-swap re-walks via mountNewIslands().\n capturedManifest = manifest;\n installCompositionTracker(document);\n\n const ssrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island]\");\n for (const el of Array.from(ssrIslands)) {\n const replacing = prepareMount(el);\n // Skip the empty-skeleton case left behind when the server-side\n // rewriter has not run yet (data-zfb-island=\"\" with no component\n // name). The hydration emit step is expected to fill this in\n // before the page reaches the browser; if it didn't, we cannot\n // dispatch.\n const name = el.getAttribute(\"data-zfb-island\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, replacing ? \"render\" : \"hydrate\", { force: replacing });\n }\n\n const skipSsrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island-skip-ssr]\");\n for (const el of Array.from(skipSsrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island-skip-ssr\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, \"render\", { force: replacing });\n }\n}\n\n/**\n * Re-walk the current document body and mount any new island markers introduced\n * by an SPA body swap. Uses the manifest captured by the previous `mountIslands`\n * call — no manifest arg required.\n *\n * The caller (client-router `router.ts`) invokes this after `swap()` + `runScripts()`\n * and before dispatching `zfb:page-load`, per W1B §12.2 contract.\n *\n * No-op when called before `mountIslands` (capturedManifest is null) or when\n * `document` is undefined.\n */\nexport function mountNewIslands(): void {\n if (typeof document === \"undefined\") return;\n if (capturedManifest === null) return;\n\n const manifest = capturedManifest;\n\n const ssrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island]\");\n for (const el of Array.from(ssrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island\");\n if (!name) continue;\n // The router marks changed persisted identity/props on the surviving node.\n const forceRemount = clearMountedForRemount(el) || replacing;\n warnIfNestedIsland(el, name);\n scheduleMount(manifest, el, name, forceRemount ? \"render\" : \"hydrate\", { force: forceRemount });\n }\n\n const skipSsrIslands = document.querySelectorAll<HTMLElement>(\"[data-zfb-island-skip-ssr]\");\n for (const el of Array.from(skipSsrIslands)) {\n const replacing = prepareMount(el);\n const name = el.getAttribute(\"data-zfb-island-skip-ssr\");\n if (!name) continue;\n warnIfNestedIsland(el, name);\n const forceRemount = clearMountedForRemount(el) || replacing;\n scheduleMount(manifest, el, name, \"render\", { force: forceRemount });\n }\n}\n\n/** Consume a persisted root's remount flag and dispose its previous resources. */\nfunction clearMountedForRemount(el: Element): boolean {\n if (!el.hasAttribute(ISLAND_REMOUNT_ATTR)) return false;\n el.removeAttribute(ISLAND_REMOUNT_ATTR);\n if (rootHandle(el)) disposeIsland(el, \"remount disposal\");\n else el.removeAttribute(ISLAND_MOUNTED_ATTR);\n return true;\n}\n\nfunction prepareMount(el: Element): boolean {\n let replacing = false;\n if (rootHandle(el) && !owned.has(el)) {\n disposeIsland(el, \"dev replacement disposal\");\n replacing = true;\n }\n if (!rootHandle(el)) el.removeAttribute(ISLAND_MOUNTED_ATTR);\n return replacing;\n}\n\n/**\n * Cancel deferred-hydration callbacks for all islands in the old body before a\n * swap. Prevents idle / visibility callbacks from running against orphan elements\n * after `swapBodyElement` removes them from the live document. (W1B §12.5)\n *\n * Call this on `zfb:before-swap` (or equivalently, in the router's swap sequence\n * before `swap()` mutates the DOM). Fire-and-forget; safe to call if nothing is\n * pending.\n */\nexport function cancelPendingIslands(): void {\n for (const [el, cancel] of pendingCancels) {\n cancel();\n pendingCancels.delete(el);\n }\n}\n\n/**\n * Warn (once per element, dev-only) when an island marker element is found\n * nested inside another island marker. Self-wrapping an island — emitting a\n * `data-zfb-island` or `data-zfb-island-skip-ssr` container *inside* another\n * island component's render output — mis-hydrates because the runtime will\n * try to mount both the outer and inner islands independently. The outer\n * island's framework instance owns the inner DOM, so a second `hydrate()` /\n * `render()` call against the inner element races with the outer render and\n * produces undefined behaviour.\n *\n * The fix is to author the inner component bare (no `<Island>` in its own\n * render output) and apply the `<Island when=\"...\">` wrapper at the call site.\n */\nfunction warnIfNestedIsland(el: Element, componentName: string): void {\n if (typeof process === \"undefined\" || !process.env || process.env[\"NODE_ENV\"] === \"production\") {\n return;\n }\n if (warnedNested.has(el)) return;\n const parent = el.parentElement;\n if (!parent || typeof parent.closest !== \"function\") return;\n const ancestor = parent.closest(\"[data-zfb-island],[data-zfb-island-skip-ssr]\");\n if (!ancestor) return;\n warnedNested.add(el);\n // eslint-disable-next-line no-console\n console.warn(\n `[zfb] Island \"${componentName}\" is nested inside another island marker. ` +\n `Self-wrapping an island mis-hydrates: the outer framework instance owns ` +\n `the inner DOM, causing a conflicting mount. ` +\n `Fix: author \"${componentName}\" bare (remove <Island> from its own render output) ` +\n `and apply <Island when=\"...\"> at the call site instead.`,\n );\n}\n\nfunction scheduleMount(\n manifest: IslandManifest,\n element: Element,\n componentName: string,\n mode: \"hydrate\" | \"render\",\n options: { force?: boolean } = {},\n): void {\n if (rootHandle(element)) return;\n\n const entry = manifest[componentName];\n if (entry == null) {\n if (typeof process !== \"undefined\" && process.env && process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n `[zfb] no island manifest entry for component \"${componentName}\" — ` +\n `the runtime manifest is out of sync with the rendered HTML.`,\n );\n }\n return;\n }\n\n fireInlineMount(element, entry, mode, options);\n}\n\n/**\n * Run the mount step for the inline-module manifest shape used by the\n * shared-bundle path. The module is already in memory (it was imported\n * into the bundle at build time), so there is no async window to\n * coordinate around — we just call `mount` / `default` directly,\n * gated by `data-when` semantics.\n */\nfunction fireInlineMount(\n element: Element,\n mod: IslandModule,\n mode: \"hydrate\" | \"render\",\n options: { force?: boolean } = {},\n): void {\n const fn = mod.mount;\n if (typeof fn !== \"function\") {\n if (typeof process !== \"undefined\" && process.env && process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\"[zfb] owned island manifest entry did not export mount()\");\n }\n return;\n }\n\n const fire = (): void => {\n // Re-check the guard in case `fire` is invoked from a deferred\n // scheduler (rIC/rAF/visibility) after a sibling caller already\n // mounted this element.\n if (rootHandle(element)) return;\n // When the deferred fire actually runs, the cancel handle is no longer\n // needed — remove it so pendingCancels doesn't hold stale entries.\n pendingCancels.delete(element);\n // Stale-mount race guard for deferred inline mounts: skip if the element\n // was detached (e.g. body swap) while the idle/visible callback was queued.\n if (!element.isConnected) return;\n // Lazy props parse: read and parse data-props only at mount time.\n // For deferred strategies (media, visible, idle) this avoids JSON.parse\n // work at boot time for islands that may never hydrate.\n try {\n const props = readProps(element, mod.identity);\n const result = fn(props, element, mode);\n if (result === null) return;\n if (!result || typeof result.dispose !== \"function\" || typeof result.unmount !== \"function\") {\n throw new TypeError(\n `ZR_ROOT_HANDLE: island ${mod.identity.component} returned no root handle`,\n );\n }\n const handle: RootHandle = result;\n setRootHandle(element, handle);\n owned.add(element);\n element.setAttribute(ISLAND_MOUNTED_ATTR, \"\");\n } catch (error) {\n element.removeAttribute(ISLAND_MOUNTED_ATTR);\n reportIslandError(element, \"mount\", error);\n }\n };\n\n if (options.force) {\n fire();\n return;\n }\n\n const when = element.getAttribute(\"data-when\") ?? undefined;\n const { fired, cancel } = scheduleHydrateInternal(element, when, fire);\n // Track deferred-hydration cancel handle so cancelPendingIslands() can abort\n // idle / visibility callbacks before a body swap. (W1B §12.5)\n // Only register when the scheduler did NOT fire synchronously — a synchronous\n // fire means the island is already handling its mount and there is no\n // deferred callback to cancel. Registering noop after a sync fire would leave\n // a stale pendingCancels entry for an already-handled element. (#743)\n if (when && when !== \"load\" && !fired) {\n pendingCancels.set(element, cancel);\n }\n}\n\n/**\n * Dispose roots that the incoming body will discard. Persisted roots keep their\n * handles and DOM until the post-swap scan determines whether to recreate them.\n */\nexport function unmountIslands(\n root: ParentNode = document.body,\n incomingBody?: ParentNode | null,\n): void {\n const selector = \"[data-zfb-island],[data-zfb-island-skip-ssr]\";\n // Persisted nodes are lifted by the router and retain their live resources.\n const preservedPersistIds = collectPersistIds(incomingBody);\n const elements = root.querySelectorAll<HTMLElement>(selector);\n for (const el of Array.from(elements)) {\n const persistId = el.getAttribute(PERSIST_ATTR);\n if (persistId !== null && preservedPersistIds.has(persistId)) continue;\n disposeIsland(el, \"disposal\");\n }\n}\n\n/**\n * Collect the `data-zfb-transition-persist` ids present in the incoming body so\n * `unmountIslands` can tell which old-body islands `swapBodyElement` will lift\n * (and therefore must be left mounted). Returns an empty set when no incoming\n * body is supplied.\n */\nfunction collectPersistIds(incomingBody?: ParentNode | null): Set<string> {\n const ids = new Set<string>();\n if (!incomingBody) return ids;\n for (const el of incomingBody.querySelectorAll(`[${PERSIST_ATTR}]`)) {\n const id = el.getAttribute(PERSIST_ATTR);\n if (id !== null) ids.add(id);\n }\n return ids;\n}\n\nfunction readProps(\n element: Element,\n identity: { component: string; build: string },\n): Record<string, unknown> {\n const raw = element.getAttribute(\"data-props\");\n const hasHydrate = element.hasAttribute(\"data-zfb-island\");\n const hasSkipSsr = element.hasAttribute(\"data-zfb-island-skip-ssr\");\n const component =\n element.getAttribute(\"data-zfb-island\") ?? element.getAttribute(\"data-zfb-island-skip-ssr\");\n if (\n hasHydrate === hasSkipSsr ||\n component !== identity.component ||\n element.getAttribute(\"data-zfb-transport\") !== \"json/1\" ||\n element.getAttribute(\"data-zfb-protocol\") !== \"zudo-react/1\" ||\n element.getAttribute(\"data-zfb-build\") !== identity.build ||\n raw === null\n ) {\n throw new TypeError(`ZR_IDENTITY: island ${identity.component} has invalid transport identity`);\n }\n if (element.querySelector(\"[data-zfb-island],[data-zfb-island-skip-ssr]\")) {\n throw new TypeError(`ZR_NESTED_ISLAND: island ${identity.component} contains another island`);\n }\n try {\n return parseOwnedProps(raw);\n } catch (error) {\n throw new TypeError(`ZR_PROPS: island ${identity.component}: ${String(error)}`);\n }\n}\n\n/**\n * Test-only seam. Returns whether the given element has an entry in the\n * module-private `pendingCancels` Map. Used to assert that a synchronous\n * scheduler fire does not leave a stale entry behind. (#743)\n */\nexport function __hasPendingCancelForTests(element: Element): boolean {\n return pendingCancels.has(element);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/zudo-react/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["export { hydrate, mount } from \"./hydrate.js\";\nexport { parseProps } from \"./props-transport.js\";\nexport type { RootHandle, RootOptions } from \"./root.js\";\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ReadonlySignal } from "./reactive-types.js";
|
|
2
|
+
export type Key = string | number;
|
|
3
|
+
export type Scalar = string | number | boolean | null | undefined;
|
|
4
|
+
export type Child = Scalar | Description | ReadonlySignal<Scalar> | readonly Child[];
|
|
5
|
+
export type Component<P = Record<string, unknown>> = (props: P) => Child;
|
|
6
|
+
export declare const Fragment: unique symbol;
|
|
7
|
+
export type ElementType = string | Component<any> | typeof import("../island.js").Island | typeof Fragment;
|
|
8
|
+
export interface Description {
|
|
9
|
+
readonly $$zudo: "zudo-react.description.v1";
|
|
10
|
+
readonly type: ElementType;
|
|
11
|
+
readonly props: Readonly<Record<string, unknown>>;
|
|
12
|
+
readonly key: Key | null;
|
|
13
|
+
}
|
|
14
|
+
export declare function createDescription(type: ElementType, props: Record<string, unknown> | null, key?: Key | undefined): Description;
|
|
15
|
+
export declare function isDescription(value: unknown): value is Description;
|
|
16
|
+
export declare function flattenChildren(children: Child): readonly Exclude<Child, readonly Child[] | boolean | null | undefined>[];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export const Fragment = Symbol.for("@takazudo/zfb/zudo-react/fragment-v1");
|
|
2
|
+
function valueKind(value) {
|
|
3
|
+
if (value === null)
|
|
4
|
+
return "null";
|
|
5
|
+
if (Array.isArray(value))
|
|
6
|
+
return "array";
|
|
7
|
+
if (typeof value === "object" && value instanceof Promise)
|
|
8
|
+
return "promise";
|
|
9
|
+
return typeof value;
|
|
10
|
+
}
|
|
11
|
+
function validKey(value) {
|
|
12
|
+
return typeof value === "string" || (typeof value === "number" && Number.isFinite(value));
|
|
13
|
+
}
|
|
14
|
+
export function createDescription(type, props, key) {
|
|
15
|
+
const copy = { ...props };
|
|
16
|
+
const resolved = key === undefined ? copy.key : key;
|
|
17
|
+
if (resolved !== undefined && resolved !== null && !validKey(resolved)) {
|
|
18
|
+
throw new TypeError(`Invalid key: ${valueKind(resolved)}`);
|
|
19
|
+
}
|
|
20
|
+
delete copy.key;
|
|
21
|
+
return {
|
|
22
|
+
$$zudo: "zudo-react.description.v1",
|
|
23
|
+
type,
|
|
24
|
+
props: copy,
|
|
25
|
+
key: resolved == null ? null : resolved,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function isDescription(value) {
|
|
29
|
+
return (typeof value === "object" &&
|
|
30
|
+
value !== null &&
|
|
31
|
+
"$$zudo" in value &&
|
|
32
|
+
value.$$zudo === "zudo-react.description.v1" &&
|
|
33
|
+
"type" in value &&
|
|
34
|
+
"props" in value &&
|
|
35
|
+
"key" in value);
|
|
36
|
+
}
|
|
37
|
+
function isReactive(value) {
|
|
38
|
+
return (typeof value === "object" &&
|
|
39
|
+
value !== null &&
|
|
40
|
+
"$$zudoReactive" in value &&
|
|
41
|
+
value.$$zudoReactive === "zudo-react.reactive.v1");
|
|
42
|
+
}
|
|
43
|
+
export function flattenChildren(children) {
|
|
44
|
+
const result = [];
|
|
45
|
+
function visit(value, path) {
|
|
46
|
+
if (value === null || value === undefined || typeof value === "boolean")
|
|
47
|
+
return;
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
value.forEach((child, index) => visit(child, `${path}[${index}]`));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (typeof value === "string" ||
|
|
53
|
+
(typeof value === "number" && Number.isFinite(value)) ||
|
|
54
|
+
isDescription(value) ||
|
|
55
|
+
isReactive(value)) {
|
|
56
|
+
result.push(value);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
throw new TypeError(`Invalid child ${valueKind(value)} at ${path} in parent <root>`);
|
|
60
|
+
}
|
|
61
|
+
visit(children, "children");
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=description.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"description.js","sourceRoot":"","sources":["../../src/zudo-react/description.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReadonlySignal } from \"./reactive-types.js\";\n\nexport type Key = string | number;\nexport type Scalar = string | number | boolean | null | undefined;\nexport type Child = Scalar | Description | ReadonlySignal<Scalar> | readonly Child[];\nexport type Component<P = Record<string, unknown>> = (props: P) => Child;\nexport const Fragment: unique symbol = Symbol.for(\n \"@takazudo/zfb/zudo-react/fragment-v1\",\n) as typeof Fragment;\nexport type ElementType =\n | string\n | Component<any>\n | typeof import(\"../island.js\").Island\n | typeof Fragment;\n\nexport interface Description {\n readonly $$zudo: \"zudo-react.description.v1\";\n readonly type: ElementType;\n readonly props: Readonly<Record<string, unknown>>;\n readonly key: Key | null;\n}\n\nfunction valueKind(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"array\";\n if (typeof value === \"object\" && value instanceof Promise) return \"promise\";\n return typeof value;\n}\n\nfunction validKey(value: unknown): value is Key {\n return typeof value === \"string\" || (typeof value === \"number\" && Number.isFinite(value));\n}\n\nexport function createDescription(\n type: ElementType,\n props: Record<string, unknown> | null,\n key?: Key | undefined,\n): Description {\n const copy = { ...props };\n const resolved = key === undefined ? copy.key : key;\n if (resolved !== undefined && resolved !== null && !validKey(resolved)) {\n throw new TypeError(`Invalid key: ${valueKind(resolved)}`);\n }\n delete copy.key;\n return {\n $$zudo: \"zudo-react.description.v1\",\n type,\n props: copy,\n key: resolved == null ? null : resolved,\n };\n}\n\nexport function isDescription(value: unknown): value is Description {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"$$zudo\" in value &&\n value.$$zudo === \"zudo-react.description.v1\" &&\n \"type\" in value &&\n \"props\" in value &&\n \"key\" in value\n );\n}\n\nfunction isReactive(value: unknown): value is ReadonlySignal<Scalar> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"$$zudoReactive\" in value &&\n value.$$zudoReactive === \"zudo-react.reactive.v1\"\n );\n}\n\nexport function flattenChildren(\n children: Child,\n): readonly Exclude<Child, readonly Child[] | boolean | null | undefined>[] {\n const result: Exclude<Child, readonly Child[] | boolean | null | undefined>[] = [];\n function visit(value: unknown, path: string): void {\n if (value === null || value === undefined || typeof value === \"boolean\") return;\n if (Array.isArray(value)) {\n value.forEach((child, index) => visit(child, `${path}[${index}]`));\n return;\n }\n if (\n typeof value === \"string\" ||\n (typeof value === \"number\" && Number.isFinite(value)) ||\n isDescription(value) ||\n isReactive(value)\n ) {\n result.push(value as (typeof result)[number]);\n return;\n }\n throw new TypeError(`Invalid child ${valueKind(value)} at ${path} in parent <root>`);\n }\n visit(children, \"children\");\n return result;\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Subscription } from "./reactive.js";
|
|
2
|
+
import type { ReadonlySignal } from "./reactive-types.js";
|
|
3
|
+
import type { RuntimeScope } from "./scope.js";
|
|
4
|
+
import type { RootOptions } from "./root.js";
|
|
5
|
+
export declare function isReactive(value: unknown): value is ReadonlySignal<unknown>;
|
|
6
|
+
export declare function read(value: unknown): unknown;
|
|
7
|
+
export declare function styleText(value: unknown): string;
|
|
8
|
+
export declare function setAttribute(element: Element, name: string, value: unknown): void;
|
|
9
|
+
export declare function bind<T>(source: ReadonlySignal<T>, scope: RuntimeScope, options: RootOptions, container: Element, path: string, apply: (value: T) => void, initial: T): Subscription;
|
|
10
|
+
export declare function listener(name: string): {
|
|
11
|
+
name: string;
|
|
12
|
+
capture: boolean;
|
|
13
|
+
} | null;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { subscribe, readSnapshot } from "./reactive.js";
|
|
2
|
+
import { diagnostic, report, rootPath } from "./root.js";
|
|
3
|
+
export function isReactive(value) {
|
|
4
|
+
return (typeof value === "object" &&
|
|
5
|
+
value !== null &&
|
|
6
|
+
"$$zudoReactive" in value &&
|
|
7
|
+
value.$$zudoReactive === "zudo-react.reactive.v1");
|
|
8
|
+
}
|
|
9
|
+
export function read(value) {
|
|
10
|
+
return isReactive(value) ? readSnapshot(value) : value;
|
|
11
|
+
}
|
|
12
|
+
export function styleText(value) {
|
|
13
|
+
if (typeof value === "string")
|
|
14
|
+
return value;
|
|
15
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
16
|
+
throw new TypeError("ZR_STYLE");
|
|
17
|
+
let result = "";
|
|
18
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
19
|
+
if (!/^(--[a-zA-Z0-9_-]+|[a-z][a-z0-9-]*)$/.test(name) || /[A-Z]/.test(name))
|
|
20
|
+
throw new TypeError(`ZR_STYLE: ${name}`);
|
|
21
|
+
if (entry == null)
|
|
22
|
+
continue;
|
|
23
|
+
if (typeof entry !== "string" && !(typeof entry === "number" && Number.isFinite(entry)))
|
|
24
|
+
throw new TypeError(`ZR_STYLE: ${name}`);
|
|
25
|
+
result += `${name}:${entry};`;
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
const booleanAttrs = new Set("hidden inert readonly autofocus required disabled checked selected multiple open controls muted loop autoplay novalidate formnovalidate allowfullscreen".split(" "));
|
|
30
|
+
export function setAttribute(element, name, value) {
|
|
31
|
+
if (value == null || (booleanAttrs.has(name) && value === false)) {
|
|
32
|
+
element.removeAttribute(name);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const text = name === "style" ? styleText(value) : booleanAttrs.has(name) ? "" : String(value);
|
|
36
|
+
if (element.getAttribute(name) !== text)
|
|
37
|
+
element.setAttribute(name, text);
|
|
38
|
+
}
|
|
39
|
+
export function bind(source, scope, options, container, path, apply, initial) {
|
|
40
|
+
let previous = initial;
|
|
41
|
+
const subscription = subscribe(() => {
|
|
42
|
+
const next = source.value;
|
|
43
|
+
if (Object.is(previous, next))
|
|
44
|
+
return;
|
|
45
|
+
previous = next;
|
|
46
|
+
apply(next);
|
|
47
|
+
}, {
|
|
48
|
+
active: () => scope.active,
|
|
49
|
+
report: (code, actual) => report(options, diagnostic(options, code, "update", `${rootPath(container)}${path}`, "binding update", actual)),
|
|
50
|
+
});
|
|
51
|
+
subscription.run();
|
|
52
|
+
return subscription;
|
|
53
|
+
}
|
|
54
|
+
export function listener(name) {
|
|
55
|
+
const match = /^on:([A-Za-z][A-Za-z0-9_-]*)(:capture)?$/.exec(name);
|
|
56
|
+
return match ? { name: match[1], capture: Boolean(match[2]) } : null;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=dom-bindings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-bindings.js","sourceRoot":"","sources":["../../src/zudo-react/dom-bindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { subscribe, readSnapshot, type Subscription } from \"./reactive.js\";\nimport type { ReadonlySignal } from \"./reactive-types.js\";\nimport type { RuntimeScope } from \"./scope.js\";\nimport type { RootOptions } from \"./root.js\";\nimport { diagnostic, report, rootPath } from \"./root.js\";\n\nexport function isReactive(value: unknown): value is ReadonlySignal<unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"$$zudoReactive\" in value &&\n value.$$zudoReactive === \"zudo-react.reactive.v1\"\n );\n}\nexport function read(value: unknown): unknown {\n return isReactive(value) ? readSnapshot(value) : value;\n}\nexport function styleText(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (value === null || typeof value !== \"object\" || Array.isArray(value))\n throw new TypeError(\"ZR_STYLE\");\n let result = \"\";\n for (const [name, entry] of Object.entries(value)) {\n if (!/^(--[a-zA-Z0-9_-]+|[a-z][a-z0-9-]*)$/.test(name) || /[A-Z]/.test(name))\n throw new TypeError(`ZR_STYLE: ${name}`);\n if (entry == null) continue;\n if (typeof entry !== \"string\" && !(typeof entry === \"number\" && Number.isFinite(entry)))\n throw new TypeError(`ZR_STYLE: ${name}`);\n result += `${name}:${entry};`;\n }\n return result;\n}\nconst booleanAttrs = new Set(\n \"hidden inert readonly autofocus required disabled checked selected multiple open controls muted loop autoplay novalidate formnovalidate allowfullscreen\".split(\n \" \",\n ),\n);\nexport function setAttribute(element: Element, name: string, value: unknown): void {\n if (value == null || (booleanAttrs.has(name) && value === false)) {\n element.removeAttribute(name);\n return;\n }\n const text = name === \"style\" ? styleText(value) : booleanAttrs.has(name) ? \"\" : String(value);\n if (element.getAttribute(name) !== text) element.setAttribute(name, text);\n}\nexport function bind<T>(\n source: ReadonlySignal<T>,\n scope: RuntimeScope,\n options: RootOptions,\n container: Element,\n path: string,\n apply: (value: T) => void,\n initial: T,\n): Subscription {\n let previous = initial;\n const subscription = subscribe(\n () => {\n const next = source.value;\n if (Object.is(previous, next)) return;\n previous = next;\n apply(next);\n },\n {\n active: () => scope.active,\n report: (code, actual) =>\n report(\n options,\n diagnostic(\n options,\n code,\n \"update\",\n `${rootPath(container)}${path}`,\n \"binding update\",\n actual,\n ),\n ),\n },\n );\n subscription.run();\n return subscription;\n}\nexport function listener(name: string): { name: string; capture: boolean } | null {\n const match = /^on:([A-Za-z][A-Za-z0-9_-]*)(:capture)?$/.exec(name);\n return match ? { name: match[1]!, capture: Boolean(match[2]) } : null;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape.js","sourceRoot":"","sources":["../../src/zudo-react/escape.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnD,CAAC","sourcesContent":["export function escapeText(value: string): string {\n return value.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\nexport function escapeAttribute(value: string): string {\n return escapeText(value).replace(/\"/g, \""\");\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Signal } from "./reactive-types.js";
|
|
2
|
+
import type { RuntimeScope } from "./scope.js";
|
|
3
|
+
import { type RootOptions } from "./root.js";
|
|
4
|
+
type Control = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
5
|
+
type Model = Signal<string | boolean | null>;
|
|
6
|
+
export interface FormPlan {
|
|
7
|
+
element: Element;
|
|
8
|
+
props: Readonly<Record<string, unknown>>;
|
|
9
|
+
path: string;
|
|
10
|
+
}
|
|
11
|
+
interface Binding {
|
|
12
|
+
node: Control;
|
|
13
|
+
model: Model;
|
|
14
|
+
kind: "text" | "textarea" | "checkbox" | "select" | "radio";
|
|
15
|
+
read(): string | boolean | null;
|
|
16
|
+
write(value: string | boolean | null): void;
|
|
17
|
+
event: "input" | "change";
|
|
18
|
+
path: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class FormError extends TypeError {
|
|
21
|
+
readonly code: string;
|
|
22
|
+
readonly path: string;
|
|
23
|
+
readonly detail: string;
|
|
24
|
+
constructor(code: string, path: string, detail: string);
|
|
25
|
+
}
|
|
26
|
+
export declare function prepareForms(plans: FormPlan[], map: Map<Node, Node>, mode: "hydrate" | "mount", container: Element): Binding[];
|
|
27
|
+
export declare function reconcileForms(bindings: Binding[], mode: "hydrate" | "mount"): void;
|
|
28
|
+
export declare function activateForms(bindings: Binding[], scope: RuntimeScope, cleanups: Array<() => void>, options: RootOptions, container: Element): void;
|
|
29
|
+
export {};
|