@nanisoft/prism-ui 0.16.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/blocks/activity-feed-01/activity-feed-01.d.ts +120 -190
  3. package/dist/blocks/activity-feed-01/activity-feed-01.d.ts.map +1 -1
  4. package/dist/blocks/activity-feed-01/activity-feed-01.js +107 -97
  5. package/dist/blocks/activity-feed-01/index.d.ts +1 -1
  6. package/dist/blocks/activity-feed-01/index.d.ts.map +1 -1
  7. package/dist/blocks/auth-form-01/auth-form.d.ts +86 -53
  8. package/dist/blocks/auth-form-01/auth-form.d.ts.map +1 -1
  9. package/dist/blocks/auth-form-01/auth-form.js +95 -31
  10. package/dist/blocks/auth-form-01/index.d.ts +1 -1
  11. package/dist/blocks/auth-form-01/index.d.ts.map +1 -1
  12. package/dist/blocks/calendar-01/calendar.d.ts +28 -0
  13. package/dist/blocks/calendar-01/calendar.d.ts.map +1 -1
  14. package/dist/blocks/calendar-01/calendar.js +15 -1
  15. package/dist/blocks/card-index-01/card-index.d.ts +225 -0
  16. package/dist/blocks/card-index-01/card-index.d.ts.map +1 -0
  17. package/dist/blocks/card-index-01/card-index.js +154 -0
  18. package/dist/blocks/card-index-01/index.d.ts +3 -0
  19. package/dist/blocks/card-index-01/index.d.ts.map +1 -0
  20. package/dist/blocks/card-index-01/index.js +1 -0
  21. package/dist/blocks/chart-card-01/chart-card-01.d.ts +23 -21
  22. package/dist/blocks/chart-card-01/chart-card-01.d.ts.map +1 -1
  23. package/dist/blocks/chart-card-01/chart-card-01.js +46 -1
  24. package/dist/blocks/chart-card-01/index.d.ts +1 -1
  25. package/dist/blocks/chart-card-01/index.d.ts.map +1 -1
  26. package/dist/blocks/chart-group-01/chart-group-01.d.ts +3 -3
  27. package/dist/blocks/chart-group-01/chart-group-01.d.ts.map +1 -1
  28. package/dist/blocks/contact-01/contact.d.ts +30 -82
  29. package/dist/blocks/contact-01/contact.d.ts.map +1 -1
  30. package/dist/blocks/contact-01/contact.js +59 -30
  31. package/dist/blocks/contact-01/index.d.ts +1 -1
  32. package/dist/blocks/contact-01/index.d.ts.map +1 -1
  33. package/dist/blocks/dashboard-01/dashboard-01.d.ts +26 -71
  34. package/dist/blocks/dashboard-01/dashboard-01.d.ts.map +1 -1
  35. package/dist/blocks/dashboard-01/dashboard-01.js +34 -23
  36. package/dist/blocks/dashboard-01/index.d.ts +1 -1
  37. package/dist/blocks/dashboard-01/index.d.ts.map +1 -1
  38. package/dist/blocks/data-table-01/data-table.d.ts +276 -59
  39. package/dist/blocks/data-table-01/data-table.d.ts.map +1 -1
  40. package/dist/blocks/data-table-01/data-table.js +217 -35
  41. package/dist/blocks/data-table-01/index.d.ts +1 -1
  42. package/dist/blocks/data-table-01/index.d.ts.map +1 -1
  43. package/dist/blocks/directory-01/directory-01.d.ts +23 -2
  44. package/dist/blocks/directory-01/directory-01.d.ts.map +1 -1
  45. package/dist/blocks/directory-01/directory-01.js +3 -3
  46. package/dist/blocks/empty-state-01/empty-state.d.ts +60 -21
  47. package/dist/blocks/empty-state-01/empty-state.d.ts.map +1 -1
  48. package/dist/blocks/empty-state-01/empty-state.js +52 -17
  49. package/dist/blocks/index-detail-01/index-detail.d.ts +85 -0
  50. package/dist/blocks/index-detail-01/index-detail.d.ts.map +1 -0
  51. package/dist/blocks/index-detail-01/index-detail.js +58 -0
  52. package/dist/blocks/index-detail-01/index.d.ts +3 -0
  53. package/dist/blocks/index-detail-01/index.d.ts.map +1 -0
  54. package/dist/blocks/index-detail-01/index.js +1 -0
  55. package/dist/blocks/index.d.ts +20 -8
  56. package/dist/blocks/index.d.ts.map +1 -1
  57. package/dist/blocks/index.js +7 -0
  58. package/dist/blocks/issue-detail-01/issue-detail.d.ts +18 -0
  59. package/dist/blocks/issue-detail-01/issue-detail.d.ts.map +1 -1
  60. package/dist/blocks/issue-detail-01/issue-detail.js +18 -0
  61. package/dist/blocks/nothing-chosen-01/index.d.ts +3 -0
  62. package/dist/blocks/nothing-chosen-01/index.d.ts.map +1 -0
  63. package/dist/blocks/nothing-chosen-01/index.js +1 -0
  64. package/dist/blocks/nothing-chosen-01/nothing-chosen.d.ts +119 -0
  65. package/dist/blocks/nothing-chosen-01/nothing-chosen.d.ts.map +1 -0
  66. package/dist/blocks/nothing-chosen-01/nothing-chosen.js +79 -0
  67. package/dist/blocks/project-dashboard-01/index.d.ts +1 -1
  68. package/dist/blocks/project-dashboard-01/index.d.ts.map +1 -1
  69. package/dist/blocks/project-dashboard-01/project-dashboard.d.ts +21 -27
  70. package/dist/blocks/project-dashboard-01/project-dashboard.d.ts.map +1 -1
  71. package/dist/blocks/project-dashboard-01/project-dashboard.js +45 -5
  72. package/dist/blocks/provisioning-01/index.d.ts +1 -1
  73. package/dist/blocks/provisioning-01/index.d.ts.map +1 -1
  74. package/dist/blocks/provisioning-01/provisioning.d.ts +9 -97
  75. package/dist/blocks/provisioning-01/provisioning.d.ts.map +1 -1
  76. package/dist/blocks/provisioning-01/provisioning.js +26 -13
  77. package/dist/blocks/record-detail-01/index.d.ts +3 -0
  78. package/dist/blocks/record-detail-01/index.d.ts.map +1 -0
  79. package/dist/blocks/record-detail-01/index.js +1 -0
  80. package/dist/blocks/record-detail-01/record-detail.d.ts +239 -0
  81. package/dist/blocks/record-detail-01/record-detail.d.ts.map +1 -0
  82. package/dist/blocks/record-detail-01/record-detail.js +150 -0
  83. package/dist/blocks/record-form-01/index.d.ts +3 -0
  84. package/dist/blocks/record-form-01/index.d.ts.map +1 -0
  85. package/dist/blocks/record-form-01/index.js +1 -0
  86. package/dist/blocks/record-form-01/record-form.d.ts +148 -0
  87. package/dist/blocks/record-form-01/record-form.d.ts.map +1 -0
  88. package/dist/blocks/record-form-01/record-form.js +107 -0
  89. package/dist/blocks/record-grid-01/index.d.ts +3 -0
  90. package/dist/blocks/record-grid-01/index.d.ts.map +1 -0
  91. package/dist/blocks/record-grid-01/index.js +1 -0
  92. package/dist/blocks/record-grid-01/record-grid.d.ts +145 -0
  93. package/dist/blocks/record-grid-01/record-grid.d.ts.map +1 -0
  94. package/dist/blocks/record-grid-01/record-grid.js +114 -0
  95. package/dist/blocks/record-wizard-01/index.d.ts +3 -0
  96. package/dist/blocks/record-wizard-01/index.d.ts.map +1 -0
  97. package/dist/blocks/record-wizard-01/index.js +1 -0
  98. package/dist/blocks/record-wizard-01/record-wizard.d.ts +152 -0
  99. package/dist/blocks/record-wizard-01/record-wizard.d.ts.map +1 -0
  100. package/dist/blocks/record-wizard-01/record-wizard.js +144 -0
  101. package/dist/blocks/settings-members-01/settings-members.d.ts +2 -1
  102. package/dist/blocks/settings-members-01/settings-members.d.ts.map +1 -1
  103. package/dist/blocks/settings-panel-01/index.d.ts +1 -1
  104. package/dist/blocks/settings-panel-01/index.d.ts.map +1 -1
  105. package/dist/blocks/settings-panel-01/settings-panel.d.ts +165 -67
  106. package/dist/blocks/settings-panel-01/settings-panel.d.ts.map +1 -1
  107. package/dist/blocks/settings-panel-01/settings-panel.js +92 -33
  108. package/dist/blocks/signup-01/index.d.ts +1 -1
  109. package/dist/blocks/signup-01/index.d.ts.map +1 -1
  110. package/dist/blocks/signup-01/signup-01.d.ts +10 -84
  111. package/dist/blocks/signup-01/signup-01.d.ts.map +1 -1
  112. package/dist/blocks/signup-01/signup-01.js +41 -23
  113. package/dist/blocks/stats-01/index.d.ts +5 -5
  114. package/dist/blocks/stats-01/index.d.ts.map +1 -1
  115. package/dist/blocks/stats-01/index.js +4 -4
  116. package/dist/blocks/stats-01/stats.d.ts +49 -14
  117. package/dist/blocks/stats-01/stats.d.ts.map +1 -1
  118. package/dist/blocks/stats-01/stats.js +65 -15
  119. package/dist/blocks/trend-01/index.d.ts +1 -1
  120. package/dist/blocks/trend-01/index.d.ts.map +1 -1
  121. package/dist/blocks/trend-01/trend.d.ts +26 -73
  122. package/dist/blocks/trend-01/trend.d.ts.map +1 -1
  123. package/dist/blocks/trend-01/trend.js +47 -30
  124. package/dist/catalog.d.ts.map +1 -1
  125. package/dist/catalog.js +93 -3
  126. package/dist/components/ui/metric.d.ts +4 -2
  127. package/dist/components/ui/metric.d.ts.map +1 -1
  128. package/dist/index.d.ts +10 -0
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +6 -0
  131. package/dist/lib/field-render.d.ts +107 -0
  132. package/dist/lib/field-render.d.ts.map +1 -0
  133. package/dist/lib/field-render.js +251 -0
  134. package/dist/lib/spec.d.ts +609 -0
  135. package/dist/lib/spec.d.ts.map +1 -0
  136. package/dist/lib/spec.js +1 -0
  137. package/dist/live/index.d.ts +2 -0
  138. package/dist/live/index.d.ts.map +1 -1
  139. package/dist/live/index.js +6 -0
  140. package/dist/live/message-thread-01/index.d.ts +3 -0
  141. package/dist/live/message-thread-01/index.d.ts.map +1 -0
  142. package/dist/live/message-thread-01/index.js +1 -0
  143. package/dist/live/message-thread-01/message-thread.d.ts +282 -0
  144. package/dist/live/message-thread-01/message-thread.d.ts.map +1 -0
  145. package/dist/live/message-thread-01/message-thread.js +221 -0
  146. package/dist/live/run-stream-01/run-stream.d.ts +2 -1
  147. package/dist/live/run-stream-01/run-stream.d.ts.map +1 -1
  148. package/dist/live/run-stream-01/run-stream.js +1 -7
  149. package/dist/live/status.d.ts +27 -0
  150. package/dist/live/status.d.ts.map +1 -0
  151. package/dist/live/status.js +15 -0
  152. package/dist/live/tool-call-row.d.ts +26 -0
  153. package/dist/live/tool-call-row.d.ts.map +1 -0
  154. package/dist/live/tool-call-row.js +60 -0
  155. package/dist/live/tool-ledger-01/tool-ledger.d.ts.map +1 -1
  156. package/dist/live/tool-ledger-01/tool-ledger.js +2 -42
  157. package/dist/pages/contact-page/index.d.ts +7 -7
  158. package/dist/pages/contact-page/index.d.ts.map +1 -1
  159. package/dist/pages/contact-page/index.js +17 -5
  160. package/dist/pages/docs-shell/docs-shell.d.ts +42 -30
  161. package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -1
  162. package/dist/pages/docs-shell/docs-shell.js +70 -48
  163. package/dist/pages/document-page/document-page.d.ts +146 -0
  164. package/dist/pages/document-page/document-page.d.ts.map +1 -0
  165. package/dist/pages/document-page/document-page.js +80 -0
  166. package/dist/pages/document-page/index.d.ts +3 -0
  167. package/dist/pages/document-page/index.d.ts.map +1 -0
  168. package/dist/pages/document-page/index.js +1 -0
  169. package/dist/pages/index.d.ts +2 -0
  170. package/dist/pages/index.d.ts.map +1 -1
  171. package/dist/pages/index.js +6 -0
  172. package/dist/styles.css +59 -3
  173. package/package.json +7 -2
@@ -0,0 +1,60 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { cn } from '../lib/utils.js';
3
+ /**
4
+ * The ink each state is stated in, and the tick beside it.
5
+ *
6
+ * The tick is the state's own first letter rather than a glyph this file invented,
7
+ * so there is nothing to translate and nothing to learn twice: `f` is the failed
8
+ * call in every locale, and it is a letter rather than a shape, so it survives a
9
+ * monochrome render and a screen at 200 per cent the way a hairline does not.
10
+ *
11
+ * `queued` and `cancelled` share the muted ink, and the letters are what tell them
12
+ * apart. That is the same trade `Status` makes and states: a wider palette on a
13
+ * surface a reader scans is a wider set of colours they have to learn, and the
14
+ * cost of a shared ink is one letter.
15
+ */
16
+ const STATE_INK = {
17
+ queued: 'text-muted-foreground',
18
+ running: 'text-foreground',
19
+ succeeded: 'text-success',
20
+ failed: 'text-destructive',
21
+ cancelled: 'text-muted-foreground',
22
+ };
23
+ /** The tick each state draws, so the five are told apart without relying on colour. */
24
+ const STATE_MARK = {
25
+ queued: 'q',
26
+ running: 'r',
27
+ succeeded: 's',
28
+ failed: 'f',
29
+ cancelled: 'c',
30
+ };
31
+ /** The clock a row reads, in UTC, because the surface holds no locale to format in. */
32
+ export const clockOf = (at) => new Date(at).toISOString().slice(11, 19);
33
+ /**
34
+ * One tool call, drawn as the ledger draws it.
35
+ *
36
+ * **This is the tool-call row the `live` Kind owns, and it is shared rather than
37
+ * copied.** `ToolLedger01` draws one row per call in its ledger, and a
38
+ * conversation's tool-call part draws the same row inside a message, so the two
39
+ * surfaces cannot drift into two shapes for one call. `ToolLedger01` renders this
40
+ * inside its own `<li>`; the message thread renders it inside a part. The
41
+ * Component owns no `<li>`, so it can sit in either list without nesting one.
42
+ *
43
+ * **The duration is the difference between two sightings of the same call, and
44
+ * only when there are two.** `openedAt` is the moment the surface first saw the
45
+ * call's `id`; a call seen once has no second timestamp and draws no duration,
46
+ * because a zero is a claim that a call took no time. The sentence is the
47
+ * consumer's, on `call.durationLabel`, and the arithmetic is one subtraction of
48
+ * the consumer's own `at` values. There is no clock in this file.
49
+ */
50
+ export function ToolCallRow({ call, openedAt }) {
51
+ // The difference between two sightings of the same call, and only when there
52
+ // are two. The sentence is the consumer's, the arithmetic is one subtraction of
53
+ // the consumer's own timestamps, and there is no clock in this file.
54
+ const elapsed = call.at - openedAt;
55
+ const duration = elapsed > 0 && call.durationLabel !== undefined
56
+ ? call.durationLabel(elapsed, { id: call.id, name: call.name })
57
+ : null;
58
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [_jsx("span", { "aria-hidden": "true", className: cn('font-mono text-xs', STATE_INK[call.state]), children: STATE_MARK[call.state] }), _jsx("time", { dateTime: new Date(openedAt).toISOString(), className: "text-muted-foreground font-mono text-xs tabular-nums", children: clockOf(openedAt) }), _jsx("span", { className: "text-foreground text-sm font-medium", children: call.name }), call.spanLabel ? (_jsx("span", { "data-slot": "tool-ledger-span", className: "border-border text-muted-foreground rounded border px-1 font-mono text-xs", children: call.spanLabel })) : null, duration === null ? null : (_jsx("span", { "data-slot": "tool-ledger-duration", className: "text-muted-foreground ml-auto font-mono text-xs tabular-nums", children: duration }))] }), call.argumentsText === undefined ? null : (_jsx("span", { "data-slot": "tool-ledger-arguments", className: "text-muted-foreground font-mono text-xs break-words", children: call.argumentsText })), call.resultText === undefined ? null : (_jsx("span", { "data-slot": "tool-ledger-result", className: "text-muted-foreground text-pretty text-xs", children: call.resultText })), call.errorText === undefined ? null : (_jsx("span", { "data-slot": "tool-ledger-error", className: "text-destructive text-pretty text-xs", children: call.errorText })), call.link === undefined ? null : (_jsx("a", { "data-slot": "tool-ledger-link", href: call.link.href, className: "text-foreground self-start rounded-sm text-xs underline-offset-4 hover:underline", children: call.link.label }))] }));
59
+ }
60
+ export default ToolCallRow;
@@ -1 +1 @@
1
- {"version":3,"file":"tool-ledger.d.ts","sourceRoot":"","sources":["../../../src/live/tool-ledger-01/tool-ledger.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAOnE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAA;AAEvF;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB;;;;;;OAMG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;OAOG;IACH,EAAE,EAAE,MAAM,CAAA;IACV,sDAAsD;IACtD,KAAK,EAAE,aAAa,CAAA;IACpB;;;;;;;;;;;;;;;;;OAiBG;IACH,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;IAC1E;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE;QACL,qBAAqB;QACrB,IAAI,EAAE,MAAM,CAAA;QACZ,6BAA6B;QAC7B,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;AAE1E;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;;;;OAQG;IACH,SAAS,EAAE,aAAa,CAAA;IACxB;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC/B;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;OAOG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,KAAK,EAAE,SAAS,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACxC;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,CACA;IAAE,YAAY,CAAC,EAAE,KAAK,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,KAAK,CAAA;CAAE,GACjE;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAClE,CAAA;AA+FD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AACH,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,SAAS,EACT,cAAc,EACd,KAAK,EACL,KAAK,EACL,KAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,WAAW,EACX,MAAM,EACN,SAAS,GACV,EAAE,iBAAiB,+BAwNnB;AAED,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"tool-ledger.d.ts","sourceRoot":"","sources":["../../../src/live/tool-ledger-01/tool-ledger.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAQnE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAA;AAEvF;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB;;;;;;OAMG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;OAOG;IACH,EAAE,EAAE,MAAM,CAAA;IACV,sDAAsD;IACtD,KAAK,EAAE,aAAa,CAAA;IACpB;;;;;;;;;;;;;;;;;OAiBG;IACH,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;IAC1E;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE;QACL,qBAAqB;QACrB,IAAI,EAAE,MAAM,CAAA;QACZ,6BAA6B;QAC7B,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;AAE1E;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;;;;OAQG;IACH,SAAS,EAAE,aAAa,CAAA;IACxB;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC/B;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;OAOG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,KAAK,EAAE,SAAS,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACxC;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,CACA;IAAE,YAAY,CAAC,EAAE,KAAK,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,KAAK,CAAA;CAAE,GACjE;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAClE,CAAA;AA8DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AACH,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,SAAS,EACT,cAAc,EACd,KAAK,EACL,KAAK,EACL,KAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,WAAW,EACX,MAAM,EACN,SAAS,GACV,EAAE,iBAAiB,+BAgInB;AAED,eAAe,YAAY,CAAA"}
@@ -5,6 +5,7 @@ import { Button } from '../../components/ui/button.js';
5
5
  import { LiveRegion } from '../../components/ui/live-region.js';
6
6
  import { ScrollArea } from '../../components/ui/scroll-area.js';
7
7
  import { cn } from '../../lib/utils.js';
8
+ import { ToolCallRow } from '../tool-call-row.js';
8
9
  /**
9
10
  * The one source of truth for order, so a late call with an earlier `at` sorts
10
11
  * there and two runs of the same suite render the same ledger. Ties break on
@@ -27,36 +28,6 @@ function seedOf(calls, limit) {
27
28
  const dropped = rows.length - limit;
28
29
  return { rows: rows.slice(dropped), dropped };
29
30
  }
30
- /**
31
- * The ink each state is stated in, and the tick beside it.
32
- *
33
- * The tick is the state's own first letter rather than a glyph this file invented,
34
- * so there is nothing to translate and nothing to learn twice: `f` is the failed
35
- * call in every locale, and it is a letter rather than a shape, so it survives a
36
- * monochrome render and a screen at 200 per cent the way a hairline does not.
37
- *
38
- * `queued` and `cancelled` share the muted ink, and the letters are what tell them
39
- * apart. That is the same trade `Status` makes and states: a wider palette on a
40
- * surface a reader scans is a wider set of colours they have to learn, and the
41
- * cost of a shared ink is one letter.
42
- */
43
- const STATE_INK = {
44
- queued: 'text-muted-foreground',
45
- running: 'text-foreground',
46
- succeeded: 'text-success',
47
- failed: 'text-destructive',
48
- cancelled: 'text-muted-foreground',
49
- };
50
- /** The tick each state draws, so the five are told apart without relying on colour. */
51
- const STATE_MARK = {
52
- queued: 'q',
53
- running: 'r',
54
- succeeded: 's',
55
- failed: 'f',
56
- cancelled: 'c',
57
- };
58
- /** The clock a row reads, in UTC, because the surface holds no locale to format in. */
59
- const clockOf = (at) => new Date(at).toISOString().slice(11, 19);
60
31
  /** One call merged into the ledger, and what fell off the top doing it. */
61
32
  function merge(rows, call, limit) {
62
33
  const at = rows.findIndex((row) => row.call.id === call.id);
@@ -229,17 +200,6 @@ export function ToolLedger01({ subscribe, callbacks, resubscribeKey, label, empt
229
200
  stop();
230
201
  };
231
202
  }, [subscribe, resubscribeKey, limit]);
232
- return (_jsxs("section", { "data-slot": "tool-ledger", className: cn('border-border flex flex-col gap-4 rounded-lg border p-4', className), children: [LiveRegion({ politeness: 'polite', children: newest }), droppedLabel === undefined && pauseControl !== true ? null : (_jsxs("div", { "data-slot": "tool-ledger-bar", className: "flex flex-wrap items-center gap-3", children: [run.dropped > 0 && droppedLabel !== undefined ? (_jsx("p", { "data-slot": "tool-ledger-dropped", className: "text-muted-foreground text-xs", children: droppedLabel(run.dropped) })) : null, pauseControl !== true ? null : (_jsx(Button, { "data-slot": "tool-ledger-pause", type: "button", variant: "outline", size: "sm", "aria-pressed": held, className: "ml-auto", onClick: () => setHeld(!heldRef.current), children: held ? resumeLabel : pauseLabel }))] })), rows.length === 0 ? (_jsx("p", { "data-slot": "tool-ledger-empty", className: "text-muted-foreground text-sm", children: empty })) : (_jsx(ScrollArea, { label: label, className: "max-h-96", children: _jsx("ol", { "data-slot": "tool-ledger-calls", className: "flex flex-col", children: rows.map((row) => {
233
- const { call } = row;
234
- // The difference between two sightings of the same call, and only when
235
- // there are two. The sentence is the consumer's, the arithmetic is one
236
- // subtraction of the consumer's own timestamps, and there is no clock
237
- // in this file.
238
- const elapsed = call.at - row.openedAt;
239
- const duration = elapsed > 0 && call.durationLabel !== undefined
240
- ? call.durationLabel(elapsed, { id: call.id, name: call.name })
241
- : null;
242
- return (_jsxs("li", { "data-slot": "tool-ledger-call", "data-state": call.state, className: "border-border flex flex-col gap-1 border-b py-3 last:border-b-0", children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [_jsx("span", { "aria-hidden": "true", className: cn('font-mono text-xs', STATE_INK[call.state]), children: STATE_MARK[call.state] }), _jsx("time", { dateTime: new Date(row.openedAt).toISOString(), className: "text-muted-foreground font-mono text-xs tabular-nums", children: clockOf(row.openedAt) }), _jsx("span", { className: "text-foreground text-sm font-medium", children: call.name }), call.spanLabel ? (_jsx("span", { "data-slot": "tool-ledger-span", className: "border-border text-muted-foreground rounded border px-1 font-mono text-xs", children: call.spanLabel })) : null, duration === null ? null : (_jsx("span", { "data-slot": "tool-ledger-duration", className: "text-muted-foreground ml-auto font-mono text-xs tabular-nums", children: duration }))] }), call.argumentsText === undefined ? null : (_jsx("span", { "data-slot": "tool-ledger-arguments", className: "text-muted-foreground font-mono text-xs break-words", children: call.argumentsText })), call.resultText === undefined ? null : (_jsx("span", { "data-slot": "tool-ledger-result", className: "text-muted-foreground text-pretty text-xs", children: call.resultText })), call.errorText === undefined ? null : (_jsx("span", { "data-slot": "tool-ledger-error", className: "text-destructive text-pretty text-xs", children: call.errorText })), call.link === undefined ? null : (_jsx("a", { "data-slot": "tool-ledger-link", href: call.link.href, className: "text-foreground self-start rounded-sm text-xs underline-offset-4 hover:underline", children: call.link.label }))] }, call.id));
243
- }) }) }))] }));
203
+ return (_jsxs("section", { "data-slot": "tool-ledger", className: cn('border-border flex flex-col gap-4 rounded-lg border p-4', className), children: [LiveRegion({ politeness: 'polite', children: newest }), droppedLabel === undefined && pauseControl !== true ? null : (_jsxs("div", { "data-slot": "tool-ledger-bar", className: "flex flex-wrap items-center gap-3", children: [run.dropped > 0 && droppedLabel !== undefined ? (_jsx("p", { "data-slot": "tool-ledger-dropped", className: "text-muted-foreground text-xs", children: droppedLabel(run.dropped) })) : null, pauseControl !== true ? null : (_jsx(Button, { "data-slot": "tool-ledger-pause", type: "button", variant: "outline", size: "sm", "aria-pressed": held, className: "ml-auto", onClick: () => setHeld(!heldRef.current), children: held ? resumeLabel : pauseLabel }))] })), rows.length === 0 ? (_jsx("p", { "data-slot": "tool-ledger-empty", className: "text-muted-foreground text-sm", children: empty })) : (_jsx(ScrollArea, { label: label, className: "max-h-96", children: _jsx("ol", { "data-slot": "tool-ledger-calls", className: "flex flex-col", children: rows.map((row) => (_jsx("li", { "data-slot": "tool-ledger-call", "data-state": row.call.state, className: "border-border flex flex-col gap-1 border-b py-3 last:border-b-0", children: _jsx(ToolCallRow, { call: row.call, openedAt: row.openedAt }) }, row.call.id))) }) }))] }));
244
204
  }
245
205
  export default ToolLedger01;
@@ -18,16 +18,16 @@ export type ContactPageOption = {
18
18
  /**
19
19
  * One declared field of the contact form.
20
20
  *
21
- * **Flat, on purpose, where `ContactField` is a union.** A consumer's form data is
21
+ * **Flat, on purpose, where `FieldSpec` is a union.** A consumer's form data is
22
22
  * flat: a record read out of a content type, a CMS entry or a JSON file has one
23
23
  * shape with an optional `options` key, and a caller that had to narrow their own
24
24
  * record before they could hand it to a page would be doing the Block's type work
25
- * at every call site. So the union is built once, inside this module, and the one
26
- * shape it cannot build is refused here with a message that names the Page's own
27
- * prop. That is `AboutPage`'s arrangement for the same pair of link fields, and the
28
- * cost is the same: a caller who wants the compile error rather than the thrown one
29
- * types their fields against `ContactField` and passes the result here, which
30
- * works because the two are structurally the same.
25
+ * at every call site. So the flat record is converted to the shared specification
26
+ * once, inside this module, and the one shape it cannot build is refused here with
27
+ * a message that names the Page's own prop. That is `AboutPage`'s arrangement for
28
+ * the same pair of link fields, and the cost is the same: a caller who wants the
29
+ * compile error rather than the thrown one types their fields as `FieldSpec` and
30
+ * composes `Contact01` directly.
31
31
  */
32
32
  export type ContactPageField = {
33
33
  /** The caller's key for this field, and the key the value arrives under. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/contact-page/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/contact-page/index.tsx"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ import { Contact01, } from '../../blocks/contact-01/index.js';
4
4
  import { Card, CardContent, CardHeader, CardTitle } from '../../components/ui/card.js';
5
5
  import { CtaLink } from '../../components/ui/cta-link.js';
6
6
  import { Section, SectionHeading, childLevel } from '../../components/ui/section.js';
7
+ import { FieldKindName } from '../../lib/field-render.js';
7
8
  import { cn } from '../../lib/utils.js';
8
9
  /**
9
10
  * One declared field as `Contact01` draws it, with the two shapes kept apart.
@@ -16,15 +17,26 @@ import { cn } from '../../lib/utils.js';
16
17
  */
17
18
  function asContactField(field) {
18
19
  const shared = {
19
- id: field.id,
20
+ key: field.id,
20
21
  label: field.label,
21
22
  required: field.required,
22
- description: field.description,
23
+ help: field.description,
23
24
  placeholder: field.placeholder,
24
25
  autoComplete: field.autoComplete,
25
26
  };
27
+ if (field.type === 'textarea')
28
+ return { ...shared, kind: FieldKindName.textarea, rows: 4 };
29
+ /*
30
+ `text`, `email` and `tel` all draw Prism's `Input`, which is the control this
31
+ package ships for a run of characters; the platform's own `type` attributes are
32
+ not part of the shared vocabulary, so asking for an email is asking for an
33
+ `Input` with the `autoComplete` hint a password manager reads. `inputMode` and
34
+ `type` are the platform's, and the caller who needs a numeric keypad reaches for
35
+ the `NumberField` kind on the Block directly rather than through this Page's
36
+ flat prop.
37
+ */
26
38
  if (field.type !== 'select')
27
- return { ...shared, type: field.type };
39
+ return { ...shared, kind: FieldKindName.input };
28
40
  const options = field.options ?? [];
29
41
  if (options.length === 0) {
30
42
  throw new Error(`ContactPage: the field "${field.id}" is a select and passes no options, so the control would render with ` +
@@ -32,7 +44,7 @@ function asContactField(field) {
32
44
  'there and focusable. Pass the choices, or declare the field as a text field and check the answer in ' +
33
45
  'your own handler.');
34
46
  }
35
- return { ...shared, type: 'select', options: options.map((option) => ({ ...option })) };
47
+ return { ...shared, kind: FieldKindName.nativeSelect, options: options.map((option) => ({ ...option })) };
36
48
  }
37
49
  /**
38
50
  * The two checks the office union makes for a TypeScript caller, run here for the
@@ -125,7 +137,7 @@ export function ContactPage({ eyebrow, title, description, form, fields, onSubmi
125
137
  */
126
138
  const BandHeading = childLevel(headingLevel);
127
139
  const OfficeHeading = childLevel(BandHeading);
128
- return (_jsxs("div", { "data-slot": "contact-page", className: cn(className), children: [_jsx(Section, { "data-slot": "contact-page-heading", children: _jsx(SectionHeading, { as: headingLevel, align: "left", eyebrow: eyebrow, title: title, description: description }) }), _jsx(Contact01, { title: form.title, description: form.description, fields: fields.map(asContactField), onSubmit: onSubmit, submitLabel: submitLabel, consent: consent, status: status, variant: "stacked", headingLevel: BandHeading }), offices === undefined ? null : (_jsxs(Section, { "data-slot": "contact-page-offices", children: [_jsx(SectionHeading, { as: BandHeading, align: "left", title: officesLabel, className: "mb-10" }), _jsx("div", { "data-slot": "contact-page-office-row", className: "grid items-start gap-6 md:grid-cols-2 lg:grid-cols-3", children: offices.map((office) => (_jsxs(Card, { "data-slot": "contact-page-office", "data-office": office.id, className: "h-full", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { as: OfficeHeading, children: office.name }) }), _jsxs(CardContent, { className: "flex flex-col items-start gap-4", children: [_jsx("address", { "data-slot": "contact-page-office-address", className: "text-muted-foreground flex flex-col gap-1 not-italic text-sm", children: office.lines.map((line, index) => (
140
+ return (_jsxs("div", { "data-slot": "contact-page", className: cn(className), children: [_jsx(Section, { "data-slot": "contact-page-heading", children: _jsx(SectionHeading, { as: headingLevel, align: "left", eyebrow: eyebrow, title: title, description: description }) }), _jsx(Contact01, { title: form.title, description: form.description, groups: [{ fields: fields.map(asContactField) }], onSubmit: onSubmit, submitLabel: submitLabel, consent: consent, status: status, variant: "stacked", headingLevel: BandHeading }), offices === undefined ? null : (_jsxs(Section, { "data-slot": "contact-page-offices", children: [_jsx(SectionHeading, { as: BandHeading, align: "left", title: officesLabel, className: "mb-10" }), _jsx("div", { "data-slot": "contact-page-office-row", className: "grid items-start gap-6 md:grid-cols-2 lg:grid-cols-3", children: offices.map((office) => (_jsxs(Card, { "data-slot": "contact-page-office", "data-office": office.id, className: "h-full", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { as: OfficeHeading, children: office.name }) }), _jsxs(CardContent, { className: "flex flex-col items-start gap-4", children: [_jsx("address", { "data-slot": "contact-page-office-address", className: "text-muted-foreground flex flex-col gap-1 not-italic text-sm", children: office.lines.map((line, index) => (
129
141
  /*
130
142
  Positional, because a postal line is display content and a
131
143
  business with two branches on one street can legitimately
@@ -188,17 +188,11 @@ export type DocsShellProps = {
188
188
  * The accessible name of the rail. Required whenever `nav` is passed, because
189
189
  * it is a word a reader hears and a Page that ships no copy ships no
190
190
  * reader-facing copy either.
191
- *
192
- * It is also the visible word on the disclosure that stands in for the rail
193
- * below `lg`, because it is already this navigation's name and a Page cannot
194
- * invent a second one. A consumer that files its navigation in another language
195
- * gets the control in that language by having done this once.
196
191
  */
197
192
  navLabel: string;
198
193
  /**
199
194
  * The accessible name of the contents rail. Required whenever `toc` is passed,
200
- * for the same reason `navLabel` is, and the contents disclosure below `lg`
201
- * carries it for the same reason too.
195
+ * for the same reason `navLabel` is.
202
196
  */
203
197
  tocLabel: string;
204
198
  /**
@@ -347,32 +341,51 @@ export type DocsShellProps = {
347
341
  * a fact about ink, and announcing it would put a sentence in the middle of a
348
342
  * list of a consumer's own pages.
349
343
  *
350
- * **Below `lg` there was no navigation at all, and the fix is a native
351
- * disclosure.** At 768 and at 1024 both rails were `hidden` and the only
352
- * navigation left inside `<main>` was the two-item pager at the foot of the
353
- * article, so a reader on a thirty-one document reference at tablet width had no
354
- * contents, no on-this-page and no way to a sibling page except Previous and
355
- * Next. The disclosure is `<details>` and `<summary>`, which is the one
356
- * disclosure widget that needs no runtime at all: it is expanded and collapsed by
357
- * the platform, it is a real control in the Tab order with a real expanded state,
358
- * and adding a client boundary to a server Component to reinvent it would put
359
- * bytes on every documentation page in the family to save a reader one click.
344
+ * **The tree is in the document once, at every width, and the price of that is a
345
+ * phone reader crossing the whole navigation to reach the article.** At 768 and
346
+ * at 1024 both rails used to be `hidden`, so the only navigation left inside
347
+ * `<main>` was the two-item pager at the foot of the article, and a reader on a
348
+ * twenty-seven document reference at tablet width had no contents, no
349
+ * on-this-page and no way to a sibling page except Previous and Next. 0.16.0
350
+ * closed that gap by drawing the tree a second time behind a `<details>`, one
351
+ * copy for the rail and one for the narrow frame, and it shipped a doubled
352
+ * document to every documentation page in the family with it: two
353
+ * `aria-current` markers for one page, two lists of a consumer's own pages, two
354
+ * `docs-nav-page` rows for every document, and a second `<nav>` carrying the
355
+ * rail's own accessible name, which is the thing a consumer's suite reaches the
356
+ * rail by. Three consumer test files failed against the published package: two on
357
+ * a count that came back doubled, and two on a `getByRole('navigation', { name })`
358
+ * that had two answers where it expects one. So there is one copy now, and it
359
+ * shows at every width.
360
+ *
361
+ * **What that costs, with the number.** A consumer's rail measured 1,318 pixels
362
+ * of content in a built export at 1280 by 680, and those rows wrap on a phone, so
363
+ * a reader arriving at the top of a documentation page scrolls past a thousand
364
+ * pixels of navigation before the article begins. That is a real regression for
365
+ * that reader and it is the reason a disclosure was reached for in the first
366
+ * place. It is paid rather than hidden, because every arrangement that avoids it
367
+ * is worse: a rail at `lg` and nothing below it reopens the gap this change
368
+ * closes, and drawing the tree twice to keep the scroll short is what broke three
369
+ * consumer test files in the first place.
360
370
  *
361
- * The tree is rendered twice, once in each arrangement, and only one of them is
362
- * in the document at any width: the rail is `hidden lg:block` and the disclosure
363
- * is `lg:hidden`, so the other one is `display: none` and is out of the
364
- * accessibility tree and out of the tab order rather than a second copy a reader
365
- * meets. The summary carries `navLabel` or `tocLabel`, which is the caller's own
366
- * word for that navigation and therefore the one word on the control that cannot
367
- * be wrong in a language the consumer did not write in.
371
+ * **What would actually remove the scroll.** A collapsed rail below `lg` needs an
372
+ * open state. A server Component cannot hold one, and `<details>` is the only
373
+ * disclosure the platform holds on the Page's behalf, so the control that opens
374
+ * it has to be a client island inside the Page. That is a separate piece of work
375
+ * with its own budget, and it is not built here: a Page that ships a client
376
+ * boundary to save one scroll is making a different trade than the one stated
377
+ * above, and it should be made deliberately rather than smuggled in as the side
378
+ * effect of fixing a duplicate.
368
379
  *
369
380
  * **The frame is three columns from `lg`, and the third is the consumer's to
370
381
  * fill.** The rail is 15rem, the document takes the rest, and the contents rail
371
382
  * is 13rem. The third track exists only when `toc` is passed, because the
372
383
  * document takes the second track by auto-placement and a template that named a
373
384
  * track no child occupies would leave the document in the 15rem one. Below `lg`
374
- * the frame is a single column: the document fills it and the two navigations sit
375
- * above it behind their disclosures.
385
+ * the frame is a single column and the children flow in the order they are
386
+ * written: the rail, then the document, then the contents rail. The rail is the
387
+ * first child for that reason, so a reader below `lg` meets the navigation before
388
+ * the text rather than after it, and one arrangement serves both widths.
376
389
  *
377
390
  * It is a Page rather than a Block because it is a whole screen and it is the
378
391
  * screen a content pipeline targets: a route that reads one document and hands
@@ -383,10 +396,9 @@ export type DocsShellProps = {
383
396
  *
384
397
  * It is a server Component. It fetches nothing, it holds no state and it imports
385
398
  * no router, so a consumer renders it from whichever route their framework names
386
- * and hands it the document their pipeline produced. The sub-`lg` disclosure is
387
- * the reason that stays true under pressure: it is the one feature on this Page
388
- * that a hand would be tempted to write as a client Component, and it is written
389
- * as markup instead.
399
+ * and hands it the document their pipeline produced. Nothing here needs a client
400
+ * boundary, and the one feature that would want one is named above as work not
401
+ * done rather than quietly added.
390
402
  */
391
403
  export declare function DocsShell({ title, description, nav, toc, currentHref, navLabel, tocLabel, pagerLabel, pagerLabels, header, footer, className, children, }: DocsShellProps): import("react").JSX.Element;
392
404
  export default DocsShell;
@@ -1 +1 @@
1
- {"version":3,"file":"docs-shell.d.ts","sourceRoot":"","sources":["../../../src/pages/docs-shell/docs-shell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAOtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;CAC/B,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAA;IACf,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,cAAc,CAAA;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7B;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;OASG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,WAAW,EAAE,eAAe,CAAA;IAC5B;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,CAAA;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsJG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,WAAW,EACX,GAAG,EACH,GAAG,EACH,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,SAAS,EACT,QAAQ,GACT,EAAE,cAAc,+BA6GhB;AAsgBD,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"docs-shell.d.ts","sourceRoot":"","sources":["../../../src/pages/docs-shell/docs-shell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAOtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;CAC/B,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAA;IACf,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,cAAc,CAAA;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7B;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,WAAW,EAAE,eAAe,CAAA;IAC5B;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,CAAA;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwKG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,WAAW,EACX,GAAG,EACH,GAAG,EACH,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,SAAS,EACT,QAAQ,GACT,EAAE,cAAc,+BAiFhB;AA+fD,eAAe,SAAS,CAAA"}
@@ -113,32 +113,51 @@ import { cn } from '../../lib/utils.js';
113
113
  * a fact about ink, and announcing it would put a sentence in the middle of a
114
114
  * list of a consumer's own pages.
115
115
  *
116
- * **Below `lg` there was no navigation at all, and the fix is a native
117
- * disclosure.** At 768 and at 1024 both rails were `hidden` and the only
118
- * navigation left inside `<main>` was the two-item pager at the foot of the
119
- * article, so a reader on a thirty-one document reference at tablet width had no
120
- * contents, no on-this-page and no way to a sibling page except Previous and
121
- * Next. The disclosure is `<details>` and `<summary>`, which is the one
122
- * disclosure widget that needs no runtime at all: it is expanded and collapsed by
123
- * the platform, it is a real control in the Tab order with a real expanded state,
124
- * and adding a client boundary to a server Component to reinvent it would put
125
- * bytes on every documentation page in the family to save a reader one click.
126
- *
127
- * The tree is rendered twice, once in each arrangement, and only one of them is
128
- * in the document at any width: the rail is `hidden lg:block` and the disclosure
129
- * is `lg:hidden`, so the other one is `display: none` and is out of the
130
- * accessibility tree and out of the tab order rather than a second copy a reader
131
- * meets. The summary carries `navLabel` or `tocLabel`, which is the caller's own
132
- * word for that navigation and therefore the one word on the control that cannot
133
- * be wrong in a language the consumer did not write in.
116
+ * **The tree is in the document once, at every width, and the price of that is a
117
+ * phone reader crossing the whole navigation to reach the article.** At 768 and
118
+ * at 1024 both rails used to be `hidden`, so the only navigation left inside
119
+ * `<main>` was the two-item pager at the foot of the article, and a reader on a
120
+ * twenty-seven document reference at tablet width had no contents, no
121
+ * on-this-page and no way to a sibling page except Previous and Next. 0.16.0
122
+ * closed that gap by drawing the tree a second time behind a `<details>`, one
123
+ * copy for the rail and one for the narrow frame, and it shipped a doubled
124
+ * document to every documentation page in the family with it: two
125
+ * `aria-current` markers for one page, two lists of a consumer's own pages, two
126
+ * `docs-nav-page` rows for every document, and a second `<nav>` carrying the
127
+ * rail's own accessible name, which is the thing a consumer's suite reaches the
128
+ * rail by. Three consumer test files failed against the published package: two on
129
+ * a count that came back doubled, and two on a `getByRole('navigation', { name })`
130
+ * that had two answers where it expects one. So there is one copy now, and it
131
+ * shows at every width.
132
+ *
133
+ * **What that costs, with the number.** A consumer's rail measured 1,318 pixels
134
+ * of content in a built export at 1280 by 680, and those rows wrap on a phone, so
135
+ * a reader arriving at the top of a documentation page scrolls past a thousand
136
+ * pixels of navigation before the article begins. That is a real regression for
137
+ * that reader and it is the reason a disclosure was reached for in the first
138
+ * place. It is paid rather than hidden, because every arrangement that avoids it
139
+ * is worse: a rail at `lg` and nothing below it reopens the gap this change
140
+ * closes, and drawing the tree twice to keep the scroll short is what broke three
141
+ * consumer test files in the first place.
142
+ *
143
+ * **What would actually remove the scroll.** A collapsed rail below `lg` needs an
144
+ * open state. A server Component cannot hold one, and `<details>` is the only
145
+ * disclosure the platform holds on the Page's behalf, so the control that opens
146
+ * it has to be a client island inside the Page. That is a separate piece of work
147
+ * with its own budget, and it is not built here: a Page that ships a client
148
+ * boundary to save one scroll is making a different trade than the one stated
149
+ * above, and it should be made deliberately rather than smuggled in as the side
150
+ * effect of fixing a duplicate.
134
151
  *
135
152
  * **The frame is three columns from `lg`, and the third is the consumer's to
136
153
  * fill.** The rail is 15rem, the document takes the rest, and the contents rail
137
154
  * is 13rem. The third track exists only when `toc` is passed, because the
138
155
  * document takes the second track by auto-placement and a template that named a
139
156
  * track no child occupies would leave the document in the 15rem one. Below `lg`
140
- * the frame is a single column: the document fills it and the two navigations sit
141
- * above it behind their disclosures.
157
+ * the frame is a single column and the children flow in the order they are
158
+ * written: the rail, then the document, then the contents rail. The rail is the
159
+ * first child for that reason, so a reader below `lg` meets the navigation before
160
+ * the text rather than after it, and one arrangement serves both widths.
142
161
  *
143
162
  * It is a Page rather than a Block because it is a whole screen and it is the
144
163
  * screen a content pipeline targets: a route that reads one document and hands
@@ -149,10 +168,9 @@ import { cn } from '../../lib/utils.js';
149
168
  *
150
169
  * It is a server Component. It fetches nothing, it holds no state and it imports
151
170
  * no router, so a consumer renders it from whichever route their framework names
152
- * and hands it the document their pipeline produced. The sub-`lg` disclosure is
153
- * the reason that stays true under pressure: it is the one feature on this Page
154
- * that a hand would be tempted to write as a client Component, and it is written
155
- * as markup instead.
171
+ * and hands it the document their pipeline produced. Nothing here needs a client
172
+ * boundary, and the one feature that would want one is named above as work not
173
+ * done rather than quietly added.
156
174
  */
157
175
  export function DocsShell({ title, description, nav, toc, currentHref, navLabel, tocLabel, pagerLabel, pagerLabels, header, footer, className, children, }) {
158
176
  readTree(nav, 'nav');
@@ -177,10 +195,10 @@ export function DocsShell({ title, description, nav, toc, currentHref, navLabel,
177
195
  // contents rail landed in an implicit `auto` track rather than the
178
196
  // 13rem one. `check-breakpoint-variants.mjs` is the gate that says so
179
197
  // to the next class written against a screen the theme does not emit.
180
- contents ? 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)_13rem]' : 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)]'), children: [rail || contents ? (_jsxs("div", { "data-slot": "docs-nav-compact", className: "flex flex-col gap-4 lg:hidden", children: [rail ? (_jsx(Disclosure, { label: navLabel, unnamed: unnamedNav, children: _jsx(NavList, { entries: rail, currentHref: currentHref, depth: 0 }) })) : null, contents ? (_jsx(Disclosure, { label: tocLabel, unnamed: unnamedToc, children: _jsx(NavList, { entries: contents, currentHref: currentHref, depth: 0 }) })) : null] })) : null, rail ? (_jsx("aside", { "data-slot": "docs-rail", className: "hidden lg:col-start-1 lg:row-start-1 lg:block", children: _jsx(Rail, { label: navLabel, entries: rail, currentHref: currentHref, unnamed: unnamedNav }) })) : null, _jsxs("article", { "data-slot": "docs-article", className: "flex min-w-0 flex-col gap-8", children: [title ? (_jsxs("header", { className: "flex flex-col gap-3", children: [_jsx(Heading, { as: "h1", className: headingSizeClass('h1'), children: title }), description ? (_jsx(Text, { size: "lg", tone: "muted", className: "max-w-measure", children: description })) : null] })) : description ? (_jsx(Text, { size: "lg", tone: "muted", className: "max-w-measure", children: description })) : null, _jsx(Prose, { fullWidth: true, children: children }), neighbours ? (_jsx(Pager, { previous: neighbours.previous, next: neighbours.next, label: pagerLabel, labels: pagerLabels })) : null] }), contents ? (_jsx("aside", { "data-slot": "docs-contents", className: "hidden lg:col-start-3 lg:row-start-1 lg:block", children: _jsx(Rail, { label: tocLabel, entries: contents, currentHref: currentHref, unnamed: unnamedToc }) })) : null] }), footer] }));
198
+ contents ? 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)_13rem]' : 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)]'), children: [rail ? (_jsx("aside", { "data-slot": "docs-rail", className: "lg:col-start-1 lg:row-start-1", children: _jsx(Rail, { label: navLabel, entries: rail, currentHref: currentHref, unnamed: unnamedNav }) })) : null, _jsxs("article", { "data-slot": "docs-article", className: "flex min-w-0 flex-col gap-8", children: [title ? (_jsxs("header", { className: "flex flex-col gap-3", children: [_jsx(Heading, { as: "h1", className: headingSizeClass('h1'), children: title }), description ? (_jsx(Text, { size: "lg", tone: "muted", className: "max-w-measure", children: description })) : null] })) : description ? (_jsx(Text, { size: "lg", tone: "muted", className: "max-w-measure", children: description })) : null, _jsx(Prose, { fullWidth: true, children: children }), neighbours ? (_jsx(Pager, { previous: neighbours.previous, next: neighbours.next, label: pagerLabel, labels: pagerLabels })) : null] }), contents ? (_jsx("aside", { "data-slot": "docs-contents", className: "lg:col-start-3 lg:row-start-1", children: _jsx(Rail, { label: tocLabel, entries: contents, currentHref: currentHref, unnamed: unnamedToc }) })) : null] }), footer] }));
181
199
  }
182
200
  /* ------------------------------------------------------------------ *
183
- * The two rails at lg
201
+ * The two rails
184
202
  * ------------------------------------------------------------------ */
185
203
  /**
186
204
  * One rail: a region that scrolls inside a bound against the viewport, with the
@@ -214,32 +232,36 @@ export function DocsShell({ title, description, nav, toc, currentHref, navLabel,
214
232
  * usual cost of a fade and the reason the padding is part of the answer rather
215
233
  * than a detail.
216
234
  *
235
+ * **The bound, the sticky offset, the band and the fade are all written against
236
+ * the same `lg:`, so below `lg` this rail is an ordinary block in the flow: no
237
+ * scroll region, no cut, no reservation, no fade.** That is the right shape for a
238
+ * rail that is the first thing in a single column, because a sticky region a full
239
+ * viewport tall above the article would be worse than a long one above it.
240
+ *
241
+ * **The fade and the band are bound to the cut rather than to the rail, and the
242
+ * reason is what a fade is for.** A fade marks a cut, so it may only exist where
243
+ * there is one, and the cut is the `overflow-y` at `lg`: the scroll region, the
244
+ * cap, the sticky offset, the reserved band and the gradient are one arrangement
245
+ * or none of them. The fade shipped unprefixed, which put the arrangement out of
246
+ * step with itself at the one width that has no cut to mark. Below `lg` the region
247
+ * is an ordinary block, so the `pb-8` reserving the band is inert there and the
248
+ * gradient fell on the last row or two of a rail that was simply running on. The
249
+ * band and the fade still measured equal and the reader still lost nothing
250
+ * legible, which is why looking did not catch it: a gradient painted over content
251
+ * is a defect, and it is not a legibility one.
252
+ *
253
+ * **The limit bought here is stated rather than left to be found.** Below `lg` the
254
+ * rail is bounded by its content rather than by the viewport, so a long tree runs
255
+ * past the fold of a phone screen with nothing marking where it ends: no cut to
256
+ * mark, no band to reserve and no scroll region to scroll inside. That is the
257
+ * honest price of one copy of the tree at every width, and the measurement behind
258
+ * it is stated once on the Page above rather than repeated here.
259
+ *
217
260
  * `unnamed` is carried on the `<nav>` rather than logged, for the reason
218
261
  * `unnamedIn` gives.
219
262
  */
220
263
  function Rail({ label, entries, currentHref, unnamed, }) {
221
- return (_jsxs("div", { className: "relative lg:sticky lg:top-20", children: [_jsx("nav", { "aria-label": label, "data-unnamed-entries": unnamed, className: "lg:max-h-[calc(100svh-7rem)] lg:overflow-y-auto lg:pe-4 lg:pb-8", children: _jsx(NavList, { entries: entries, currentHref: currentHref, depth: 0 }) }), _jsx("div", { "aria-hidden": "true", "data-slot": "docs-rail-fade", className: "from-background pointer-events-none absolute inset-x-0 bottom-0 h-8 bg-gradient-to-t to-transparent" })] }));
222
- }
223
- /**
224
- * One tree behind a native disclosure, for the widths where there is no rail.
225
- *
226
- * `<details>` rather than a Component, and the whole argument is that it needs no
227
- * runtime: the platform holds the expanded state, the control is in the Tab order
228
- * with a real expanded state, and the Page stays a server Component. A Page that
229
- * shipped a client disclosure for this would put JavaScript on every documentation
230
- * page in the family to replace a browser feature that has been in the platform
231
- * since 2018.
232
- *
233
- * **The summary's word is the caller's.** `navLabel` and `tocLabel` are already
234
- * required props and already name these two navigations for a screen reader, so
235
- * the control that opens one says the same thing the region inside it is called
236
- * and the Page ships no word of its own. Nothing suppresses the browser's own
237
- * disclosure marker or its own focus ring: the marker is the cheapest honest
238
- * signal that the row is a disclosure, and `py-3` puts the target at 44 pixels for
239
- * a coarse pointer without a variant.
240
- */
241
- function Disclosure({ label, unnamed, children, }) {
242
- return (_jsxs("details", { "data-slot": "docs-nav-disclosure", children: [_jsx("summary", { className: "text-foreground cursor-pointer py-3 text-sm font-medium", children: label }), _jsx("nav", { "aria-label": label, "data-unnamed-entries": unnamed, className: "pb-4", children: children })] }));
264
+ return (_jsxs("div", { className: "relative lg:sticky lg:top-20", children: [_jsx("nav", { "aria-label": label, "data-unnamed-entries": unnamed, className: "lg:max-h-[calc(100svh-7rem)] lg:overflow-y-auto lg:pe-4 lg:pb-8", children: _jsx(NavList, { entries: entries, currentHref: currentHref, depth: 0 }) }), _jsx("div", { "aria-hidden": "true", "data-slot": "docs-rail-fade", className: "pointer-events-none lg:absolute lg:inset-x-0 lg:bottom-0 lg:h-8 lg:bg-gradient-to-t lg:from-background lg:to-transparent" })] }));
243
265
  }
244
266
  /* ------------------------------------------------------------------ *
245
267
  * The tree