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
package/dist/href.d.ts CHANGED
@@ -12,14 +12,42 @@ export type Href = Register extends {
12
12
  export type SearchValue = string | number | boolean | null | undefined;
13
13
  /** A query string as an object: a value per key, or a list of values for a key that repeats. */
14
14
  export type SearchParamsInput = Record<string, SearchValue | readonly SearchValue[]>;
15
+ /**
16
+ * Whether a URL has the shape of a link, as a C# `Href` checks it: root-relative (`/…`, but not `//…` or `/\…`, which
17
+ * browsers read as another host), a link within the page (`?…`, `#…`), or an `http:`, `https:`, `mailto:` or `tel:`
18
+ * URL, with no ASCII control character and no space at either end. It does not ask which page a path names: a page
19
+ * package's generated file, which cannot know the app's pages, checks its `Href` with this.
20
+ */
21
+ export declare function isHrefShape(value: string): boolean;
15
22
  /**
16
23
  * Whether a URL is one of the app's pages (by route pattern), a link within the page (`?…`, `#…`), or another
17
- * site. The generated `isHref()` and `Href` schema call this to check URLs that come from data.
24
+ * site. The generated `isHref()` and `Href` schema call this to check URLs that come from data. A URL with an ASCII
25
+ * control character, or with a space at either end, is none of these.
18
26
  */
19
27
  export declare function isRouteHref(value: string, patterns: readonly string[]): boolean;
20
28
  /**
21
29
  * Builds the URL for a route pattern written in file-name syntax (`/blog/[slug]`, `/docs/[...path]`,
22
- * `/shop/[[...filters]]`), encoding every segment value. The generated `route()` helper calls this with typed params.
30
+ * `/shop/[[...filters]]`), encoding every segment value. A value, or a catch-all entry, that is `.`, `..` or empty
31
+ * throws, since it would change the path the URL names. `options.hash` adds a fragment after the query: the id of an
32
+ * element in the page, with one leading `#` dropped and the rest encoded; with nothing left, no fragment is added. The
33
+ * generated `route()` helper calls this with typed params.
34
+ */
35
+ export declare function buildHref(pattern: string, params: Record<string, unknown>, search?: SearchParamsInput, options?: {
36
+ hash?: string | undefined;
37
+ }): string;
38
+ /**
39
+ * Builds the URL of one of the app's endpoints from its route template, as the generated file writes it: the
40
+ * literals as they are (with `%`, `{`, `}`, `#` and `\` encoded), `{name}`, `{name?}`, `{name=default}` (the default
41
+ * encoded), `{*name}` and `{**name}`, without constraints. Each route value is encoded; a `{**name}` value keeps its
42
+ * slashes, and a `{*name}` value has them encoded. A value that would make a segment `.` or `..`, or a `{**name}` value
43
+ * with such a piece or with an empty one before its end (`/x`, `a//b`), throws `netjes: endpoint '<endpoint>' cannot
44
+ * take '<value>' for the route value '<name>'`, since it would change the path the URL names. A missing, `null` or
45
+ * empty optional value drops its segment, or its
46
+ * part of a segment with the `.` before it (`{name}.{ext?}`); a missing value with a default is filled in, unless it
47
+ * is a whole segment at the end, which is dropped; a missing, `null` or empty required value, or an optional one whose
48
+ * segment is followed by one that stays, throws `netjes: endpoint '<endpoint>' needs the route value '<name>'`. The
49
+ * values the template does not name are the query string, followed by `search`. The result is root-relative and has no base path: pass it through
50
+ * `useHref` for a `fetch` or an `<a href>`. The generated `endpointUrl()` calls this with typed values.
23
51
  */
24
- export declare function buildHref(pattern: string, params: Record<string, unknown>, search?: SearchParamsInput): string;
52
+ export declare function buildEndpointUrl(template: string, values: Readonly<Record<string, unknown>>, search?: SearchParamsInput, endpoint?: string): string;
25
53
  //# sourceMappingURL=href.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"href.d.ts","sourceRoot":"","sources":["../src/href.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,QAAQ;CAAG;AAE5B,sGAAsG;AACtG,MAAM,MAAM,IAAI,GAAG,QAAQ,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC,SAAS,MAAM,CAAA;CAAE,GAAG,CAAC,GAAG,MAAM,CAAC;AAElF,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AACvE,gGAAgG;AAChG,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,WAAW,EAAE,CAAC,CAAC;AAarF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAM/E;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAoC9G"}
1
+ {"version":3,"file":"href.d.ts","sourceRoot":"","sources":["../src/href.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,QAAQ;CAAG;AAE5B,sGAAsG;AACtG,MAAM,MAAM,IAAI,GAAG,QAAQ,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC,SAAS,MAAM,CAAA;CAAE,GAAG,CAAC,GAAG,MAAM,CAAC;AAElF,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AACvE,gGAAgG;AAChG,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,WAAW,EAAE,CAAC,CAAC;AAarF;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAK/E;AAYD;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,CAAC,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACtC,MAAM,CAwCR;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,MAAM,CAAC,EAAE,iBAAiB,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAsDR"}
package/dist/href.js CHANGED
@@ -13,26 +13,60 @@ function matches(pattern, path) {
13
13
  return pattern.length === path.length;
14
14
  }
15
15
  /**
16
- * Whether a URL is one of the app's pages (by route pattern), a link within the page (`?…`, `#…`), or another
17
- * site. The generated `isHref()` and `Href` schema call this to check URLs that come from data.
16
+ * Whether a URL has the shape of a link, as a C# `Href` checks it: root-relative (`/…`, but not `//…` or `/\…`, which
17
+ * browsers read as another host), a link within the page (`?…`, `#…`), or an `http:`, `https:`, `mailto:` or `tel:`
18
+ * URL, with no ASCII control character and no space at either end. It does not ask which page a path names: a page
19
+ * package's generated file, which cannot know the app's pages, checks its `Href` with this.
18
20
  */
19
- export function isRouteHref(value, patterns) {
21
+ export function isHrefShape(value) {
22
+ // Browsers drop tabs and newlines anywhere in a URL, and control characters and spaces at either end: `/\t/host`
23
+ // would be `//host`. A C# Href refuses the same.
24
+ if (/[\u0000-\u001F\u007F]/.test(value) || value.startsWith(' ') || value.endsWith(' '))
25
+ return false;
20
26
  if (/^(https?:|mailto:|tel:)/i.test(value) || value.startsWith('?') || value.startsWith('#'))
21
27
  return true;
22
28
  // "//host" and "/\host" are other hosts as far as browsers are concerned.
23
- if (!value.startsWith('/') || value.startsWith('//') || value.startsWith('/\\'))
29
+ return value.startsWith('/') && !value.startsWith('//') && !value.startsWith('/\\');
30
+ }
31
+ /**
32
+ * Whether a URL is one of the app's pages (by route pattern), a link within the page (`?…`, `#…`), or another
33
+ * site. The generated `isHref()` and `Href` schema call this to check URLs that come from data. A URL with an ASCII
34
+ * control character, or with a space at either end, is none of these.
35
+ */
36
+ export function isRouteHref(value, patterns) {
37
+ if (!isHrefShape(value))
24
38
  return false;
39
+ if (!value.startsWith('/'))
40
+ return true;
25
41
  const path = (value.split(/[?#]/, 1)[0] ?? '').split('/').filter(Boolean);
26
42
  return patterns.some((pattern) => matches(pattern.split('/').filter(Boolean), path));
27
43
  }
44
+ /**
45
+ * A segment that would change the URL's path when a browser or `fetch` resolves it: `.` and `..` are dot segments,
46
+ * which move up the path, and an empty one doubles a slash, which right after the leading one names another host.
47
+ */
48
+ function changesThePath(segment) {
49
+ return segment === '' || segment === '.' || segment === '..';
50
+ }
51
+ const changesThePathMessage = "a '.', '..' or empty segment would change the URL's path";
28
52
  /**
29
53
  * Builds the URL for a route pattern written in file-name syntax (`/blog/[slug]`, `/docs/[...path]`,
30
- * `/shop/[[...filters]]`), encoding every segment value. The generated `route()` helper calls this with typed params.
54
+ * `/shop/[[...filters]]`), encoding every segment value. A value, or a catch-all entry, that is `.`, `..` or empty
55
+ * throws, since it would change the path the URL names. `options.hash` adds a fragment after the query: the id of an
56
+ * element in the page, with one leading `#` dropped and the rest encoded; with nothing left, no fragment is added. The
57
+ * generated `route()` helper calls this with typed params.
31
58
  */
32
- export function buildHref(pattern, params, search) {
59
+ export function buildHref(pattern, params, search, options) {
33
60
  const missing = (name) => {
34
61
  throw new Error(`netjes: route '${pattern}' needs the parameter '${name}'`);
35
62
  };
63
+ const encode = (name, value) => {
64
+ const text = String(value);
65
+ if (changesThePath(text)) {
66
+ throw new Error(`netjes: route '${pattern}' cannot take '${text}' for the parameter '${name}': ${changesThePathMessage}`);
67
+ }
68
+ return encodeURIComponent(text);
69
+ };
36
70
  const segments = pattern
37
71
  .split('/')
38
72
  .filter(Boolean)
@@ -40,32 +74,119 @@ export function buildHref(pattern, params, search) {
40
74
  const optional = /^\[\[\.\.\.(\w+)\]\]$/.exec(segment)?.[1];
41
75
  if (optional) {
42
76
  const values = params[optional];
43
- return Array.isArray(values) ? values.map((v) => encodeURIComponent(String(v))) : [];
77
+ return Array.isArray(values) ? values.map((v) => encode(optional, v)) : [];
44
78
  }
45
79
  const catchAll = /^\[\.\.\.(\w+)\]$/.exec(segment)?.[1];
46
80
  if (catchAll) {
47
81
  const values = params[catchAll];
48
82
  if (!Array.isArray(values) || values.length === 0)
49
83
  return missing(catchAll);
50
- return values.map((v) => encodeURIComponent(String(v)));
84
+ return values.map((v) => encode(catchAll, v));
51
85
  }
52
86
  const single = /^\[(\w+)\]$/.exec(segment)?.[1];
53
87
  if (single) {
54
88
  const value = params[single];
55
89
  if (value === undefined || value === null || value === '')
56
90
  return missing(single);
57
- return [encodeURIComponent(String(value))];
91
+ return [encode(single, value)];
58
92
  }
59
93
  return [segment];
60
94
  });
61
95
  const query = new URLSearchParams();
96
+ appendSearch(query, search);
97
+ const queryString = query.toString();
98
+ const fragment = (options?.hash ?? '').replace(/^#/, '');
99
+ return `/${segments.join('/')}${queryString ? `?${queryString}` : ''}${fragment ? `#${encodeURIComponent(fragment)}` : ''}`;
100
+ }
101
+ /** Appends each value of `search`, a list repeating its key; `null` and `undefined` leave the key out. */
102
+ function appendSearch(query, search) {
62
103
  for (const [key, value] of Object.entries(search ?? {})) {
63
104
  for (const item of Array.isArray(value) ? value : [value]) {
64
105
  if (item !== undefined && item !== null)
65
106
  query.append(key, String(item));
66
107
  }
67
108
  }
109
+ }
110
+ /** A missing route value: `undefined`, `null` or `''`. */
111
+ function absent(value) {
112
+ return value === undefined || value === null || value === '';
113
+ }
114
+ /**
115
+ * Builds the URL of one of the app's endpoints from its route template, as the generated file writes it: the
116
+ * literals as they are (with `%`, `{`, `}`, `#` and `\` encoded), `{name}`, `{name?}`, `{name=default}` (the default
117
+ * encoded), `{*name}` and `{**name}`, without constraints. Each route value is encoded; a `{**name}` value keeps its
118
+ * slashes, and a `{*name}` value has them encoded. A value that would make a segment `.` or `..`, or a `{**name}` value
119
+ * with such a piece or with an empty one before its end (`/x`, `a//b`), throws `netjes: endpoint '<endpoint>' cannot
120
+ * take '<value>' for the route value '<name>'`, since it would change the path the URL names. A missing, `null` or
121
+ * empty optional value drops its segment, or its
122
+ * part of a segment with the `.` before it (`{name}.{ext?}`); a missing value with a default is filled in, unless it
123
+ * is a whole segment at the end, which is dropped; a missing, `null` or empty required value, or an optional one whose
124
+ * segment is followed by one that stays, throws `netjes: endpoint '<endpoint>' needs the route value '<name>'`. The
125
+ * values the template does not name are the query string, followed by `search`. The result is root-relative and has no base path: pass it through
126
+ * `useHref` for a `fetch` or an `<a href>`. The generated `endpointUrl()` calls this with typed values.
127
+ */
128
+ export function buildEndpointUrl(template, values, search, endpoint) {
129
+ const needs = (name) => new Error(`netjes: endpoint '${endpoint ?? template}' needs the route value '${name}'`);
130
+ const cannotTake = (name, value) => new Error(`netjes: endpoint '${endpoint ?? template}' cannot take '${String(value)}' for the route value '${name}': ${changesThePathMessage}`);
131
+ const named = new Set();
132
+ // Each segment's text, and the name of the value it is missing, when the segment can go for want of it.
133
+ const segments = [];
134
+ for (const segment of template.split('/').filter(Boolean)) {
135
+ let text = '';
136
+ let missing;
137
+ // The value that made the segment's text, which must not leave it a dot segment.
138
+ let filled;
139
+ for (const part of segment.split(/(\{[^}]*\})/).filter(Boolean)) {
140
+ const parameter = /^\{(\*\*?)?([^=?]+?)(\?|=([^]*))?\}$/.exec(part);
141
+ if (!parameter) {
142
+ text += part;
143
+ continue;
144
+ }
145
+ const [, star, name = '', marker, fallback] = parameter;
146
+ named.add(name);
147
+ const value = values[name];
148
+ if (!absent(value) && star === '**') {
149
+ // Each piece is a segment of its own; an empty last one is a trailing slash.
150
+ const pieces = String(value).split('/');
151
+ if (pieces.some((piece, i) => (piece === '' ? i < pieces.length - 1 : changesThePath(piece))))
152
+ throw cannotTake(name, value);
153
+ text += pieces.map((piece) => encodeURIComponent(piece)).join('/');
154
+ }
155
+ else if (!absent(value)) {
156
+ text += encodeURIComponent(String(value));
157
+ filled = name;
158
+ }
159
+ else if (fallback !== undefined) {
160
+ text += fallback;
161
+ if (part === segment)
162
+ missing = name;
163
+ }
164
+ else if (marker === '?' || star) {
165
+ // An optional value after a literal `.` takes the dot with it.
166
+ if (text.endsWith('.'))
167
+ text = text.slice(0, -1);
168
+ if (!text)
169
+ missing = name;
170
+ }
171
+ else {
172
+ throw needs(name);
173
+ }
174
+ }
175
+ if (filled && changesThePath(text))
176
+ throw cannotTake(filled, values[filled]);
177
+ if (text || missing)
178
+ segments.push({ text, missing });
179
+ }
180
+ while (segments.at(-1)?.missing)
181
+ segments.pop();
182
+ // A segment left out before one that stays: routing would not match, or would read the next value as this one.
183
+ const leftOut = segments.find((segment) => !segment.text)?.missing;
184
+ if (leftOut)
185
+ throw needs(leftOut);
186
+ const query = new URLSearchParams();
187
+ appendSearch(query, Object.fromEntries(Object.entries(values).filter(([key]) => !named.has(key))));
188
+ appendSearch(query, search);
68
189
  const queryString = query.toString();
69
- return `/${segments.join('/')}${queryString ? `?${queryString}` : ''}`;
190
+ return `/${segments.map((s) => s.text).join('/')}${queryString ? `?${queryString}` : ''}`;
70
191
  }
71
192
  //# sourceMappingURL=href.js.map
package/dist/href.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"href.js","sourceRoot":"","sources":["../src/href.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"href.js","sourceRoot":"","sources":["../src/href.ts"],"names":[],"mappings":"AAeA,SAAS,OAAO,CAAC,OAA0B,EAAE,IAAuB;IAClE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7C,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACpE,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,iHAAiH;IACjH,iDAAiD;IACjD,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACtG,IAAI,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1G,0EAA0E;IAC1E,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACtF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,QAA2B;IACpE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1E,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACvF,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,OAAe;IACrC,OAAO,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC;AAC/D,CAAC;AAED,MAAM,qBAAqB,GAAG,0DAA0D,CAAC;AAEzF;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,OAAe,EACf,MAA+B,EAC/B,MAA0B,EAC1B,OAAuC;IAEvC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAS,EAAE;QACtC,MAAM,IAAI,KAAK,CAAC,kBAAkB,OAAO,0BAA0B,IAAI,GAAG,CAAC,CAAC;IAC9E,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAc,EAAU,EAAE;QACtD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,kBAAkB,OAAO,kBAAkB,IAAI,wBAAwB,IAAI,MAAM,qBAAqB,EAAE,CAAC,CAAC;QAC5H,CAAC;QACD,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,OAAO;SACrB,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,OAAO,CAAC;SACf,OAAO,CAAC,CAAC,OAAO,EAAY,EAAE;QAC7B,MAAM,QAAQ,GAAG,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,CAAC;QACD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxD,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC5E,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;gBAAE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;YAClF,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IAEL,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IACpC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5B,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACzD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC9H,CAAC;AAED,0GAA0G;AAC1G,SAAS,YAAY,CAAC,KAAsB,EAAE,MAAqD;IACjG,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAA4B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAClF,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI;gBAAE,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,SAAS,MAAM,CAAC,KAAc;IAC5B,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAAgB,EAChB,MAAyC,EACzC,MAA0B,EAC1B,QAAiB;IAEjB,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,qBAAqB,QAAQ,IAAI,QAAQ,4BAA4B,IAAI,GAAG,CAAC,CAAC;IACxH,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE,CAClD,IAAI,KAAK,CAAC,qBAAqB,QAAQ,IAAI,QAAQ,kBAAkB,MAAM,CAAC,KAAK,CAAC,0BAA0B,IAAI,MAAM,qBAAqB,EAAE,CAAC,CAAC;IACjJ,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,wGAAwG;IACxG,MAAM,QAAQ,GAAoD,EAAE,CAAC;IACrE,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1D,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,OAA2B,CAAC;QAChC,iFAAiF;QACjF,IAAI,MAA0B,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAChE,MAAM,SAAS,GAAG,sCAAsC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpE,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,IAAI,IAAI,IAAI,CAAC;gBACb,SAAS;YACX,CAAC;YAED,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC;YACxD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBACpC,6EAA6E;gBAC7E,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACxC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;oBAAE,MAAM,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBAC7H,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrE,CAAC;iBAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1B,IAAI,IAAI,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC1C,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAClC,IAAI,IAAI,QAAQ,CAAC;gBACjB,IAAI,IAAI,KAAK,OAAO;oBAAE,OAAO,GAAG,IAAI,CAAC;YACvC,CAAC;iBAAM,IAAI,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;gBAClC,+DAA+D;gBAC/D,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;oBAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACjD,IAAI,CAAC,IAAI;oBAAE,OAAO,GAAG,IAAI,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QACD,IAAI,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC;YAAE,MAAM,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7E,IAAI,IAAI,IAAI,OAAO;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO;QAAE,QAAQ,CAAC,GAAG,EAAE,CAAC;IAChD,+GAA+G;IAC/G,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACnE,IAAI,OAAO;QAAE,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IACpC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnG,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5B,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IACrC,OAAO,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC5F,CAAC"}
package/dist/image.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type ImgHTMLAttributes } from 'react';
1
+ import { type ComponentPropsWithRef } from 'react';
2
2
  /**
3
3
  * Where the optimizer lives, and the widths and qualities it serves: Netjes:Images on the server, sent with the first
4
4
  * document. Without `qualities`, any quality is requested as given.
@@ -10,8 +10,8 @@ export type ImageConfig = {
10
10
  basePath?: string;
11
11
  };
12
12
  export declare const ImageConfigProvider: import("react").Provider<ImageConfig>;
13
- /** The props of `<Image>`: an `<img>`'s own, with a required size and `alt`, and the optimizer's options. */
14
- export type ImageProps = Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'srcSet' | 'width' | 'height' | 'loading' | 'alt'> & {
13
+ /** The props of `<Image>`: an `<img>`'s own and its ref, with a required size and `alt`, and the optimizer's options. */
14
+ export type ImageProps = Omit<ComponentPropsWithRef<'img'>, 'src' | 'srcSet' | 'width' | 'height' | 'loading' | 'alt'> & {
15
15
  /** A path in `public/` (`/img/hero.png`) or a URL on a host in Netjes:Images:RemoteHosts. */
16
16
  src: string;
17
17
  /** Required, as for any image; `""` for decorative ones. */
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/image.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAA6B,MAAM,OAAO,CAAC;AAG1E;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAUxH,eAAO,MAAM,mBAAmB,uCAA8B,CAAC;AAE/D,6GAA6G;AAC7G,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC,GAAG;IAC9H,6FAA6F;IAC7F,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,8GAA8G;IAC9G,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAyBF;;;GAGG;AACH,wBAAgB,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAY,EAAE,QAAgB,EAAE,WAAmB,EAAE,GAAG,IAAI,EAAE,EAAE,UAAU,+BAyBjI"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/image.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAA6B,MAAM,OAAO,CAAC;AAG9E;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAUxH,eAAO,MAAM,mBAAmB,uCAA8B,CAAC;AAE/D,yHAAyH;AACzH,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC,GAAG;IACvH,6FAA6F;IAC7F,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,8GAA8G;IAC9G,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAyBF;;;GAGG;AACH,wBAAgB,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAY,EAAE,QAAgB,EAAE,WAAmB,EAAE,GAAG,IAAI,EAAE,EAAE,UAAU,+BAyBjI"}
package/dist/image.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","sourceRoot":"","sources":["../src/image.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../src/image.tsx"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  export { type ActionState, type PageActionFailure, type ServerAction, ServerActionError, type UseActionOptions, serverAction, useAction, usePageActionState, } from './actions.tsx';
2
2
  export { defineLayout, definePage } from './define-page.tsx';
3
+ export { CSP_SCRIPT_HASHES } from './deferred.ts';
3
4
  export { useDraftMode } from './draft-mode.ts';
4
5
  export { type DynamicOptions, clientOnly, dynamic } from './dynamic.tsx';
5
6
  export { Form, type FormAction, type FormProps, SubmitButton, type SubmitButtonProps } from './form.tsx';
6
- export { type Href, type Register, type SearchParamsInput, type SearchValue, buildHref, isRouteHref } from './href.ts';
7
+ export { type Href, type Register, type SearchParamsInput, type SearchValue, buildEndpointUrl, buildHref, isHrefShape, isRouteHref, } from './href.ts';
7
8
  export { Image, type ImageProps } from './image.tsx';
8
9
  export { Link, type LinkProps } from './link.tsx';
9
10
  export { useLocale } from './locale.ts';
10
11
  export type { ErrorPageProps, LayoutProps } from './modules.ts';
12
+ export { type Mounted, type MountedFormProps, type MountedLinkProps, type MountedRouter, type MountedSubmitButtonProps, mounted, } from './mounted.tsx';
11
13
  export { useNonce } from './nonce.tsx';
12
14
  export type { PageKind, Params, SeededQuery, SegmentRef } from './payload.ts';
13
15
  export { usePublicConfig } from './public-config.tsx';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,YAAY,EACZ,SAAS,EACT,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,KAAK,cAAc,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,KAAK,iBAAiB,EAAE,KAAK,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACvH,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,WAAW,EACX,OAAO,EACP,aAAa,EACb,SAAS,EACT,WAAW,EACX,SAAS,EACT,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,YAAY,EACZ,SAAS,EACT,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,KAAK,cAAc,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,EACL,KAAK,IAAI,EACT,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,gBAAgB,EAChB,SAAS,EACT,WAAW,EACX,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,wBAAwB,EAC7B,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,WAAW,EACX,OAAO,EACP,aAAa,EACb,SAAS,EACT,WAAW,EACX,SAAS,EACT,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,12 +1,14 @@
1
1
  export { ServerActionError, serverAction, useAction, usePageActionState, } from './actions.js';
2
2
  export { defineLayout, definePage } from './define-page.js';
3
+ export { CSP_SCRIPT_HASHES } from './deferred.js';
3
4
  export { useDraftMode } from './draft-mode.js';
4
5
  export { clientOnly, dynamic } from './dynamic.js';
5
6
  export { Form, SubmitButton } from './form.js';
6
- export { buildHref, isRouteHref } from './href.js';
7
+ export { buildEndpointUrl, buildHref, isHrefShape, isRouteHref, } from './href.js';
7
8
  export { Image } from './image.js';
8
9
  export { Link } from './link.js';
9
10
  export { useLocale } from './locale.js';
11
+ export { mounted, } from './mounted.js';
10
12
  export { useNonce } from './nonce.js';
11
13
  export { usePublicConfig } from './public-config.js';
12
14
  export { Script } from './script.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,iBAAiB,EAEjB,YAAY,EACZ,SAAS,EACT,kBAAkB,GACnB,MAAM,cAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAmB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAuB,UAAU,EAAE,OAAO,EAAE,MAAM,cAAe,CAAC;AACzE,OAAO,EAAE,IAAI,EAAmC,YAAY,EAA0B,MAAM,WAAY,CAAC;AACzG,OAAO,EAAsE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACvH,OAAO,EAAE,KAAK,EAAmB,MAAM,YAAa,CAAC;AACrD,OAAO,EAAE,IAAI,EAAkB,MAAM,WAAY,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAa,CAAC;AAEvC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAyC,MAAM,aAAc,CAAC;AAC7E,OAAO,EAIL,WAAW,EACX,OAAO,EACP,aAAa,EACb,SAAS,EACT,WAAW,EACX,SAAS,EACT,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,GACf,MAAM,aAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,iBAAiB,EAEjB,YAAY,EACZ,SAAS,EACT,kBAAkB,GACnB,MAAM,cAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAmB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAuB,UAAU,EAAE,OAAO,EAAE,MAAM,cAAe,CAAC;AACzE,OAAO,EAAE,IAAI,EAAmC,YAAY,EAA0B,MAAM,WAAY,CAAC;AACzG,OAAO,EAKL,gBAAgB,EAChB,SAAS,EACT,WAAW,EACX,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,EAAmB,MAAM,YAAa,CAAC;AACrD,OAAO,EAAE,IAAI,EAAkB,MAAM,WAAY,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAML,OAAO,GACR,MAAM,cAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAa,CAAC;AAEvC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAyC,MAAM,aAAc,CAAC;AAC7E,OAAO,EAIL,WAAW,EACX,OAAO,EACP,aAAa,EACb,SAAS,EACT,WAAW,EACX,SAAS,EACT,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,GACf,MAAM,aAAc,CAAC"}
package/dist/link.d.ts CHANGED
@@ -1,17 +1,25 @@
1
- import type { AnchorHTMLAttributes } from 'react';
1
+ import type { ComponentPropsWithRef } from 'react';
2
2
  import type { Href } from './href.ts';
3
- /** The props of `<Link>`: an anchor's own, with a typed `href` and the client navigation options. */
4
- export type LinkProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {
3
+ /** The props of `<Link>`: an anchor's own and its ref, with a typed `href` and the client navigation options. */
4
+ export type LinkProps = Omit<ComponentPropsWithRef<'a'>, 'href'> & {
5
5
  /** Typed by the app's routes once `netjes generate` has registered them. */
6
6
  href: Href;
7
7
  replace?: boolean;
8
- /** Scroll to the top (or the #fragment) after navigating. Default true. */
8
+ /**
9
+ * Scroll to the top after navigating, or to the #fragment's element, which then takes the focus. Default true. `false`
10
+ * keeps the scroll position, and the focus on the link while the link has it.
11
+ */
9
12
  scroll?: boolean;
10
- /** `intent` (default) fetches the next page on hover or focus. */
13
+ /** `intent` (default) fetches the next page on hover, focus or touch. */
11
14
  prefetch?: 'intent' | 'none';
12
- /** Let the browser follow it with a full page load, e.g. for a file download or a page outside Netjes. */
15
+ /** Let the browser follow it with a full page load: for a page of the app that must load in full, or a page on another site. */
13
16
  reloadDocument?: boolean;
14
17
  };
15
- /** An `<a>` that navigates on the client. Ctrl/cmd-click, new tabs and external URLs behave like a normal link. */
18
+ /**
19
+ * An `<a>` that navigates on the client. Ctrl/cmd-click, new tabs and external URLs behave like a normal link. It sets
20
+ * `aria-current="page"` on a link to the page on screen: the same path, one trailing slash aside, and the page's values
21
+ * for each query parameter the link names. A link with a `#` is never marked, and an `aria-current` prop wins. After a
22
+ * navigation to another page, the router announces the page and starts the focus over at the top of the document.
23
+ */
16
24
  export declare function Link({ href, replace, scroll, prefetch, reloadDocument, onClick, onMouseEnter, onFocus, onTouchStart, ...rest }: LinkProps): import("react").JSX.Element;
17
25
  //# sourceMappingURL=link.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../src/link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAc,MAAM,OAAO,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGtC,qGAAqG;AACrG,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,GAAG;IAC9E,4EAA4E;IAC5E,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC7B,0GAA0G;IAC1G,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAsBF,mHAAmH;AACnH,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,OAAe,EAAE,MAAa,EAAE,QAAmB,EAAE,cAAsB,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,+BAkC3K"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../src/link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAc,MAAM,OAAO,CAAC;AAC/D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGtC,iHAAiH;AACjH,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,GAAG;IACjE,4EAA4E;IAC5E,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC7B,gIAAgI;IAChI,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AA4CF;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,OAAe,EAAE,MAAa,EAAE,QAAmB,EAAE,cAAsB,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,+BAsC3K"}
package/dist/link.js CHANGED
@@ -1,9 +1,31 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useBasePath, useInternalRouter, usePathname, withBasePath } from './router.js';
2
+ import { useBasePath, useInternalRouter, usePathname, useSearchParams, withBasePath } from './router.js';
3
3
  const BASE = 'http://netjes.invalid';
4
- function isCurrentPath(href, pathname) {
5
- const url = new URL(href, BASE + pathname);
6
- return url.origin === BASE && url.pathname === pathname;
4
+ /** One trailing slash makes no other page: `/docs/` is `/docs`, and `/` stays `/`. */
5
+ function withoutTrailingSlash(path) {
6
+ return path.length > 1 && path.endsWith('/') ? path.slice(0, -1) : path;
7
+ }
8
+ /** The same values, in any order, as often each. */
9
+ function sameValues(a, b) {
10
+ const sorted = [...b].sort();
11
+ return a.length === b.length && [...a].sort().every((value, i) => value === sorted[i]);
12
+ }
13
+ /**
14
+ * Whether the link goes to the page on screen. An href with a `#` points to a place in a page, so it never does.
15
+ * Otherwise its URL under the base path has the page's path, give or take one trailing slash, and the page's
16
+ * values for each query parameter it names; parameters it leaves out do not count. Only the path and the query
17
+ * enter, against a fixed origin, so the server and the browser agree.
18
+ */
19
+ function isCurrentPage(href, pathname, search, basePath) {
20
+ if (href.includes('#'))
21
+ return false;
22
+ const query = search.toString();
23
+ // The page's URL as the browser has it: the base path, then the page's path, even one that starts like the base path.
24
+ const page = new URL(BASE + basePath + pathname + (query ? `?${query}` : ''));
25
+ const target = new URL(withBasePath(href, basePath), page);
26
+ if (target.origin !== BASE || withoutTrailingSlash(target.pathname) !== withoutTrailingSlash(page.pathname))
27
+ return false;
28
+ return [...new Set(target.searchParams.keys())].every((key) => sameValues(target.searchParams.getAll(key), search.getAll(key)));
7
29
  }
8
30
  function isPlainLeftClick(event) {
9
31
  const anchor = event.currentTarget;
@@ -15,23 +37,32 @@ function isPlainLeftClick(event) {
15
37
  (!anchor.target || anchor.target === '_self') &&
16
38
  !anchor.hasAttribute('download'));
17
39
  }
18
- /** An `<a>` that navigates on the client. Ctrl/cmd-click, new tabs and external URLs behave like a normal link. */
40
+ /**
41
+ * An `<a>` that navigates on the client. Ctrl/cmd-click, new tabs and external URLs behave like a normal link. It sets
42
+ * `aria-current="page"` on a link to the page on screen: the same path, one trailing slash aside, and the page's values
43
+ * for each query parameter the link names. A link with a `#` is never marked, and an `aria-current` prop wins. After a
44
+ * navigation to another page, the router announces the page and starts the focus over at the top of the document.
45
+ */
19
46
  export function Link({ href, replace = false, scroll = true, prefetch = 'intent', reloadDocument = false, onClick, onMouseEnter, onFocus, onTouchStart, ...rest }) {
20
47
  const router = useInternalRouter();
21
48
  const pathname = usePathname();
49
+ const search = useSearchParams();
22
50
  const basePath = useBasePath();
23
51
  const warm = () => {
24
52
  if (prefetch === 'intent' && !reloadDocument)
25
53
  router.prefetch(href);
26
54
  };
27
- return (_jsx("a", { href: withBasePath(href, basePath), "aria-current": isCurrentPath(href, pathname) ? 'page' : undefined, ...rest, onClick: (event) => {
55
+ return (_jsx("a", { href: withBasePath(href, basePath), "aria-current": isCurrentPage(href, pathname, search, basePath) ? 'page' : undefined, ...rest, onClick: (event) => {
56
+ // Read before the app's own onClick, which runs as the link is followed: where it moves the focus, such as
57
+ // back to the button of a menu that closes, the router leaves it.
58
+ const focusedAtStart = document.activeElement;
28
59
  onClick?.(event);
29
60
  if (event.defaultPrevented || reloadDocument || !isPlainLeftClick(event))
30
61
  return;
31
62
  if (new URL(href, window.location.href).origin !== window.location.origin)
32
63
  return;
33
64
  event.preventDefault();
34
- void (replace ? router.replace(href, { scroll }) : router.push(href, { scroll }));
65
+ void (replace ? router.replace(href, { scroll, focusedAtStart }) : router.push(href, { scroll, focusedAtStart }));
35
66
  }, onMouseEnter: (event) => {
36
67
  onMouseEnter?.(event);
37
68
  warm();
package/dist/link.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.tsx"],"names":[],"mappings":"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"}
@@ -1,4 +1,8 @@
1
- /** A title, or a layout's `default` and `template` (`'%s · Site'`), or an `absolute` title that skips templates. */
1
+ /**
2
+ * A title, a layout's `template` (`'%s · Site'`) and `default`, or an `absolute` title that skips templates. A
3
+ * `default`, on a layout or a page, goes through the nearest `template` of the layouts above it like a string title,
4
+ * never through the one beside it; a layout's `default` is also the title of the pages below it that set none.
5
+ */
2
6
  export type MetadataTitle = string | {
3
7
  default?: string;
4
8
  template?: string;
@@ -72,7 +76,9 @@ export type ResolvedMetadata = Omit<Metadata, 'title' | 'openGraph' | 'twitter'>
72
76
  };
73
77
  /**
74
78
  * Merges the layouts' metadata (outermost first), the page's, and the server's. A layout's `title.template` applies
75
- * to titles below it, `title.default` is used when nothing below sets one, `title.absolute` skips templates.
79
+ * to the titles below it. `title.default`, on a layout or a page, goes through the templates above it like a string
80
+ * title and never through its own; on a layout it is the title when nothing below sets one. `title.absolute` skips
81
+ * templates.
76
82
  */
77
83
  export declare function resolveMetadata(layouts: readonly (Metadata | undefined)[], page: Metadata | undefined, server?: Metadata): ResolvedMetadata;
78
84
  /** The tags for resolved metadata; rendered anywhere, React puts them in <head>. */
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.tsx"],"names":[],"mappings":"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"}
package/dist/metadata.js CHANGED
@@ -2,15 +2,21 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
2
2
  // The Next.js Metadata API: `export const metadata` from pages and layouts, plus metadata sent by the C# loader
3
3
  // (`.WithMetadata(...)`, the counterpart of generateMetadata). React 19 hoists the tags into <head>.
4
4
  import { Fragment } from 'react';
5
+ /**
6
+ * The title that `title` stands for, given the template from the layouts above it. A string and a `default` go
7
+ * through the template, an `absolute` title does not, and an object with no `default` and no `absolute` (a layout
8
+ * that only sets a template) has no title of its own.
9
+ */
5
10
  function titleOf(title, template) {
6
11
  if (title === undefined)
7
12
  return undefined;
8
13
  // A function replacer: a title such as "Save $& now" must not be read as a replacement pattern.
14
+ const inTemplate = (text) => (template ? template.replace('%s', () => text) : text);
9
15
  if (typeof title === 'string')
10
- return template ? template.replace('%s', () => title) : title;
16
+ return inTemplate(title);
11
17
  if (title.absolute !== undefined)
12
18
  return title.absolute;
13
- return title.default;
19
+ return title.default === undefined ? undefined : inTemplate(title.default);
14
20
  }
15
21
  /** The images as a list of descriptors with string URLs; like Next.js, a null image or one without a URL is left out. */
16
22
  function imagesOf(images) {
@@ -26,7 +32,9 @@ function withImages(group) {
26
32
  }
27
33
  /**
28
34
  * Merges the layouts' metadata (outermost first), the page's, and the server's. A layout's `title.template` applies
29
- * to titles below it, `title.default` is used when nothing below sets one, `title.absolute` skips templates.
35
+ * to the titles below it. `title.default`, on a layout or a page, goes through the templates above it like a string
36
+ * title and never through its own; on a layout it is the title when nothing below sets one. `title.absolute` skips
37
+ * templates.
30
38
  */
31
39
  export function resolveMetadata(layouts, page, server) {
32
40
  let resolved = {};
@@ -37,8 +45,9 @@ export function resolveMetadata(layouts, page, server) {
37
45
  const { title, openGraph, twitter, alternates, icons, other, ...rest } = metadata;
38
46
  resolved = { ...resolved, ...rest };
39
47
  if (title !== undefined) {
40
- // A layout's own default is not put through its own template, only templates from above.
41
- const own = titleOf(title, typeof title === 'string' || title.default === undefined ? template : undefined);
48
+ // The template from above applies to every title but an absolute one, a default included. This title's own
49
+ // template is stored after its title is written, so it applies only to the titles below.
50
+ const own = titleOf(title, template);
42
51
  if (own !== undefined)
43
52
  resolved.title = own;
44
53
  if (typeof title === 'object' && title.template)