@nifrajs/web-solid 5.5.1 → 5.6.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/dist/client.js +2 -2
  3. package/dist/client.js.map +1 -1
  4. package/dist/content.d.ts +1 -1
  5. package/dist/content.js +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +40 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/keep-alive-view.d.ts +35 -0
  10. package/dist/keep-alive-view.d.ts.map +1 -0
  11. package/dist/keep-alive-view.js +135 -0
  12. package/dist/keep-alive-view.js.map +1 -0
  13. package/dist/keep-alive.d.ts +25 -0
  14. package/dist/keep-alive.d.ts.map +1 -0
  15. package/dist/keep-alive.js +51 -0
  16. package/dist/keep-alive.js.map +1 -0
  17. package/dist/mdx.d.ts.map +1 -1
  18. package/dist/mdx.js +5 -16
  19. package/dist/mdx.js.map +1 -1
  20. package/dist/page-visibility.d.ts +28 -0
  21. package/dist/page-visibility.d.ts.map +1 -0
  22. package/dist/page-visibility.js +42 -0
  23. package/dist/page-visibility.js.map +1 -0
  24. package/dist/ppr-client.d.ts +9 -0
  25. package/dist/ppr-client.d.ts.map +1 -0
  26. package/dist/ppr-client.js +63 -0
  27. package/dist/ppr-client.js.map +1 -0
  28. package/dist/ppr.d.ts +37 -0
  29. package/dist/ppr.d.ts.map +1 -0
  30. package/dist/ppr.js +61 -0
  31. package/dist/ppr.js.map +1 -0
  32. package/dist/query.d.ts +4 -3
  33. package/dist/query.d.ts.map +1 -1
  34. package/dist/query.js +7 -8
  35. package/dist/query.js.map +1 -1
  36. package/dist/route-props.d.ts +5 -2
  37. package/dist/route-props.d.ts.map +1 -1
  38. package/dist/route-props.js +16 -7
  39. package/dist/route-props.js.map +1 -1
  40. package/dist/router.d.ts +3 -2
  41. package/dist/router.d.ts.map +1 -1
  42. package/dist/router.js +7 -3
  43. package/dist/router.js.map +1 -1
  44. package/dist/server-components/Outlet.jsx +1 -1
  45. package/dist/server-components/Outlet.jsx.map +1 -1
  46. package/package.json +16 -5
  47. package/src/client.ts +2 -2
  48. package/src/content.ts +1 -1
  49. package/src/index.ts +48 -4
  50. package/src/keep-alive-view.ts +202 -0
  51. package/src/keep-alive.ts +76 -0
  52. package/src/mdx.ts +5 -9
  53. package/src/page-visibility.ts +53 -0
  54. package/src/ppr-client.ts +77 -0
  55. package/src/ppr.ts +86 -0
  56. package/src/query.ts +13 -8
  57. package/src/route-props.ts +16 -6
  58. package/src/router.ts +8 -3
  59. package/src/server-components/Outlet.tsx +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,102 @@
1
1
  # @nifrajs/web-solid
2
2
 
3
+ ## 5.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f1d794e: `keepAlive` routes work with the Preact, Solid and Vue adapters as well as React and Svelte. Each of the three ships `usePageVisibility()`, `onPageHide` and `onPageShow` from its `/router` subpath; Vue keeps pages with its own `<KeepAlive>` and renders no wrapper elements. `@nifrajs/web-svelte/router` gains `usePageVisibility()`, and a `useBlocker` in a hidden Svelte page blocks nothing.
8
+
9
+ A page left with a route open in a modal is kept with it, and back to that entry opens the modal again. Islands in a kept page can pause with `onPageHide(el, fn)` and `onPageShow(el, fn)` from `@nifrajs/web/islands`. Server components in a kept page stay mounted while it is hidden: `bindComponentRouter` parks them on the page events, and outlets pass their host to `controller.unmount(instance, host)` so a parked page and the page on screen can hold the same instance. A parked component waits for its page, taken back when the page is shown and released when it is dropped; `controller.isParked(instance, host)` tells an outlet whose framework cleans up a hidden page's effects, as React's `<Activity>` does, to leave it parked. In Vue, a layout inside a kept branch reads the branch's visibility, and a page dropped inside a hidden branch unmounts. In Preact, as in React, props a layout adds with `cloneElement` reach a kept page.
10
+
11
+ The `nifra:pagehide` event fires as the router hides a page, while the page is still in the document and before the router's subscribers see the state that hides it.
12
+ - 4f40009: `useQuery` (and Solid's `createQuery`) take the query cache's options as a third argument: `staleTime`, and `live` to refetch on the live keys a page's loaders grant. React's `useQuery` now hands its options to the client whole.
13
+ - 7eab8d8: Experimental partial prerendering on Solid: `Hole` from the new `@nifrajs/web-solid/ppr` subpath places a hole and hydrates an interactive one as its own root, which keeps its state when the page reloads the hole. A hole's `render` returns JSX and its `fallback` is a function returning JSX. The adapter renders a hole's HTML with `renderFragment` under the hole's own hydration key prefix. Solid's client renders new DOM from plain strings under no Trusted Types policy, so a Solid app cannot enforce Trusted Types.
14
+
15
+ ### Patch Changes
16
+
17
+ - af398dc: A kept page's two wrappers, `[data-nifra-entry]` and `[data-nifra-page]`, are `<slot>` elements, which browsers lay out as `display: contents`. They carry no inline style, so under a `style-src` without `'unsafe-inline'` they take no box from the first paint and the console reports nothing, and a wrapper inside a `<p>` stays inside it.
18
+ - 9ebcb1f: Every `nifra mcp` project tool carries MCP tool annotations, so a host can tell the tools that only read the project from the ones that write files or run project code and ask before those. A tool that writes only under a flag, such as `nifra_review` with `fix` and `write`, is marked as a writer. A tool that imports the project's config or backend runs its top-level code, so `nifra_routes`, `nifra_context`, `nifra_openapi`, `nifra_diff`, `nifra_prove` and the `nifra_db_*` tools are marked as running project code. Each tool's input fields that had no description now have one. The `nifra --help` line for `nifra docs-mcp` names all six tools that server offers.
19
+
20
+ `entry.html` from `@nifrajs/content` is documented as unsanitized Markdown output: render it with `trustHtml(entry.html)` for content you wrote, or run it through `sanitizeHtml(entry.html, yourSanitizer)` when contributors or a CMS write it. The `<Content>` examples in the React, Preact and Solid adapters show the `trustHtml` call.
21
+ - dfb59d1: The Solid and Svelte MDX plugins load `@mdx-js/mdx` and `mdsvex` through the same optional-peer
22
+ loader as the Sass, PostCSS, StyleX and SVG plugins. A missing peer still fails with an install hint.
23
+ A peer that is installed but throws while loading now fails with that error as the cause, where it
24
+ was reported as not installed.
25
+ - 328003a: While an intercept boundary shows a route over the page, the route props describe the page underneath: `path`, the typed `search`, and so `useLocation`, `useSearch` and `useMatches`, come from the page's own path. Before, they read the modal's URL, so the page lost its query string and `useMatches` sliced the modal's URL against the page's route chain.
26
+ - 18c3d73: A reload of a path on screen keeps the identity of the parts of its data that it did not change. This covers an action's revalidation, `invalidate()`, the paths an action names with `revalidate()`, a live refresh, a fetcher loading its path again, and a target an intercept boundary holds. Plain objects and arrays compare by content, Dates by time, and array elements with an `id` pair by it, so a prepend or a reorder keeps every unchanged row, and each earlier element is kept for at most one new one; an array whose first 32 elements keep nothing is taken whole, later unchanged elements included. A plain JSON response with the same text as the one the page was read from reuses the page's data without parsing it; a response with deferred parts is always parsed. An unchanged reload publishes only its `pending` flag.
27
+
28
+ A page exports `shareData = false` to get fresh data on every reload. `FetchRouteData` takes an optional seventh argument, `read` (a `DataText`), after `purpose` and `hosts`, that a custom transport may ignore; the same-text skip then does not apply, while sharing still does.
29
+
30
+ The adapters' client mounts take advantage of it. React and Preact render each layout and the page memoized on its own props, with a layout's children read through context, so an unchanged reload re-renders neither a layout nor a memoized row. Vue passes each layout the next level as a stable slot. Svelte and Solid derive `data` and the layouts' data with an identity check, so an effect on them runs again only when a reload changed them; Solid's `<For>` then keeps every unchanged row and its DOM state. Svelte pages receive `data` as the router published it rather than as a deep reactive proxy of it. React, Preact and Vue keep `search` as the same object while the query is the same.
31
+ - Updated dependencies [676a1f0]
32
+ - Updated dependencies [f1a424d]
33
+ - Updated dependencies [a0ae2e6]
34
+ - Updated dependencies [0743b66]
35
+ - Updated dependencies [671a952]
36
+ - Updated dependencies [0ec3f30]
37
+ - Updated dependencies [caa1ef8]
38
+ - Updated dependencies [7c5fc94]
39
+ - Updated dependencies [13f6b38]
40
+ - Updated dependencies [d76bc3f]
41
+ - Updated dependencies [d76bc3f]
42
+ - Updated dependencies [4bc7d8d]
43
+ - Updated dependencies [b73319d]
44
+ - Updated dependencies [aa567fa]
45
+ - Updated dependencies [6b90278]
46
+ - Updated dependencies [5ce69b2]
47
+ - Updated dependencies [d43bc92]
48
+ - Updated dependencies [7810dc5]
49
+ - Updated dependencies [6126cb1]
50
+ - Updated dependencies [ef2d101]
51
+ - Updated dependencies [dec48fc]
52
+ - Updated dependencies [c403814]
53
+ - Updated dependencies [db0bacd]
54
+ - Updated dependencies [6582724]
55
+ - Updated dependencies [f48b257]
56
+ - Updated dependencies [0222181]
57
+ - Updated dependencies [f1d794e]
58
+ - Updated dependencies [b7fb47f]
59
+ - Updated dependencies [c387fb9]
60
+ - Updated dependencies [8db6a2c]
61
+ - Updated dependencies [4b196d2]
62
+ - Updated dependencies [1b4b448]
63
+ - Updated dependencies [f39ee8c]
64
+ - Updated dependencies [4f40009]
65
+ - Updated dependencies [05608b9]
66
+ - Updated dependencies [baa926f]
67
+ - Updated dependencies [2eabd83]
68
+ - Updated dependencies [328003a]
69
+ - Updated dependencies [a6010f9]
70
+ - Updated dependencies [87f475d]
71
+ - Updated dependencies [3e1e275]
72
+ - Updated dependencies [c4cf782]
73
+ - Updated dependencies [9efc061]
74
+ - Updated dependencies [9889273]
75
+ - Updated dependencies [fb1cc25]
76
+ - Updated dependencies [23d0644]
77
+ - Updated dependencies [15c9d60]
78
+ - Updated dependencies [78e64e2]
79
+ - Updated dependencies [f25a8d2]
80
+ - Updated dependencies [778e430]
81
+ - Updated dependencies [18c3d73]
82
+ - Updated dependencies [7ec0f81]
83
+ - Updated dependencies [2538b70]
84
+ - Updated dependencies [48f78f0]
85
+ - Updated dependencies [baaac3d]
86
+ - Updated dependencies [2c213b2]
87
+ - Updated dependencies [db9f041]
88
+ - Updated dependencies [033ed0f]
89
+ - Updated dependencies [1704919]
90
+ - Updated dependencies [375711b]
91
+ - Updated dependencies [bb35ad0]
92
+ - Updated dependencies [c7d233d]
93
+ - Updated dependencies [feff82f]
94
+ - Updated dependencies [a540dad]
95
+ - @nifrajs/core@5.6.0
96
+ - @nifrajs/web@5.6.0
97
+ - @nifrajs/i18n@5.6.0
98
+ - @nifrajs/image@5.6.0
99
+
3
100
  ## 5.5.1
4
101
 
5
102
  ### Patch Changes
package/dist/client.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * build; kept in its own entry so SSR code never ships to the client bundle. No JSX - Solid's package
7
7
  * build is plain `tsc`, so this uses Solid's runtime functions directly, like `compose`.
8
8
  */
9
- import { createSignal } from "solid-js";
9
+ import { createMemo, createSignal } from "solid-js";
10
10
  import { hydrate as solidHydrate, render as solidRender } from "solid-js/web";
11
11
  import { compose } from "./compose.js";
12
12
  import { setMountedRouter } from "./fetcher.js";
@@ -50,7 +50,7 @@ export function mountRouter(options) {
50
50
  update = setSnapshot;
51
51
  // The matched chain is fixed for this mount (routeId is constant here); a route *change* disposes
52
52
  // and re-mounts below, so the root render fn reads no signal and never re-runs on its own.
53
- return compose(routes[initial.routeId] ?? [], routeProps(snapshot, searchSchemas, matchChains))();
53
+ return compose(routes[initial.routeId] ?? [], routeProps(snapshot, searchSchemas, matchChains, (read) => createMemo(read)))();
54
54
  }, el);
55
55
  };
56
56
  mount(true);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,cAAc,CAAA;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,sGAAsG;AACtG,gFAAgF;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB,EAAE,SAAkB;IACvF,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,SAAoB,CAAC,CAAA;AAC3D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IACzE,gBAAgB,CAAC,MAAM,CAAC,CAAA,CAAC,kEAAkE;IAC3F,MAAM,EAAE,GAAG,SAAoB,CAAA;IAE/B,IAAI,OAAiC,CAAA;IACrC,IAAI,cAAc,GAAkB,IAAI,CAAA;IACxC,oGAAoG;IACpG,IAAI,MAAM,GAAoE,IAAI,CAAA;IAElF,MAAM,KAAK,GAAG,CAAC,KAAc,EAAQ,EAAE;QACrC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QACjC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAA;QACnD,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE;YACtB,kGAAkG;YAClG,6FAA6F;YAC7F,2DAA2D;YAC3D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;YACrD,MAAM,GAAG,WAAW,CAAA;YACpB,kGAAkG;YAClG,2FAA2F;YAC3F,OAAO,OAAO,CACZ,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAC7B,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,CACjD,EAAE,CAAA;QACL,CAAC,EAAE,EAAE,CAAC,CAAA;IACR,CAAC,CAAA;IAED,KAAK,CAAC,IAAI,CAAC,CAAA;IACX,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE;QACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QAClC,gGAAgG;QAChG,yFAAyF;QACzF,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc;YAAE,OAAM;QACnE,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAA,CAAC,wEAAwE;QAC7F,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,EAAE,CAAA,CAAC,qDAAqD;YACjE,KAAK,CAAC,KAAK,CAAC,CAAA;QACd,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,cAAc,CAAA;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,sGAAsG;AACtG,gFAAgF;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB,EAAE,SAAkB;IACvF,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,SAAoB,CAAC,CAAA;AAC3D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IACzE,gBAAgB,CAAC,MAAM,CAAC,CAAA,CAAC,kEAAkE;IAC3F,MAAM,EAAE,GAAG,SAAoB,CAAA;IAE/B,IAAI,OAAiC,CAAA;IACrC,IAAI,cAAc,GAAkB,IAAI,CAAA;IACxC,oGAAoG;IACpG,IAAI,MAAM,GAAoE,IAAI,CAAA;IAElF,MAAM,KAAK,GAAG,CAAC,KAAc,EAAQ,EAAE;QACrC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QACjC,cAAc,GAAG,OAAO,CAAC,OAAO,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAA;QACnD,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE;YACtB,kGAAkG;YAClG,6FAA6F;YAC7F,2DAA2D;YAC3D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;YACrD,MAAM,GAAG,WAAW,CAAA;YACpB,kGAAkG;YAClG,2FAA2F;YAC3F,OAAO,OAAO,CACZ,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAC7B,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAC7E,EAAE,CAAA;QACL,CAAC,EAAE,EAAE,CAAC,CAAA;IACR,CAAC,CAAA;IAED,KAAK,CAAC,IAAI,CAAC,CAAA;IACX,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE;QACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QAClC,gGAAgG;QAChG,yFAAyF;QACzF,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc;YAAE,OAAM;QACnE,IAAI,QAAQ,CAAC,OAAO,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAA,CAAC,wEAAwE;QAC7F,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,EAAE,CAAA,CAAC,qDAAqD;YACjE,KAAK,CAAC,KAAK,CAAC,CAAA;QACd,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
package/dist/content.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * `@nifrajs/web-solid/content` - render pre-rendered HTML (e.g. a `@nifrajs/content` collection entry's
3
3
  * `.html`) into the DOM. Solid sets `innerHTML` reactively on a `<Dynamic>` element. Pairs with content
4
- * collections: `<Content html={entry.html} />`. No JSX (`createComponent`/`Dynamic`), so it builds with
4
+ * collections: `<Content html={trustHtml(entry.html)} />`, with `trustHtml` from `@nifrajs/web`. No JSX (`createComponent`/`Dynamic`), so it builds with
5
5
  * plain `tsc`.
6
6
  *
7
7
  * Security: injects raw HTML, so `html` MUST be trusted (your own Markdown/content, rendered at
package/dist/content.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * `@nifrajs/web-solid/content` - render pre-rendered HTML (e.g. a `@nifrajs/content` collection entry's
3
3
  * `.html`) into the DOM. Solid sets `innerHTML` reactively on a `<Dynamic>` element. Pairs with content
4
- * collections: `<Content html={entry.html} />`. No JSX (`createComponent`/`Dynamic`), so it builds with
4
+ * collections: `<Content html={trustHtml(entry.html)} />`, with `trustHtml` from `@nifrajs/web`. No JSX (`createComponent`/`Dynamic`), so it builds with
5
5
  * plain `tsc`.
6
6
  *
7
7
  * Security: injects raw HTML, so `html` MUST be trusted (your own Markdown/content, rendered at
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAgDjD,6EAA6E;AAC7E,eAAO,MAAM,YAAY,EAAE,aA8B1B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,aAAa,EAAiD,MAAM,cAAc,CAAA;AAsEhG,6EAA6E;AAC7E,eAAO,MAAM,YAAY,EAAE,aAoD1B,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { sharedConfig } from "solid-js";
2
2
  import { generateHydrationScript, renderToStream as solidRenderToStream, renderToString as solidRenderToString, } from "solid-js/web";
3
3
  import { compose } from "./compose.js";
4
+ import { documentTree, KeepAliveView } from "./keep-alive-view.js";
4
5
  const HYDRATION_HEAD = generateHydrationScript();
5
6
  // An unset NODE_ENV counts as production, as for the framework's own error pages.
6
7
  const showsErrors = () => {
@@ -33,6 +34,20 @@ function redactingErrors(app) {
33
34
  return app();
34
35
  };
35
36
  }
37
+ const noRef = () => undefined;
38
+ /** The chain as the browser's keep-alive view renders it, in an app with a `keepAlive` route. */
39
+ function documentView(chain, props, slots) {
40
+ const state = { routeId: "", params: {}, path: "", data: props.data, pending: false };
41
+ const tree = documentTree(chain, state, slots);
42
+ return () => KeepAliveView({
43
+ tree: () => tree,
44
+ shown: props,
45
+ mount: { propsOf: () => props, chainOf: () => chain, entry: noRef, page: noRef },
46
+ });
47
+ }
48
+ const appOf = (chain, props, options) => redactingErrors(options?.slots === undefined
49
+ ? compose(chain, props)
50
+ : documentView(chain, props, options.slots));
36
51
  /** The Solid server render adapter - pass to @nifrajs/web's `renderPage`. */
37
52
  export const solidAdapter = {
38
53
  // Synchronous one-pass render for non-deferred pages (renderPage's buffered fast path). Solid's
@@ -41,11 +56,34 @@ export const solidAdapter = {
41
56
  // streaming machinery - the heaviest of the five renderers on Bun. A page that defer()s/Suspends
42
57
  // takes `renderToStream` below (progressive resolution needs it).
43
58
  renderToString(chain, props, options) {
44
- const app = redactingErrors(compose(chain, props));
59
+ const app = appOf(chain, props, options);
45
60
  return options?.nonce === undefined
46
61
  ? solidRenderToString(app)
47
62
  : solidRenderToString(app, { nonce: options.nonce });
48
63
  },
64
+ // A partially prerendered hole's HTML: its own root under `renderId`, so its hydration keys and
65
+ // `createUniqueId`s never collide with the page's, and its JSX runs inside the render that keys it.
66
+ // Without a prefix (a fallback, never hydrated) it carries no hydration keys at all.
67
+ renderFragment(ui, options) {
68
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: a hole's render returns Solid output; the seam erases it to unknown.
69
+ const view = () => ui();
70
+ // `renderToString` leaves its context in Solid's shared config; a page mid-render keeps its own.
71
+ const page = sharedConfig.context;
72
+ try {
73
+ return options.idPrefix === undefined
74
+ ? solidRenderToString(() => {
75
+ // On the root context, so nodes resolved after `view` returns are unkeyed too.
76
+ if (sharedConfig.context !== undefined)
77
+ Reflect.set(sharedConfig.context, "noHydrate", true);
78
+ return view();
79
+ })
80
+ : solidRenderToString(view, { renderId: options.idPrefix });
81
+ }
82
+ finally {
83
+ // Unset included: `context` is an optional property.
84
+ Reflect.set(sharedConfig, "context", page);
85
+ }
86
+ },
49
87
  renderToStream(chain, props, options) {
50
88
  // Solid's `renderToStream` streams `Uint8Array` chunks into a Web `WritableStream` via
51
89
  // `pipeTo` (fire-and-forget - returns void); pipe into a TransformStream and hand back the
@@ -53,7 +91,7 @@ export const solidAdapter = {
53
91
  // <head>) seeds client hydration. A render failure errors `ts.readable`, which `renderPage`
54
92
  // surfaces on the response body. The nonce reaches the resource and boundary scripts Solid streams.
55
93
  const ts = new TransformStream();
56
- const app = redactingErrors(compose(chain, props));
94
+ const app = appOf(chain, props, options);
57
95
  const stream = options?.nonce === undefined
58
96
  ? solidRenderToStream(app)
59
97
  : solidRenderToStream(app, { nonce: options.nonce });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The view of an app with a `keepAlive` route: the page on screen and every kept page as a tree of
3
+ * slots (`slotTree` from `@nifrajs/web/keep-alive`), grouped by the layouts they share. The server
4
+ * renders it with the one page a document shows and the browser hydrates it, so both sides create the
5
+ * same components in the same order and Solid's hydration keys line up.
6
+ *
7
+ * A slot is keyed by its node's key, not the node object: a node is replaced whenever its state or its
8
+ * visibility changes, and keying on it would remount the page. A slot reads its node through a memo,
9
+ * so a hidden page, whose node the tree keeps, updates nothing while it is hidden.
10
+ */
11
+ import type { RenderProps, RouterState } from "@nifrajs/web";
12
+ import type { SlotNode } from "@nifrajs/web/keep-alive";
13
+ import { type Accessor, type JSX } from "solid-js";
14
+ /** What the view renders with: one per mount, on the server or in the browser. */
15
+ export interface KeepAliveViewMount {
16
+ /** The props of a state, as getters over it. */
17
+ readonly propsOf: (state: Accessor<RouterState>) => RenderProps;
18
+ readonly chainOf: (state: RouterState) => readonly unknown[];
19
+ readonly entry: (key: string) => ((element: Element) => void) | undefined;
20
+ readonly page: (key: string) => ((element: Element) => void) | undefined;
21
+ }
22
+ export interface KeepAliveViewProps {
23
+ readonly tree: Accessor<readonly SlotNode[]>;
24
+ /** The props of the state on screen, which the layouts every page shares render with. */
25
+ readonly shown: RenderProps;
26
+ readonly mount: KeepAliveViewMount;
27
+ }
28
+ /** The keep-alive view. */
29
+ export declare function KeepAliveView(props: KeepAliveViewProps): JSX.Element;
30
+ /**
31
+ * The tree of a server render: the chain as one path of slot nodes, the entries at `slots` inside
32
+ * the slot wrappers, which is what the browser's first render builds from the same state.
33
+ */
34
+ export declare function documentTree(chain: readonly unknown[], state: RouterState, slots: readonly number[]): readonly SlotNode[];
35
+ //# sourceMappingURL=keep-alive-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keep-alive-view.d.ts","sourceRoot":"","sources":["../src/keep-alive-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EACL,KAAK,QAAQ,EAMb,KAAK,GAAG,EAGT,MAAM,UAAU,CAAA;AAKjB,kFAAkF;AAClF,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,KAAK,WAAW,CAAA;IAC/D,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,SAAS,OAAO,EAAE,CAAA;IAC5D,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;IACzE,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;CACzE;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,QAAQ,EAAE,CAAC,CAAA;IAC5C,yFAAyF;IACzF,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;CACnC;AA6HD,2BAA2B;AAC3B,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAIpE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,SAAS,QAAQ,EAAE,CAoBrB"}
@@ -0,0 +1,135 @@
1
+ import { createComponent, createComputed, createMemo, For, on, untrack, } from "solid-js";
2
+ import { Dynamic } from "solid-js/web";
3
+ import { PageContext } from "./page-visibility.js";
4
+ import { RenderPropsContext, SearchContext } from "./router.js";
5
+ const EMPTY_SEARCH = Object.freeze({});
6
+ // The providers `compose` puts around a chain, for one slot's props.
7
+ const withRouteContext = (props, children) => createComponent(SearchContext.Provider, {
8
+ value: () => props.search ?? EMPTY_SEARCH,
9
+ get children() {
10
+ return createComponent(RenderPropsContext.Provider, {
11
+ value: props,
12
+ get children() {
13
+ return children();
14
+ },
15
+ });
16
+ },
17
+ });
18
+ // The page's own chain from `depth` on: an `_error` boundary, then the page.
19
+ const pageChain = (chain, depth, props) => {
20
+ if (depth >= chain.length - 1)
21
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: a chain holds the route's modules' default exports, its last entry the page component
22
+ return createComponent(chain[chain.length - 1], props);
23
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: an entry between the layouts and the page is the `_error` boundary component
24
+ return createComponent(chain[depth], {
25
+ get data() {
26
+ return props.layoutData?.[depth] ?? null;
27
+ },
28
+ get boundaries() {
29
+ return props.boundaries;
30
+ },
31
+ get children() {
32
+ return pageChain(chain, depth + 1, props);
33
+ },
34
+ });
35
+ };
36
+ const sameKeys = (a, b) => a.length === b.length && a.every((key, i) => key === b[i]);
37
+ function Level(props) {
38
+ const keys = createMemo(() => props.nodes().map((node) => node.key), [], { equals: sameKeys });
39
+ return createComponent(For, {
40
+ get each() {
41
+ return keys();
42
+ },
43
+ children: (key) => createComponent(Slot, { key, nodes: props.nodes, mount: props.mount }),
44
+ });
45
+ }
46
+ function Slot(props) {
47
+ const { key, mount } = props;
48
+ const find = () => props.nodes().find((node) => node.key === key);
49
+ const first = untrack(find);
50
+ if (first === undefined)
51
+ throw new Error(`[nifra/web-solid] no slot node "${key}"`);
52
+ // The last node with this key stays while the slot is being removed with it.
53
+ const node = createMemo((last) => find() ?? last, first);
54
+ const state = createMemo(() => node().state);
55
+ const hidden = createMemo(() => node().hidden);
56
+ const slotProps = mount.propsOf(state);
57
+ // A key keeps its depth, its wrappers and its chain: a page's key is one instance of one route, a
58
+ // layout's key the layout every page under it shares.
59
+ const { depth } = first;
60
+ const chain = mount.chainOf(first.state);
61
+ const content = () => first.children === undefined
62
+ ? pageChain(chain, depth, slotProps)
63
+ : // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: a chain entry above the page is a layout module's default export, a layout component
64
+ createComponent(chain[depth], {
65
+ get data() {
66
+ return slotProps.layoutData?.[depth] ?? null;
67
+ },
68
+ get boundaries() {
69
+ return slotProps.boundaries;
70
+ },
71
+ get children() {
72
+ return createComponent(Level, { nodes: () => node().children ?? [], mount });
73
+ },
74
+ });
75
+ if (!first.wrapped)
76
+ return content();
77
+ const slot = { hidden, hide: new Set(), show: new Set() };
78
+ // A computation, not an effect: it runs as the tree changes, before the mount parks the page.
79
+ createComputed(on(hidden, (now, before) => {
80
+ if (before === undefined || now === before)
81
+ return;
82
+ for (const callback of [...(now ? slot.hide : slot.show)])
83
+ callback();
84
+ }));
85
+ return createComponent(Dynamic, {
86
+ component: "slot",
87
+ "data-nifra-entry": "",
88
+ ref: mount.entry(key),
89
+ get children() {
90
+ return createComponent(Dynamic, {
91
+ component: "slot",
92
+ "data-nifra-page": "",
93
+ ref: mount.page(key),
94
+ get children() {
95
+ return createComponent(PageContext.Provider, {
96
+ value: slot,
97
+ get children() {
98
+ return withRouteContext(slotProps, content);
99
+ },
100
+ });
101
+ },
102
+ });
103
+ },
104
+ });
105
+ }
106
+ /** The keep-alive view. */
107
+ export function KeepAliveView(props) {
108
+ return withRouteContext(props.shown, () => createComponent(Level, { nodes: props.tree, mount: props.mount }));
109
+ }
110
+ /**
111
+ * The tree of a server render: the chain as one path of slot nodes, the entries at `slots` inside
112
+ * the slot wrappers, which is what the browser's first render builds from the same state.
113
+ */
114
+ export function documentTree(chain, state, slots) {
115
+ const page = chain.length - 1;
116
+ let node = {
117
+ key: "\0page",
118
+ depth: page,
119
+ state,
120
+ hidden: false,
121
+ wrapped: slots.includes(page),
122
+ };
123
+ for (let depth = page - 1; depth >= 0; depth--) {
124
+ node = {
125
+ key: `\0layout${depth}`,
126
+ depth,
127
+ state,
128
+ hidden: false,
129
+ wrapped: slots.includes(depth),
130
+ children: [node],
131
+ };
132
+ }
133
+ return [node];
134
+ }
135
+ //# sourceMappingURL=keep-alive-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keep-alive-view.js","sourceRoot":"","sources":["../src/keep-alive-view.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @nifrajs/web-solid/keep-alive - the client mount of an app with a `keepAlive` route, which the
3
+ * generated client entry imports in place of `@nifrajs/web-solid/client` (whose exports it carries).
4
+ *
5
+ * One root renders the page on screen and every page the router keeps (`KeepAliveView`), grouped by
6
+ * the layouts they share; the DOM half takes a hidden page out of the document. A hidden page keeps
7
+ * running: `onPageHide`, `onPageShow` and `usePageVisibility` (from `@nifrajs/web-solid/router`) let
8
+ * it pause. Unlike the plain mount, a route change does not remount the root: Solid updates the tree
9
+ * in place, synchronously, so the DOM half runs right after each publish.
10
+ */
11
+ import type { MountRouterOptions } from "@nifrajs/web";
12
+ import { type KeepAliveRouter, type KeepAliveTable } from "@nifrajs/web/keep-alive";
13
+ export * from "./client.js";
14
+ export { onPageHide, onPageShow, usePageVisibility } from "./page-visibility.js";
15
+ /** `mountRouter`'s options in a keep-alive app: the generated entry adds where the wrappers go. */
16
+ export interface KeepAliveMountOptions extends MountRouterOptions {
17
+ readonly router: KeepAliveRouter;
18
+ readonly keepAlive: KeepAliveTable;
19
+ }
20
+ /**
21
+ * Hydrate the keep-alive view. Its first render matches the server's (the same view, with the slot
22
+ * wrappers the server rendered), so hydration claims the document as it is.
23
+ */
24
+ export declare function mountRouter(options: KeepAliveMountOptions): void;
25
+ //# sourceMappingURL=keep-alive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keep-alive.d.ts","sourceRoot":"","sources":["../src/keep-alive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAe,MAAM,cAAc,CAAA;AACnE,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,cAAc,EAGpB,MAAM,yBAAyB,CAAA;AAOhC,cAAc,aAAa,CAAA;AAC3B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAEhF,mGAAmG;AACnG,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAA;IAChC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAA;CACnC;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAsChE"}
@@ -0,0 +1,51 @@
1
+ import { createSlotParking, slotTree, } from "@nifrajs/web/keep-alive";
2
+ import { createMemo, createSignal } from "solid-js";
3
+ import { hydrate as solidHydrate } from "solid-js/web";
4
+ import { setMountedRouter } from "./fetcher.js";
5
+ import { KeepAliveView } from "./keep-alive-view.js";
6
+ import { routeProps } from "./route-props.js";
7
+ export * from "./client.js";
8
+ export { onPageHide, onPageShow, usePageVisibility } from "./page-visibility.js";
9
+ /**
10
+ * Hydrate the keep-alive view. Its first render matches the server's (the same view, with the slot
11
+ * wrappers the server rendered), so hydration claims the document as it is.
12
+ */
13
+ export function mountRouter(options) {
14
+ const { router, routes, searchSchemas, container, keepAlive: table } = options;
15
+ const matchChains = options.matchChains ?? {};
16
+ setMountedRouter(router);
17
+ const parking = createSlotParking();
18
+ let committed;
19
+ router.beforePublish((next) => parking.before(slotTree(next, matchChains, table, committed)));
20
+ let current = [];
21
+ let publish;
22
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: the generated entry passes the element the server rendered the app into
23
+ solidHydrate(() => {
24
+ const [state, setState] = createSignal(router.snapshot());
25
+ publish = (next) => setState(() => next);
26
+ const tree = createMemo(() => {
27
+ current = slotTree(state(), matchChains, table, current);
28
+ return current;
29
+ });
30
+ const mount = {
31
+ propsOf: (of) => routeProps(of, searchSchemas, matchChains, (read) => createMemo(read)),
32
+ chainOf: (of) => routes[of.routeId] ?? [],
33
+ entry: parking.entry,
34
+ page: parking.page,
35
+ };
36
+ return KeepAliveView({ tree, shown: mount.propsOf(state), mount });
37
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: the generated entry passes the element the server rendered the app into
38
+ }, container);
39
+ // Solid has updated the document by the time a publish returns: park what it hid, restore what it
40
+ // showed again.
41
+ const after = () => {
42
+ committed = current;
43
+ parking.after(current);
44
+ };
45
+ after();
46
+ router.subscribe(() => {
47
+ publish?.(router.snapshot());
48
+ after();
49
+ });
50
+ }
51
+ //# sourceMappingURL=keep-alive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keep-alive.js","sourceRoot":"","sources":["../src/keep-alive.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,iBAAiB,EAIjB,QAAQ,GACT,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,aAAa,EAA2B,MAAM,sBAAsB,CAAA;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,cAAc,aAAa,CAAA;AAC3B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAQhF;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAA8B;IACxD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;IAC9E,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAA;IAC7C,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACxB,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAA;IACnC,IAAI,SAA0C,CAAA;IAC9C,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IAE7F,IAAI,OAAO,GAAwB,EAAE,CAAA;IACrC,IAAI,OAAmD,CAAA;IACvD,yIAAyI;IACzI,YAAY,CAAC,GAAG,EAAE;QAChB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QACzD,OAAO,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE;YAC3B,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;YACxD,OAAO,OAAO,CAAA;QAChB,CAAC,CAAC,CAAA;QACF,MAAM,KAAK,GAAuB;YAChC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACvF,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE;YACzC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAA;QACD,OAAO,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAClE,yIAAyI;IAC3I,CAAC,EAAE,SAAoB,CAAC,CAAA;IACxB,kGAAkG;IAClG,gBAAgB;IAChB,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,SAAS,GAAG,OAAO,CAAA;QACnB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACxB,CAAC,CAAA;IACD,KAAK,EAAE,CAAA;IACP,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE;QACpB,OAAO,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC5B,KAAK,EAAE,CAAA;IACT,CAAC,CAAC,CAAA;AACJ,CAAC"}
package/dist/mdx.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mdx.d.ts","sourceRoot":"","sources":["../src/mdx.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AASpC;sEACsE;AACtE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAmCpE"}
1
+ {"version":3,"file":"mdx.d.ts","sourceRoot":"","sources":["../src/mdx.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AASpC;sEACsE;AACtE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CA+BpE"}
package/dist/mdx.js CHANGED
@@ -1,11 +1,3 @@
1
- var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
- return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
- });
6
- }
7
- return path;
8
- };
9
1
  /**
10
2
  * `solidMdxBunPlugin` - compile `.mdx` routes/files to **Solid** components. MDX is JSX-oriented but
11
3
  * Solid's JSX is compile-time, so this: (1) compiles MDX → JSX with `@mdx-js` (keeping JSX), pointing
@@ -17,7 +9,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
17
9
  import { transformAsync } from "@babel/core";
18
10
  // @ts-expect-error - no type declarations published
19
11
  import presetTypeScript from "@babel/preset-typescript";
20
- import { normalizeFilePath, rewriteSsrImports } from "@nifrajs/web/plugins/kit";
12
+ import { normalizeFilePath, requirePeer, rewriteSsrImports } from "@nifrajs/web/plugins/kit";
21
13
  // @ts-expect-error - no type declarations published
22
14
  import presetSolid from "babel-preset-solid";
23
15
  // Non-literal so tsc/consumers don't need `@mdx-js/mdx`'s types to typecheck this file (optional peer).
@@ -28,13 +20,10 @@ export function solidMdxBunPlugin(generate) {
28
20
  return {
29
21
  name: `nifra-solid-mdx-${generate}`,
30
22
  async setup(build) {
31
- let compile;
32
- try {
33
- compile = (await import(__rewriteRelativeImportExtension(MDX_MODULE, true))).compile;
34
- }
35
- catch {
36
- throw new Error("@nifrajs/web-solid/mdx: compiling `.mdx` needs the `@mdx-js/mdx` package - install it (`bun add @mdx-js/mdx`).");
37
- }
23
+ const { compile } = await requirePeer(MDX_MODULE, {
24
+ feature: "Solid MDX support",
25
+ install: "bun add @mdx-js/mdx",
26
+ });
38
27
  build.onLoad({ filter: /\.mdx(\?|$)/ }, async (args) => {
39
28
  const path = normalizeFilePath(args.path);
40
29
  // 1. MDX → JSX, with intrinsics provided by the Solid runtime (rendered via `<Dynamic>`).
package/dist/mdx.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mdx.js","sourceRoot":"","sources":["../src/mdx.ts"],"names":[],"mappings":";;;;;;;;AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,oDAAoD;AACpD,OAAO,gBAAgB,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC/E,oDAAoD;AACpD,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAG5C,wGAAwG;AACxG,MAAM,UAAU,GAAG,aAAa,CAAA;AAMhC;sEACsE;AACtE,MAAM,UAAU,iBAAiB,CAAC,QAAuB;IACvD,OAAO;QACL,IAAI,EAAE,mBAAmB,QAAQ,EAAE;QACnC,KAAK,CAAC,KAAK,CAAC,KAAK;YACf,IAAI,OAA+B,CAAA;YACnC,IAAI,CAAC;gBACH,OAAO,GAAI,CAAC,MAAM,MAAM,kCAAC,UAAU,QAAC,CAAiB,CAAC,OAAO,CAAA;YAC/D,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CACb,gHAAgH,CACjH,CAAA;YACH,CAAC;YACD,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBACrD,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACzC,0FAA0F;gBAC1F,MAAM,GAAG,GAAG,MAAM,CAChB,MAAM,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;oBACzC,GAAG,EAAE,IAAI;oBACT,oBAAoB,EAAE,gCAAgC;iBACvD,CAAC,CACH,CAAA;gBACD,4EAA4E;gBAC5E,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE;oBACvC,QAAQ,EAAE,GAAG,IAAI,MAAM;oBACvB,OAAO,EAAE;wBACP,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;wBAC7C,CAAC,gBAAgB,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;qBACpD;oBACD,OAAO,EAAE,KAAK;oBACd,UAAU,EAAE,KAAK;iBAClB,CAAC,CAAA;gBACF,OAAO,EAAE,QAAQ,EAAE,iBAAiB,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;YAC1F,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"mdx.js","sourceRoot":"","sources":["../src/mdx.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,oDAAoD;AACpD,OAAO,gBAAgB,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5F,oDAAoD;AACpD,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAG5C,wGAAwG;AACxG,MAAM,UAAU,GAAG,aAAa,CAAA;AAMhC;sEACsE;AACtE,MAAM,UAAU,iBAAiB,CAAC,QAAuB;IACvD,OAAO;QACL,IAAI,EAAE,mBAAmB,QAAQ,EAAE;QACnC,KAAK,CAAC,KAAK,CAAC,KAAK;YACf,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,WAAW,CAAc,UAAU,EAAE;gBAC7D,OAAO,EAAE,mBAAmB;gBAC5B,OAAO,EAAE,qBAAqB;aAC/B,CAAC,CAAA;YACF,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBACrD,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACzC,0FAA0F;gBAC1F,MAAM,GAAG,GAAG,MAAM,CAChB,MAAM,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;oBACzC,GAAG,EAAE,IAAI;oBACT,oBAAoB,EAAE,gCAAgC;iBACvD,CAAC,CACH,CAAA;gBACD,4EAA4E;gBAC5E,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE;oBACvC,QAAQ,EAAE,GAAG,IAAI,MAAM;oBACvB,OAAO,EAAE;wBACP,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;wBAC7C,CAAC,gBAAgB,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;qBACpD;oBACD,OAAO,EAAE,KAAK;oBACd,UAAU,EAAE,KAAK;iBAClB,CAAC,CAAA;gBACF,OAAO,EAAE,QAAQ,EAAE,iBAAiB,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;YAC1F,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Whether a page is on screen, for a `keepAlive` page that stays mounted while it is hidden. Pages read
3
+ * it through `@nifrajs/web-solid/router`; the keep-alive view provides it per kept slot.
4
+ */
5
+ import { type Accessor, type Context } from "solid-js";
6
+ /** What one kept slot provides: whether it is hidden, and the callbacks it runs as that changes. */
7
+ export interface PageSlot {
8
+ readonly hidden: Accessor<boolean>;
9
+ readonly hide: Set<() => void>;
10
+ readonly show: Set<() => void>;
11
+ }
12
+ export declare const PageContext: Context<PageSlot | undefined>;
13
+ /**
14
+ * Whether the page this component renders in is on screen, as an accessor: `false` while it is kept
15
+ * hidden behind another page, where it keeps running. Always `true` on the server and on a page that
16
+ * does not keep alive.
17
+ */
18
+ export declare function usePageVisibility(): Accessor<boolean>;
19
+ /**
20
+ * Run `callback` each time the `keepAlive` page this component renders in is hidden behind another
21
+ * page, before it leaves the document. The page keeps running while it is hidden: pause its timers,
22
+ * sockets and media here. Call it while the component sets up; it is removed with the component. A
23
+ * no-op outside a kept page.
24
+ */
25
+ export declare function onPageHide(callback: () => void): void;
26
+ /** Run `callback` each time the `keepAlive` page this component renders in is shown again. */
27
+ export declare function onPageShow(callback: () => void): void;
28
+ //# sourceMappingURL=page-visibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-visibility.d.ts","sourceRoot":"","sources":["../src/page-visibility.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAwC,MAAM,UAAU,CAAA;AAE5F,oGAAoG;AACpG,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAA;IAC9B,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAA;CAC/B;AAMD,eAAO,MAAM,WAAW,+BAAkE,CAAA;AAK1F;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,QAAQ,CAAC,OAAO,CAAC,CAGrD;AASD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAErD;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAErD"}