netjes 0.0.2 → 0.0.4

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 (160) hide show
  1. package/README.md +13 -11
  2. package/cli/agents.mjs +25 -2
  3. package/cli/commands.mjs +56 -6
  4. package/cli/help.mjs +7 -2
  5. package/cli/info.mjs +275 -33
  6. package/cli/routes.mjs +35 -8
  7. package/cli/scaffold.mjs +31 -4
  8. package/dist/actions.d.ts +7 -2
  9. package/dist/actions.d.ts.map +1 -1
  10. package/dist/actions.js +9 -3
  11. package/dist/actions.js.map +1 -1
  12. package/dist/client-entry.d.ts +1 -0
  13. package/dist/client-entry.d.ts.map +1 -1
  14. package/dist/client-entry.js +19 -2
  15. package/dist/client-entry.js.map +1 -1
  16. package/dist/deferred.d.ts +11 -0
  17. package/dist/deferred.d.ts.map +1 -1
  18. package/dist/deferred.js +15 -1
  19. package/dist/deferred.js.map +1 -1
  20. package/dist/document.d.ts.map +1 -1
  21. package/dist/document.js +10 -1
  22. package/dist/document.js.map +1 -1
  23. package/dist/errors.d.ts +7 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +11 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/form.d.ts +5 -5
  28. package/dist/form.d.ts.map +1 -1
  29. package/dist/form.js +5 -2
  30. package/dist/form.js.map +1 -1
  31. package/dist/href.d.ts +31 -3
  32. package/dist/href.d.ts.map +1 -1
  33. package/dist/href.js +131 -10
  34. package/dist/href.js.map +1 -1
  35. package/dist/image.d.ts +3 -3
  36. package/dist/image.d.ts.map +1 -1
  37. package/dist/image.js.map +1 -1
  38. package/dist/index.d.ts +3 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +3 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/link.d.ts +15 -7
  43. package/dist/link.d.ts.map +1 -1
  44. package/dist/link.js +38 -7
  45. package/dist/link.js.map +1 -1
  46. package/dist/metadata.d.ts +8 -2
  47. package/dist/metadata.d.ts.map +1 -1
  48. package/dist/metadata.js +14 -5
  49. package/dist/metadata.js.map +1 -1
  50. package/dist/modules.d.ts +15 -1
  51. package/dist/modules.d.ts.map +1 -1
  52. package/dist/modules.js.map +1 -1
  53. package/dist/mounted.d.ts +55 -0
  54. package/dist/mounted.d.ts.map +1 -0
  55. package/dist/mounted.js +110 -0
  56. package/dist/mounted.js.map +1 -0
  57. package/dist/navigation-focus.d.ts +38 -0
  58. package/dist/navigation-focus.d.ts.map +1 -0
  59. package/dist/navigation-focus.js +71 -0
  60. package/dist/navigation-focus.js.map +1 -0
  61. package/dist/payload.d.ts +8 -0
  62. package/dist/payload.d.ts.map +1 -1
  63. package/dist/payload.js +28 -0
  64. package/dist/payload.js.map +1 -1
  65. package/dist/query.d.ts +5 -2
  66. package/dist/query.d.ts.map +1 -1
  67. package/dist/query.js +11 -8
  68. package/dist/query.js.map +1 -1
  69. package/dist/render-document.d.ts +74 -0
  70. package/dist/render-document.d.ts.map +1 -0
  71. package/dist/render-document.js +393 -0
  72. package/dist/render-document.js.map +1 -0
  73. package/dist/route-announcer.d.ts +18 -0
  74. package/dist/route-announcer.d.ts.map +1 -0
  75. package/dist/route-announcer.js +58 -0
  76. package/dist/route-announcer.js.map +1 -0
  77. package/dist/route-tree.d.ts +6 -2
  78. package/dist/route-tree.d.ts.map +1 -1
  79. package/dist/route-tree.js +17 -7
  80. package/dist/route-tree.js.map +1 -1
  81. package/dist/router.d.ts +28 -5
  82. package/dist/router.d.ts.map +1 -1
  83. package/dist/router.js +71 -26
  84. package/dist/router.js.map +1 -1
  85. package/dist/script.d.ts +28 -5
  86. package/dist/script.d.ts.map +1 -1
  87. package/dist/script.js +192 -21
  88. package/dist/script.js.map +1 -1
  89. package/dist/server-render.d.ts.map +1 -1
  90. package/dist/server-render.js +4 -1
  91. package/dist/server-render.js.map +1 -1
  92. package/dist/testing-vitest.d.ts +8 -0
  93. package/dist/testing-vitest.d.ts.map +1 -0
  94. package/dist/testing-vitest.js +26 -0
  95. package/dist/testing-vitest.js.map +1 -0
  96. package/dist/testing.d.ts +17 -1
  97. package/dist/testing.d.ts.map +1 -1
  98. package/dist/testing.js +18 -3
  99. package/dist/testing.js.map +1 -1
  100. package/dist/zod-jitless.d.ts +2 -0
  101. package/dist/zod-jitless.d.ts.map +1 -0
  102. package/dist/zod-jitless.js +4 -0
  103. package/dist/zod-jitless.js.map +1 -0
  104. package/package.json +1 -1
  105. package/sidecar/server.mjs +109 -15
  106. package/skills/netjes/SKILL.md +15 -7
  107. package/skills/netjes/references/caching-and-streaming.md +37 -4
  108. package/skills/netjes/references/data-and-actions.md +15 -7
  109. package/skills/netjes/references/deployment.md +7 -3
  110. package/skills/netjes/references/routing.md +32 -9
  111. package/skills/netjes/references/testing.md +23 -7
  112. package/src/actions.tsx +9 -3
  113. package/src/client-entry.tsx +20 -2
  114. package/src/deferred.ts +14 -1
  115. package/src/document.tsx +22 -3
  116. package/src/errors.ts +12 -0
  117. package/src/form.tsx +10 -7
  118. package/src/href.ts +137 -11
  119. package/src/image.tsx +3 -3
  120. package/src/index.ts +19 -1
  121. package/src/link.tsx +47 -13
  122. package/src/metadata.tsx +19 -6
  123. package/src/modules.ts +15 -2
  124. package/src/mounted.tsx +160 -0
  125. package/src/navigation-focus.ts +75 -0
  126. package/src/payload.ts +32 -0
  127. package/src/query.tsx +14 -8
  128. package/src/render-document.tsx +483 -0
  129. package/src/route-announcer.tsx +69 -0
  130. package/src/route-tree.tsx +17 -6
  131. package/src/router.tsx +116 -31
  132. package/src/script.tsx +214 -23
  133. package/src/server-render.tsx +4 -1
  134. package/src/testing-vitest.ts +37 -0
  135. package/src/testing.tsx +38 -5
  136. package/src/virtual.d.ts +8 -1
  137. package/src/zod-jitless.ts +15 -0
  138. package/template/.dockerignore +3 -0
  139. package/template/Dockerfile +11 -1
  140. package/template/README.md +11 -7
  141. package/template/_AGENTS.md +38 -9
  142. package/template/__NAME__.csproj +2 -0
  143. package/template/app/document.test.ts +29 -0
  144. package/template/app/error.tsx +3 -2
  145. package/template/app/layout.tsx +10 -1
  146. package/template/docker-compose.override.yml +4 -3
  147. package/template/docker-compose.prod.yml +2 -1
  148. package/template/e2e/home.spec.ts +32 -0
  149. package/template/generated/netjes.ts +43 -14
  150. package/template/package.json +4 -1
  151. package/template/playwright.config.ts +36 -0
  152. package/template/tests/__NAME__.Tests/AppFactory.cs +31 -0
  153. package/template/tests/__NAME__.Tests/HomePageTests.cs +55 -0
  154. package/template/tests/__NAME__.Tests/__NAME__.Tests.csproj +30 -0
  155. package/template/tsconfig.app.json +20 -0
  156. package/template/tsconfig.json +2 -17
  157. package/template/tsconfig.node.json +8 -0
  158. package/vite/packages.mjs +345 -0
  159. package/vite/plugin.d.ts +16 -1
  160. package/vite/plugin.mjs +224 -34
@@ -1,6 +1,6 @@
1
1
  import { Component, type ReactElement, type ReactNode } from 'react';
2
2
  import { type Metadata } from './metadata.tsx';
3
- import type { RouteModules } from './modules.ts';
3
+ import type { ErrorPageProps, RouteModules } from './modules.ts';
4
4
  import type { PageKind, Params, SegmentRef } from './payload.ts';
5
5
  export type { ErrorPageProps } from './modules.ts';
6
6
  type RouteTreeProps = {
@@ -15,6 +15,8 @@ type RouteTreeProps = {
15
15
  pageKey: string;
16
16
  /** What `reset` does on an error page the server chose: load the page again. */
17
17
  retry?: () => void;
18
+ /** The error an error page (`pageKind` error) gets in place of the one the server's props describe: one caught here. */
19
+ error?: ErrorPageProps['error'];
18
20
  /** Metadata from the C# loader. */
19
21
  metadata?: Metadata | undefined;
20
22
  };
@@ -42,12 +44,14 @@ export declare class ErrorBoundary extends Component<BoundaryProps, {
42
44
  private readonly reset;
43
45
  render(): ReactNode;
44
46
  }
47
+ /** What a boundary caught, as the Error `error.tsx` gets: an Error as it is, a string as its message, else a stand-in. */
48
+ export declare function asError(error: unknown): ErrorPageProps['error'];
45
49
  /**
46
50
  * The page wrapped in its segments, outermost first. Per segment, as in the Next.js App Router:
47
51
  * layout > template > error boundary > Suspense (loading) > the next segment or the page. Layouts keep their state
48
52
  * while the page underneath changes; templates remount.
49
53
  */
50
- export declare function RouteTree({ modules, segments, props, params, status, pageKind, pageKey, retry, metadata }: RouteTreeProps): ReactElement;
54
+ export declare function RouteTree({ modules, segments, props, params, status, pageKind, pageKey, retry, metadata, error }: RouteTreeProps): ReactElement;
51
55
  /** Shown for 404s and errors when the app has no not-found or error page of its own. */
52
56
  export declare function BuiltInPage({ status, props }: {
53
57
  status: number;
@@ -1 +1 @@
1
- {"version":3,"file":"route-tree.d.ts","sourceRoot":"","sources":["../src/route-tree.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAA2B,MAAM,OAAO,CAAC;AAC9F,OAAO,EAAE,KAAK,QAAQ,EAAiC,MAAM,gBAAgB,CAAC;AAC9E,OAAO,KAAK,EAAiC,YAAY,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEjE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,YAAY,CAAC;IACtB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,+GAA+G;IAC/G,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,2GAA2G;AAC3G,eAAO,MAAM,kBAAkB,iCAAmB,CAAC;AAUnD,KAAK,aAAa,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,SAAS,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC;AAE5H,0GAA0G;AAC1G,qBAAa,aAAc,SAAQ,SAAS,CAAC,aAAa,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;IACrF,KAAK;QAAK,KAAK,EAAU,OAAO;QAAE,MAAM;MAAU;IAE3D,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO;;;MAE7C;IAEQ,kBAAkB,CAAC,QAAQ,EAAE,aAAa,QAElD;IAED,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuD;IAEpE,MAAM,cAEd;CACF;AAcD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,QAAa,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,cAAc,GAAG,YAAY,CAoC7I;AAWD,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,+BAkBhG"}
1
+ {"version":3,"file":"route-tree.d.ts","sourceRoot":"","sources":["../src/route-tree.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAA2B,MAAM,OAAO,CAAC;AAE9F,OAAO,EAAE,KAAK,QAAQ,EAAiC,MAAM,gBAAgB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAiB,YAAY,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEjE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,YAAY,CAAC;IACtB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,+GAA+G;IAC/G,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,wHAAwH;IACxH,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IAChC,mCAAmC;IACnC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,2GAA2G;AAC3G,eAAO,MAAM,kBAAkB,iCAAmB,CAAC;AAUnD,KAAK,aAAa,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,SAAS,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC;AAE5H,0GAA0G;AAC1G,qBAAa,aAAc,SAAQ,SAAS,CAAC,aAAa,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;IACrF,KAAK;QAAK,KAAK,EAAU,OAAO;QAAE,MAAM;MAAU;IAE3D,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO;;;MAE7C;IAEQ,kBAAkB,CAAC,QAAQ,EAAE,aAAa,QAElD;IAED,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuD;IAEpE,MAAM,cAEd;CACF;AAED,0HAA0H;AAC1H,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAG/D;AAgBD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,QAAa,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,cAAc,GAAG,YAAY,CAoCpJ;AAWD,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,+BAkBhG"}
@@ -1,5 +1,6 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Component, Suspense, createContext } from 'react';
3
+ import { withheldError } from './errors.js';
3
4
  import { MetadataTags, resolveMetadata } from './metadata.js';
4
5
  /** How many URL segments the layout rendering here covers: what useSelectedLayoutSegment(s) count from. */
5
6
  export const LayoutDepthContext = createContext(0);
@@ -25,16 +26,25 @@ export class ErrorBoundary extends Component {
25
26
  return this.state.failed ? this.props.fallback(this.state.error, this.reset) : this.props.children;
26
27
  }
27
28
  }
28
- function asError(error) {
29
- return error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Something went wrong');
29
+ /** What a boundary caught, as the Error `error.tsx` gets: an Error as it is, a string as its message, else a stand-in. */
30
+ export function asError(error) {
31
+ if (error instanceof Error)
32
+ return error;
33
+ return typeof error === 'string' ? new Error(error) : withheldError();
30
34
  }
31
- /** The error the server reported (props of the error page it rendered), as an Error for `error.tsx`. */
35
+ /**
36
+ * The error the server reported (props of the error page it rendered), as an Error for `error.tsx`: marked withheld
37
+ * when the server says its message stands in for the exception's, and with the server's stack or none, never the
38
+ * stack of the code here that built it.
39
+ */
32
40
  function serverError(props) {
33
41
  const error = new Error(typeof props.message === 'string' ? props.message : 'Something went wrong');
34
42
  if (typeof props.status === 'number')
35
43
  error.status = props.status;
36
- if (typeof props.stack === 'string')
37
- error.stack = props.stack;
44
+ if (props.withheld === true)
45
+ error.withheld = true;
46
+ // Defined rather than assigned, as an own property: Firefox keeps the stack in an accessor on Error.prototype.
47
+ Object.defineProperty(error, 'stack', { value: typeof props.stack === 'string' ? props.stack : undefined, writable: true, configurable: true });
38
48
  return error;
39
49
  }
40
50
  /**
@@ -42,9 +52,9 @@ function serverError(props) {
42
52
  * layout > template > error boundary > Suspense (loading) > the next segment or the page. Layouts keep their state
43
53
  * while the page underneath changes; templates remount.
44
54
  */
45
- export function RouteTree({ modules, segments = [], props, params, status, pageKind, pageKey, retry, metadata }) {
55
+ export function RouteTree({ modules, segments = [], props, params, status, pageKind, pageKey, retry, metadata, error }) {
46
56
  const Page = modules.page;
47
- const pageProps = pageKind === 'error' ? { ...props, error: serverError(props), reset: retry ?? (() => { }) } : props;
57
+ const pageProps = pageKind === 'error' ? { ...props, error: error ?? serverError(props), reset: retry ?? (() => { }) } : props;
48
58
  let element = Page ? _jsx(Page, { ...pageProps }, pageKey) : _jsx(BuiltInPage, { status: status, props: props }, pageKey);
49
59
  for (let i = modules.segments.length - 1; i >= 0; i--) {
50
60
  const { Layout, Template, Loading, Error: SegmentError, slots } = modules.segments[i];
@@ -1 +1 @@
1
- {"version":3,"file":"route-tree.js","sourceRoot":"","sources":["../src/route-tree.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"route-tree.js","sourceRoot":"","sources":["../src/route-tree.tsx"],"names":[],"mappings":"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"}
package/dist/router.d.ts CHANGED
@@ -19,15 +19,23 @@ export type NavigationState = {
19
19
  };
20
20
  /** The client router that `useRouter()` returns. */
21
21
  export type Router = {
22
+ /**
23
+ * Navigates, adding a history entry. The promise resolves once the router has handed the page to React, which can be
24
+ * before React shows it, or once the navigation has ended another way.
25
+ */
22
26
  push(href: Href, options?: {
23
27
  scroll?: boolean;
24
28
  }): Promise<void>;
29
+ /** Navigates, replacing the history entry. The promise resolves as `push`'s does. */
25
30
  replace(href: Href, options?: {
26
31
  scroll?: boolean;
27
32
  }): Promise<void>;
28
- /** Fetches the page payload and modules ahead of a navigation. Links do this on hover and focus. */
33
+ /** Fetches the page payload and modules ahead of a navigation. Links do this on hover, focus and touch. */
29
34
  prefetch(href: Href): void;
30
- /** Re-runs the current page's loader and re-renders with the new props. */
35
+ /**
36
+ * Runs every loader of the page on screen again, layout loaders included, and renders the page with the new props, in
37
+ * the same history entry and without scrolling. The promise resolves as `push`'s does.
38
+ */
31
39
  refresh(): Promise<void>;
32
40
  back(): void;
33
41
  forward(): void;
@@ -35,8 +43,22 @@ export type Router = {
35
43
  export type SubmitBody = EncodedForm;
36
44
  /** Called with every server action response, e.g. by the query shell to apply query updates. */
37
45
  export type ActionListener = (response: ActionResponse) => void;
38
- export type InternalRouter = Router & {
39
- submit(action: URL, body: SubmitBody): Promise<void>;
46
+ /**
47
+ * What `<Link>` and `<Form>` also pass: what had the focus before the app's own `onClick` or `onSubmit` ran. Those run
48
+ * as the navigation starts, so where they move the focus, such as back to the button of a menu that closes, is where
49
+ * the navigation put it.
50
+ */
51
+ type FocusAtStart = {
52
+ focusedAtStart?: Element | null;
53
+ };
54
+ export type InternalRouter = Omit<Router, 'push' | 'replace'> & {
55
+ push(href: Href, options?: {
56
+ scroll?: boolean;
57
+ } & FocusAtStart): Promise<void>;
58
+ replace(href: Href, options?: {
59
+ scroll?: boolean;
60
+ } & FocusAtStart): Promise<void>;
61
+ submit(action: URL, body: SubmitBody, options?: FocusAtStart): Promise<void>;
40
62
  onActionResponse(listener: ActionListener): () => void;
41
63
  /**
42
64
  * Called as soon as a server action call or form post says it set or deleted a cookie (signed someone in or out),
@@ -82,7 +104,7 @@ export declare function useInternalRouter(): InternalRouter;
82
104
  export declare function useRouter(): Router;
83
105
  /** The path without the base path, as the app's routes see it (like Next.js's `usePathname` with `basePath`). */
84
106
  export declare function usePathname(): string;
85
- /** An href for a plain `<a>` or attribute, under the base path: what `<Link>` does for its own. */
107
+ /** An href for a plain `<a>`, another attribute or a `fetch`, under the base path: what `<Link>` does for its own. */
86
108
  export declare function useHref(href: string): string;
87
109
  /** `UsePathBase`'s base path for this page, or '' when the app is mounted at the root. */
88
110
  export declare function useBasePath(): string;
@@ -115,4 +137,5 @@ export declare function useSelectedLayoutSegment(): string | null;
115
137
  export declare function usePagePayload(): PagePayload;
116
138
  /** The router's state: `loading` during a navigation, `submitting` during a form post, else `idle` (with `error` after a post that produced no page). */
117
139
  export declare function useNavigation(): NavigationState;
140
+ export {};
118
141
  //# sourceMappingURL=router.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.tsx"],"names":[],"mappings":"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"}
package/dist/router.js CHANGED
@@ -1,19 +1,33 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Suspense, createContext, startTransition, use, useContext, useEffect, useLayoutEffect, useMemo, useState, } from 'react';
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Suspense, createContext, startTransition, use, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
3
3
  import { actionRequest, expectActionClient, fetchAction, setActionClient } from './actions.js';
4
4
  import { deferredRegistry, revivePayload } from './deferred.js';
5
5
  import { MissingModuleError } from './modules.js';
6
+ import { moveFocusAfterNavigation } from './navigation-focus.js';
6
7
  import { COOKIES_HEADER, DATA_HEADER, SEGMENTS_HEADER, SERVER_TIME_HEADER, parseAntiforgery, parseNavigationPayload, } from './payload.js';
7
- import { ErrorBoundary, LayoutDepthContext, RouteTree } from './route-tree.js';
8
+ import { RouteAnnouncer } from './route-announcer.js';
9
+ import { ErrorBoundary, LayoutDepthContext, RouteTree, asError } from './route-tree.js';
8
10
  import { parseLenient, parseWith } from './schema.js';
9
11
  function isLoaded(result) {
10
12
  return 'payload' in result;
11
13
  }
14
+ /**
15
+ * What remounts the page and its templates when it changes: the page's path, or for an intercepted page the key of the
16
+ * page under it, which stays on screen. Two views with one key show the same page.
17
+ */
18
+ const pageKeyOf = (loaded) => loaded.pageKey ?? loaded.url.pathname;
12
19
  const IDLE = { state: 'idle' };
13
20
  const ANTIFORGERY_URL = '/_netjes/antiforgery';
14
21
  const NONE = { kind: 'none' };
15
22
  const TOP = { kind: 'top' };
16
23
  const STATE_KEY = '__netjes';
24
+ /**
25
+ * On `<html>` while the client router runs in the document, and the public sign that it does: end-to-end tests wait
26
+ * for it before they click. (The history entry's key is no such sign: the entry keeps it when the browser loads the
27
+ * document again.) The effect that sets it must stay after the one that registers the router as the action client,
28
+ * so that once it shows, the router has keyed the entry, listens for back and forward, and runs server action calls.
29
+ */
30
+ const HYDRATED_ATTRIBUTE = 'data-netjes-hydrated';
17
31
  const PREFETCH_TTL_MS = 30_000;
18
32
  const MAX_REDIRECTS = 10;
19
33
  const MAX_REMEMBERED_ENTRIES = 50;
@@ -247,7 +261,8 @@ class Navigator {
247
261
  this.channel?.close();
248
262
  this.channel = null;
249
263
  }
250
- async navigate(href, history, scroll) {
264
+ /** `focusedAtStart`: what had the focus as the navigation started, by default what has it as this is called. */
265
+ async navigate(href, history, scroll, focusedAtStart = document.activeElement) {
251
266
  const url = new URL(withBasePath(href, this.deps.basePath), window.location.href);
252
267
  if (!isWebUrl(url)) {
253
268
  console.error(`netjes: refusing to navigate to ${url.protocol} URL`);
@@ -264,7 +279,7 @@ class Navigator {
264
279
  const key = createKey();
265
280
  window.history[history === 'push' ? 'pushState' : 'replaceState']({ [STATE_KEY]: key }, '', url.href);
266
281
  this.setCurrent(key, { ...this.current, url });
267
- this.deps.commit(this.current, scroll ? { kind: 'hash', hash: url.hash } : NONE);
282
+ this.deps.commit(this.current, scroll ? { kind: 'hash', hash: url.hash } : NONE, focusedAtStart);
268
283
  return;
269
284
  }
270
285
  await this.go(url, { method: 'GET' }, {
@@ -273,10 +288,11 @@ class Navigator {
273
288
  pending: 'loading',
274
289
  usePrefetch: true,
275
290
  reuseSegments: true,
291
+ focusedAtStart,
276
292
  });
277
293
  }
278
- submit(action, body) {
279
- return this.go(action, { method: 'POST', ...body }, { history: 'auto', scroll: 'auto', pending: 'submitting', usePrefetch: false, reuseSegments: false });
294
+ submit(action, body, focusedAtStart = document.activeElement) {
295
+ return this.go(action, { method: 'POST', ...body }, { history: 'auto', scroll: 'auto', pending: 'submitting', usePrefetch: false, reuseSegments: false, focusedAtStart });
280
296
  }
281
297
  /**
282
298
  * Loads the page on screen again, in place: same history entry, fragment and scroll position. `keepPrefetched` after
@@ -420,12 +436,16 @@ class Navigator {
420
436
  if (known) {
421
437
  this.active?.controller.abort();
422
438
  this.setCurrent(key, { ...known, url });
423
- this.deps.commit(this.current, scroll);
439
+ this.deps.commit(this.current, scroll, document.activeElement);
424
440
  return;
425
441
  }
426
442
  void this.go(url, { method: 'GET' }, { history: 'none', scroll, pending: 'loading', key, usePrefetch: false, reuseSegments: true });
427
443
  }
428
444
  async go(url, request, options) {
445
+ // Read before anything this navigation starts can move it: inside the click (or the keypress) that started it,
446
+ // before React has handled that event's own state updates, such as a menu that closes. navigate() and submit()
447
+ // pass what they read, or what a link or a form read before the app's own handler ran.
448
+ const focusedAtStart = options.focusedAtStart === undefined ? document.activeElement : options.focusedAtStart;
429
449
  if (url.origin !== window.location.origin) {
430
450
  // navigate() and Form hand other origins to the browser, and every page URL the router keeps is on this one.
431
451
  // Refuse one that gets here all the same: a failed load would send the browser to it.
@@ -505,7 +525,7 @@ class Navigator {
505
525
  this.forgetToken();
506
526
  committed = true;
507
527
  const scroll = shown.base ? NONE : options.scroll === 'auto' ? (shown.url.pathname === previous.pathname ? NONE : TOP) : options.scroll;
508
- this.deps.commit(shown, scroll);
528
+ this.deps.commit(shown, scroll, focusedAtStart);
509
529
  }
510
530
  catch (error) {
511
531
  if (controller.signal.aborted)
@@ -678,23 +698,24 @@ function elementForFragment(fragment) {
678
698
  }
679
699
  return document.getElementById(decoded) ?? document.getElementById(fragment);
680
700
  }
701
+ /** Scrolls as the intent says, and returns the element a fragment names, which then takes the focus. */
681
702
  function applyScroll(intent) {
682
703
  switch (intent.kind) {
683
704
  case 'none':
684
- return;
705
+ return null;
685
706
  case 'top':
686
707
  window.scrollTo(0, 0);
687
- return;
708
+ return null;
688
709
  case 'restore':
689
710
  window.scrollTo(intent.x, intent.y);
690
- return;
711
+ return null;
691
712
  case 'hash': {
692
713
  const target = elementForFragment(intent.hash.slice(1));
693
714
  if (target)
694
715
  target.scrollIntoView();
695
716
  else
696
717
  window.scrollTo(0, 0);
697
- return;
718
+ return target;
698
719
  }
699
720
  default: {
700
721
  const exhaustive = intent;
@@ -737,6 +758,7 @@ export function RouterProvider({ initial, initialModules, loader, errorPage, har
737
758
  },
738
759
  id: 0,
739
760
  scroll: NONE,
761
+ focusedAtStart: null,
740
762
  }));
741
763
  const [navigation, setNavigation] = useState(IDLE);
742
764
  const [navigator] = useState(() => {
@@ -751,8 +773,8 @@ export function RouterProvider({ initial, initialModules, loader, errorPage, har
751
773
  showDocument,
752
774
  download,
753
775
  setPending: setNavigation,
754
- commit: (loaded, scroll) => startTransition(() => {
755
- setView((previous) => ({ loaded, id: previous.id + 1, scroll }));
776
+ commit: (loaded, scroll, focusedAtStart) => startTransition(() => {
777
+ setView((previous) => ({ loaded, id: previous.id + 1, scroll, focusedAtStart }));
756
778
  setNavigation(IDLE);
757
779
  }),
758
780
  }, view.loaded);
@@ -811,18 +833,36 @@ export function RouterProvider({ initial, initialModules, loader, errorPage, har
811
833
  return response;
812
834
  },
813
835
  }), [navigator, actionListeners]);
836
+ // Directly after the registration above, and in a passive effect, never a layout one: React runs a component's
837
+ // effects in order, a commit's layout effects before any passive one, and the mark must not show while server
838
+ // action calls still wait for the router.
839
+ useEffect(() => {
840
+ const html = document.documentElement;
841
+ html.setAttribute(HYDRATED_ATTRIBUTE, '');
842
+ return () => html.removeAttribute(HYDRATED_ATTRIBUTE);
843
+ }, []);
844
+ // The key of the page on screen before this commit.
845
+ const committedPageKey = useRef(pageKeyOf(view.loaded));
846
+ // In the commit that shows the page, before the browser paints it, and after the layout effects of the page and its
847
+ // layouts, which have focused an autoFocus element by then. Every focus call keeps the scroll position applyScroll
848
+ // sets, the one Back restores included.
814
849
  useLayoutEffect(() => {
815
- if (view.id > 0)
816
- applyScroll(view.scroll);
850
+ if (view.id === 0)
851
+ return;
852
+ const target = applyScroll(view.scroll);
853
+ const key = pageKeyOf(view.loaded);
854
+ const replaced = key !== committedPageKey.current;
855
+ committedPageKey.current = key;
856
+ moveFocusAfterNavigation({ target, replaced, keep: view.scroll.kind === 'none', focusedAtStart: view.focusedAtStart });
817
857
  }, [view]);
818
858
  const router = useMemo(() => ({
819
- push: (href, options) => navigator.navigate(href, 'push', options?.scroll ?? true),
820
- replace: (href, options) => navigator.navigate(href, 'replace', options?.scroll ?? true),
859
+ push: (href, options) => navigator.navigate(href, 'push', options?.scroll ?? true, options?.focusedAtStart),
860
+ replace: (href, options) => navigator.navigate(href, 'replace', options?.scroll ?? true, options?.focusedAtStart),
821
861
  prefetch: (href) => navigator.prefetch(href),
822
862
  refresh: () => navigator.refresh(),
823
863
  back: () => window.history.back(),
824
864
  forward: () => window.history.forward(),
825
- submit: (action, body) => navigator.submit(action, body),
865
+ submit: (action, body, options) => navigator.submit(action, body, options?.focusedAtStart),
826
866
  onActionResponse: (listener) => {
827
867
  actionListeners.add(listener);
828
868
  return () => actionListeners.delete(listener);
@@ -831,11 +871,16 @@ export function RouterProvider({ initial, initialModules, loader, errorPage, har
831
871
  }), [navigator, actionListeners]);
832
872
  const { payload, modules, url } = view.loaded;
833
873
  const viewValue = useMemo(() => ({ payload, url }), [payload, url]);
834
- return (_jsx(RouterContext, { value: router, children: _jsx(ViewContext, { value: viewValue, children: _jsx(NavigationContext, { value: navigation, children: _jsx(Shell, { children: _jsx(ErrorBoundary, { resetKey: view.id, fallback: (error) => _jsx(ErrorFallback, { error: error, errorPage: errorPage, loader: loader, payload: payload }), children: _jsx(RouteTree, { modules: modules, segments: payload.segments, props: payload.props, params: payload.params, status: payload.status, pageKind: payload.pageKind, pageKey: view.loaded.pageKey ?? url.pathname, retry: () => void router.refresh(), metadata: payload.metadata }) }) }) }) }) }));
874
+ return (_jsx(RouterContext, { value: router, children: _jsx(ViewContext, { value: viewValue, children: _jsxs(NavigationContext, { value: navigation, children: [_jsx(Shell, { children: _jsx(ErrorBoundary, { resetKey: view.id, fallback: (error) => _jsx(ErrorFallback, { error: error, errorPage: errorPage, loader: loader, payload: payload }), children: _jsx(RouteTree, { modules: modules, segments: payload.segments, props: payload.props, params: payload.params, status: payload.status, pageKind: payload.pageKind, pageKey: pageKeyOf(view.loaded), retry: () => void router.refresh(), metadata: payload.metadata }) }) }), _jsx(RouteAnnouncer, { location: url.pathname + url.search, path: withoutBasePath(url.pathname, payload.basePath ?? '') })] }) }) }));
835
875
  }
836
876
  const errorPageModules = new WeakMap();
877
+ /**
878
+ * What the router shows for an error no segment's boundary caught: the app's root error page, handed the error as it
879
+ * was thrown (its class, its stack, a server action's status), or the built-in page, which says 500.
880
+ */
837
881
  function ErrorFallback({ error, errorPage, loader, payload }) {
838
- const props = { status: 500, message: error instanceof Error ? error.message : 'Something went wrong' };
882
+ const caught = asError(error);
883
+ const props = { status: 500, message: caught.message };
839
884
  const builtIn = _jsx(RouteTree, { modules: { page: null, segments: [] }, props: props, params: payload.params, status: 500, pageKey: "error" });
840
885
  if (!errorPage)
841
886
  return builtIn;
@@ -844,10 +889,10 @@ function ErrorFallback({ error, errorPage, loader, payload }) {
844
889
  modules = loader.loadRoute(errorPage);
845
890
  errorPageModules.set(loader, modules);
846
891
  }
847
- return (_jsx(ErrorBoundary, { resetKey: 0, fallback: () => builtIn, children: _jsx(Suspense, { fallback: null, children: _jsx(LoadedErrorPage, { modules: modules, props: props, payload: payload }) }) }));
892
+ return (_jsx(ErrorBoundary, { resetKey: 0, fallback: () => builtIn, children: _jsx(Suspense, { fallback: null, children: _jsx(LoadedErrorPage, { modules: modules, props: props, error: caught, payload: payload }) }) }));
848
893
  }
849
- function LoadedErrorPage({ modules, props, payload }) {
850
- return _jsx(RouteTree, { modules: use(modules), props: props, params: payload.params, status: 500, pageKind: "error", pageKey: "error" });
894
+ function LoadedErrorPage({ modules, props, error, payload, }) {
895
+ return _jsx(RouteTree, { modules: use(modules), props: props, params: payload.params, status: 500, pageKind: "error", pageKey: "error", error: error });
851
896
  }
852
897
  /** The router's contexts without the router: for the test harness (netjes/testing), which fakes navigation. */
853
898
  export function RouterContexts({ router, payload, url, navigation, children, }) {
@@ -875,7 +920,7 @@ export function usePathname() {
875
920
  const { url, payload } = useView();
876
921
  return withoutBasePath(url.pathname, payload.basePath ?? '');
877
922
  }
878
- /** An href for a plain `<a>` or attribute, under the base path: what `<Link>` does for its own. */
923
+ /** An href for a plain `<a>`, another attribute or a `fetch`, under the base path: what `<Link>` does for its own. */
879
924
  export function useHref(href) {
880
925
  return withBasePath(href, useBasePath());
881
926
  }