@fluixi/core 1.0.0-alpha.84 → 1.0.0-alpha.85

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 (49) hide show
  1. package/dist/cdn/core.global.js +2 -2
  2. package/dist/src/cdn/{chunk-VNLCQBFQ.mjs → chunk-MDJLC3PE.mjs} +87 -4
  3. package/dist/src/cdn/core.cjs +91 -5
  4. package/dist/src/cdn/core.mjs +3 -3
  5. package/dist/src/cdn/{router-WMN2AA7E.mjs → router-JYFZP3EZ.mjs} +5 -1
  6. package/dist/src/index.cjs +84 -5
  7. package/dist/src/index.mjs +86 -6
  8. package/dist/src/lib/client/{chunk-2C2KDDQV.mjs → chunk-7IUN2FLI.mjs} +1 -1
  9. package/dist/src/lib/client/index.cjs +92 -6
  10. package/dist/src/lib/client/index.mjs +4 -4
  11. package/dist/src/lib/client/{router-X526HSWQ.mjs → router-NOFEMOEH.mjs} +89 -6
  12. package/dist/src/lib/core.cjs +83 -4
  13. package/dist/src/lib/core.mjs +85 -5
  14. package/dist/src/lib/i18n/index.cjs +1 -1
  15. package/dist/src/lib/i18n/index.mjs +1 -1
  16. package/dist/src/lib/index.cjs +1 -1
  17. package/dist/src/lib/index.mjs +1 -1
  18. package/dist/src/lib/jsx-runtime/index.cjs +1 -1
  19. package/dist/src/lib/jsx-runtime/index.mjs +1 -1
  20. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +1 -1
  21. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +1 -1
  22. package/dist/src/lib/plugins/index.cjs +1 -1
  23. package/dist/src/lib/plugins/index.mjs +1 -1
  24. package/dist/src/lib/render/index.cjs +1 -1
  25. package/dist/src/lib/render/index.mjs +1 -1
  26. package/dist/src/lib/render/versions.cjs +1 -1
  27. package/dist/src/lib/render/versions.mjs +1 -1
  28. package/dist/src/lib/router/index.cjs +86 -4
  29. package/dist/src/lib/router/index.d.ts +17 -14
  30. package/dist/src/lib/router/index.d.ts.map +1 -1
  31. package/dist/src/lib/router/index.js +76 -4
  32. package/dist/src/lib/router/index.mjs +88 -5
  33. package/dist/src/lib/router/transition.cjs +75 -0
  34. package/dist/src/lib/router/transition.d.ts +81 -0
  35. package/dist/src/lib/router/transition.d.ts.map +1 -0
  36. package/dist/src/lib/router/transition.js +136 -0
  37. package/dist/src/lib/router/transition.mjs +54 -0
  38. package/dist/src/lib/server/index.cjs +1 -1
  39. package/dist/src/lib/server/index.mjs +1 -1
  40. package/dist/src/routes.cjs +1 -1
  41. package/dist/src/routes.mjs +1 -1
  42. package/dist/src/utils.cjs +1 -1
  43. package/dist/src/utils.mjs +1 -1
  44. package/dist/src/version.generated.cjs +1 -1
  45. package/dist/src/version.generated.d.ts +1 -1
  46. package/dist/src/version.generated.js +1 -1
  47. package/dist/src/version.generated.mjs +1 -1
  48. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  49. package/package.json +11 -11
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Navigation presentation: preparing a route before it is shown, and handing the DOM
3
+ * swap to the browser's View Transition API when there is one.
4
+ *
5
+ * ## The lifecycle this replaces
6
+ *
7
+ * Navigation used to be one synchronous chain. `navigate()` pushed history, the core
8
+ * router recomputed the match and notified, the `Router` component wrote the match
9
+ * signal, and the render memo rebuilt the layer at the depth that changed. The old DOM
10
+ * came out at that moment: whether or not the new route had anything to put in its
11
+ * place:
12
+ *
13
+ * - a route with a `data` loader renders `null` until the resource resolves,
14
+ * - a `lazy()` route whose chunk is not loaded suspends to the nearest fallback.
15
+ *
16
+ * Both are an empty intermediate state with the old page already gone, which is what
17
+ * reads as a flash. It is not a paint-timing artifact and no animation would hide it.
18
+ *
19
+ * ## The lifecycle now
20
+ *
21
+ * navigation-start
22
+ * │ the match is computed, but not committed
23
+ * prepare
24
+ * │ every matched layer's module is loaded (`lazy().preload()`), so the
25
+ * │ component renders synchronously instead of suspending
26
+ * begin transition
27
+ * │ `document.startViewTransition`, when it applies
28
+ * commit
29
+ * │ the match signal is written and effects are flushed, inside the
30
+ * │ transition's callback, so the browser snapshots a settled DOM
31
+ * navigation-complete
32
+ *
33
+ * Nothing here delays anything. The commit happens as soon as preparation resolves; on
34
+ * a warm route that is the same tick it always was.
35
+ */
36
+ /** How a navigation should be presented. */
37
+ export type TransitionMode = 'auto' | 'none';
38
+ /**
39
+ * Whether this environment can animate a route swap.
40
+ *
41
+ * Read at call time rather than cached at module load: a test swaps the API in and out,
42
+ * and a cached answer would make the second case unreachable.
43
+ */
44
+ export declare function supportsViewTransitions(): boolean;
45
+ /**
46
+ * Whether the reader asked not to be animated.
47
+ *
48
+ * A stated preference outranks the app's configuration, so this is checked on every
49
+ * navigation rather than once: the setting can change while the page is open.
50
+ */
51
+ export declare function prefersReducedMotion(): boolean;
52
+ /** Whether this particular commit should go through a view transition. */
53
+ export declare function shouldAnimate(mode: TransitionMode): boolean;
54
+ /**
55
+ * Load what the next route needs to render without suspending.
56
+ *
57
+ * Only the route's own modules. Data loaders are deliberately left alone: the resource
58
+ * belongs to the layer's owner and is created when that layer renders, so calling the
59
+ * loader here would either run the request twice or require a cache this router does not
60
+ * own. See the note in the router on what that leaves.
61
+ *
62
+ * A module that fails to load resolves anyway. Preparation is an optimisation, and a
63
+ * rejected import should surface through the route's own error handling when it renders,
64
+ * not by leaving the navigation permanently pending.
65
+ */
66
+ export declare function prepareComponents(components: readonly unknown[]): Promise<void> | null;
67
+ /**
68
+ * Run `commit` inside a view transition, or directly when one does not apply.
69
+ *
70
+ * The callback is async because writing the match signal only queues the work: effects
71
+ * are scheduled, so the DOM is not settled when the write returns. `startViewTransition`
72
+ * waits for the returned promise before snapshotting the new state, so flushing inside
73
+ * it is what makes the browser compare two finished frames rather than one finished and
74
+ * one half-built.
75
+ *
76
+ * The returned promise resolves when the DOM has been updated, not when the animation
77
+ * ends. A caller waiting on navigation wants the former; blocking on the latter would
78
+ * make every navigation as slow as its animation.
79
+ */
80
+ export declare function runTransition(mode: TransitionMode, commit: () => void | Promise<void>): Promise<void>;
81
+ //# sourceMappingURL=transition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transition.d.ts","sourceRoot":"","sources":["../../../../src/lib/router/transition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAcH,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAMjD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAU9C;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAE3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAqBtF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAsBf"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Navigation presentation: preparing a route before it is shown, and handing the DOM
3
+ * swap to the browser's View Transition API when there is one.
4
+ *
5
+ * ## The lifecycle this replaces
6
+ *
7
+ * Navigation used to be one synchronous chain. `navigate()` pushed history, the core
8
+ * router recomputed the match and notified, the `Router` component wrote the match
9
+ * signal, and the render memo rebuilt the layer at the depth that changed. The old DOM
10
+ * came out at that moment: whether or not the new route had anything to put in its
11
+ * place:
12
+ *
13
+ * - a route with a `data` loader renders `null` until the resource resolves,
14
+ * - a `lazy()` route whose chunk is not loaded suspends to the nearest fallback.
15
+ *
16
+ * Both are an empty intermediate state with the old page already gone, which is what
17
+ * reads as a flash. It is not a paint-timing artifact and no animation would hide it.
18
+ *
19
+ * ## The lifecycle now
20
+ *
21
+ * navigation-start
22
+ * │ the match is computed, but not committed
23
+ * prepare
24
+ * │ every matched layer's module is loaded (`lazy().preload()`), so the
25
+ * │ component renders synchronously instead of suspending
26
+ * begin transition
27
+ * │ `document.startViewTransition`, when it applies
28
+ * commit
29
+ * │ the match signal is written and effects are flushed, inside the
30
+ * │ transition's callback, so the browser snapshots a settled DOM
31
+ * navigation-complete
32
+ *
33
+ * Nothing here delays anything. The commit happens as soon as preparation resolves; on
34
+ * a warm route that is the same tick it always was.
35
+ */
36
+ /**
37
+ * Whether this environment can animate a route swap.
38
+ *
39
+ * Read at call time rather than cached at module load: a test swaps the API in and out,
40
+ * and a cached answer would make the second case unreachable.
41
+ */
42
+ export function supportsViewTransitions() {
43
+ return (typeof document !== 'undefined' &&
44
+ typeof document
45
+ .startViewTransition === 'function');
46
+ }
47
+ /**
48
+ * Whether the reader asked not to be animated.
49
+ *
50
+ * A stated preference outranks the app's configuration, so this is checked on every
51
+ * navigation rather than once: the setting can change while the page is open.
52
+ */
53
+ export function prefersReducedMotion() {
54
+ if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
55
+ return false;
56
+ }
57
+ try {
58
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
59
+ }
60
+ catch {
61
+ // A matchMedia that throws on an unknown query is not a reason to fail navigation.
62
+ return false;
63
+ }
64
+ }
65
+ /** Whether this particular commit should go through a view transition. */
66
+ export function shouldAnimate(mode) {
67
+ return mode !== 'none' && supportsViewTransitions() && !prefersReducedMotion();
68
+ }
69
+ /**
70
+ * Load what the next route needs to render without suspending.
71
+ *
72
+ * Only the route's own modules. Data loaders are deliberately left alone: the resource
73
+ * belongs to the layer's owner and is created when that layer renders, so calling the
74
+ * loader here would either run the request twice or require a cache this router does not
75
+ * own. See the note in the router on what that leaves.
76
+ *
77
+ * A module that fails to load resolves anyway. Preparation is an optimisation, and a
78
+ * rejected import should surface through the route's own error handling when it renders,
79
+ * not by leaving the navigation permanently pending.
80
+ */
81
+ export function prepareComponents(components) {
82
+ const pending = [];
83
+ for (const component of components) {
84
+ const preload = component
85
+ ?.preload;
86
+ if (typeof preload === 'function') {
87
+ try {
88
+ const result = preload();
89
+ if (result && typeof result.then === 'function') {
90
+ pending.push(result.catch(() => undefined));
91
+ }
92
+ }
93
+ catch {
94
+ // A preload that throws synchronously is the same as one that rejects.
95
+ }
96
+ }
97
+ }
98
+ // Null rather than a resolved promise: the caller commits synchronously when there is
99
+ // nothing to wait for, which keeps a warm navigation on the tick it was already on.
100
+ return pending.length ? Promise.all(pending).then(() => undefined) : null;
101
+ }
102
+ /**
103
+ * Run `commit` inside a view transition, or directly when one does not apply.
104
+ *
105
+ * The callback is async because writing the match signal only queues the work: effects
106
+ * are scheduled, so the DOM is not settled when the write returns. `startViewTransition`
107
+ * waits for the returned promise before snapshotting the new state, so flushing inside
108
+ * it is what makes the browser compare two finished frames rather than one finished and
109
+ * one half-built.
110
+ *
111
+ * The returned promise resolves when the DOM has been updated, not when the animation
112
+ * ends. A caller waiting on navigation wants the former; blocking on the latter would
113
+ * make every navigation as slow as its animation.
114
+ */
115
+ export function runTransition(mode, commit) {
116
+ if (!shouldAnimate(mode)) {
117
+ return Promise.resolve(commit()).then(() => undefined);
118
+ }
119
+ const start = document
120
+ .startViewTransition;
121
+ try {
122
+ const transition = start.call(document, () => commit());
123
+ // Swallow the rejections a skipped or interrupted transition produces. Both of
124
+ // these reject when the animation is cut short, by `skipTransition()`, by another
125
+ // navigation starting, or by the tab going to the background. The DOM update inside
126
+ // the callback still happened, so a navigation must not fail because an animation
127
+ // did not play, and an unobserved rejection here would surface as an unhandled one.
128
+ transition.finished?.catch(() => undefined);
129
+ transition.ready?.catch(() => undefined);
130
+ return transition.updateCallbackDone.catch(() => undefined);
131
+ }
132
+ catch {
133
+ // A browser that has the method but refuses the call still has to navigate.
134
+ return Promise.resolve(commit()).then(() => undefined);
135
+ }
136
+ }
@@ -0,0 +1,54 @@
1
+ // src/lib/router/transition.ts
2
+ function supportsViewTransitions() {
3
+ return typeof document !== "undefined" && typeof document.startViewTransition === "function";
4
+ }
5
+ function prefersReducedMotion() {
6
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
7
+ return false;
8
+ }
9
+ try {
10
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
11
+ } catch {
12
+ return false;
13
+ }
14
+ }
15
+ function shouldAnimate(mode) {
16
+ return mode !== "none" && supportsViewTransitions() && !prefersReducedMotion();
17
+ }
18
+ function prepareComponents(components) {
19
+ const pending = [];
20
+ for (const component of components) {
21
+ const preload = component?.preload;
22
+ if (typeof preload === "function") {
23
+ try {
24
+ const result = preload();
25
+ if (result && typeof result.then === "function") {
26
+ pending.push(result.catch(() => void 0));
27
+ }
28
+ } catch {
29
+ }
30
+ }
31
+ }
32
+ return pending.length ? Promise.all(pending).then(() => void 0) : null;
33
+ }
34
+ function runTransition(mode, commit) {
35
+ if (!shouldAnimate(mode)) {
36
+ return Promise.resolve(commit()).then(() => void 0);
37
+ }
38
+ const start = document.startViewTransition;
39
+ try {
40
+ const transition = start.call(document, () => commit());
41
+ transition.finished?.catch(() => void 0);
42
+ transition.ready?.catch(() => void 0);
43
+ return transition.updateCallbackDone.catch(() => void 0);
44
+ } catch {
45
+ return Promise.resolve(commit()).then(() => void 0);
46
+ }
47
+ }
48
+ export {
49
+ prefersReducedMotion,
50
+ prepareComponents,
51
+ runTransition,
52
+ shouldAnimate,
53
+ supportsViewTransitions
54
+ };
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/lib/server/hydration.ts
4
4
  import { isServer as domIsServer } from "@fluixi/dom";
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/routes.ts
4
4
  function missingPlugin() {
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/utils.ts
4
4
  export * from "@fluixi/utils";
@@ -23,4 +23,4 @@ __export(version_generated_exports, {
23
23
  VERSION: () => VERSION
24
24
  });
25
25
  module.exports = __toCommonJS(version_generated_exports);
26
- var VERSION = "1.0.0-alpha.84";
26
+ var VERSION = "1.0.0-alpha.85";
@@ -1,3 +1,3 @@
1
1
  /** The published version of @fluixi/core that this build came from. */
2
- export declare const VERSION = "1.0.0-alpha.84";
2
+ export declare const VERSION = "1.0.0-alpha.85";
3
3
  //# sourceMappingURL=version.generated.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // GENERATED by scripts/gen-version.mjs. Do not edit.
2
2
  /** The published version of @fluixi/core that this build came from. */
3
- export const VERSION = '1.0.0-alpha.84';
3
+ export const VERSION = '1.0.0-alpha.85';
@@ -1,5 +1,5 @@
1
1
  // src/version.generated.ts
2
- var VERSION = "1.0.0-alpha.84";
2
+ var VERSION = "1.0.0-alpha.85";
3
3
  export {
4
4
  VERSION
5
5
  };