@nanisoft/prism-ui 0.10.1 → 0.13.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.
- package/LICENSE +21 -21
- package/dist/.tsbuildinfo +1 -1
- package/dist/blocks/app-shell-01/app-shell.js +4 -4
- package/dist/blocks/app-shell-01/index.d.ts +2 -2
- package/dist/blocks/app-shell-01/index.js +1 -1
- package/dist/blocks/auth-form-01/auth-form.d.ts +11 -1
- package/dist/blocks/auth-form-01/auth-form.d.ts.map +1 -1
- package/dist/blocks/auth-form-01/auth-form.js +11 -8
- package/dist/blocks/auth-form-01/index.d.ts +2 -2
- package/dist/blocks/auth-form-01/index.js +1 -1
- package/dist/blocks/cta-01/cta.d.ts +26 -21
- package/dist/blocks/cta-01/cta.d.ts.map +1 -1
- package/dist/blocks/cta-01/cta.js +2 -2
- package/dist/blocks/cta-01/index.d.ts +2 -2
- package/dist/blocks/cta-01/index.js +1 -1
- package/dist/blocks/data-table-01/data-table.js +7 -7
- package/dist/blocks/data-table-01/index.d.ts +2 -2
- package/dist/blocks/data-table-01/index.js +1 -1
- package/dist/blocks/empty-state-01/empty-state.d.ts +143 -0
- package/dist/blocks/empty-state-01/empty-state.d.ts.map +1 -0
- package/dist/blocks/empty-state-01/empty-state.js +104 -0
- package/dist/blocks/empty-state-01/index.d.ts +3 -0
- package/dist/blocks/empty-state-01/index.d.ts.map +1 -0
- package/dist/blocks/empty-state-01/index.js +1 -0
- package/dist/blocks/feature-grid-01/feature-grid.d.ts +28 -1
- package/dist/blocks/feature-grid-01/feature-grid.d.ts.map +1 -1
- package/dist/blocks/feature-grid-01/feature-grid.js +34 -3
- package/dist/blocks/feature-grid-01/index.d.ts +2 -2
- package/dist/blocks/feature-grid-01/index.js +1 -1
- package/dist/blocks/hero-01/hero.d.ts +49 -17
- package/dist/blocks/hero-01/hero.d.ts.map +1 -1
- package/dist/blocks/hero-01/hero.js +14 -9
- package/dist/blocks/hero-01/index.d.ts +2 -1
- package/dist/blocks/hero-01/index.d.ts.map +1 -1
- package/dist/blocks/hero-01/index.js +1 -1
- package/dist/blocks/index.d.ts +20 -20
- package/dist/blocks/index.js +19 -19
- package/dist/blocks/instrument-panel-01/index.d.ts +2 -2
- package/dist/blocks/instrument-panel-01/index.js +1 -1
- package/dist/blocks/instrument-panel-01/instrument-panel.js +1 -1
- package/dist/blocks/logo-strip-01/index.d.ts +2 -2
- package/dist/blocks/logo-strip-01/index.js +1 -1
- package/dist/blocks/logo-strip-01/logo-strip.d.ts +1 -1
- package/dist/blocks/logo-strip-01/logo-strip.js +2 -2
- package/dist/blocks/note-grid-01/index.d.ts +2 -2
- package/dist/blocks/note-grid-01/index.js +1 -1
- package/dist/blocks/note-grid-01/note-grid.d.ts +1 -1
- package/dist/blocks/note-grid-01/note-grid.js +1 -1
- package/dist/blocks/page-header-01/index.d.ts +2 -2
- package/dist/blocks/page-header-01/index.js +1 -1
- package/dist/blocks/page-header-01/page-header.d.ts +1 -1
- package/dist/blocks/page-header-01/page-header.js +4 -4
- package/dist/blocks/pricing-01/index.d.ts +1 -1
- package/dist/blocks/pricing-01/index.js +1 -1
- package/dist/blocks/pricing-01/pricing.d.ts +8 -1
- package/dist/blocks/pricing-01/pricing.d.ts.map +1 -1
- package/dist/blocks/pricing-01/pricing.js +15 -5
- package/dist/blocks/process-flow-01/index.d.ts +3 -0
- package/dist/blocks/process-flow-01/index.d.ts.map +1 -0
- package/dist/blocks/process-flow-01/index.js +1 -0
- package/dist/blocks/process-flow-01/process-flow.d.ts +118 -0
- package/dist/blocks/process-flow-01/process-flow.d.ts.map +1 -0
- package/dist/blocks/process-flow-01/process-flow.js +71 -0
- package/dist/blocks/process-rail-01/index.d.ts +2 -2
- package/dist/blocks/process-rail-01/index.js +1 -1
- package/dist/blocks/process-rail-01/process-rail.d.ts +1 -1
- package/dist/blocks/process-rail-01/process-rail.js +2 -2
- package/dist/blocks/product-grid-01/index.d.ts +2 -2
- package/dist/blocks/product-grid-01/index.js +1 -1
- package/dist/blocks/product-grid-01/product-grid.d.ts +37 -5
- package/dist/blocks/product-grid-01/product-grid.d.ts.map +1 -1
- package/dist/blocks/product-grid-01/product-grid.js +20 -6
- package/dist/blocks/run-console-01/index.d.ts +3 -0
- package/dist/blocks/run-console-01/index.d.ts.map +1 -0
- package/dist/blocks/run-console-01/index.js +1 -0
- package/dist/blocks/run-console-01/run-console.d.ts +111 -0
- package/dist/blocks/run-console-01/run-console.d.ts.map +1 -0
- package/dist/blocks/run-console-01/run-console.js +48 -0
- package/dist/blocks/settings-panel-01/index.d.ts +2 -2
- package/dist/blocks/settings-panel-01/index.js +1 -1
- package/dist/blocks/settings-panel-01/settings-panel.d.ts +11 -1
- package/dist/blocks/settings-panel-01/settings-panel.d.ts.map +1 -1
- package/dist/blocks/settings-panel-01/settings-panel.js +15 -10
- package/dist/blocks/site-footer/index.d.ts +2 -2
- package/dist/blocks/site-footer/index.js +1 -1
- package/dist/blocks/site-footer/site-footer.d.ts +1 -1
- package/dist/blocks/site-footer/site-footer.js +2 -2
- package/dist/blocks/site-header/index.d.ts +2 -2
- package/dist/blocks/site-header/index.js +1 -1
- package/dist/blocks/site-header/site-header.d.ts +2 -2
- package/dist/blocks/site-header/site-header.js +3 -3
- package/dist/blocks/site-navbar/index.d.ts +3 -0
- package/dist/blocks/site-navbar/index.d.ts.map +1 -0
- package/dist/blocks/site-navbar/index.js +1 -0
- package/dist/blocks/site-navbar/mobile-nav.d.ts +48 -0
- package/dist/blocks/site-navbar/mobile-nav.d.ts.map +1 -0
- package/dist/blocks/site-navbar/mobile-nav.js +35 -0
- package/dist/blocks/site-navbar/mode-toggle.d.ts +39 -0
- package/dist/blocks/site-navbar/mode-toggle.d.ts.map +1 -0
- package/dist/blocks/site-navbar/mode-toggle.js +39 -0
- package/dist/blocks/site-navbar/navbar-controls.d.ts +79 -0
- package/dist/blocks/site-navbar/navbar-controls.d.ts.map +1 -0
- package/dist/blocks/site-navbar/navbar-controls.js +40 -0
- package/dist/blocks/site-navbar/search-entry.d.ts +29 -0
- package/dist/blocks/site-navbar/search-entry.d.ts.map +1 -0
- package/dist/blocks/site-navbar/search-entry.js +52 -0
- package/dist/blocks/site-navbar/site-navbar.d.ts +212 -0
- package/dist/blocks/site-navbar/site-navbar.d.ts.map +1 -0
- package/dist/blocks/site-navbar/site-navbar.js +61 -0
- package/dist/blocks/site-navbar/sites-menu.d.ts +40 -0
- package/dist/blocks/site-navbar/sites-menu.d.ts.map +1 -0
- package/dist/blocks/site-navbar/sites-menu.js +48 -0
- package/dist/blocks/site-navbar/theme-menu.d.ts +47 -0
- package/dist/blocks/site-navbar/theme-menu.d.ts.map +1 -0
- package/dist/blocks/site-navbar/theme-menu.js +55 -0
- package/dist/blocks/stack-grid-01/index.d.ts +2 -2
- package/dist/blocks/stack-grid-01/index.js +1 -1
- package/dist/blocks/stack-grid-01/stack-grid.d.ts +42 -11
- package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -1
- package/dist/blocks/stack-grid-01/stack-grid.js +15 -7
- package/dist/blocks/stats-01/index.d.ts +9 -1
- package/dist/blocks/stats-01/index.d.ts.map +1 -1
- package/dist/blocks/stats-01/index.js +8 -1
- package/dist/blocks/stats-01/stats.d.ts +1 -1
- package/dist/blocks/stats-01/stats.js +2 -2
- package/dist/blocks/status-ledger-01/index.d.ts +2 -2
- package/dist/blocks/status-ledger-01/index.js +1 -1
- package/dist/blocks/status-ledger-01/status-ledger.d.ts +1 -1
- package/dist/blocks/status-ledger-01/status-ledger.js +2 -2
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +473 -1
- package/dist/components/index.d.ts +104 -66
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +74 -40
- package/dist/components/ui/accordion.js +1 -1
- package/dist/components/ui/alert-dialog.d.ts +119 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.js +82 -0
- package/dist/components/ui/alert.js +1 -1
- package/dist/components/ui/aspect-ratio.d.ts +60 -0
- package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
- package/dist/components/ui/aspect-ratio.js +61 -0
- package/dist/components/ui/avatar.js +1 -1
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/breadcrumb.js +1 -1
- package/dist/components/ui/button-group.d.ts +68 -0
- package/dist/components/ui/button-group.d.ts.map +1 -0
- package/dist/components/ui/button-group.js +54 -0
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/calendar.d.ts +158 -0
- package/dist/components/ui/calendar.d.ts.map +1 -0
- package/dist/components/ui/calendar.js +216 -0
- package/dist/components/ui/card.d.ts +18 -6
- package/dist/components/ui/card.d.ts.map +1 -1
- package/dist/components/ui/card.js +23 -8
- package/dist/components/ui/carousel.d.ts +118 -0
- package/dist/components/ui/carousel.d.ts.map +1 -0
- package/dist/components/ui/carousel.js +152 -0
- package/dist/components/ui/chart-frame.d.ts +216 -0
- package/dist/components/ui/chart-frame.d.ts.map +1 -0
- package/dist/components/ui/chart-frame.js +286 -0
- package/dist/components/ui/checkbox.js +1 -1
- package/dist/components/ui/collapsible.d.ts +97 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +54 -0
- package/dist/components/ui/combobox.d.ts +141 -0
- package/dist/components/ui/combobox.d.ts.map +1 -0
- package/dist/components/ui/combobox.js +243 -0
- package/dist/components/ui/command-palette.d.ts +106 -0
- package/dist/components/ui/command-palette.d.ts.map +1 -0
- package/dist/components/ui/command-palette.js +176 -0
- package/dist/components/ui/command.d.ts +82 -0
- package/dist/components/ui/command.d.ts.map +1 -0
- package/dist/components/ui/command.js +37 -0
- package/dist/components/ui/context-menu.d.ts +151 -0
- package/dist/components/ui/context-menu.d.ts.map +1 -0
- package/dist/components/ui/context-menu.js +97 -0
- package/dist/components/ui/cta-link.js +1 -1
- package/dist/components/ui/date-picker.d.ts +111 -0
- package/dist/components/ui/date-picker.d.ts.map +1 -0
- package/dist/components/ui/date-picker.js +74 -0
- package/dist/components/ui/diagram.d.ts +84 -15
- package/dist/components/ui/diagram.d.ts.map +1 -1
- package/dist/components/ui/diagram.js +77 -7
- package/dist/components/ui/dialog.js +1 -1
- package/dist/components/ui/diff.d.ts +105 -0
- package/dist/components/ui/diff.d.ts.map +1 -0
- package/dist/components/ui/diff.js +113 -0
- package/dist/components/ui/dropdown-menu.d.ts +18 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.js +1 -1
- package/dist/components/ui/fact-list.js +1 -1
- package/dist/components/ui/field.js +1 -1
- package/dist/components/ui/form.d.ts +151 -0
- package/dist/components/ui/form.d.ts.map +1 -0
- package/dist/components/ui/form.js +73 -0
- package/dist/components/ui/hover-card.d.ts +105 -0
- package/dist/components/ui/hover-card.d.ts.map +1 -0
- package/dist/components/ui/hover-card.js +49 -0
- package/dist/components/ui/input-group.d.ts +99 -0
- package/dist/components/ui/input-group.d.ts.map +1 -0
- package/dist/components/ui/input-group.js +83 -0
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/item.d.ts +113 -0
- package/dist/components/ui/item.d.ts.map +1 -0
- package/dist/components/ui/item.js +61 -0
- package/dist/components/ui/kbd.js +1 -1
- package/dist/components/ui/label.d.ts +58 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +29 -0
- package/dist/components/ui/live-region.d.ts +9 -0
- package/dist/components/ui/live-region.d.ts.map +1 -1
- package/dist/components/ui/live-region.js +10 -2
- package/dist/components/ui/mark.js +1 -1
- package/dist/components/ui/menubar.d.ts +197 -0
- package/dist/components/ui/menubar.d.ts.map +1 -0
- package/dist/components/ui/menubar.js +109 -0
- package/dist/components/ui/meter.d.ts +121 -0
- package/dist/components/ui/meter.d.ts.map +1 -0
- package/dist/components/ui/meter.js +82 -0
- package/dist/components/ui/native-select.d.ts +72 -0
- package/dist/components/ui/native-select.d.ts.map +1 -0
- package/dist/components/ui/native-select.js +55 -0
- package/dist/components/ui/navigation-menu.d.ts +186 -0
- package/dist/components/ui/navigation-menu.d.ts.map +1 -0
- package/dist/components/ui/navigation-menu.js +94 -0
- package/dist/components/ui/number-field.d.ts +111 -0
- package/dist/components/ui/number-field.d.ts.map +1 -0
- package/dist/components/ui/number-field.js +84 -0
- package/dist/components/ui/one-time-code.d.ts +127 -0
- package/dist/components/ui/one-time-code.d.ts.map +1 -0
- package/dist/components/ui/one-time-code.js +57 -0
- package/dist/components/ui/pagination.js +1 -1
- package/dist/components/ui/popover.js +1 -1
- package/dist/components/ui/product-mark.d.ts +1 -1
- package/dist/components/ui/product-mark.js +1 -1
- package/dist/components/ui/product-switcher.d.ts +1 -1
- package/dist/components/ui/product-switcher.js +2 -2
- package/dist/components/ui/progress.js +1 -1
- package/dist/components/ui/prose.js +1 -1
- package/dist/components/ui/pulse-graph.js +1 -1
- package/dist/components/ui/pulse-series.js +1 -1
- package/dist/components/ui/radio-group.js +1 -1
- package/dist/components/ui/resizable.d.ts +129 -0
- package/dist/components/ui/resizable.d.ts.map +1 -0
- package/dist/components/ui/resizable.js +205 -0
- package/dist/components/ui/scroll-area.d.ts +97 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.js +68 -0
- package/dist/components/ui/search-dialog.d.ts +139 -0
- package/dist/components/ui/search-dialog.d.ts.map +1 -0
- package/dist/components/ui/search-dialog.js +178 -0
- package/dist/components/ui/section.d.ts +26 -0
- package/dist/components/ui/section.d.ts.map +1 -1
- package/dist/components/ui/section.js +32 -1
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/separator.js +1 -1
- package/dist/components/ui/sheet.d.ts +103 -0
- package/dist/components/ui/sheet.d.ts.map +1 -0
- package/dist/components/ui/sheet.js +58 -0
- package/dist/components/ui/sidebar.d.ts +228 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -0
- package/dist/components/ui/sidebar.js +172 -0
- package/dist/components/ui/signal-field.js +1 -1
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/slider.js +1 -1
- package/dist/components/ui/spinner.d.ts +79 -0
- package/dist/components/ui/spinner.d.ts.map +1 -0
- package/dist/components/ui/spinner.js +79 -0
- package/dist/components/ui/switch.js +1 -1
- package/dist/components/ui/table-sort.d.ts +97 -0
- package/dist/components/ui/table-sort.d.ts.map +1 -0
- package/dist/components/ui/table-sort.js +102 -0
- package/dist/components/ui/table.js +1 -1
- package/dist/components/ui/tabs.js +1 -1
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/timeline.d.ts +106 -0
- package/dist/components/ui/timeline.d.ts.map +1 -0
- package/dist/components/ui/timeline.js +111 -0
- package/dist/components/ui/toast.d.ts +219 -0
- package/dist/components/ui/toast.d.ts.map +1 -0
- package/dist/components/ui/toast.js +270 -0
- package/dist/components/ui/toggle-group.d.ts +118 -0
- package/dist/components/ui/toggle-group.d.ts.map +1 -0
- package/dist/components/ui/toggle-group.js +194 -0
- package/dist/components/ui/toggle.d.ts +73 -0
- package/dist/components/ui/toggle.d.ts.map +1 -0
- package/dist/components/ui/toggle.js +44 -0
- package/dist/components/ui/tooltip.js +1 -1
- package/dist/components/ui/tree.js +1 -1
- package/dist/components/ui/typography.js +1 -1
- package/dist/fonts/Inter-OFL.txt +93 -93
- package/dist/index.d.ts +72 -70
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +61 -60
- package/dist/lib/rank.d.ts +69 -0
- package/dist/lib/rank.d.ts.map +1 -0
- package/dist/lib/rank.js +77 -0
- package/dist/live/index.d.ts +22 -0
- package/dist/live/index.d.ts.map +1 -0
- package/dist/live/index.js +20 -0
- package/dist/live/run-stream-01/index.d.ts +3 -0
- package/dist/live/run-stream-01/index.d.ts.map +1 -0
- package/dist/live/run-stream-01/index.js +1 -0
- package/dist/live/run-stream-01/run-stream.d.ts +125 -0
- package/dist/live/run-stream-01/run-stream.d.ts.map +1 -0
- package/dist/live/run-stream-01/run-stream.js +111 -0
- package/dist/pages/auth-page/index.d.ts +15 -2
- package/dist/pages/auth-page/index.d.ts.map +1 -1
- package/dist/pages/auth-page/index.js +8 -4
- package/dist/pages/blog-post-page/index.js +5 -5
- package/dist/pages/dashboard-page/index.d.ts +4 -4
- package/dist/pages/dashboard-page/index.js +4 -4
- package/dist/pages/docs-shell/docs-shell.d.ts +37 -4
- package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -1
- package/dist/pages/docs-shell/docs-shell.js +107 -16
- package/dist/pages/docs-shell/index.d.ts +2 -2
- package/dist/pages/docs-shell/index.js +1 -1
- package/dist/pages/index.d.ts +14 -14
- package/dist/pages/index.js +7 -7
- package/dist/pages/marketing-page/index.d.ts +6 -6
- package/dist/pages/marketing-page/index.js +5 -5
- package/dist/pages/not-found-page/index.js +4 -4
- package/dist/pages/settings-page/index.d.ts +3 -3
- package/dist/pages/settings-page/index.js +4 -4
- package/dist/provider/index.d.ts +4 -4
- package/dist/provider/index.js +2 -2
- package/dist/provider/provider.d.ts +1 -1
- package/dist/provider/provider.js +1 -1
- package/dist/provider/theme-script.d.ts +1 -1
- package/dist/provider/theme-script.js +1 -1
- package/dist/styles.css +689 -0
- package/package.json +9 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who produced an event, as a closed set.
|
|
3
|
+
*
|
|
4
|
+
* The four are the ones an agent run actually has, and they are closed because the
|
|
5
|
+
* treatment is not the caller's: a role is a slot for a colour, a mark and an
|
|
6
|
+
* announcement, and a free-text role would be a string with no rendering behind it.
|
|
7
|
+
* The **words** are still the caller's, in `message`. Prism owns which role looks
|
|
8
|
+
* like what, and ships none of the labels.
|
|
9
|
+
*/
|
|
10
|
+
export type RunEventRole = 'agent' | 'tool' | 'system' | 'error';
|
|
11
|
+
/** One event, as the surface receives it. */
|
|
12
|
+
export type RunEvent = {
|
|
13
|
+
/** Stable across re-renders, so an event is never re-announced because its index moved. */
|
|
14
|
+
id: string;
|
|
15
|
+
role: RunEventRole;
|
|
16
|
+
/** Epoch milliseconds, used for order and for the elapsed column. */
|
|
17
|
+
at: number;
|
|
18
|
+
/** What happened, in the consumer's words. */
|
|
19
|
+
message: string;
|
|
20
|
+
/** Optional second line: a tool's arguments, a path, a code. */
|
|
21
|
+
detail?: string;
|
|
22
|
+
};
|
|
23
|
+
/** Where a run has got to. The tiers are Prism's; the words beside them are the caller's. */
|
|
24
|
+
export type RunStatus = 'queued' | 'running' | 'waiting' | 'done' | 'failed';
|
|
25
|
+
/**
|
|
26
|
+
* How the surface receives events.
|
|
27
|
+
*
|
|
28
|
+
* The consumer owns the socket, the transport and the persistence, so this is a
|
|
29
|
+
* function it supplies rather than a connection Prism opens. It is called once on
|
|
30
|
+
* mount and must return an unsubscribe, which is what makes a WebSocket, an
|
|
31
|
+
* `EventSource`, a polling timer or a test's own array all the same shape to the
|
|
32
|
+
* surface. Nothing here knows which one it got.
|
|
33
|
+
*/
|
|
34
|
+
export type RunSubscribe = (emit: (event: RunEvent) => void) => () => void;
|
|
35
|
+
export type RunStream01Props = {
|
|
36
|
+
/**
|
|
37
|
+
* Called once to begin receiving, and again whenever `resubscribeKey` changes.
|
|
38
|
+
* Must return an unsubscribe; the surface calls it on unmount and before
|
|
39
|
+
* re-subscribing, so a consumer that returns nothing leaks its connection.
|
|
40
|
+
*/
|
|
41
|
+
subscribe: RunSubscribe;
|
|
42
|
+
/**
|
|
43
|
+
* Which run this surface is showing, and the reset lever.
|
|
44
|
+
*
|
|
45
|
+
* Changing it **clears the log and reseeds it from `initial`**, as well as
|
|
46
|
+
* tearing the subscription down and opening a new one. A run is identified by
|
|
47
|
+
* whatever the consumer already uses to identify it, so a second run in the same
|
|
48
|
+
* surface is a new subscription rather than two consumers of one, and it is a new
|
|
49
|
+
* log rather than the old run's events with the new run's appended, which is the
|
|
50
|
+
* reading a reader would not distinguish from one run being longer than it was.
|
|
51
|
+
*/
|
|
52
|
+
resubscribeKey?: string | number;
|
|
53
|
+
/**
|
|
54
|
+
* The events already known when this run is opened, so a surface opened mid-run
|
|
55
|
+
* is not blank. Oldest first.
|
|
56
|
+
*
|
|
57
|
+
* Read when the run is opened, and again whenever `resubscribeKey` changes. It is
|
|
58
|
+
* **not** read on every render: a prop that looked like the current event list
|
|
59
|
+
* and quietly seeded only once would be a trap, and a prop that re-seeded on
|
|
60
|
+
* every render would discard the stream. This seeds, and the stream takes over.
|
|
61
|
+
*/
|
|
62
|
+
initial?: readonly RunEvent[];
|
|
63
|
+
/** Where the run has got to. */
|
|
64
|
+
status?: RunStatus;
|
|
65
|
+
/** The word beside the status. Required when a status is passed. */
|
|
66
|
+
statusLabel?: string;
|
|
67
|
+
/** Optional label above the surface's heading. See the No-Default-Eyebrow Rule. */
|
|
68
|
+
eyebrow?: string;
|
|
69
|
+
/** The surface's heading. Omit it for one composed under its own. */
|
|
70
|
+
title?: string;
|
|
71
|
+
/** One or two sentences under the heading. */
|
|
72
|
+
description?: string;
|
|
73
|
+
/** What the surface says when it holds no events yet. */
|
|
74
|
+
emptyLabel?: string;
|
|
75
|
+
/**
|
|
76
|
+
* The accessible name of the scrolling region.
|
|
77
|
+
*
|
|
78
|
+
* Required, because `ScrollArea` requires it and the reason is the right one: a
|
|
79
|
+
* scroll region with no name is announced as a group of focusable nothing, and a
|
|
80
|
+
* keyboard reader who tabs into it cannot tell what is in it or what is past the
|
|
81
|
+
* edge. The name is the consumer's word, as every other word here is.
|
|
82
|
+
*/
|
|
83
|
+
eventsLabel: string;
|
|
84
|
+
/** Announced to assistive technology as events arrive. */
|
|
85
|
+
liveLabel?: string;
|
|
86
|
+
/** How many events to keep. Older events fall off the top. */
|
|
87
|
+
limit?: number;
|
|
88
|
+
className?: string;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The event log of a run, receiving events as they arrive.
|
|
92
|
+
*
|
|
93
|
+
* **This is the first surface in the package that is a client Component**, and that
|
|
94
|
+
* is the whole of what the fourth Kind is for. A Block takes its content as props,
|
|
95
|
+
* so it is rendered once and re-rendered when the consumer's framework decides; a
|
|
96
|
+
* `live` surface's content changes **without a navigation event**, which no amount
|
|
97
|
+
* of prop-passing expresses. So this owns a subscription and the accumulation
|
|
98
|
+
* behind it.
|
|
99
|
+
*
|
|
100
|
+
* **Prism owns the surface, the consumer owns the transport.** `subscribe` is a
|
|
101
|
+
* function the consumer supplies and a function it tears down. There is no socket
|
|
102
|
+
* in this file, no endpoint, no retry policy and no persistence, and there is no
|
|
103
|
+
* provider to mount: a consumer that already has a connection passes it in, and one
|
|
104
|
+
* that does not has not acquired a client runtime by importing this.
|
|
105
|
+
*
|
|
106
|
+
* **The events are kept sorted by `at`, not by arrival.** A consumer's transport
|
|
107
|
+
* decides when a message is delivered, and a reconnect can deliver an older event
|
|
108
|
+
* after a newer one. Sorting on arrival would put a run's own history out of order
|
|
109
|
+
* in exactly the case where a reader is most likely to be watching. Ties break on
|
|
110
|
+
* `id`, so the order is total and two runs of the same suite render the same log.
|
|
111
|
+
*
|
|
112
|
+
* **New events are announced once, politely, and the log itself is not a live
|
|
113
|
+
* region.** Announcing a growing list would make a screen reader read the whole run
|
|
114
|
+
* again on every arrival, which is the failure a live region on a list guarantees.
|
|
115
|
+
* `LiveRegion` carries the newest event's message alone, and the log is an ordinary
|
|
116
|
+
* scrollable list a reader can move through at their own pace.
|
|
117
|
+
*
|
|
118
|
+
* `limit` bounds what is held, because an agent run can produce thousands of events
|
|
119
|
+
* and a surface that grows without bound is a surface that eventually stops
|
|
120
|
+
* repainting. Older events fall off the top, which is the direction a reader wants:
|
|
121
|
+
* the run's beginning is the part they can scroll back to in another surface.
|
|
122
|
+
*/
|
|
123
|
+
export declare function RunStream01({ subscribe, resubscribeKey, initial, status, statusLabel, eyebrow, title, description, emptyLabel, eventsLabel, liveLabel, limit, className, }: RunStream01Props): import("react").JSX.Element;
|
|
124
|
+
export default RunStream01;
|
|
125
|
+
//# sourceMappingURL=run-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/live/run-stream-01/run-stream.tsx"],"names":[],"mappings":"AAQA;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;AAEhE,6CAA6C;AAC7C,MAAM,MAAM,QAAQ,GAAG;IACrB,2FAA2F;IAC3F,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,YAAY,CAAA;IAClB,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAA;IACV,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,6FAA6F;AAC7F,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAA;AAE5E;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;AAE1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;OAIG;IACH,SAAS,EAAE,YAAY,CAAA;IACvB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAChC;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC7B,gCAAgC;IAChC,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;;OAOG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AA8BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EACT,cAAc,EACd,OAAO,EACP,MAAM,EACN,WAAW,EACX,OAAO,EACP,KAAK,EACL,WAAW,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,KAAW,EACX,SAAS,GACV,EAAE,gBAAgB,+BA8HlB;AAED,eAAe,WAAW,CAAA"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { LiveRegion } from '../../components/ui/live-region.js';
|
|
5
|
+
import { ScrollArea } from '../../components/ui/scroll-area.js';
|
|
6
|
+
import { cn } from '../../lib/utils.js';
|
|
7
|
+
/** The ink each role is stated in, and the tick beside it. */
|
|
8
|
+
const ROLE_INK = {
|
|
9
|
+
agent: 'text-foreground',
|
|
10
|
+
tool: 'text-foreground',
|
|
11
|
+
system: 'text-muted-foreground',
|
|
12
|
+
error: 'text-destructive',
|
|
13
|
+
};
|
|
14
|
+
/** The tick each role draws, so the four are told apart without relying on colour. */
|
|
15
|
+
const ROLE_MARK = {
|
|
16
|
+
agent: 'â—Â',
|
|
17
|
+
tool: 'â–¸',
|
|
18
|
+
system: '·',
|
|
19
|
+
error: '×',
|
|
20
|
+
};
|
|
21
|
+
const STATUS_INK = {
|
|
22
|
+
queued: 'text-muted-foreground',
|
|
23
|
+
running: 'text-foreground',
|
|
24
|
+
waiting: 'text-warning',
|
|
25
|
+
done: 'text-success',
|
|
26
|
+
failed: 'text-destructive',
|
|
27
|
+
};
|
|
28
|
+
/** The one source of truth for order, so a late event with an earlier `at` sorts there. */
|
|
29
|
+
const byTimeThenId = (a, b) => a.at - b.at || a.id.localeCompare(b.id);
|
|
30
|
+
/**
|
|
31
|
+
* The event log of a run, receiving events as they arrive.
|
|
32
|
+
*
|
|
33
|
+
* **This is the first surface in the package that is a client Component**, and that
|
|
34
|
+
* is the whole of what the fourth Kind is for. A Block takes its content as props,
|
|
35
|
+
* so it is rendered once and re-rendered when the consumer's framework decides; a
|
|
36
|
+
* `live` surface's content changes **without a navigation event**, which no amount
|
|
37
|
+
* of prop-passing expresses. So this owns a subscription and the accumulation
|
|
38
|
+
* behind it.
|
|
39
|
+
*
|
|
40
|
+
* **Prism owns the surface, the consumer owns the transport.** `subscribe` is a
|
|
41
|
+
* function the consumer supplies and a function it tears down. There is no socket
|
|
42
|
+
* in this file, no endpoint, no retry policy and no persistence, and there is no
|
|
43
|
+
* provider to mount: a consumer that already has a connection passes it in, and one
|
|
44
|
+
* that does not has not acquired a client runtime by importing this.
|
|
45
|
+
*
|
|
46
|
+
* **The events are kept sorted by `at`, not by arrival.** A consumer's transport
|
|
47
|
+
* decides when a message is delivered, and a reconnect can deliver an older event
|
|
48
|
+
* after a newer one. Sorting on arrival would put a run's own history out of order
|
|
49
|
+
* in exactly the case where a reader is most likely to be watching. Ties break on
|
|
50
|
+
* `id`, so the order is total and two runs of the same suite render the same log.
|
|
51
|
+
*
|
|
52
|
+
* **New events are announced once, politely, and the log itself is not a live
|
|
53
|
+
* region.** Announcing a growing list would make a screen reader read the whole run
|
|
54
|
+
* again on every arrival, which is the failure a live region on a list guarantees.
|
|
55
|
+
* `LiveRegion` carries the newest event's message alone, and the log is an ordinary
|
|
56
|
+
* scrollable list a reader can move through at their own pace.
|
|
57
|
+
*
|
|
58
|
+
* `limit` bounds what is held, because an agent run can produce thousands of events
|
|
59
|
+
* and a surface that grows without bound is a surface that eventually stops
|
|
60
|
+
* repainting. Older events fall off the top, which is the direction a reader wants:
|
|
61
|
+
* the run's beginning is the part they can scroll back to in another surface.
|
|
62
|
+
*/
|
|
63
|
+
export function RunStream01({ subscribe, resubscribeKey, initial, status, statusLabel, eyebrow, title, description, emptyLabel, eventsLabel, liveLabel, limit = 500, className, }) {
|
|
64
|
+
/**
|
|
65
|
+
* The run's log, held against the key that produced it.
|
|
66
|
+
*
|
|
67
|
+
* Adjusting state during render when the key changes is React's documented
|
|
68
|
+
* pattern for "a prop changed, start over", and it is the right one here: the
|
|
69
|
+
* alternative is an effect, and an effect that clears the log runs *after* a
|
|
70
|
+
* render, so the surface would paint one frame holding the previous run's events
|
|
71
|
+
* under the new run's heading.
|
|
72
|
+
*/
|
|
73
|
+
const [newest, setNewest] = useState(undefined);
|
|
74
|
+
const [run, setRun] = useState(() => ({
|
|
75
|
+
key: resubscribeKey,
|
|
76
|
+
events: [...(initial ?? [])].sort(byTimeThenId),
|
|
77
|
+
}));
|
|
78
|
+
if (run.key !== resubscribeKey) {
|
|
79
|
+
setRun({ key: resubscribeKey, events: [...(initial ?? [])].sort(byTimeThenId) });
|
|
80
|
+
// The announcement is cleared with the log it announced, so a run switch does
|
|
81
|
+
// not leave the previous run's last event in the live region saying so.
|
|
82
|
+
setNewest(undefined);
|
|
83
|
+
}
|
|
84
|
+
const events = run.events;
|
|
85
|
+
const setEvents = (next) => {
|
|
86
|
+
setRun((current) => ({ ...current, events: next(current.events) }));
|
|
87
|
+
};
|
|
88
|
+
// A ref rather than state, so the effect does not re-subscribe because an event
|
|
89
|
+
// arrived. An effect that depended on the value it writes re-runs itself, and the
|
|
90
|
+
// surface would open a new subscription per event.
|
|
91
|
+
const emit = useRef(() => { });
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
emit.current = (event) => {
|
|
94
|
+
setEvents((current) => {
|
|
95
|
+
const next = [...current, event].sort(byTimeThenId);
|
|
96
|
+
return next.length > limit ? next.slice(next.length - limit) : next;
|
|
97
|
+
});
|
|
98
|
+
setNewest(event.message);
|
|
99
|
+
};
|
|
100
|
+
const stop = subscribe(emit.current);
|
|
101
|
+
return () => {
|
|
102
|
+
// Calling an unsubscribe the consumer did not return would throw during
|
|
103
|
+
// unmount, so a missing one is stepped over and the leak is the consumer's to
|
|
104
|
+
// fix rather than a crash in someone else's teardown.
|
|
105
|
+
if (typeof stop === 'function')
|
|
106
|
+
stop();
|
|
107
|
+
};
|
|
108
|
+
}, [subscribe, resubscribeKey, limit]);
|
|
109
|
+
return (_jsxs("section", { "data-slot": "run-stream", className: cn('border-border flex flex-col gap-4 rounded-lg border p-4', className), children: [LiveRegion({ politeness: 'polite', label: liveLabel, children: newest }), title !== undefined || eyebrow !== undefined || description !== undefined ? (_jsxs("header", { className: "flex flex-col gap-1", children: [eyebrow ? (_jsx("span", { className: "text-muted-foreground text-xs font-medium tracking-wide uppercase", children: eyebrow })) : null, title ? _jsx("h2", { className: "text-lg font-semibold tracking-tight", children: title }) : null, description ? (_jsx("p", { className: "text-muted-foreground text-pretty text-sm", children: description })) : null] })) : null, status !== undefined ? (_jsx("p", { "data-slot": "run-status", className: cn('font-mono text-xs', STATUS_INK[status]), children: statusLabel })) : null, events.length === 0 ? (_jsx("p", { "data-slot": "run-stream-empty", className: "text-muted-foreground text-sm", children: emptyLabel })) : (_jsx(ScrollArea, { label: eventsLabel, className: "max-h-80", children: _jsx("ol", { "data-slot": "run-events", className: "flex flex-col gap-2", children: events.map((event) => (_jsxs("li", { "data-slot": "run-event", "data-role": event.role, className: "grid grid-cols-[auto_auto_1fr] items-baseline gap-x-3 gap-y-0.5", children: [_jsx("span", { "aria-hidden": "true", className: cn('font-mono text-xs', ROLE_INK[event.role]), children: ROLE_MARK[event.role] }), _jsx("time", { dateTime: new Date(event.at).toISOString(), className: "text-muted-foreground font-mono text-xs tabular-nums", children: new Date(event.at).toISOString().slice(11, 19) }), _jsxs("span", { className: cn('text-pretty text-sm', ROLE_INK[event.role]), children: [event.message, event.detail ? (_jsx("span", { className: "text-muted-foreground block font-mono text-xs", children: event.detail })) : null] })] }, event.id))) }) }))] }));
|
|
110
|
+
}
|
|
111
|
+
export default RunStream01;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
-
import { AuthForm01 } from '../../blocks/auth-form-01';
|
|
2
|
+
import { AuthForm01 } from '../../blocks/auth-form-01/index.js';
|
|
3
|
+
import type { HeadingLevel } from '../../components/ui/section.js';
|
|
3
4
|
export type AuthPageAside = {
|
|
4
5
|
/** The supporting card's title. */
|
|
5
6
|
title: string;
|
|
@@ -17,6 +18,18 @@ export type AuthPageProps = {
|
|
|
17
18
|
aside?: AuthPageAside;
|
|
18
19
|
/** A node under the form, such as a legal line or a link to another screen. */
|
|
19
20
|
footer?: ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* Heading level for the two region titles, the form's and the aside's. See
|
|
23
|
+
* `HeadingLevel`.
|
|
24
|
+
*
|
|
25
|
+
* The page draws no heading of its own, so each region names itself and the two
|
|
26
|
+
* are siblings in the outline. They therefore take one level between them
|
|
27
|
+
* rather than each choosing one: two regions that announced themselves at
|
|
28
|
+
* different depths would read as one inside the other, and nothing in the layout
|
|
29
|
+
* says so. Defaults to `h2`, because a page composes under a document that has
|
|
30
|
+
* its own `h1`.
|
|
31
|
+
*/
|
|
32
|
+
headingLevel?: HeadingLevel;
|
|
20
33
|
};
|
|
21
34
|
/**
|
|
22
35
|
* A complete authentication screen.
|
|
@@ -31,6 +44,6 @@ export type AuthPageProps = {
|
|
|
31
44
|
* split from the large breakpoint up when one is. That keeps the docs preview
|
|
32
45
|
* and a narrow screen on the same, readable path.
|
|
33
46
|
*/
|
|
34
|
-
export declare function AuthPage({ form, aside, footer }: AuthPageProps): import("react").JSX.Element;
|
|
47
|
+
export declare function AuthPage({ form, aside, footer, headingLevel }: AuthPageProps): import("react").JSX.Element;
|
|
35
48
|
export default AuthPage;
|
|
36
49
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/auth-page/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/auth-page/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAQtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAE/D,MAAM,MAAM,aAAa,GAAG;IAC1B,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,2BAA2B;IAC3B,IAAI,EAAE,cAAc,CAAC,OAAO,UAAU,CAAC,CAAA;IACvC;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,YAAmB,EAAE,EAAE,aAAa,+BAqCnF;AAED,eAAe,QAAQ,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { AuthForm01 } from '../../blocks/auth-form-01';
|
|
4
|
-
import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '../../components/ui/card';
|
|
3
|
+
import { AuthForm01 } from '../../blocks/auth-form-01/index.js';
|
|
4
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '../../components/ui/card.js';
|
|
5
5
|
/**
|
|
6
6
|
* A complete authentication screen.
|
|
7
7
|
*
|
|
@@ -15,9 +15,13 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '../.
|
|
|
15
15
|
* split from the large breakpoint up when one is. That keeps the docs preview
|
|
16
16
|
* and a narrow screen on the same, readable path.
|
|
17
17
|
*/
|
|
18
|
-
export function AuthPage({ form, aside, footer }) {
|
|
18
|
+
export function AuthPage({ form, aside, footer, headingLevel = 'h2' }) {
|
|
19
|
+
// The form and the aside are sibling regions, so they announce themselves at the
|
|
20
|
+
// same depth: at different depths one would read as inside the other, and
|
|
21
|
+
// nothing in the layout says so.
|
|
22
|
+
const Title = headingLevel;
|
|
19
23
|
return (_jsx("div", { className: "bg-background text-foreground flex min-h-svh w-full items-center justify-center px-6 py-16", children: _jsxs("div", { className: aside
|
|
20
24
|
? 'grid w-full max-w-page items-center gap-10 lg:grid-cols-2'
|
|
21
|
-
: 'w-full max-w-measure-narrow', children: [aside ? (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: aside.title }), aside.description ? (_jsx(CardDescription, { children: aside.description })) : null] }), aside.children ? _jsx(CardContent, { children: aside.children }) : null] })) : null, _jsxs("div", { className: "mx-auto w-full max-w-measure-narrow", children: [_jsx(AuthForm01, { ...form }), footer ? (_jsx("div", { className: "text-muted-foreground mt-4 text-center text-sm", children: footer })) : null] })] }) }));
|
|
25
|
+
: 'w-full max-w-measure-narrow', children: [aside ? (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: _jsx(Title, { children: aside.title }) }), aside.description ? (_jsx(CardDescription, { children: aside.description })) : null] }), aside.children ? _jsx(CardContent, { children: aside.children }) : null] })) : null, _jsxs("div", { className: "mx-auto w-full max-w-measure-narrow", children: [_jsx(AuthForm01, { ...form, headingLevel: headingLevel }), footer ? (_jsx("div", { className: "text-muted-foreground mt-4 text-center text-sm", children: footer })) : null] })] }) }));
|
|
22
26
|
}
|
|
23
27
|
export default AuthPage;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Badge } from '../../components/ui/badge';
|
|
3
|
-
import { CtaLink } from '../../components/ui/cta-link';
|
|
4
|
-
import { Heading, Text } from '../../components/ui/typography';
|
|
5
|
-
import { Prose } from '../../components/ui/prose';
|
|
6
|
-
import { Section } from '../../components/ui/section';
|
|
2
|
+
import { Badge } from '../../components/ui/badge.js';
|
|
3
|
+
import { CtaLink } from '../../components/ui/cta-link.js';
|
|
4
|
+
import { Heading, Text } from '../../components/ui/typography.js';
|
|
5
|
+
import { Prose } from '../../components/ui/prose.js';
|
|
6
|
+
import { Section } from '../../components/ui/section.js';
|
|
7
7
|
/**
|
|
8
8
|
* A complete blog post screen: the title, the standfirst, the byline, the body at
|
|
9
9
|
* the measure, and the trail to the neighbouring posts.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ComponentProps } from 'react';
|
|
2
|
-
import { AppShell01 } from '../../blocks/app-shell-01';
|
|
3
|
-
import { DataTable01 } from '../../blocks/data-table-01';
|
|
4
|
-
import { PageHeader01 } from '../../blocks/page-header-01';
|
|
5
|
-
import { Stats01 } from '../../blocks/stats-01';
|
|
2
|
+
import { AppShell01 } from '../../blocks/app-shell-01/index.js';
|
|
3
|
+
import { DataTable01 } from '../../blocks/data-table-01/index.js';
|
|
4
|
+
import { PageHeader01 } from '../../blocks/page-header-01/index.js';
|
|
5
|
+
import { Stats01 } from '../../blocks/stats-01/index.js';
|
|
6
6
|
export type DashboardPageProps = {
|
|
7
7
|
/**
|
|
8
8
|
* The frame: the navigation rail, the top bar and the mobile navigation
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { AppShell01 } from '../../blocks/app-shell-01';
|
|
4
|
-
import { DataTable01 } from '../../blocks/data-table-01';
|
|
5
|
-
import { PageHeader01 } from '../../blocks/page-header-01';
|
|
6
|
-
import { Stats01 } from '../../blocks/stats-01';
|
|
3
|
+
import { AppShell01 } from '../../blocks/app-shell-01/index.js';
|
|
4
|
+
import { DataTable01 } from '../../blocks/data-table-01/index.js';
|
|
5
|
+
import { PageHeader01 } from '../../blocks/page-header-01/index.js';
|
|
6
|
+
import { Stats01 } from '../../blocks/stats-01/index.js';
|
|
7
7
|
/**
|
|
8
8
|
* A complete dashboard screen.
|
|
9
9
|
*
|
|
@@ -5,12 +5,27 @@ import type { ReactNode } from 'react';
|
|
|
5
5
|
* `href` is required. A page in the navigation that goes nowhere is an entry a
|
|
6
6
|
* reader can focus and not follow, and the Page renders every page entry as a
|
|
7
7
|
* native anchor so a reader can see where a destination is before taking it.
|
|
8
|
+
*
|
|
9
|
+
* **Required is not the same as enforced, and the difference is stated here
|
|
10
|
+
* rather than left to be discovered.** `href: string` admits `''`, because the
|
|
11
|
+
* empty string is a legal `string` and the only type that refuses it is a branded
|
|
12
|
+
* one, which would put an `as` in every consumer's adapter for three sites this
|
|
13
|
+
* Page is already published to. So the type admits the value and `readTree`
|
|
14
|
+
* refuses it, at the boundary, by throwing and naming the entry. The promise this
|
|
15
|
+
* block used to make was true only of the group arm; it is now true of what the
|
|
16
|
+
* Page renders, and it says which of the two is doing the work.
|
|
17
|
+
*
|
|
18
|
+
* `title` may be the empty string, and an entry with no words is not a page: it
|
|
19
|
+
* renders as a label on the same rule that makes a group with no index a label,
|
|
20
|
+
* and it is not a page the pager can reach either. A link with no accessible name
|
|
21
|
+
* is announced as "link" and nothing else, which is the one thing a link in a
|
|
22
|
+
* rail must never be.
|
|
8
23
|
*/
|
|
9
24
|
export type DocsNavPage = {
|
|
10
25
|
type: 'page';
|
|
11
|
-
/** The words the reader meets. */
|
|
26
|
+
/** The words the reader meets. An empty string makes this a label, not a link. */
|
|
12
27
|
title: string;
|
|
13
|
-
/** The address the page is read at. */
|
|
28
|
+
/** The address the page is read at. An empty string is refused, by name. */
|
|
14
29
|
href: string;
|
|
15
30
|
};
|
|
16
31
|
/**
|
|
@@ -37,6 +52,13 @@ export type DocsNavGroup = {
|
|
|
37
52
|
/**
|
|
38
53
|
* The group's own index page, where it has one. Omit it for a group that is
|
|
39
54
|
* only a heading over its pages.
|
|
55
|
+
*
|
|
56
|
+
* An empty or blank string is the same answer as omitting it, and deliberately
|
|
57
|
+
* so: all three consumer adapters write `url: node.index?.url ?? ''` for a
|
|
58
|
+
* folder holding no `index.mdx`, so the empty string is how they have always
|
|
59
|
+
* spelled "this group is not a route", and reading it as the absence is what
|
|
60
|
+
* keeps those adapters correct without a change in any of them. A page has no
|
|
61
|
+
* such reading: there, an empty address is a fault, and `readTree` says so.
|
|
40
62
|
*/
|
|
41
63
|
href?: string;
|
|
42
64
|
/** The pages under this group, in the order a reader should meet them. */
|
|
@@ -209,8 +231,19 @@ export type DocsShellProps = {
|
|
|
209
231
|
* consumer sites all write `url: node.index?.url ?? ''` in their own adapter
|
|
210
232
|
* today, which is the same fact spelled as an empty string, and two of the three
|
|
211
233
|
* then carry a stylesheet rule that styles the resulting anchor-with-no-href
|
|
212
|
-
* back into a label.
|
|
213
|
-
*
|
|
234
|
+
* back into a label. So the Page reads an empty or blank `href` as the absence on
|
|
235
|
+
* this arm, and the two stylesheet rules are dead rather than load-bearing. It
|
|
236
|
+
* takes one function rather than only a type, because an optional field the
|
|
237
|
+
* caller spells as `''` is not an optional field the type can see.
|
|
238
|
+
*
|
|
239
|
+
* **An entry with no words is a label too, and a page with no address is
|
|
240
|
+
* refused.** Both halves of "what makes this a destination" are answered in one
|
|
241
|
+
* function, `destinationOf`, and both the rail and the pager ask it. An entry
|
|
242
|
+
* that is a label on the rail is not a page the pager reaches either, so one
|
|
243
|
+
* malformed row cannot become two surfaces' worth of broken link. A page whose
|
|
244
|
+
* address is empty or blank has no such reading: there is nothing to render in
|
|
245
|
+
* place of the link, so the Page throws, naming the entry, before any of the tree
|
|
246
|
+
* renders.
|
|
214
247
|
*
|
|
215
248
|
* **The pager is derived from the navigation rather than passed.** The rail
|
|
216
249
|
* already knows every page and the order a reader meets them in, and deriving the
|
|
@@ -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;AAMtC
|
|
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;AAMtC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,kFAAkF;IAClF,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,sEAAsE;IACtE,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;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,+BAsFhB;AAwWD,eAAe,SAAS,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Prose } from '../../components/ui/prose';
|
|
3
|
-
import { Heading, Text } from '../../components/ui/typography';
|
|
4
|
-
import { cn } from '../../lib/utils';
|
|
2
|
+
import { Prose } from '../../components/ui/prose.js';
|
|
3
|
+
import { Heading, Text } from '../../components/ui/typography.js';
|
|
4
|
+
import { cn } from '../../lib/utils.js';
|
|
5
5
|
/**
|
|
6
6
|
* A documentation screen: a navigation rail, the document, a contents rail and
|
|
7
7
|
* the pager to the neighbouring pages.
|
|
@@ -31,8 +31,19 @@ import { cn } from '../../lib/utils';
|
|
|
31
31
|
* consumer sites all write `url: node.index?.url ?? ''` in their own adapter
|
|
32
32
|
* today, which is the same fact spelled as an empty string, and two of the three
|
|
33
33
|
* then carry a stylesheet rule that styles the resulting anchor-with-no-href
|
|
34
|
-
* back into a label.
|
|
35
|
-
*
|
|
34
|
+
* back into a label. So the Page reads an empty or blank `href` as the absence on
|
|
35
|
+
* this arm, and the two stylesheet rules are dead rather than load-bearing. It
|
|
36
|
+
* takes one function rather than only a type, because an optional field the
|
|
37
|
+
* caller spells as `''` is not an optional field the type can see.
|
|
38
|
+
*
|
|
39
|
+
* **An entry with no words is a label too, and a page with no address is
|
|
40
|
+
* refused.** Both halves of "what makes this a destination" are answered in one
|
|
41
|
+
* function, `destinationOf`, and both the rail and the pager ask it. An entry
|
|
42
|
+
* that is a label on the rail is not a page the pager reaches either, so one
|
|
43
|
+
* malformed row cannot become two surfaces' worth of broken link. A page whose
|
|
44
|
+
* address is empty or blank has no such reading: there is nothing to render in
|
|
45
|
+
* place of the link, so the Page throws, naming the entry, before any of the tree
|
|
46
|
+
* renders.
|
|
36
47
|
*
|
|
37
48
|
* **The pager is derived from the navigation rather than passed.** The rail
|
|
38
49
|
* already knows every page and the order a reader meets them in, and deriving the
|
|
@@ -68,6 +79,8 @@ import { cn } from '../../lib/utils';
|
|
|
68
79
|
* and hands it the document their pipeline produced.
|
|
69
80
|
*/
|
|
70
81
|
export function DocsShell({ title, description, nav, toc, currentHref, navLabel, tocLabel, pagerLabel, pagerLabels, header, footer, className, children, }) {
|
|
82
|
+
readTree(nav, 'nav');
|
|
83
|
+
readTree(toc, 'toc');
|
|
71
84
|
const rail = nav && nav.length > 0 ? nav : undefined;
|
|
72
85
|
const contents = toc && toc.length > 0 ? toc : undefined;
|
|
73
86
|
const neighbours = currentHref === undefined ? undefined : deriveNeighbours(nav ?? [], currentHref);
|
|
@@ -79,6 +92,68 @@ export function DocsShell({ title, description, nav, toc, currentHref, navLabel,
|
|
|
79
92
|
// them.
|
|
80
93
|
contents ? 'lg:grid lg:grid-cols-[15rem_minmax(0,1fr)] xl: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: "hidden lg:col-start-1 lg:row-start-1 lg:block", children: _jsx("nav", { "aria-label": navLabel, className: "lg:sticky lg:top-20 lg:max-h-[calc(100svh-7rem)] lg:overflow-y-auto lg:pe-4", children: _jsx(NavList, { entries: rail, currentHref: currentHref, depth: 0 }) }) })) : 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", size: "3xl", 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("nav", { "aria-label": tocLabel, className: "lg:sticky lg:top-20 lg:max-h-[calc(100svh-7rem)] lg:overflow-y-auto", children: _jsx(NavList, { entries: contents, currentHref: currentHref, depth: 0 }) }) })) : null] }), footer] }));
|
|
81
94
|
}
|
|
95
|
+
/* ------------------------------------------------------------------ *
|
|
96
|
+
* The tree
|
|
97
|
+
* ------------------------------------------------------------------ */
|
|
98
|
+
/**
|
|
99
|
+
* The address an entry has, or `undefined` when it has none.
|
|
100
|
+
*
|
|
101
|
+
* Blank counts as none, which is not pedantry. All three consumer adapters write
|
|
102
|
+
* `url: node.index?.url ?? ''` for a folder holding no index, so the empty string
|
|
103
|
+
* is how they spell "this group is not a route", and a guard that read only
|
|
104
|
+
* `=== undefined` let that same spelling through to the renderer on the arm where
|
|
105
|
+
* it means something else entirely.
|
|
106
|
+
*/
|
|
107
|
+
function addressOf(href) {
|
|
108
|
+
return href !== undefined && href.trim() !== '' ? href : undefined;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The address an entry is reachable at, or `undefined` when it is not a
|
|
112
|
+
* destination at all.
|
|
113
|
+
*
|
|
114
|
+
* An entry is a destination only when it has an address AND words, and both
|
|
115
|
+
* halves live here so that one rule answers for both surfaces that read a tree.
|
|
116
|
+
* The rail asks it to decide between an anchor and a label; the pager asks it to
|
|
117
|
+
* decide between a neighbour and nothing. Two places deciding that separately is
|
|
118
|
+
* how one malformed row becomes a nameless anchor in the rail and a nameless
|
|
119
|
+
* `Next` link under it.
|
|
120
|
+
*/
|
|
121
|
+
function destinationOf(entry) {
|
|
122
|
+
return entry.title === '' ? undefined : addressOf(entry.href);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Reads a tree before any of it renders, and refuses the one shape it cannot
|
|
126
|
+
* render honestly.
|
|
127
|
+
*
|
|
128
|
+
* A page entry whose address is empty or blank is an entry whose whole content is
|
|
129
|
+
* a route the consumer does not have. There is no honest rendering of it: a label
|
|
130
|
+
* in its place would hide a page the tree is missing rather than report it, and an
|
|
131
|
+
* anchor would be a control a reader can focus and cannot operate. So the Page
|
|
132
|
+
* throws, naming the entry, which is the opposite of copy and reaches a developer
|
|
133
|
+
* rather than a reader.
|
|
134
|
+
*
|
|
135
|
+
* Two things are deliberate here. The pass is in the component and not in a
|
|
136
|
+
* renderer, so it runs once for both trees and cannot be reached only on the path
|
|
137
|
+
* that happens to draw the bad row. And a GROUP is not refused: no address is a
|
|
138
|
+
* documented state for a group and the empty string is how all three consumers
|
|
139
|
+
* already spell it, so it renders as a label. Only the arm where an address is
|
|
140
|
+
* the entire entry is a fault.
|
|
141
|
+
*/
|
|
142
|
+
function readTree(entries, source) {
|
|
143
|
+
for (const entry of entries ?? []) {
|
|
144
|
+
if (entry.type === 'divider')
|
|
145
|
+
continue;
|
|
146
|
+
if (entry.type === 'group') {
|
|
147
|
+
readTree(entry.items, source);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (addressOf(entry.href) === undefined) {
|
|
151
|
+
throw new Error(`docs-shell: a page entry in the ${source} has no address, and an anchor with no address is a ` +
|
|
152
|
+
'control a reader can focus and cannot follow. Give the entry the address its page is read at, or ' +
|
|
153
|
+
`remove it from the tree. Its title is ${JSON.stringify(entry.title)}.`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
82
157
|
/* ------------------------------------------------------------------ *
|
|
83
158
|
* The rail
|
|
84
159
|
* ------------------------------------------------------------------ */
|
|
@@ -111,12 +186,17 @@ function NavNode({ entry, currentHref, depth, }) {
|
|
|
111
186
|
// above the hairline rather than a word a reader has to interpret.
|
|
112
187
|
return (_jsx("li", { "data-slot": "docs-nav-divider", className: "border-border mt-2 border-t pt-2 first:mt-0 first:border-t-0 first:pt-0", children: entry.title ? (_jsx("span", { className: "text-muted-foreground text-xs font-medium tracking-wide uppercase", children: entry.title })) : null }));
|
|
113
188
|
}
|
|
189
|
+
const href = destinationOf(entry);
|
|
114
190
|
if (entry.type === 'group') {
|
|
115
|
-
return (_jsx("li", { "data-slot": "docs-nav-group", children: _jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
191
|
+
return (_jsx("li", { "data-slot": "docs-nav-group", children: _jsxs("div", { className: "flex flex-col gap-1", children: [href === undefined ? (_jsx("span", { "data-slot": "docs-nav-label", className: cn('rounded-sm text-sm font-semibold tracking-tight', containsHref(entry, currentHref) ? 'text-foreground' : 'text-muted-foreground'), children: entry.title })) : (_jsx("a", { "data-slot": "docs-nav-heading", href: href, "aria-current": currentHref === href ? 'page' : undefined, className: cn('hover:text-foreground rounded-sm text-sm font-semibold tracking-tight transition-colors duration-fast ease-out', under(href, currentHref) ? 'text-foreground' : 'text-muted-foreground'), children: entry.title })), entry.items.length > 0 ? (_jsx(NavList, { entries: entry.items, currentHref: currentHref, depth: depth + 1 })) : null] }) }));
|
|
116
192
|
}
|
|
117
|
-
|
|
193
|
+
// The page arm. `href` is never empty here: `readTree` refused that above and
|
|
194
|
+
// named the entry, so what is left to decide is the words. A nameless page is
|
|
195
|
+
// the same rule as a group with no index, rendered as a label, because a link
|
|
196
|
+
// with no accessible name is announced as "link" and nothing else.
|
|
197
|
+
return (_jsx("li", { "data-slot": "docs-nav-page", children: href === undefined ? (_jsx("span", { "data-slot": "docs-nav-label", className: "-ms-px block border-l-2 border-transparent py-1 ps-3 text-sm text-muted-foreground", children: entry.title })) : (_jsx("a", { "data-slot": "docs-nav-link", href: href, "aria-current": currentHref === href ? 'page' : undefined, className: cn('-ms-px block border-l-2 py-1 ps-3 text-sm transition-colors duration-fast ease-out', currentHref === href
|
|
118
198
|
? 'text-foreground border-primary font-medium'
|
|
119
|
-
: 'text-muted-foreground hover:text-foreground border-transparent'), children: entry.title }) }));
|
|
199
|
+
: 'text-muted-foreground hover:text-foreground border-transparent'), children: entry.title })) }));
|
|
120
200
|
}
|
|
121
201
|
/**
|
|
122
202
|
* Every page the tree holds, in the order a reader meets them.
|
|
@@ -126,18 +206,23 @@ function NavNode({ entry, currentHref, depth, }) {
|
|
|
126
206
|
* contributes its children and nothing else, which is the second thing that
|
|
127
207
|
* makes an absent `href` a label rather than a route: there is no page there for
|
|
128
208
|
* the pager to reach either. A divider contributes nothing at all.
|
|
209
|
+
*
|
|
210
|
+
* The row a reader can click and the row the pager can reach are decided by the
|
|
211
|
+
* SAME function, `destinationOf`. A nameless entry is a label on the rail and is
|
|
212
|
+
* dropped here, so one malformed row cannot be published twice: a nameless anchor
|
|
213
|
+
* in the rail, and a `Next` link under it carrying the text of whichever entry
|
|
214
|
+
* happened to follow, is what deriving without asking produced. The two surfaces
|
|
215
|
+
* do not each get their own opinion about a row that is not a page.
|
|
129
216
|
*/
|
|
130
217
|
function flatten(entries, into = []) {
|
|
131
218
|
for (const entry of entries) {
|
|
132
|
-
if (entry.type === '
|
|
133
|
-
into.push({ title: entry.title, href: entry.href });
|
|
219
|
+
if (entry.type === 'divider')
|
|
134
220
|
continue;
|
|
135
|
-
|
|
136
|
-
if (
|
|
137
|
-
|
|
138
|
-
|
|
221
|
+
const href = destinationOf(entry);
|
|
222
|
+
if (href !== undefined)
|
|
223
|
+
into.push({ title: entry.title, href });
|
|
224
|
+
if (entry.type === 'group')
|
|
139
225
|
flatten(entry.items, into);
|
|
140
|
-
}
|
|
141
226
|
}
|
|
142
227
|
return into;
|
|
143
228
|
}
|
|
@@ -182,9 +267,15 @@ function under(href, currentHref) {
|
|
|
182
267
|
* A group with a route answers for that route and everything under it. A group
|
|
183
268
|
* without one has no route to answer with, so it asks its children, which is the
|
|
184
269
|
* only way a label can still show a reader that they are inside it.
|
|
270
|
+
*
|
|
271
|
+
* The group's own address is read through `addressOf`, like every other read of
|
|
272
|
+
* it. A group whose `href` is the empty string is a label, and a blank string
|
|
273
|
+
* handed to `under` as though it were a route matches every absolute address on
|
|
274
|
+
* the site, which is every label-only section claiming to be the current one at
|
|
275
|
+
* once.
|
|
185
276
|
*/
|
|
186
277
|
function containsHref(group, currentHref) {
|
|
187
|
-
if (under(group.href, currentHref))
|
|
278
|
+
if (under(addressOf(group.href), currentHref))
|
|
188
279
|
return true;
|
|
189
280
|
return group.items.some((entry) => {
|
|
190
281
|
if (entry.type === 'page')
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { DocsShell, default } from './docs-shell';
|
|
2
|
-
export type { DocsShellProps, DocsNavEntry, DocsNavPage, DocsNavGroup, DocsNavDivider, DocsPagerLabels, } from './docs-shell';
|
|
1
|
+
export { DocsShell, default } from './docs-shell.js';
|
|
2
|
+
export type { DocsShellProps, DocsNavEntry, DocsNavPage, DocsNavGroup, DocsNavDivider, DocsPagerLabels, } from './docs-shell.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { DocsShell, default } from './docs-shell';
|
|
1
|
+
export { DocsShell, default } from './docs-shell.js';
|