@nisli/core 0.54.1 → 0.55.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/README.md +93 -3
- package/dist/component.js +146 -5
- package/dist/component.js.map +1 -1
- package/dist/diagnostics.d.ts +48 -0
- package/dist/diagnostics.js +118 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/disposable.d.ts +14 -0
- package/dist/disposable.js +8 -0
- package/dist/disposable.js.map +1 -0
- package/dist/emitter.d.ts +2 -1
- package/dist/emitter.js +2 -1
- package/dist/emitter.js.map +1 -1
- package/dist/hmr/registry.js +8 -1
- package/dist/hmr/registry.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/injector.d.ts +9 -2
- package/dist/injector.js +18 -0
- package/dist/injector.js.map +1 -1
- package/dist/lifecycle.d.ts +9 -0
- package/dist/lifecycle.js +17 -7
- package/dist/lifecycle.js.map +1 -1
- package/dist/projection.js +24 -5
- package/dist/projection.js.map +1 -1
- package/dist/query.d.ts +134 -55
- package/dist/query.js +379 -188
- package/dist/query.js.map +1 -1
- package/dist/resource.d.ts +2 -1
- package/dist/resource.js +21 -4
- package/dist/resource.js.map +1 -1
- package/dist/settle.d.ts +61 -0
- package/dist/settle.js +106 -0
- package/dist/settle.js.map +1 -0
- package/dist/signal.d.ts +42 -7
- package/dist/signal.js +248 -68
- package/dist/signal.js.map +1 -1
- package/dist/template-audit.d.ts +64 -0
- package/dist/template-audit.js +246 -0
- package/dist/template-audit.js.map +1 -0
- package/dist/template.d.ts +70 -1
- package/dist/template.js +322 -65
- package/dist/template.js.map +1 -1
- package/dist/view-transition.d.ts +70 -0
- package/dist/view-transition.js +98 -0
- package/dist/view-transition.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* view-transition.ts — opt-in View Transitions over the synchronous flush.
|
|
3
|
+
*
|
|
4
|
+
* `viewTransition()` wraps a state update so the browser animates between the
|
|
5
|
+
* before and after frames. It is a thin, opt-in wrapper: nothing here runs
|
|
6
|
+
* unless you call it, and no scheduler behaviour changes.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* viewTransition(() => { items.value = sorted; }, { types: ['reorder'] });
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* ## Why `flush()` is the whole trick
|
|
13
|
+
*
|
|
14
|
+
* `document.startViewTransition()` captures the OLD frame, runs the update
|
|
15
|
+
* callback, then captures the NEW frame. Nisli coalesces signal writes onto a
|
|
16
|
+
* microtask (ADR 0015), so a bare `items.value = sorted` inside that callback
|
|
17
|
+
* would mutate the DOM *after* the capture window — the browser would animate
|
|
18
|
+
* a frame to itself. Calling `flush()` inside the callback drains the effect
|
|
19
|
+
* cascade synchronously, so the DOM mutation the browser snapshots is nisli's
|
|
20
|
+
* own synchronous flush. `flush()` keeps its documented contract exactly
|
|
21
|
+
* ("effects executed before the next line", ADR 0015); this is a consumer of
|
|
22
|
+
* it, not a change to it. N303's cascade cap still applies inside the
|
|
23
|
+
* callback — a runaway cascade degrades to a skipped transition, not a hang.
|
|
24
|
+
*
|
|
25
|
+
* ## Progressive enhancement
|
|
26
|
+
*
|
|
27
|
+
* Where `document.startViewTransition` is missing (no DOM at all, or an engine
|
|
28
|
+
* without the API) the update still applies — synchronously, flushed, and
|
|
29
|
+
* unanimated — and the return is `null`. Where the API exists but the
|
|
30
|
+
* object/`types` form does not (Chrome 111–124), the plain callback form is
|
|
31
|
+
* used: the transition still runs, `:active-view-transition-type()` CSS simply
|
|
32
|
+
* never matches. There is no polyfill and no UA sniffing.
|
|
33
|
+
*
|
|
34
|
+
* ## Companion CSS (author-side, core ships no stylesheet)
|
|
35
|
+
*
|
|
36
|
+
* The root crossfade is the UA default and needs no CSS; tune it, and cut
|
|
37
|
+
* motion for users who ask, with:
|
|
38
|
+
*
|
|
39
|
+
* ```css
|
|
40
|
+
* ::view-transition-old(root),
|
|
41
|
+
* ::view-transition-new(root) { animation-duration: 200ms; }
|
|
42
|
+
*
|
|
43
|
+
* @media (prefers-reduced-motion: reduce) {
|
|
44
|
+
* ::view-transition-group(*),
|
|
45
|
+
* ::view-transition-old(*),
|
|
46
|
+
* ::view-transition-new(*) { animation: none !important; }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Reduced motion is answered in CSS, not JS: `viewTransition()` is still
|
|
51
|
+
* called, so the swap stays atomic and typed styles stay active — only the
|
|
52
|
+
* motion is neutralised. `skipTransition()` on the returned handle is the hard
|
|
53
|
+
* opt-out.
|
|
54
|
+
*/
|
|
55
|
+
export interface ViewTransitionOptions {
|
|
56
|
+
/** Transition types, surfaced to `:active-view-transition-type()` CSS. */
|
|
57
|
+
types?: string[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run a state update inside a view transition.
|
|
61
|
+
*
|
|
62
|
+
* `update` must be synchronous: everything it does happens inside the
|
|
63
|
+
* browser's capture window, where the page is frozen. Keep async work
|
|
64
|
+
* (loaders, fetches) outside and wrap only the commit.
|
|
65
|
+
*
|
|
66
|
+
* @returns the live `ViewTransition` handle (`finished`, `ready`,
|
|
67
|
+
* `skipTransition()`), or `null` when the platform has no support and the
|
|
68
|
+
* update was applied directly.
|
|
69
|
+
*/
|
|
70
|
+
export declare function viewTransition(update: () => void, options?: ViewTransitionOptions): ViewTransition | null;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* view-transition.ts — opt-in View Transitions over the synchronous flush.
|
|
3
|
+
*
|
|
4
|
+
* `viewTransition()` wraps a state update so the browser animates between the
|
|
5
|
+
* before and after frames. It is a thin, opt-in wrapper: nothing here runs
|
|
6
|
+
* unless you call it, and no scheduler behaviour changes.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* viewTransition(() => { items.value = sorted; }, { types: ['reorder'] });
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* ## Why `flush()` is the whole trick
|
|
13
|
+
*
|
|
14
|
+
* `document.startViewTransition()` captures the OLD frame, runs the update
|
|
15
|
+
* callback, then captures the NEW frame. Nisli coalesces signal writes onto a
|
|
16
|
+
* microtask (ADR 0015), so a bare `items.value = sorted` inside that callback
|
|
17
|
+
* would mutate the DOM *after* the capture window — the browser would animate
|
|
18
|
+
* a frame to itself. Calling `flush()` inside the callback drains the effect
|
|
19
|
+
* cascade synchronously, so the DOM mutation the browser snapshots is nisli's
|
|
20
|
+
* own synchronous flush. `flush()` keeps its documented contract exactly
|
|
21
|
+
* ("effects executed before the next line", ADR 0015); this is a consumer of
|
|
22
|
+
* it, not a change to it. N303's cascade cap still applies inside the
|
|
23
|
+
* callback — a runaway cascade degrades to a skipped transition, not a hang.
|
|
24
|
+
*
|
|
25
|
+
* ## Progressive enhancement
|
|
26
|
+
*
|
|
27
|
+
* Where `document.startViewTransition` is missing (no DOM at all, or an engine
|
|
28
|
+
* without the API) the update still applies — synchronously, flushed, and
|
|
29
|
+
* unanimated — and the return is `null`. Where the API exists but the
|
|
30
|
+
* object/`types` form does not (Chrome 111–124), the plain callback form is
|
|
31
|
+
* used: the transition still runs, `:active-view-transition-type()` CSS simply
|
|
32
|
+
* never matches. There is no polyfill and no UA sniffing.
|
|
33
|
+
*
|
|
34
|
+
* ## Companion CSS (author-side, core ships no stylesheet)
|
|
35
|
+
*
|
|
36
|
+
* The root crossfade is the UA default and needs no CSS; tune it, and cut
|
|
37
|
+
* motion for users who ask, with:
|
|
38
|
+
*
|
|
39
|
+
* ```css
|
|
40
|
+
* ::view-transition-old(root),
|
|
41
|
+
* ::view-transition-new(root) { animation-duration: 200ms; }
|
|
42
|
+
*
|
|
43
|
+
* @media (prefers-reduced-motion: reduce) {
|
|
44
|
+
* ::view-transition-group(*),
|
|
45
|
+
* ::view-transition-old(*),
|
|
46
|
+
* ::view-transition-new(*) { animation: none !important; }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Reduced motion is answered in CSS, not JS: `viewTransition()` is still
|
|
51
|
+
* called, so the swap stays atomic and typed styles stay active — only the
|
|
52
|
+
* motion is neutralised. `skipTransition()` on the returned handle is the hard
|
|
53
|
+
* opt-out.
|
|
54
|
+
*/
|
|
55
|
+
import { flush } from './signal.js';
|
|
56
|
+
// ── Feature detection ───────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Does this engine accept `startViewTransition({ update, types })`?
|
|
59
|
+
*
|
|
60
|
+
* The object form and the `ViewTransition.types` accessor shipped together,
|
|
61
|
+
* so the accessor is the probe. Engines predating it take a bare callback —
|
|
62
|
+
* passing them an object would throw. A false negative costs only type-scoped
|
|
63
|
+
* CSS, never the transition.
|
|
64
|
+
*/
|
|
65
|
+
function supportsTransitionTypes() {
|
|
66
|
+
return typeof ViewTransition !== 'undefined'
|
|
67
|
+
&& 'types' in ViewTransition.prototype;
|
|
68
|
+
}
|
|
69
|
+
// ── Public API ──────────────────────────────────────────────────────
|
|
70
|
+
/**
|
|
71
|
+
* Run a state update inside a view transition.
|
|
72
|
+
*
|
|
73
|
+
* `update` must be synchronous: everything it does happens inside the
|
|
74
|
+
* browser's capture window, where the page is frozen. Keep async work
|
|
75
|
+
* (loaders, fetches) outside and wrap only the commit.
|
|
76
|
+
*
|
|
77
|
+
* @returns the live `ViewTransition` handle (`finished`, `ready`,
|
|
78
|
+
* `skipTransition()`), or `null` when the platform has no support and the
|
|
79
|
+
* update was applied directly.
|
|
80
|
+
*/
|
|
81
|
+
export function viewTransition(update, options = {}) {
|
|
82
|
+
// The commit the browser snapshots: apply the update, then settle the
|
|
83
|
+
// reactive cascade now rather than on the next microtask.
|
|
84
|
+
const commit = () => {
|
|
85
|
+
update();
|
|
86
|
+
flush();
|
|
87
|
+
};
|
|
88
|
+
if (typeof document === 'undefined'
|
|
89
|
+
|| typeof document.startViewTransition !== 'function') {
|
|
90
|
+
commit();
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const types = options.types;
|
|
94
|
+
return types !== undefined && types.length > 0 && supportsTransitionTypes()
|
|
95
|
+
? document.startViewTransition({ update: commit, types })
|
|
96
|
+
: document.startViewTransition(commit);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=view-transition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-transition.js","sourceRoot":"","sources":["../src/view-transition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AASpC,uEAAuE;AAEvE;;;;;;;GAOG;AACH,SAAS,uBAAuB;IAC9B,OAAO,OAAO,cAAc,KAAK,WAAW;WACvC,OAAO,IAAI,cAAc,CAAC,SAAS,CAAC;AAC3C,CAAC;AAED,uEAAuE;AAEvE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAkB,EAClB,UAAiC,EAAE;IAEnC,sEAAsE;IACtE,0DAA0D;IAC1D,MAAM,MAAM,GAAG,GAAS,EAAE;QACxB,MAAM,EAAE,CAAC;QACT,KAAK,EAAE,CAAC;IACV,CAAC,CAAC;IAEF,IAAI,OAAO,QAAQ,KAAK,WAAW;WAC9B,OAAO,QAAQ,CAAC,mBAAmB,KAAK,UAAU,EAAE,CAAC;QACxD,MAAM,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,uBAAuB,EAAE;QACzE,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QACzD,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC"}
|
package/package.json
CHANGED