@nifrajs/web-solid 0.1.0-alpha.1

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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +18 -0
  3. package/dist/await.d.ts +29 -0
  4. package/dist/await.d.ts.map +1 -0
  5. package/dist/await.js +46 -0
  6. package/dist/await.js.map +1 -0
  7. package/dist/client.d.ts +18 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +85 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/compose.d.ts +9 -0
  12. package/dist/compose.d.ts.map +1 -0
  13. package/dist/compose.js +17 -0
  14. package/dist/compose.js.map +1 -0
  15. package/dist/content.d.ts +21 -0
  16. package/dist/content.d.ts.map +1 -0
  17. package/dist/content.js +18 -0
  18. package/dist/content.js.map +1 -0
  19. package/dist/error.d.ts +8 -0
  20. package/dist/error.d.ts.map +1 -0
  21. package/dist/error.js +25 -0
  22. package/dist/error.js.map +1 -0
  23. package/dist/fetcher.d.ts +37 -0
  24. package/dist/fetcher.d.ts.map +1 -0
  25. package/dist/fetcher.js +48 -0
  26. package/dist/fetcher.js.map +1 -0
  27. package/dist/i18n.d.ts +21 -0
  28. package/dist/i18n.d.ts.map +1 -0
  29. package/dist/i18n.js +31 -0
  30. package/dist/i18n.js.map +1 -0
  31. package/dist/image.d.ts +23 -0
  32. package/dist/image.d.ts.map +1 -0
  33. package/dist/image.js +49 -0
  34. package/dist/image.js.map +1 -0
  35. package/dist/index.d.ts +12 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +67 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/mdx-runtime.d.ts +4 -0
  40. package/dist/mdx-runtime.d.ts.map +1 -0
  41. package/dist/mdx-runtime.js +52 -0
  42. package/dist/mdx-runtime.js.map +1 -0
  43. package/dist/mdx.d.ts +5 -0
  44. package/dist/mdx.d.ts.map +1 -0
  45. package/dist/mdx.js +59 -0
  46. package/dist/mdx.js.map +1 -0
  47. package/dist/query.d.ts +28 -0
  48. package/dist/query.d.ts.map +1 -0
  49. package/dist/query.js +54 -0
  50. package/dist/query.js.map +1 -0
  51. package/package.json +112 -0
  52. package/src/await.ts +58 -0
  53. package/src/client.ts +89 -0
  54. package/src/compose.ts +18 -0
  55. package/src/content.ts +30 -0
  56. package/src/error.ts +26 -0
  57. package/src/fetcher.ts +63 -0
  58. package/src/i18n.ts +46 -0
  59. package/src/image.ts +68 -0
  60. package/src/index.ts +75 -0
  61. package/src/mdx-runtime.ts +54 -0
  62. package/src/mdx.ts +60 -0
  63. package/src/query.ts +63 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nifra Authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # @nifrajs/web-solid
2
+
3
+ Solid render adapter for @nifrajs/web — SSR + hydration + the Solid Babel build plugin.
4
+
5
+ Part of the **[nifra](https://nifra.dev)** full-stack TypeScript framework — one core, five UI libraries, every runtime. Scaffold a new app with `bun create nifra`.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ bun add @nifrajs/web-solid
11
+ ```
12
+
13
+ ## Docs
14
+
15
+ - Reference: <https://nifra.dev/docs>
16
+ - AI-readable: <https://nifra.dev/llms.txt>
17
+
18
+ MIT
@@ -0,0 +1,29 @@
1
+ import type { Deferred } from "@nifrajs/web";
2
+ /**
3
+ * `@nifrajs/web-solid/await` — the `<Await>` primitive for deferred loader data (`defer()`). Isomorphic
4
+ * and imports only `solid-js` + a type from `@nifrajs/web` (never `solid-js/web`'s server or the Babel
5
+ * plugin), so route components can use it without dragging server/build code into the client bundle.
6
+ * No JSX (the package builds with plain `tsc`).
7
+ *
8
+ * Solid streams the boundary natively: on the server `createResource` awaits the deferred promise,
9
+ * `<Suspense>` flushes the fallback then the resolved content mid-stream, and Solid serializes the
10
+ * resource value into its hydration data — so the client hydrates the streamed content without a
11
+ * re-fetch (it reads `_$HY`, not the registry promise).
12
+ */
13
+ import { type JSX } from "solid-js";
14
+ export interface AwaitProps<T> {
15
+ /** A `Deferred<T>` from a loader's `defer(...)`, or an already-resolved value (client nav). */
16
+ readonly resolve: Deferred<T> | T;
17
+ readonly fallback?: JSX.Element;
18
+ /** Rendered if the deferred rejects. Without it the error propagates to the nearest
19
+ * `<ErrorBoundary>`. */
20
+ readonly errorFallback?: (error: unknown) => JSX.Element;
21
+ readonly children: (value: T) => JSX.Element;
22
+ }
23
+ /**
24
+ * Render deferred loader data: show `fallback` until the `Deferred` settles (streamed in by the
25
+ * server), then `children(value)`. An already-resolved `resolve` (a client navigation awaited it)
26
+ * renders immediately. Pairs with a loader's `defer(...)`.
27
+ */
28
+ export declare function Await<T>(props: AwaitProps<T>): JSX.Element;
29
+ //# sourceMappingURL=await.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"await.d.ts","sourceRoot":"","sources":["../src/await.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5C;;;;;;;;;;GAUG;AACH,OAAO,EAAmC,KAAK,GAAG,EAAY,MAAM,UAAU,CAAA;AAE9E,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,+FAA+F;IAC/F,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAC/B;4BACwB;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,GAAG,CAAC,OAAO,CAAA;IACxD,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAA;CAC7C;AAUD;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAoB1D"}
package/dist/await.js ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `@nifrajs/web-solid/await` — the `<Await>` primitive for deferred loader data (`defer()`). Isomorphic
3
+ * and imports only `solid-js` + a type from `@nifrajs/web` (never `solid-js/web`'s server or the Babel
4
+ * plugin), so route components can use it without dragging server/build code into the client bundle.
5
+ * No JSX (the package builds with plain `tsc`).
6
+ *
7
+ * Solid streams the boundary natively: on the server `createResource` awaits the deferred promise,
8
+ * `<Suspense>` flushes the fallback then the resolved content mid-stream, and Solid serializes the
9
+ * resource value into its hydration data — so the client hydrates the streamed content without a
10
+ * re-fetch (it reads `_$HY`, not the registry promise).
11
+ */
12
+ import { createComponent, createResource, Suspense } from "solid-js";
13
+ function isDeferred(value) {
14
+ return (typeof value === "object" &&
15
+ value !== null &&
16
+ value.__nifra_deferred === true);
17
+ }
18
+ /**
19
+ * Render deferred loader data: show `fallback` until the `Deferred` settles (streamed in by the
20
+ * server), then `children(value)`. An already-resolved `resolve` (a client navigation awaited it)
21
+ * renders immediately. Pairs with a loader's `defer(...)`.
22
+ */
23
+ export function Await(props) {
24
+ if (!isDeferred(props.resolve))
25
+ return props.children(props.resolve);
26
+ const marker = props.resolve;
27
+ const [data] = createResource(() => marker.promise);
28
+ return createComponent(Suspense, {
29
+ get fallback() {
30
+ return props.fallback;
31
+ },
32
+ get children() {
33
+ // Errored? Render `errorFallback`, else rethrow to an outer <ErrorBoundary>. Check `data.error`
34
+ // BEFORE `data()` (which would rethrow). Otherwise: `data()` suspends until the resource
35
+ // settles (on the client Solid reads the serialized value — no re-fetch).
36
+ if (data.error !== undefined) {
37
+ if (props.errorFallback)
38
+ return props.errorFallback(data.error);
39
+ throw data.error;
40
+ }
41
+ const value = data();
42
+ return value === undefined ? null : props.children(value);
43
+ },
44
+ });
45
+ }
46
+ //# sourceMappingURL=await.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"await.js","sourceRoot":"","sources":["../src/await.ts"],"names":[],"mappings":"AACA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAY,QAAQ,EAAE,MAAM,UAAU,CAAA;AAY9E,SAAS,UAAU,CAAI,KAAsB;IAC3C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAAwC,CAAC,gBAAgB,KAAK,IAAI,CACpE,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAI,KAAoB;IAC3C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACpE,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAA;IAC5B,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACnD,OAAO,eAAe,CAAC,QAAQ,EAAE;QAC/B,IAAI,QAAQ;YACV,OAAO,KAAK,CAAC,QAAQ,CAAA;QACvB,CAAC;QACD,IAAI,QAAQ;YACV,gGAAgG;YAChG,yFAAyF;YACzF,0EAA0E;YAC1E,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC7B,IAAI,KAAK,CAAC,aAAa;oBAAE,OAAO,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBAC/D,MAAM,IAAI,CAAC,KAAK,CAAA;YAClB,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,EAAE,CAAA;YACpB,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAC3D,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { MountRouterOptions, RenderProps } from "@nifrajs/web";
2
+ export { errorBoundary } from "./error.js";
3
+ /** Hydrate a server-rendered Solid layout `chain` (with the loader `props`) inside `container`. */
4
+ export declare function hydrate(chain: readonly unknown[], props: RenderProps, container: unknown): void;
5
+ /**
6
+ * Mount a Solid Router driven by the agnostic store. The first render *hydrates* the SSR'd chain. The
7
+ * route's props are exposed as **getters over a signal** created inside the render root, so:
8
+ *
9
+ * - **Same route** (revalidation, a param change, an optimistic submit) — the snapshot signal is
10
+ * updated and only the components reading the changed props re-run; the layout chain stays mounted,
11
+ * so **focus and scroll are preserved**. This is the case the old "dispose + re-render on every
12
+ * navigation" implementation regressed.
13
+ * - **Different route** — the matched chain genuinely changed (different page + layouts), so the root
14
+ * is disposed and the new chain is rendered. (Getter-props are a transparent reactive boundary, so
15
+ * they don't shift Solid's structural hydration keys — unlike a `<Show>`, which would.)
16
+ */
17
+ export declare function mountRouter(options: MountRouterOptions): void;
18
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAgBnE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAE/F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAqD7D"}
package/dist/client.js ADDED
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @nifrajs/web-solid/client — Solid client runtime. `hydrate` hydrates a single SSR'd route;
3
+ * `mountRouter` hydrates the initial route then drives navigation through a Solid signal — so a
4
+ * same-route update (revalidation, a param change, an optimistic submit) updates **in place** via
5
+ * fine-grained reactivity, preserving the layout chain + focus + scroll. Runs against Solid's client
6
+ * build; kept in its own entry so SSR code never ships to the client bundle. No JSX — Solid's package
7
+ * build is plain `tsc`, so this uses Solid's runtime functions directly, like `compose`.
8
+ */
9
+ import { createSignal } from "solid-js";
10
+ import { hydrate as solidHydrate, render as solidRender } from "solid-js/web";
11
+ import { compose } from "./compose.js";
12
+ import { setMountedRouter } from "./fetcher.js";
13
+ // The `_error` boundary chain element — defined in its own module, re-exported here so nifra's client
14
+ // codegen resolves it from `@nifrajs/web-solid/client` alongside `mountRouter`.
15
+ export { errorBoundary } from "./error.js";
16
+ /** Hydrate a server-rendered Solid layout `chain` (with the loader `props`) inside `container`. */
17
+ export function hydrate(chain, props, container) {
18
+ solidHydrate(compose(chain, props), container);
19
+ }
20
+ /**
21
+ * Mount a Solid Router driven by the agnostic store. The first render *hydrates* the SSR'd chain. The
22
+ * route's props are exposed as **getters over a signal** created inside the render root, so:
23
+ *
24
+ * - **Same route** (revalidation, a param change, an optimistic submit) — the snapshot signal is
25
+ * updated and only the components reading the changed props re-run; the layout chain stays mounted,
26
+ * so **focus and scroll are preserved**. This is the case the old "dispose + re-render on every
27
+ * navigation" implementation regressed.
28
+ * - **Different route** — the matched chain genuinely changed (different page + layouts), so the root
29
+ * is disposed and the new chain is rendered. (Getter-props are a transparent reactive boundary, so
30
+ * they don't shift Solid's structural hydration keys — unlike a `<Show>`, which would.)
31
+ */
32
+ export function mountRouter(options) {
33
+ const { router, routes, container } = options;
34
+ setMountedRouter(router); // expose it to createFetcher/useFetchers (same page, client-only)
35
+ const el = container;
36
+ let dispose;
37
+ let mountedRouteId = null;
38
+ // The setter for the currently-mounted route's reactive props — same-route settles push through it.
39
+ let update = null;
40
+ const mount = (first) => {
41
+ const initial = router.snapshot();
42
+ mountedRouteId = initial.routeId;
43
+ const renderer = first ? solidHydrate : solidRender;
44
+ dispose = renderer(() => {
45
+ // Signal owned by THIS render root (so it's never ownerless). `props` are getters over it; a
46
+ // same-route settle calls `update(snapshot)` and the reading components update in place — no
47
+ // recompose, so the layout chain + focus + scroll survive. Cast bridges
48
+ // `exactOptionalPropertyTypes` (a getter is always present, returning `undefined` when idle —
49
+ // the documented "absent on idle" semantics for `submission`).
50
+ const [snapshot, setSnapshot] = createSignal(initial);
51
+ update = setSnapshot;
52
+ const props = {
53
+ get data() {
54
+ return snapshot().data;
55
+ },
56
+ get actionData() {
57
+ return snapshot().actionData;
58
+ },
59
+ get pending() {
60
+ return snapshot().pending;
61
+ },
62
+ get submission() {
63
+ return snapshot().submission;
64
+ },
65
+ };
66
+ // The matched chain is fixed for this mount (routeId is constant here); a route *change* disposes
67
+ // and re-mounts below, so the root render fn reads no signal and never re-runs on its own.
68
+ return compose(routes[initial.routeId] ?? [], props)();
69
+ }, el);
70
+ };
71
+ mount(true);
72
+ router.subscribe(() => {
73
+ const snapshot = router.snapshot();
74
+ if (snapshot.pending)
75
+ return; // skip the in-flight tick; act once settled
76
+ if (snapshot.routeId === mountedRouteId) {
77
+ update?.(snapshot); // same route → reactive in-place update (preserves layout/focus/scroll)
78
+ }
79
+ else {
80
+ dispose?.(); // route changed → tear down and render the new chain
81
+ mount(false);
82
+ }
83
+ });
84
+ }
85
+ //# sourceMappingURL=client.js.map
@@ -0,0 +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;AAE/C,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,SAAS,EAAE,GAAG,OAAO,CAAA;IAC7C,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,6FAA6F;YAC7F,6FAA6F;YAC7F,wEAAwE;YACxE,8FAA8F;YAC9F,+DAA+D;YAC/D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;YACrD,MAAM,GAAG,WAAW,CAAA;YACpB,MAAM,KAAK,GAAG;gBACZ,IAAI,IAAI;oBACN,OAAO,QAAQ,EAAE,CAAC,IAAI,CAAA;gBACxB,CAAC;gBACD,IAAI,UAAU;oBACZ,OAAO,QAAQ,EAAE,CAAC,UAAU,CAAA;gBAC9B,CAAC;gBACD,IAAI,OAAO;oBACT,OAAO,QAAQ,EAAE,CAAC,OAAO,CAAA;gBAC3B,CAAC;gBACD,IAAI,UAAU;oBACZ,OAAO,QAAQ,EAAE,CAAC,UAAU,CAAA;gBAC9B,CAAC;aACa,CAAA;YAChB,kGAAkG;YAClG,2FAA2F;YAC3F,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,EAAE,CAAA;QACxD,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,IAAI,QAAQ,CAAC,OAAO;YAAE,OAAM,CAAC,4CAA4C;QACzE,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"}
@@ -0,0 +1,9 @@
1
+ import type { RenderProps } from "@nifrajs/web";
2
+ import { type JSX } from "solid-js";
3
+ /**
4
+ * Fold a layout chain (outermost layout → page) into a single Solid tree: the page
5
+ * (innermost) receives `props` (the loader data); each layout wraps the child via its
6
+ * `children`. Shared by the server adapter (renderToString) and the client (hydrate).
7
+ */
8
+ export declare function compose(chain: readonly unknown[], props: RenderProps): () => JSX.Element;
9
+ //# sourceMappingURL=compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAmC,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAEpE;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,CAAC,OAAO,CASxF"}
@@ -0,0 +1,17 @@
1
+ import { createComponent } from "solid-js";
2
+ /**
3
+ * Fold a layout chain (outermost layout → page) into a single Solid tree: the page
4
+ * (innermost) receives `props` (the loader data); each layout wraps the child via its
5
+ * `children`. Shared by the server adapter (renderToString) and the client (hydrate).
6
+ */
7
+ export function compose(chain, props) {
8
+ const last = chain.length - 1;
9
+ let node = () => createComponent(chain[last], props);
10
+ for (let i = last - 1; i >= 0; i--) {
11
+ const Layout = chain[i];
12
+ const child = node;
13
+ node = () => createComponent(Layout, { children: child() });
14
+ }
15
+ return node;
16
+ }
17
+ //# sourceMappingURL=compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.js","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,eAAe,EAAY,MAAM,UAAU,CAAA;AAEpE;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,KAAyB,EAAE,KAAkB;IACnE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;IAC7B,IAAI,IAAI,GAAsB,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAA2B,EAAE,KAAK,CAAC,CAAA;IACjG,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAyC,CAAA;QAC/D,MAAM,KAAK,GAAG,IAAI,CAAA;QAClB,IAAI,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;IAC7D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * `@nifrajs/web-solid/content` — render pre-rendered HTML (e.g. a `@nifrajs/content` collection entry's
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
5
+ * plain `tsc`.
6
+ *
7
+ * Security: injects raw HTML, so `html` MUST be trusted (your own Markdown/content, rendered at
8
+ * build/server time) — never pass user-supplied HTML without sanitizing it first.
9
+ */
10
+ import { type JSX } from "solid-js";
11
+ export interface ContentProps {
12
+ /** Trusted, pre-rendered HTML (e.g. `entry.html`). */
13
+ readonly html: string;
14
+ /** Wrapper element (default `"div"`). */
15
+ readonly as?: string;
16
+ /** DOM passthrough (`class`, `style`, `id`, `data-*`, handlers). */
17
+ readonly [key: string]: unknown;
18
+ }
19
+ /** Render trusted HTML into a wrapper element. Extra props pass through reactively. */
20
+ export declare function Content(props: ContentProps): JSX.Element;
21
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAmB,KAAK,GAAG,EAA0B,MAAM,UAAU,CAAA;AAG5E,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAA;IACpB,oEAAoE;IACpE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAChC;AAED,uFAAuF;AACvF,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,GAAG,CAAC,OAAO,CAOxD"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `@nifrajs/web-solid/content` — render pre-rendered HTML (e.g. a `@nifrajs/content` collection entry's
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
5
+ * plain `tsc`.
6
+ *
7
+ * Security: injects raw HTML, so `html` MUST be trusted (your own Markdown/content, rendered at
8
+ * build/server time) — never pass user-supplied HTML without sanitizing it first.
9
+ */
10
+ import { createComponent, mergeProps, splitProps } from "solid-js";
11
+ import { Dynamic } from "solid-js/web";
12
+ /** Render trusted HTML into a wrapper element. Extra props pass through reactively. */
13
+ export function Content(props) {
14
+ const [, rest] = splitProps(props, ["html", "as"]);
15
+ // A function source keeps `component`/`innerHTML` reactive (matches the `<Image>` pattern).
16
+ return createComponent(Dynamic, mergeProps(rest, () => ({ component: props.as ?? "div", innerHTML: props.html })));
17
+ }
18
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,eAAe,EAAY,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAWtC,uFAAuF;AACvF,MAAM,UAAU,OAAO,CAAC,KAAmB;IACzC,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IAClD,4FAA4F;IAC5F,OAAO,eAAe,CACpB,OAAO,EACP,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,IAAI,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAClF,CAAA;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Build an error-boundary chain element bound to `fallback` (a route's `_error` component). nifra's
3
+ * client codegen inserts it before the page in the matched chain; a render error in the subtree renders
4
+ * `fallback` with `{ data: { name, message } }` (via Solid's `<ErrorBoundary>`) instead of crashing.
5
+ * DOM-transparent (renders its children directly — no wrapper element), so it never disturbs hydration.
6
+ */
7
+ export declare function errorBoundary(fallback: unknown): unknown;
8
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAYxD"}
package/dist/error.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `errorBoundary` — the Solid error-boundary chain element for nifra's `_error.tsx`. Its own module
3
+ * (imports only `solid-js`) so the client codegen can import it from `@nifrajs/web-solid/client` (which
4
+ * re-exports it). No JSX (`createComponent`), so the package builds with plain `tsc`.
5
+ */
6
+ import { createComponent, ErrorBoundary } from "solid-js";
7
+ /**
8
+ * Build an error-boundary chain element bound to `fallback` (a route's `_error` component). nifra's
9
+ * client codegen inserts it before the page in the matched chain; a render error in the subtree renders
10
+ * `fallback` with `{ data: { name, message } }` (via Solid's `<ErrorBoundary>`) instead of crashing.
11
+ * DOM-transparent (renders its children directly — no wrapper element), so it never disturbs hydration.
12
+ */
13
+ export function errorBoundary(fallback) {
14
+ const Fallback = fallback;
15
+ return (props) => createComponent(ErrorBoundary, {
16
+ fallback: (err) => {
17
+ const e = err instanceof Error ? err : new Error(String(err));
18
+ return createComponent(Fallback, { data: { name: e.name, message: e.message } });
19
+ },
20
+ get children() {
21
+ return props.children;
22
+ },
23
+ });
24
+ }
25
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAY,MAAM,UAAU,CAAA;AAEnE;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,QAAiB;IAC7C,MAAM,QAAQ,GAAG,QAA+E,CAAA;IAChG,OAAO,CAAC,KAAiC,EAAe,EAAE,CACxD,eAAe,CAAC,aAAa,EAAE;QAC7B,QAAQ,EAAE,CAAC,GAAY,EAAE,EAAE;YACzB,MAAM,CAAC,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;YAC7D,OAAO,eAAe,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;QAClF,CAAC;QACD,IAAI,QAAQ;YACV,OAAO,KAAK,CAAC,QAAQ,CAAA;QACvB,CAAC;KACF,CAAC,CAAA;AACN,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { ClientRouter, Fetcher, FetcherState } from "@nifrajs/web";
2
+ /**
3
+ * `@nifrajs/web-solid/fetcher` — Solid bindings for concurrent fetchers. `createFetcher(key)` bridges an
4
+ * independent {@link Fetcher}'s `subscribe`/`snapshot` store into a Solid signal (the pattern the F16
5
+ * spike confirmed) and returns its reactive state accessor plus `load`/`submit`; `useFetchers()`
6
+ * bridges the whole live collection. Imports only `solid-js` (never `solid-js/web`), so route
7
+ * components can use it on the server *and* client without pulling server/build code into the wrong
8
+ * bundle. No JSX (the package builds with plain `tsc`).
9
+ *
10
+ * The router that owns the fetchers registers itself via `setMountedRouter` from `mountRouter`. On the
11
+ * server (no mount) the accessors return an idle state — fetchers are client-only — so SSR markup is
12
+ * unchanged and the first client render after `mountRouter` takes over cleanly.
13
+ */
14
+ import { type Accessor } from "solid-js";
15
+ /** Register (or clear) the router that owns fetchers — called by `mountRouter`. Not for app use. */
16
+ export declare function setMountedRouter(router: ClientRouter | undefined): void;
17
+ /** A fetcher's reactive state accessor plus its imperative `load`/`submit`. */
18
+ export interface FetcherHandle {
19
+ /** Reactive accessor for the fetcher's {@link FetcherState} (`pending`/`data`/`actionData`/...). */
20
+ readonly state: Accessor<FetcherState>;
21
+ /** Load a route path's loader data into this fetcher (concurrent; doesn't touch the active view). */
22
+ readonly load: (path: string) => Promise<void>;
23
+ /** Submit an action into this fetcher (concurrent); honors `X-Nifra-Revalidate`. */
24
+ readonly submit: (action: string, body: NonNullable<RequestInit["body"]>) => Promise<void>;
25
+ }
26
+ /**
27
+ * Bind the independent fetcher for `key` (created lazily, stable). Returns a reactive `state()`
28
+ * accessor + `load`/`submit`. Multiple `createFetcher` calls with different keys run concurrently
29
+ * without disturbing the active route or each other. Call inside a component (owns the subscription).
30
+ */
31
+ export declare function createFetcher(key: string): FetcherHandle;
32
+ /**
33
+ * Bind the whole live fetcher collection — for a global busy view. Returns a reactive accessor; read
34
+ * each entry's `.snapshot()` for its state. Updates whenever any fetcher transitions or one is created.
35
+ */
36
+ export declare function useFetchers(): Accessor<readonly Fetcher[]>;
37
+ //# sourceMappingURL=fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACvE;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,KAAK,QAAQ,EAA2B,MAAM,UAAU,CAAA;AAKjE,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,CAEvE;AAKD,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,oGAAoG;IACpG,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAA;IACtC,qGAAqG;IACrG,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9C,oFAAoF;IACpF,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAQxD;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAAC,SAAS,OAAO,EAAE,CAAC,CAO1D"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `@nifrajs/web-solid/fetcher` — Solid bindings for concurrent fetchers. `createFetcher(key)` bridges an
3
+ * independent {@link Fetcher}'s `subscribe`/`snapshot` store into a Solid signal (the pattern the F16
4
+ * spike confirmed) and returns its reactive state accessor plus `load`/`submit`; `useFetchers()`
5
+ * bridges the whole live collection. Imports only `solid-js` (never `solid-js/web`), so route
6
+ * components can use it on the server *and* client without pulling server/build code into the wrong
7
+ * bundle. No JSX (the package builds with plain `tsc`).
8
+ *
9
+ * The router that owns the fetchers registers itself via `setMountedRouter` from `mountRouter`. On the
10
+ * server (no mount) the accessors return an idle state — fetchers are client-only — so SSR markup is
11
+ * unchanged and the first client render after `mountRouter` takes over cleanly.
12
+ */
13
+ import { createSignal, onCleanup } from "solid-js";
14
+ // The active client router (set by `mountRouter`). Module-scoped: one app per page, client-only.
15
+ let mountedRouter;
16
+ /** Register (or clear) the router that owns fetchers — called by `mountRouter`. Not for app use. */
17
+ export function setMountedRouter(router) {
18
+ mountedRouter = router;
19
+ }
20
+ const IDLE = { pending: false, data: undefined };
21
+ const noopAsync = async () => { };
22
+ /**
23
+ * Bind the independent fetcher for `key` (created lazily, stable). Returns a reactive `state()`
24
+ * accessor + `load`/`submit`. Multiple `createFetcher` calls with different keys run concurrently
25
+ * without disturbing the active route or each other. Call inside a component (owns the subscription).
26
+ */
27
+ export function createFetcher(key) {
28
+ const fetcher = mountedRouter?.fetcher(key);
29
+ const [state, setState] = createSignal(fetcher ? fetcher.snapshot() : IDLE);
30
+ if (fetcher !== undefined) {
31
+ onCleanup(fetcher.subscribe(() => setState(fetcher.snapshot())));
32
+ return { state, load: fetcher.load, submit: fetcher.submit };
33
+ }
34
+ return { state, load: noopAsync, submit: noopAsync };
35
+ }
36
+ /**
37
+ * Bind the whole live fetcher collection — for a global busy view. Returns a reactive accessor; read
38
+ * each entry's `.snapshot()` for its state. Updates whenever any fetcher transitions or one is created.
39
+ */
40
+ export function useFetchers() {
41
+ const router = mountedRouter;
42
+ const [list, setList] = createSignal(router ? router.fetchers() : []);
43
+ if (router !== undefined) {
44
+ onCleanup(router.subscribeFetchers(() => setList(router.fetchers())));
45
+ }
46
+ return list;
47
+ }
48
+ //# sourceMappingURL=fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;GAWG;AACH,OAAO,EAAiB,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEjE,iGAAiG;AACjG,IAAI,aAAuC,CAAA;AAE3C,oGAAoG;AACpG,MAAM,UAAU,gBAAgB,CAAC,MAAgC;IAC/D,aAAa,GAAG,MAAM,CAAA;AACxB,CAAC;AAED,MAAM,IAAI,GAAiB,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;AAC9D,MAAM,SAAS,GAAG,KAAK,IAAmB,EAAE,GAAE,CAAC,CAAA;AAY/C;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,OAAO,GAAG,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;IAC3C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAe,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IACzF,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAA;QAChE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAA;IAC9D,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,aAAa,CAAA;IAC5B,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,YAAY,CAAqB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IACzF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,SAAS,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAA;IACvE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
package/dist/i18n.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * `@nifrajs/web-solid/i18n` — Solid bindings for `@nifrajs/i18n`. `<I18nProvider locale messages>` builds a
3
+ * `Formatter` (a `createMemo`, so switching locale rebuilds it) and provides it; `useT()` reads it.
4
+ * Both `locale` + `messages` are serializable, so a loader returns them, the page renders with the
5
+ * negotiated catalog on the server, and the client rebuilds the same formatter on hydrate (no
6
+ * mismatch). Imports only `solid-js` + `@nifrajs/i18n`; no JSX (`createComponent`).
7
+ */
8
+ import { type Formatter, type Messages } from "@nifrajs/i18n";
9
+ import { type JSX } from "solid-js";
10
+ export interface I18nProviderProps {
11
+ readonly locale: string;
12
+ readonly messages: Messages;
13
+ readonly children?: JSX.Element;
14
+ }
15
+ /** Provide a {@link Formatter} (built from `locale` + `messages`) to the subtree. Memoized on
16
+ * `locale`/`messages`, so switching locale rebuilds it. */
17
+ export declare function I18nProvider(props: I18nProviderProps): JSX.Element;
18
+ /** Read the current {@link Formatter} (`{ locale, t, n, d }`). Throws if no `<I18nProvider>` is above.
19
+ * nifra switches locale by re-navigating, which re-runs the consuming component with the new catalog. */
20
+ export declare function useT(): Formatter;
21
+ //# sourceMappingURL=i18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC9E,OAAO,EAKL,KAAK,GAAG,EAET,MAAM,UAAU,CAAA;AAIjB,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CAChC;AAED;2DAC2D;AAC3D,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,GAAG,CAAC,OAAO,CAQlE;AAED;yGACyG;AACzG,wBAAgB,IAAI,IAAI,SAAS,CAMhC"}
package/dist/i18n.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `@nifrajs/web-solid/i18n` — Solid bindings for `@nifrajs/i18n`. `<I18nProvider locale messages>` builds a
3
+ * `Formatter` (a `createMemo`, so switching locale rebuilds it) and provides it; `useT()` reads it.
4
+ * Both `locale` + `messages` are serializable, so a loader returns them, the page renders with the
5
+ * negotiated catalog on the server, and the client rebuilds the same formatter on hydrate (no
6
+ * mismatch). Imports only `solid-js` + `@nifrajs/i18n`; no JSX (`createComponent`).
7
+ */
8
+ import { createFormatter } from "@nifrajs/i18n";
9
+ import { createComponent, createContext, createMemo, useContext, } from "solid-js";
10
+ const I18nContext = createContext();
11
+ /** Provide a {@link Formatter} (built from `locale` + `messages`) to the subtree. Memoized on
12
+ * `locale`/`messages`, so switching locale rebuilds it. */
13
+ export function I18nProvider(props) {
14
+ const formatter = createMemo(() => createFormatter(props.locale, props.messages));
15
+ return createComponent(I18nContext.Provider, {
16
+ value: formatter,
17
+ get children() {
18
+ return props.children;
19
+ },
20
+ });
21
+ }
22
+ /** Read the current {@link Formatter} (`{ locale, t, n, d }`). Throws if no `<I18nProvider>` is above.
23
+ * nifra switches locale by re-navigating, which re-runs the consuming component with the new catalog. */
24
+ export function useT() {
25
+ const formatter = useContext(I18nContext);
26
+ if (formatter === undefined) {
27
+ throw new Error("[nifra/web-solid] useT() must be used within an <I18nProvider>");
28
+ }
29
+ return formatter();
30
+ }
31
+ //# sourceMappingURL=i18n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,eAAe,EAAiC,MAAM,eAAe,CAAA;AAC9E,OAAO,EAEL,eAAe,EACf,aAAa,EACb,UAAU,EAEV,UAAU,GACX,MAAM,UAAU,CAAA;AAEjB,MAAM,WAAW,GAAG,aAAa,EAAuB,CAAA;AAQxD;2DAC2D;AAC3D,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjF,OAAO,eAAe,CAAC,WAAW,CAAC,QAAQ,EAAE;QAC3C,KAAK,EAAE,SAAS;QAChB,IAAI,QAAQ;YACV,OAAO,KAAK,CAAC,QAAQ,CAAA;QACvB,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED;yGACyG;AACzG,MAAM,UAAU,IAAI;IAClB,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACzC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;IACnF,CAAC;IACD,OAAO,SAAS,EAAE,CAAA;AACpB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `@nifrajs/web-solid/image` — a CLS-safe responsive Solid `<Image>`. A thin wrapper over `resolveImage`
3
+ * from `@nifrajs/image`: it computes the responsive `<img>` attributes (`src`/`srcset`/`sizes`/`width`/
4
+ * `height`/`loading`/`decoding`/`fetchpriority` via `toHtmlAttrs`) and renders an `<img>` through
5
+ * Solid's `<Dynamic>`. Extra DOM props (`class`, `style`, `id`, `data-*`, handlers) pass through
6
+ * reactively (`splitProps`/`mergeProps`). Resizing is delegated to the `loader`; nifra bundles no codec.
7
+ * No JSX (`createComponent`/`Dynamic`), so the package builds with plain `tsc`.
8
+ */
9
+ import { type ImageLoader, type ImageProps } from "@nifrajs/image";
10
+ import { type JSX } from "solid-js";
11
+ /** Attributes `resolveImage` computes — callers can't override them via DOM passthrough. */
12
+ type ComputedAttrs = "src" | "srcset" | "sizes" | "width" | "height" | "alt" | "loading" | "decoding" | "fetchpriority";
13
+ export interface ImageComponentProps extends ImageProps, Omit<JSX.ImgHTMLAttributes<HTMLImageElement>, ComputedAttrs | keyof ImageProps> {
14
+ /** CDN URL builder. Defaults to the identity loader (no transform — still CLS-safe + lazy). */
15
+ readonly loader?: ImageLoader;
16
+ }
17
+ /**
18
+ * Render a responsive, CLS-safe `<img>`. `width`+`height` are required (reserve layout space);
19
+ * `priority` marks the LCP image (`eager` + `fetchpriority="high"`). Extra DOM props pass through.
20
+ */
21
+ export declare function Image(props: ImageComponentProps): JSX.Element;
22
+ export {};
23
+ //# sourceMappingURL=image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/image.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAA6B,MAAM,gBAAgB,CAAA;AAC7F,OAAO,EAAmB,KAAK,GAAG,EAA0B,MAAM,UAAU,CAAA;AAG5E,4FAA4F;AAC5F,KAAK,aAAa,GACd,KAAK,GACL,QAAQ,GACR,OAAO,GACP,OAAO,GACP,QAAQ,GACR,KAAK,GACL,SAAS,GACT,UAAU,GACV,eAAe,CAAA;AAEnB,MAAM,WAAW,mBACf,SAAQ,UAAU,EAChB,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,aAAa,GAAG,MAAM,UAAU,CAAC;IACjF,+FAA+F;IAC/F,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC9B;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAgC7D"}
package/dist/image.js ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * `@nifrajs/web-solid/image` — a CLS-safe responsive Solid `<Image>`. A thin wrapper over `resolveImage`
3
+ * from `@nifrajs/image`: it computes the responsive `<img>` attributes (`src`/`srcset`/`sizes`/`width`/
4
+ * `height`/`loading`/`decoding`/`fetchpriority` via `toHtmlAttrs`) and renders an `<img>` through
5
+ * Solid's `<Dynamic>`. Extra DOM props (`class`, `style`, `id`, `data-*`, handlers) pass through
6
+ * reactively (`splitProps`/`mergeProps`). Resizing is delegated to the `loader`; nifra bundles no codec.
7
+ * No JSX (`createComponent`/`Dynamic`), so the package builds with plain `tsc`.
8
+ */
9
+ import { resolveImage, toHtmlAttrs } from "@nifrajs/image";
10
+ import { createComponent, mergeProps, splitProps } from "solid-js";
11
+ import { Dynamic } from "solid-js/web";
12
+ /**
13
+ * Render a responsive, CLS-safe `<img>`. `width`+`height` are required (reserve layout space);
14
+ * `priority` marks the LCP image (`eager` + `fetchpriority="high"`). Extra DOM props pass through.
15
+ */
16
+ export function Image(props) {
17
+ // Separate the nifra-only props (not valid DOM attributes) from the DOM passthrough (`rest`), keeping
18
+ // both reactive. `rest` carries class/style/id/handlers; the computed attrs are layered over it.
19
+ const [, rest] = splitProps(props, [
20
+ "loader",
21
+ "widths",
22
+ "quality",
23
+ "priority",
24
+ "src",
25
+ "width",
26
+ "height",
27
+ "alt",
28
+ "sizes",
29
+ "loading",
30
+ ]);
31
+ const attrs = () => {
32
+ // Build ImageProps via conditional spreads (exactOptionalPropertyTypes: an unset optional is
33
+ // absent, not `undefined`). resolveImage validates width/height > 0 (CLS contract).
34
+ const input = {
35
+ src: props.src,
36
+ width: props.width,
37
+ height: props.height,
38
+ alt: props.alt,
39
+ ...(props.sizes !== undefined ? { sizes: props.sizes } : {}),
40
+ ...(props.widths !== undefined ? { widths: props.widths } : {}),
41
+ ...(props.quality !== undefined ? { quality: props.quality } : {}),
42
+ ...(props.loading !== undefined ? { loading: props.loading } : {}),
43
+ ...(props.priority !== undefined ? { priority: props.priority } : {}),
44
+ };
45
+ return toHtmlAttrs(resolveImage(input, props.loader));
46
+ };
47
+ return createComponent(Dynamic, mergeProps(rest, attrs, { component: "img" }));
48
+ }
49
+ //# sourceMappingURL=image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../src/image.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAqC,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC7F,OAAO,EAAE,eAAe,EAAY,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAqBtC;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAC,KAA0B;IAC9C,sGAAsG;IACtG,iGAAiG;IACjG,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE;QACjC,QAAQ;QACR,QAAQ;QACR,SAAS;QACT,UAAU;QACV,KAAK;QACL,OAAO;QACP,QAAQ;QACR,KAAK;QACL,OAAO;QACP,SAAS;KACV,CAAC,CAAA;IACF,MAAM,KAAK,GAAG,GAAmC,EAAE;QACjD,6FAA6F;QAC7F,oFAAoF;QACpF,MAAM,KAAK,GAAe;YACxB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/D,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAA;QACD,OAAO,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;IACvD,CAAC,CAAA;IACD,OAAO,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;AAChF,CAAC"}