@barefootjs/router 0.14.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/src/types.ts ADDED
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Public + internal types for the BarefootJS partial-navigation router.
3
+ *
4
+ * A **region** (`[bf-region]`, spec/router.md) is the page-lifecycle boundary
5
+ * the router swaps: everything outside it persists across a navigation;
6
+ * everything inside is disposed, re-loaded, and re-hydrated. v0 swaps a single
7
+ * authored region (the broadest match); compiler-derived nested regions are v2.
8
+ */
9
+
10
+ export interface RouterOptions {
11
+ /**
12
+ * Selector for the swappable region. Defaults to `[bf-region]`. The first
13
+ * match in the document is the v0 swap point ("single authored region");
14
+ * if a page has none, the router hard-navigates (never worse than an MPA).
15
+ */
16
+ region?: string
17
+ /**
18
+ * Re-hydrate the freshly swapped region. Defaults to {@link defaultRehydrate},
19
+ * which prefers the `@barefootjs/client` runtime's subtree-scoped walk and
20
+ * degrades through the shared fallback chain. Never silently no-ops on a page
21
+ * that has islands.
22
+ */
23
+ rehydrate?: (region: Element) => void | Promise<void>
24
+ /**
25
+ * Dispose the outgoing islands after they are swapped out. Receives a
26
+ * detached holder — a shallow clone of the region element (same tag,
27
+ * attributes, id, classes) holding the previous region children — so tearing
28
+ * it down never affects the live document. When `morph` is on, any matched
29
+ * `[data-bf-permanent]` node was moved into the new tree first and so is
30
+ * absent from the holder; with `morph: false` the permanent nodes remain in
31
+ * the holder and are disposed normally. Defaults to {@link defaultDispose}.
32
+ * Pass `() => {}` to opt out (e.g. a fully static shell with no client
33
+ * runtime).
34
+ */
35
+ dispose?: (region: Element) => void | Promise<void>
36
+ /** Import an island module by src. Defaults to `(src) => import(src)`. */
37
+ loadModule?: (src: string) => Promise<unknown>
38
+ /**
39
+ * Fetch a page's HTML. Defaults to the global `fetch`. Inject to add auth
40
+ * headers / a custom transport, or to drive the router under test without
41
+ * monkeypatching the global.
42
+ */
43
+ fetch?: typeof fetch
44
+ /** Decide whether to intercept an anchor click. Defaults to {@link defaultShouldIntercept}. */
45
+ shouldIntercept?: (anchor: HTMLAnchorElement, event: Event) => boolean
46
+ /** Scroll to the top of the document after a swap. Default `true`. */
47
+ scrollToTop?: boolean
48
+ /** Move focus to the swapped region + announce the route change. Default `true`. */
49
+ manageFocus?: boolean
50
+ /**
51
+ * Preserve `[data-bf-permanent]` elements across a swap — their live DOM node
52
+ * (state, media playback, scroll, hydrated scope) is moved into the incoming
53
+ * tree instead of disposed and recreated (spec/router.md v1). Default `true`;
54
+ * a no-op when no permanent elements are present. Pass `false` for a plain
55
+ * `replaceChildren` swap.
56
+ */
57
+ morph?: boolean
58
+ /** Enable hover/focus/pointerdown prefetch. Default `true`. */
59
+ prefetch?: boolean
60
+ /** Hover dwell before prefetch (ms). Default `65`. */
61
+ prefetchDelay?: number
62
+ /** How long a cached page stays fresh (no refetch), ms. Default `15000`. */
63
+ cacheFreshMs?: number
64
+ /** How long a cached page may be served (stale-while-revalidate), ms. Default `60000`. */
65
+ cacheStaleMs?: number
66
+ /** Max cached pages (LRU). Default `30`. */
67
+ cacheCap?: number
68
+ }
69
+
70
+ export interface NavigateOptions {
71
+ /**
72
+ * How to commit history. `'push'` (default) adds an entry, `'replace'`
73
+ * overwrites the current one, `false` writes nothing (used by `popstate`,
74
+ * where the browser already moved history).
75
+ */
76
+ history?: 'push' | 'replace' | false
77
+ }
78
+
79
+ export interface Router {
80
+ /** Tear down all listeners and abort any in-flight navigation. */
81
+ stop(): void
82
+ /** Navigate programmatically. SSR no-op. */
83
+ navigate: (url: string, options?: NavigateOptions) => Promise<void>
84
+ /** Warm the cache (and modulepreload islands) for a URL. */
85
+ prefetch: (url: string) => void
86
+ }
87
+
88
+ /** A fetched page: its HTML plus the redirect-resolved final URL. */
89
+ export interface PageSnapshot {
90
+ html: string
91
+ finalUrl: string
92
+ }
93
+
94
+ export interface CacheEntry {
95
+ snap: Promise<PageSnapshot | null>
96
+ /** Past this (jittered) instant → serve cached AND refresh in the background. */
97
+ refreshAt: number
98
+ /** Past this instant → too old to serve, refetch synchronously. */
99
+ staleAt: number
100
+ /** Single-flight guard for the background refresh. */
101
+ refreshing: boolean
102
+ }
103
+
104
+ /** Mutable state for the one active router instance. */
105
+ export interface RouterState {
106
+ regionSelector: string
107
+ rehydrate: (region: Element) => void | Promise<void>
108
+ dispose: (region: Element) => void | Promise<void>
109
+ loadModule: (src: string) => Promise<unknown>
110
+ /** Fetch used for page loads (injectable; defaults to the global `fetch`). */
111
+ fetchFn: typeof fetch
112
+ /** Absolute URLs of island modules already loaded (deduped across navigations). */
113
+ loadedModules: Set<string>
114
+ prefetchEnabled: boolean
115
+ prefetchDelay: number
116
+ cacheFreshMs: number
117
+ cacheStaleMs: number
118
+ cacheCap: number
119
+ cache: Map<string, CacheEntry>
120
+ /** Module srcs already `<link rel=modulepreload>`-ed. */
121
+ preloaded: Set<string>
122
+ shouldIntercept: (anchor: HTMLAnchorElement, event: Event) => boolean
123
+ scrollToTop: boolean
124
+ manageFocus: boolean
125
+ /**
126
+ * Per-region server-render baseline: `bf-region` id → owned-content key of the
127
+ * server render currently displayed there. The swap planner compares an
128
+ * incoming region against this (not the island-mutated live DOM) so an
129
+ * unchanged region keeps its state; refreshed after each navigation.
130
+ */
131
+ regionBaselines: Map<string, string>
132
+ morph: boolean
133
+ /** Pathname of the currently-displayed region (for the query-only short-circuit). */
134
+ currentPath: string
135
+ inflight: AbortController | null
136
+ /** Hover-prefetch dwell timer + the anchor it is counting down for (per instance). */
137
+ hoverTimer: ReturnType<typeof setTimeout> | null
138
+ hoverAnchor: HTMLAnchorElement | null
139
+ stop: () => void
140
+ }