@fluixi/core 1.0.0-alpha.92 → 1.0.0-alpha.94

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 (113) hide show
  1. package/dist/cdn/core.global.js +2 -2
  2. package/dist/src/cdn/{chunk-MDJLC3PE.mjs → chunk-7XM7Q5VR.mjs} +271 -229
  3. package/dist/src/cdn/core.cjs +360 -253
  4. package/dist/src/cdn/core.mjs +92 -20
  5. package/dist/src/cdn/{router-JYFZP3EZ.mjs → router-VOY43YNM.mjs} +7 -3
  6. package/dist/src/index.cjs +548 -232
  7. package/dist/src/index.mjs +549 -224
  8. package/dist/src/lib/client/chunk-TSXM2PNY.mjs +53 -0
  9. package/dist/src/lib/client/index.cjs +310 -176
  10. package/dist/src/lib/client/index.d.ts.map +1 -1
  11. package/dist/src/lib/client/index.js +33 -18
  12. package/dist/src/lib/client/index.mjs +86 -15
  13. package/dist/src/lib/client/{router-PHLUYVQU.mjs → router-BDVPLLYX.mjs} +244 -99
  14. package/dist/src/lib/context/context.cjs +35 -72
  15. package/dist/src/lib/context/context.d.ts +45 -291
  16. package/dist/src/lib/context/context.d.ts.map +1 -1
  17. package/dist/src/lib/context/context.js +65 -397
  18. package/dist/src/lib/context/context.mjs +38 -73
  19. package/dist/src/lib/context/index.cjs +35 -72
  20. package/dist/src/lib/context/index.d.ts +2 -2
  21. package/dist/src/lib/context/index.d.ts.map +1 -1
  22. package/dist/src/lib/context/index.js +1 -5
  23. package/dist/src/lib/context/index.mjs +38 -73
  24. package/dist/src/lib/core.cjs +547 -231
  25. package/dist/src/lib/core.d.ts +5 -3
  26. package/dist/src/lib/core.d.ts.map +1 -1
  27. package/dist/src/lib/core.js +6 -4
  28. package/dist/src/lib/core.mjs +548 -223
  29. package/dist/src/lib/env/index.cjs +1 -17
  30. package/dist/src/lib/env/index.d.ts +2 -14
  31. package/dist/src/lib/env/index.d.ts.map +1 -1
  32. package/dist/src/lib/env/index.js +2 -26
  33. package/dist/src/lib/env/index.mjs +1 -17
  34. package/dist/src/lib/i18n/index.cjs +17 -2
  35. package/dist/src/lib/i18n/index.d.ts +10 -0
  36. package/dist/src/lib/i18n/index.d.ts.map +1 -1
  37. package/dist/src/lib/i18n/index.js +17 -1
  38. package/dist/src/lib/i18n/index.mjs +17 -2
  39. package/dist/src/lib/index.cjs +64 -99
  40. package/dist/src/lib/index.mjs +43 -76
  41. package/dist/src/lib/isomorphic.cjs +9 -4
  42. package/dist/src/lib/isomorphic.d.ts +9 -2
  43. package/dist/src/lib/isomorphic.d.ts.map +1 -1
  44. package/dist/src/lib/isomorphic.js +11 -4
  45. package/dist/src/lib/isomorphic.mjs +9 -4
  46. package/dist/src/lib/jsx-runtime/index.cjs +1 -1
  47. package/dist/src/lib/jsx-runtime/index.mjs +1 -1
  48. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +1 -1
  49. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +1 -1
  50. package/dist/src/lib/plugins/fluixi-routes-plugin.cjs +2 -2
  51. package/dist/src/lib/plugins/fluixi-routes-plugin.mjs +2 -2
  52. package/dist/src/lib/plugins/index.cjs +3 -3
  53. package/dist/src/lib/plugins/index.mjs +3 -3
  54. package/dist/src/lib/plugins/route-codegen.cjs +2 -2
  55. package/dist/src/lib/plugins/route-codegen.js +1 -1
  56. package/dist/src/lib/plugins/route-codegen.mjs +2 -2
  57. package/dist/src/lib/render/index.cjs +1 -1
  58. package/dist/src/lib/render/index.mjs +1 -1
  59. package/dist/src/lib/render/versions.cjs +1 -1
  60. package/dist/src/lib/render/versions.mjs +1 -1
  61. package/dist/src/lib/router/data.cjs +113 -115
  62. package/dist/src/lib/router/data.d.ts +63 -10
  63. package/dist/src/lib/router/data.d.ts.map +1 -1
  64. package/dist/src/lib/router/data.js +158 -68
  65. package/dist/src/lib/router/data.mjs +112 -112
  66. package/dist/src/lib/router/index.cjs +260 -163
  67. package/dist/src/lib/router/index.d.ts +22 -2
  68. package/dist/src/lib/router/index.d.ts.map +1 -1
  69. package/dist/src/lib/router/index.js +165 -22
  70. package/dist/src/lib/router/index.mjs +244 -143
  71. package/dist/src/lib/server/index.cjs +1 -1
  72. package/dist/src/lib/server/index.mjs +1 -1
  73. package/dist/src/lib/storage/cache.cjs +51 -0
  74. package/dist/src/lib/storage/cache.d.ts +18 -0
  75. package/dist/src/lib/storage/cache.d.ts.map +1 -0
  76. package/dist/src/lib/storage/cache.js +42 -0
  77. package/dist/src/lib/storage/cache.mjs +30 -0
  78. package/dist/src/lib/storage/index.cjs +246 -0
  79. package/dist/src/lib/storage/index.d.ts +83 -0
  80. package/dist/src/lib/storage/index.d.ts.map +1 -0
  81. package/dist/src/lib/storage/index.js +179 -0
  82. package/dist/src/lib/storage/index.mjs +231 -0
  83. package/dist/src/lib/storage/persisted.cjs +91 -0
  84. package/dist/src/lib/storage/persisted.d.ts +53 -0
  85. package/dist/src/lib/storage/persisted.d.ts.map +1 -0
  86. package/dist/src/lib/storage/persisted.js +75 -0
  87. package/dist/src/lib/storage/persisted.mjs +70 -0
  88. package/dist/src/lib/theme/color-scheme.cjs +281 -0
  89. package/dist/src/lib/theme/color-scheme.d.ts +61 -0
  90. package/dist/src/lib/theme/color-scheme.d.ts.map +1 -0
  91. package/dist/src/lib/theme/color-scheme.js +120 -0
  92. package/dist/src/lib/theme/color-scheme.mjs +265 -0
  93. package/dist/src/lib/theme/index.cjs +194 -37
  94. package/dist/src/lib/theme/index.d.ts +23 -11
  95. package/dist/src/lib/theme/index.d.ts.map +1 -1
  96. package/dist/src/lib/theme/index.js +73 -32
  97. package/dist/src/lib/theme/index.mjs +197 -35
  98. package/dist/src/lib/theme/provider.cjs +346 -0
  99. package/dist/src/lib/theme/provider.d.ts +34 -0
  100. package/dist/src/lib/theme/provider.d.ts.map +1 -0
  101. package/dist/src/lib/theme/provider.js +60 -0
  102. package/dist/src/lib/theme/provider.mjs +332 -0
  103. package/dist/src/routes.cjs +1 -1
  104. package/dist/src/routes.mjs +1 -1
  105. package/dist/src/utils.cjs +1 -1
  106. package/dist/src/utils.mjs +1 -1
  107. package/dist/src/version.generated.cjs +1 -1
  108. package/dist/src/version.generated.d.ts +1 -1
  109. package/dist/src/version.generated.js +1 -1
  110. package/dist/src/version.generated.mjs +1 -1
  111. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  112. package/package.json +18 -11
  113. package/dist/src/lib/client/chunk-VB567ABU.mjs +0 -133
@@ -6,6 +6,10 @@ interface RouterCtxValue {
6
6
  router: CoreRouter<any>;
7
7
  location: () => RouterLocation;
8
8
  params: () => Record<string, string>;
9
+ /** True from a navigation's start until the route it lands on has its modules and data. */
10
+ isRouting: () => boolean;
11
+ /** Counts a layer's data load toward `isRouting` until the promise settles. */
12
+ trackLoad: <T>(result: T) => T;
9
13
  }
10
14
  export interface RouterProps<C = any> {
11
15
  routes: RouteDefinition<C>[];
@@ -45,6 +49,22 @@ export interface RouterProps<C = any> {
45
49
  export declare function Router<C = any>(props: RouterProps<C>): any;
46
50
  /** Renders this layout's child route, inside this layout's context. */
47
51
  export declare function Outlet(): any;
52
+ /**
53
+ * Whether a navigation is in progress: from the moment it starts until the route it lands on
54
+ * has loaded its modules and its route data. For a progress bar or a busy cursor.
55
+ *
56
+ * `delay` holds the `true` back until the navigation has lasted that many milliseconds, so a
57
+ * navigation that settles at once shows nothing. It still turns `false` the moment it ends.
58
+ *
59
+ * @example
60
+ * ```tsx
61
+ * const routing = useIsRouting({ delay: 120 });
62
+ * <div class="progress" data-active={() => (routing() ? '' : undefined)} />
63
+ * ```
64
+ */
65
+ export declare function useIsRouting(options?: {
66
+ delay?: number;
67
+ }): () => boolean;
48
68
  /** Navigate to `to` on mount (replace by default). Renders nothing. */
49
69
  export declare function Redirect(props: {
50
70
  to: string;
@@ -243,8 +263,8 @@ export declare function Form(props: FormProps): any;
243
263
  export declare function preloadRoutes<C = any>(routes: RouteDefinition<C>[], pathname: string): Promise<void>;
244
264
  export { createMemoryHistory, createBrowserHistory, matchRoutes, matchPath, } from '@fluixi/router';
245
265
  export type { RouteDefinition, RouteMatch, MatchedRoute, RouterLocation, NavigateOptions, HistoryAdapter, } from '@fluixi/router';
246
- export { cache, action, revalidate, createAsync, useSubmission, useAction, } from './data.js';
247
- export type { RouteDataArgs, RouteLoadFunc, Action, Submission, CacheFn, } from './data.js';
266
+ export { cache, action, revalidate, createAsync, useSubmission, useSubmissions, useAction, } from './data.js';
267
+ export type { RouteDataArgs, RouteLoadFunc, Action, ActionOptions, CacheOptions, Submission, CacheFn, } from './data.js';
248
268
  export { lazy } from '../render/lazy.js';
249
269
  export { supportsViewTransitions, prefersReducedMotion, type TransitionMode, } from './transition.js';
250
270
  export { runWithOwner } from '@fluixi/reactive/signal';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/router/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/router/index.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@
11
11
  * matched array, never by re-entering a still-building parent, so deeply nested
12
12
  * <Outlet/> works at any depth.
13
13
  */
14
- import { createSignal, createMemo, createResource, createEffect, getOwner, onCleanup, untrack, flush, } from '@fluixi/reactive/signal';
14
+ import { createSignal, createMemo, createResource, createEffect, createRoot, getOwner, onCleanup, runWithOwner, untrack, flush, } from '@fluixi/reactive/signal';
15
15
  import { prepareComponents, runTransition, } from './transition.js';
16
16
  import { insert, createComponent, createNativeElement, setAttribute, } from '@fluixi/dom';
17
17
  // Reactive context (not fluixi createProvider, which destructures children
@@ -24,7 +24,6 @@ const RouterContext = createContext(undefined, 'router');
24
24
  const OutletContext = createContext(undefined, 'outlet');
25
25
  const LevelParamsContext = createContext(undefined, 'route-params');
26
26
  const RouteDataContext = createContext(undefined, 'route-data');
27
- // ─── Rendering ────────────────────────────────────────────────────────────────
28
27
  /** Render one matched layer: load its data, stamp its contexts, run its component. */
29
28
  function renderLayer(m, depth, base) {
30
29
  // Load this layer's data once. createResource integrates with the nearest
@@ -38,8 +37,41 @@ function renderLayer(m, depth, base) {
38
37
  cancelled = true;
39
38
  });
40
39
  const owner = getOwner();
41
- const [resource] = createResource(() => loader({ params: base.params, location: base.location }, owner, () => cancelled));
42
- data = resource;
40
+ const router = useContext(RouterContext);
41
+ // The route's `routeDeps`, once its module has loaded: a change loads the layer again.
42
+ let watching = false;
43
+ const trackDeps = (deps) => {
44
+ if (watching || cancelled)
45
+ return;
46
+ watching = true;
47
+ runWithOwner(owner, () => {
48
+ let first = true;
49
+ createEffect(() => {
50
+ deps();
51
+ if (first)
52
+ first = false;
53
+ else
54
+ untrack(() => void refetch());
55
+ });
56
+ });
57
+ };
58
+ const [resource, { refetch }] = createResource(() => {
59
+ const result = loader({ params: base.params, location: base.location }, owner, () => cancelled, trackDeps);
60
+ return router ? router.trackLoad(result) : result;
61
+ });
62
+ // A revalidated cache entry: load again. The page stays on screen with its current data.
63
+ onCleanup(onRevalidate(() => void refetch()));
64
+ // A failed load throws where the page reads it, so the nearest ErrorBoundary shows it.
65
+ // A resource reads as undefined once it has failed, which left the page empty and gave
66
+ // nothing a chance to catch the error.
67
+ data = () => {
68
+ const error = resource.error;
69
+ if (error !== undefined && error !== null)
70
+ throw error;
71
+ return resource();
72
+ };
73
+ Object.defineProperty(data, 'loading', { get: () => resource.loading });
74
+ Object.defineProperty(data, 'state', { get: () => resource.state });
43
75
  }
44
76
  const buildPage = () => RouteDataContext.Provider({
45
77
  value: data,
@@ -58,18 +90,22 @@ function renderLayer(m, depth, base) {
58
90
  },
59
91
  });
60
92
  if (!data)
61
- return buildPage();
93
+ return { view: buildPage(), ready: () => true };
62
94
  // Gate on the data being resolved, like the old router, so the page reads
63
95
  // ready data (rd() returns the value, not a thrown promise) and works without a
64
96
  // Suspense boundary. Signal-gated (`ready` only flips when loading actually
65
97
  // changes) so navigation re-renders don't re-run this and rebuild the page.
66
98
  const res = data;
67
- const isLoading = () => res.loading;
99
+ // The first load only. A refetch after revalidate keeps the page, showing the old data until the new arrives.
100
+ const isLoading = () => {
101
+ const state = res.state;
102
+ return state === undefined ? res.loading : state === 'pending' || state === 'unresolved';
103
+ };
68
104
  // untrack the initial read so the enclosing render memo doesn't subscribe to the
69
105
  // resource state (that would re-run renderLayer and recreate the resource, a loop).
70
106
  const [ready, setReady] = createSignal(untrack(() => !isLoading()));
71
107
  createEffect(() => setReady(!isLoading()));
72
- return createMemo(() => (ready() ? buildPage() : null));
108
+ return { view: createMemo(() => (ready() ? buildPage() : null)), ready };
73
109
  }
74
110
  /**
75
111
  * Renders the next matched layer, reactively but keyed on its component ref so the
@@ -84,8 +120,8 @@ function renderChild(ctx) {
84
120
  // every navigation and re-render the child. A signal only notifies when its value
85
121
  // actually changes, so the render memo below re-runs only when the route at this
86
122
  // depth changes: sibling navigation reuses the layout, deeper navigation leaves
87
- // this level untouched. The child is rendered INLINE (no detached createRoot), so
88
- // it stays connected to the Suspense / context owner chain.
123
+ // this level untouched. Each child renders in a root attached to this owner (below),
124
+ // so it stays connected to the Suspense / context owner chain.
89
125
  const [childComp, setChildComp] = createSignal(untrack(() => ctx.matched()[childIdx]?.component));
90
126
  createEffect(() => {
91
127
  const c = ctx.matched()[childIdx]?.component;
@@ -95,20 +131,53 @@ function renderChild(ctx) {
95
131
  if (untrack(childComp) !== c)
96
132
  setChildComp(() => c);
97
133
  });
98
- return createMemo(() => {
134
+ // Each layer lives in its own root under this Outlet's owner: attached, so context and
135
+ // Suspense reach it, but not owned by the memo below, so a newer layer does not dispose it.
136
+ // That is what lets the page on screen stay there while the next one loads its data.
137
+ const owner = getOwner();
138
+ let shown = null;
139
+ let pending = null;
140
+ const drop = (layer) => layer?.dispose();
141
+ onCleanup(() => {
142
+ drop(shown);
143
+ drop(pending);
144
+ shown = pending = null;
145
+ });
146
+ const incoming = createMemo(() => {
99
147
  const component = childComp();
100
- if (!component) {
148
+ if (!component)
149
+ return null;
150
+ const m = untrack(() => ctx.matched())[childIdx];
151
+ return runWithOwner(owner, () => createRoot((dispose) => ({
152
+ ...renderLayer(m, childIdx, { matched: ctx.matched, params: ctx.params, location: ctx.location }),
153
+ dispose,
154
+ })));
155
+ });
156
+ return createMemo(() => {
157
+ const next = incoming();
158
+ if (!next) {
159
+ drop(shown);
160
+ drop(pending);
161
+ shown = pending = null;
101
162
  // No route at this depth. At the root (the only ctx carrying `notFound`) that means the
102
163
  // URL matched nothing: render the not-found fallback instead of a blank page. Nested
103
164
  // Outlets have no `notFound`, so they stay null (a missing child is just an empty Outlet).
104
165
  return ctx.notFound ? ctx.notFound() : null;
105
166
  }
106
- const m = untrack(() => ctx.matched())[childIdx];
107
- return renderLayer(m, childIdx, {
108
- matched: ctx.matched,
109
- params: ctx.params,
110
- location: ctx.location,
111
- });
167
+ if (next === shown)
168
+ return shown.view;
169
+ // A newer navigation superseded the one still loading.
170
+ if (pending && pending !== next)
171
+ drop(pending);
172
+ pending = next;
173
+ // Keep the current page until the next one has its data. Nothing on screen yet (first
174
+ // render, hydration): show the next one straight away, its own gate handles loading.
175
+ if (shown && !next.ready())
176
+ return shown.view;
177
+ drop(shown);
178
+ shown = next;
179
+ pending = null;
180
+ return shown.view;
112
181
  });
113
182
  }
114
183
  /**
@@ -166,6 +235,10 @@ export function Router(props) {
166
235
  history,
167
236
  });
168
237
  const [state, setState] = createSignal(router.state());
238
+ // A navigation in flight, and the layer data loads it started: together they are
239
+ // `useIsRouting()`, what a progress bar reads.
240
+ const [navigating, setNavigating] = createSignal(false);
241
+ const [loads, setLoads] = createSignal(0);
169
242
  /**
170
243
  * Which navigation is allowed to commit.
171
244
  *
@@ -194,6 +267,7 @@ export function Router(props) {
194
267
  const unsub = router.subscribe((next) => {
195
268
  const id = ++navigationId;
196
269
  const mode = takeMode();
270
+ setNavigating(true);
197
271
  // Load the modules the next route needs before anything is torn down, so a lazy
198
272
  // route renders straight through instead of suspending into a fallback with the
199
273
  // old page already gone.
@@ -201,8 +275,12 @@ export function Router(props) {
201
275
  const commit = () => {
202
276
  setState(next);
203
277
  // The write only queues; effects are scheduled. Flushing here is what lets the
204
- // browser snapshot a settled DOM rather than a half-built one.
205
- return flush();
278
+ // browser snapshot a settled DOM rather than a half-built one. The layers built by
279
+ // the flush have registered their data loads, so `isRouting` stays true through them.
280
+ const flushed = flush();
281
+ if (id === navigationId)
282
+ setNavigating(false);
283
+ return flushed;
206
284
  };
207
285
  if (!prepared) {
208
286
  // Nothing to wait for: stay on the tick this navigation was already on.
@@ -230,6 +308,16 @@ export function Router(props) {
230
308
  router: router,
231
309
  location: createMemo(() => state().location),
232
310
  params: createMemo(() => state().match?.params ?? {}),
311
+ isRouting: () => navigating() || loads() > 0,
312
+ // Counted by the promise, not by an owner: a load a newer navigation superseded still
313
+ // settles and uncounts itself, and a resource seeded from the server never calls it.
314
+ trackLoad(result) {
315
+ if (result && typeof result.finally === 'function') {
316
+ setLoads((n) => n + 1);
317
+ void result.finally(() => setLoads((n) => n - 1)).catch(() => { });
318
+ }
319
+ return result;
320
+ },
233
321
  };
234
322
  // Render depth 0 (a virtual parent at depth -1 so the root reuses the same path).
235
323
  const root = {
@@ -260,6 +348,35 @@ export function Outlet() {
260
348
  return null;
261
349
  return renderChild(ctx);
262
350
  }
351
+ /**
352
+ * Whether a navigation is in progress: from the moment it starts until the route it lands on
353
+ * has loaded its modules and its route data. For a progress bar or a busy cursor.
354
+ *
355
+ * `delay` holds the `true` back until the navigation has lasted that many milliseconds, so a
356
+ * navigation that settles at once shows nothing. It still turns `false` the moment it ends.
357
+ *
358
+ * @example
359
+ * ```tsx
360
+ * const routing = useIsRouting({ delay: 120 });
361
+ * <div class="progress" data-active={() => (routing() ? '' : undefined)} />
362
+ * ```
363
+ */
364
+ export function useIsRouting(options = {}) {
365
+ const routing = useContext(RouterContext)?.isRouting ?? (() => false);
366
+ const delay = options.delay ?? 0;
367
+ if (delay <= 0)
368
+ return routing;
369
+ const [late, setLate] = createSignal(false);
370
+ createEffect(() => {
371
+ if (!routing()) {
372
+ setLate(false);
373
+ return;
374
+ }
375
+ const timer = setTimeout(() => setLate(true), delay);
376
+ onCleanup(() => clearTimeout(timer));
377
+ });
378
+ return () => routing() && late();
379
+ }
263
380
  /** Navigate to `to` on mount (replace by default). Renders nothing. */
264
381
  export function Redirect(props) {
265
382
  const ctx = useContext(RouterContext);
@@ -288,6 +405,8 @@ const _ssrRouterStub = {
288
405
  router: { navigate: () => { } },
289
406
  location: () => ({ pathname: '', search: '', hash: '', query: {} }),
290
407
  params: () => ({}),
408
+ isRouting: () => false,
409
+ trackLoad: (result) => result,
291
410
  };
292
411
  /**
293
412
  * The router context: the router itself, the current match, and the location.
@@ -523,7 +642,7 @@ const LINK_OWN_PROPS = new Set([
523
642
  */
524
643
  export function Link(props) {
525
644
  const ctx = useContext(RouterContext);
526
- const navigate = () => ctx?.router.navigate(read(props.href) ?? '', { replace: read(props.replace) });
645
+ const navigate = () => ctx.router.navigate(read(props.href) ?? '', { replace: read(props.replace) });
527
646
  // createNativeElement branches on isServer() -> a real ServerNode <a> (serialized as a true
528
647
  // element, not an escaped string) on the server, a real DOM <a> on the client.
529
648
  const a = createNativeElement('a');
@@ -545,7 +664,26 @@ export function Link(props) {
545
664
  if (LINK_OWN_PROPS.has(k))
546
665
  continue;
547
666
  const v = props[k];
548
- if (v != null && typeof v !== 'function')
667
+ if (typeof v === 'function') {
668
+ // An accessor (`title={() => t('…')}`, `aria-current={() => …}`): followed on the client,
669
+ // read once for the server's markup. Event handlers are not attributes.
670
+ if (/^on[A-Z]/.test(k))
671
+ continue;
672
+ const read = v;
673
+ const apply = () => {
674
+ const value = read();
675
+ if (value == null || value === false)
676
+ a.removeAttribute?.(k);
677
+ else
678
+ setAttribute(a, k, String(value));
679
+ };
680
+ if (typeof a.addEventListener === 'function')
681
+ createEffect(apply);
682
+ else
683
+ apply();
684
+ continue;
685
+ }
686
+ if (v != null)
549
687
  setAttribute(a, k, String(v));
550
688
  }
551
689
  // Client only (ServerNode has no addEventListener). Direct listener (not delegated) so
@@ -554,6 +692,10 @@ export function Link(props) {
554
692
  a.addEventListener('click', (e) => {
555
693
  if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
556
694
  return;
695
+ // No router above this link: let the browser follow it rather than cancel the click
696
+ // and go nowhere.
697
+ if (!ctx)
698
+ return;
557
699
  e.preventDefault();
558
700
  navigate();
559
701
  });
@@ -584,6 +726,7 @@ export function Link(props) {
584
726
  }
585
727
  /** Alias for {@link Link}. */
586
728
  export const A = Link;
729
+ import { onRevalidate } from './data.js';
587
730
  /**
588
731
  * A `<form>` wired to an action: on submit it builds `FormData` from the form and calls
589
732
  * `action(formData)` (which tracks submission state via `useSubmission`), without a full
@@ -665,7 +808,7 @@ export async function preloadRoutes(routes, pathname) {
665
808
  export { createMemoryHistory, createBrowserHistory, matchRoutes, matchPath, } from '@fluixi/router';
666
809
  // Action/cache/lazy layer is orthogonal to routing: re-export so a route file can
667
810
  // swap its import path wholesale. (Routing hooks above are the router ones.)
668
- export { cache, action, revalidate, createAsync, useSubmission, useAction, } from './data.js';
811
+ export { cache, action, revalidate, createAsync, useSubmission, useSubmissions, useAction, } from './data.js';
669
812
  export { lazy } from '../render/lazy.js';
670
813
  // Navigation presentation. The router owns the integration; these are exported for
671
814
  // apps that need to ask what the environment supports.