@bquery/bquery 1.1.2 → 1.3.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 +501 -323
- package/dist/batch-4LAvfLE7.js +13 -0
- package/dist/batch-4LAvfLE7.js.map +1 -0
- package/dist/component/component.d.ts +69 -0
- package/dist/component/component.d.ts.map +1 -0
- package/dist/component/html.d.ts +35 -0
- package/dist/component/html.d.ts.map +1 -0
- package/dist/component/index.d.ts +3 -126
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/props.d.ts +18 -0
- package/dist/component/props.d.ts.map +1 -0
- package/dist/component/types.d.ts +77 -0
- package/dist/component/types.d.ts.map +1 -0
- package/dist/component.es.mjs +90 -59
- package/dist/component.es.mjs.map +1 -1
- package/dist/core/collection.d.ts +36 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/dom.d.ts +6 -0
- package/dist/core/dom.d.ts.map +1 -0
- package/dist/core/element.d.ts +8 -0
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/utils/array.d.ts +74 -0
- package/dist/core/utils/array.d.ts.map +1 -0
- package/dist/core/utils/function.d.ts +70 -0
- package/dist/core/utils/function.d.ts.map +1 -0
- package/dist/core/utils/index.d.ts +70 -0
- package/dist/core/utils/index.d.ts.map +1 -0
- package/dist/core/utils/misc.d.ts +63 -0
- package/dist/core/utils/misc.d.ts.map +1 -0
- package/dist/core/utils/number.d.ts +65 -0
- package/dist/core/utils/number.d.ts.map +1 -0
- package/dist/core/utils/object.d.ts +133 -0
- package/dist/core/utils/object.d.ts.map +1 -0
- package/dist/core/utils/string.d.ts +80 -0
- package/dist/core/utils/string.d.ts.map +1 -0
- package/dist/core/utils/type-guards.d.ts +79 -0
- package/dist/core/utils/type-guards.d.ts.map +1 -0
- package/dist/core-COenAZjD.js +145 -0
- package/dist/core-COenAZjD.js.map +1 -0
- package/dist/core.es.mjs +411 -448
- package/dist/core.es.mjs.map +1 -1
- package/dist/full.d.ts +8 -2
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +86 -40
- package/dist/full.es.mjs.map +1 -1
- package/dist/full.iife.js +6 -1
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +6 -1
- package/dist/full.umd.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.mjs +137 -44
- package/dist/index.es.mjs.map +1 -1
- package/dist/motion/animate.d.ts +25 -0
- package/dist/motion/animate.d.ts.map +1 -0
- package/dist/motion/easing.d.ts +30 -0
- package/dist/motion/easing.d.ts.map +1 -0
- package/dist/motion/flip.d.ts +55 -0
- package/dist/motion/flip.d.ts.map +1 -0
- package/dist/motion/index.d.ts +11 -138
- package/dist/motion/index.d.ts.map +1 -1
- package/dist/motion/keyframes.d.ts +21 -0
- package/dist/motion/keyframes.d.ts.map +1 -0
- package/dist/motion/reduced-motion.d.ts +12 -0
- package/dist/motion/reduced-motion.d.ts.map +1 -0
- package/dist/motion/scroll.d.ts +15 -0
- package/dist/motion/scroll.d.ts.map +1 -0
- package/dist/motion/spring.d.ts +42 -0
- package/dist/motion/spring.d.ts.map +1 -0
- package/dist/motion/stagger.d.ts +22 -0
- package/dist/motion/stagger.d.ts.map +1 -0
- package/dist/motion/timeline.d.ts +21 -0
- package/dist/motion/timeline.d.ts.map +1 -0
- package/dist/motion/transition.d.ts +22 -0
- package/dist/motion/transition.d.ts.map +1 -0
- package/dist/motion/types.d.ts +182 -0
- package/dist/motion/types.d.ts.map +1 -0
- package/dist/motion.es.mjs +320 -61
- package/dist/motion.es.mjs.map +1 -1
- package/dist/persisted-Dz_ryNuC.js +278 -0
- package/dist/persisted-Dz_ryNuC.js.map +1 -0
- package/dist/reactive/batch.d.ts +13 -0
- package/dist/reactive/batch.d.ts.map +1 -0
- package/dist/reactive/computed.d.ts +50 -0
- package/dist/reactive/computed.d.ts.map +1 -0
- package/dist/reactive/core.d.ts +60 -0
- package/dist/reactive/core.d.ts.map +1 -0
- package/dist/reactive/effect.d.ts +15 -0
- package/dist/reactive/effect.d.ts.map +1 -0
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.d.ts.map +1 -1
- package/dist/reactive/internals.d.ts +36 -0
- package/dist/reactive/internals.d.ts.map +1 -0
- package/dist/reactive/linked.d.ts +36 -0
- package/dist/reactive/linked.d.ts.map +1 -0
- package/dist/reactive/persisted.d.ts +14 -0
- package/dist/reactive/persisted.d.ts.map +1 -0
- package/dist/reactive/readonly.d.ts +26 -0
- package/dist/reactive/readonly.d.ts.map +1 -0
- package/dist/reactive/signal.d.ts +13 -305
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive/type-guards.d.ts +20 -0
- package/dist/reactive/type-guards.d.ts.map +1 -0
- package/dist/reactive/untrack.d.ts +29 -0
- package/dist/reactive/untrack.d.ts.map +1 -0
- package/dist/reactive/watch.d.ts +42 -0
- package/dist/reactive/watch.d.ts.map +1 -0
- package/dist/reactive.es.mjs +30 -154
- package/dist/reactive.es.mjs.map +1 -1
- package/dist/router/index.d.ts +41 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/links.d.ts +44 -0
- package/dist/router/links.d.ts.map +1 -0
- package/dist/router/match.d.ts +20 -0
- package/dist/router/match.d.ts.map +1 -0
- package/dist/router/navigation.d.ts +45 -0
- package/dist/router/navigation.d.ts.map +1 -0
- package/dist/router/query.d.ts +16 -0
- package/dist/router/query.d.ts.map +1 -0
- package/dist/router/router.d.ts +34 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/state.d.ts +27 -0
- package/dist/router/state.d.ts.map +1 -0
- package/dist/router/types.d.ts +88 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/router/utils.d.ts +65 -0
- package/dist/router/utils.d.ts.map +1 -0
- package/dist/router.es.mjs +202 -0
- package/dist/router.es.mjs.map +1 -0
- package/dist/sanitize-1FBEPAFH.js +272 -0
- package/dist/sanitize-1FBEPAFH.js.map +1 -0
- package/dist/security/constants.d.ts +42 -0
- package/dist/security/constants.d.ts.map +1 -0
- package/dist/security/csp.d.ts +24 -0
- package/dist/security/csp.d.ts.map +1 -0
- package/dist/security/index.d.ts +4 -2
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/sanitize-core.d.ts +13 -0
- package/dist/security/sanitize-core.d.ts.map +1 -0
- package/dist/security/sanitize.d.ts +5 -57
- package/dist/security/sanitize.d.ts.map +1 -1
- package/dist/security/trusted-types.d.ts +25 -0
- package/dist/security/trusted-types.d.ts.map +1 -0
- package/dist/security/types.d.ts +36 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security.es.mjs +50 -277
- package/dist/security.es.mjs.map +1 -1
- package/dist/store/create-store.d.ts +15 -0
- package/dist/store/create-store.d.ts.map +1 -0
- package/dist/store/define-store.d.ts +28 -0
- package/dist/store/define-store.d.ts.map +1 -0
- package/dist/store/devtools.d.ts +22 -0
- package/dist/store/devtools.d.ts.map +1 -0
- package/dist/store/index.d.ts +12 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/mapping.d.ts +28 -0
- package/dist/store/mapping.d.ts.map +1 -0
- package/dist/store/persisted.d.ts +13 -0
- package/dist/store/persisted.d.ts.map +1 -0
- package/dist/store/plugins.d.ts +13 -0
- package/dist/store/plugins.d.ts.map +1 -0
- package/dist/store/registry.d.ts +28 -0
- package/dist/store/registry.d.ts.map +1 -0
- package/dist/store/types.d.ts +71 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/utils.d.ts +28 -0
- package/dist/store/utils.d.ts.map +1 -0
- package/dist/store/watch.d.ts +23 -0
- package/dist/store/watch.d.ts.map +1 -0
- package/dist/store.es.mjs +27 -0
- package/dist/store.es.mjs.map +1 -0
- package/dist/type-guards-DRma3-Kc.js +16 -0
- package/dist/type-guards-DRma3-Kc.js.map +1 -0
- package/dist/untrack-BuEQKH7_.js +6 -0
- package/dist/untrack-BuEQKH7_.js.map +1 -0
- package/dist/view/directives/bind.d.ts +7 -0
- package/dist/view/directives/bind.d.ts.map +1 -0
- package/dist/view/directives/class.d.ts +8 -0
- package/dist/view/directives/class.d.ts.map +1 -0
- package/dist/view/directives/for.d.ts +23 -0
- package/dist/view/directives/for.d.ts.map +1 -0
- package/dist/view/directives/html.d.ts +7 -0
- package/dist/view/directives/html.d.ts.map +1 -0
- package/dist/view/directives/if.d.ts +7 -0
- package/dist/view/directives/if.d.ts.map +1 -0
- package/dist/view/directives/index.d.ts +12 -0
- package/dist/view/directives/index.d.ts.map +1 -0
- package/dist/view/directives/model.d.ts +7 -0
- package/dist/view/directives/model.d.ts.map +1 -0
- package/dist/view/directives/on.d.ts +7 -0
- package/dist/view/directives/on.d.ts.map +1 -0
- package/dist/view/directives/ref.d.ts +7 -0
- package/dist/view/directives/ref.d.ts.map +1 -0
- package/dist/view/directives/show.d.ts +7 -0
- package/dist/view/directives/show.d.ts.map +1 -0
- package/dist/view/directives/style.d.ts +7 -0
- package/dist/view/directives/style.d.ts.map +1 -0
- package/dist/view/directives/text.d.ts +7 -0
- package/dist/view/directives/text.d.ts.map +1 -0
- package/dist/view/evaluate.d.ts +43 -0
- package/dist/view/evaluate.d.ts.map +1 -0
- package/dist/view/index.d.ts +111 -0
- package/dist/view/index.d.ts.map +1 -0
- package/dist/view/mount.d.ts +69 -0
- package/dist/view/mount.d.ts.map +1 -0
- package/dist/view/process.d.ts +26 -0
- package/dist/view/process.d.ts.map +1 -0
- package/dist/view/types.d.ts +36 -0
- package/dist/view/types.d.ts.map +1 -0
- package/dist/view.es.mjs +426 -0
- package/dist/view.es.mjs.map +1 -0
- package/dist/watch-CXyaBC_9.js +58 -0
- package/dist/watch-CXyaBC_9.js.map +1 -0
- package/package.json +26 -14
- package/src/component/component.ts +289 -0
- package/src/component/html.ts +53 -0
- package/src/component/index.ts +40 -414
- package/src/component/props.ts +116 -0
- package/src/component/types.ts +85 -0
- package/src/core/collection.ts +588 -454
- package/src/core/dom.ts +38 -0
- package/src/core/element.ts +746 -740
- package/src/core/index.ts +43 -0
- package/src/core/utils/array.ts +102 -0
- package/src/core/utils/function.ts +110 -0
- package/src/core/utils/index.ts +83 -0
- package/src/core/utils/misc.ts +82 -0
- package/src/core/utils/number.ts +78 -0
- package/src/core/utils/object.ts +206 -0
- package/src/core/utils/string.ts +112 -0
- package/src/core/utils/type-guards.ts +112 -0
- package/src/full.ts +187 -106
- package/src/index.ts +36 -27
- package/src/motion/animate.ts +113 -0
- package/src/motion/easing.ts +40 -0
- package/src/motion/flip.ts +176 -0
- package/src/motion/index.ts +41 -358
- package/src/motion/keyframes.ts +46 -0
- package/src/motion/reduced-motion.ts +17 -0
- package/src/motion/scroll.ts +57 -0
- package/src/motion/spring.ts +150 -0
- package/src/motion/stagger.ts +43 -0
- package/src/motion/timeline.ts +246 -0
- package/src/motion/transition.ts +51 -0
- package/src/motion/types.ts +198 -0
- package/src/reactive/batch.ts +22 -0
- package/src/reactive/computed.ts +92 -0
- package/src/reactive/core.ts +93 -0
- package/src/reactive/effect.ts +43 -0
- package/src/reactive/index.ts +23 -22
- package/src/reactive/internals.ts +105 -0
- package/src/reactive/linked.ts +56 -0
- package/src/reactive/persisted.ts +74 -0
- package/src/reactive/readonly.ts +35 -0
- package/src/reactive/signal.ts +20 -506
- package/src/reactive/type-guards.ts +22 -0
- package/src/reactive/untrack.ts +31 -0
- package/src/reactive/watch.ts +73 -0
- package/src/router/index.ts +41 -0
- package/src/router/links.ts +130 -0
- package/src/router/match.ts +106 -0
- package/src/router/navigation.ts +71 -0
- package/src/router/query.ts +35 -0
- package/src/router/router.ts +211 -0
- package/src/router/state.ts +46 -0
- package/src/router/types.ts +93 -0
- package/src/router/utils.ts +116 -0
- package/src/security/constants.ts +209 -0
- package/src/security/csp.ts +77 -0
- package/src/security/index.ts +4 -12
- package/src/security/sanitize-core.ts +343 -0
- package/src/security/sanitize.ts +66 -625
- package/src/security/trusted-types.ts +69 -0
- package/src/security/types.ts +40 -0
- package/src/store/create-store.ts +329 -0
- package/src/store/define-store.ts +48 -0
- package/src/store/devtools.ts +45 -0
- package/src/store/index.ts +22 -0
- package/src/store/mapping.ts +73 -0
- package/src/store/persisted.ts +61 -0
- package/src/store/plugins.ts +32 -0
- package/src/store/registry.ts +51 -0
- package/src/store/types.ts +94 -0
- package/src/store/utils.ts +141 -0
- package/src/store/watch.ts +52 -0
- package/src/view/directives/bind.ts +23 -0
- package/src/view/directives/class.ts +70 -0
- package/src/view/directives/for.ts +275 -0
- package/src/view/directives/html.ts +19 -0
- package/src/view/directives/if.ts +30 -0
- package/src/view/directives/index.ts +11 -0
- package/src/view/directives/model.ts +56 -0
- package/src/view/directives/on.ts +41 -0
- package/src/view/directives/ref.ts +41 -0
- package/src/view/directives/show.ts +26 -0
- package/src/view/directives/style.ts +47 -0
- package/src/view/directives/text.ts +15 -0
- package/src/view/evaluate.ts +274 -0
- package/src/view/index.ts +112 -0
- package/src/view/mount.ts +200 -0
- package/src/view/process.ts +92 -0
- package/src/view/types.ts +44 -0
- package/dist/core/utils.d.ts +0 -313
- package/dist/core/utils.d.ts.map +0 -1
- package/src/core/utils.ts +0 -444
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Motion module types.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/motion
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for view transitions.
|
|
9
|
+
*/
|
|
10
|
+
export interface TransitionOptions {
|
|
11
|
+
/** The DOM update function to execute during transition */
|
|
12
|
+
update: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Captured element bounds for FLIP animations.
|
|
17
|
+
*/
|
|
18
|
+
export interface ElementBounds {
|
|
19
|
+
top: number;
|
|
20
|
+
left: number;
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* FLIP animation configuration options.
|
|
27
|
+
*/
|
|
28
|
+
export interface FlipOptions {
|
|
29
|
+
/** Animation duration in milliseconds */
|
|
30
|
+
duration?: number;
|
|
31
|
+
/** CSS easing function */
|
|
32
|
+
easing?: string;
|
|
33
|
+
/** Callback when animation completes */
|
|
34
|
+
onComplete?: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Stagger delay function signature.
|
|
39
|
+
*/
|
|
40
|
+
export type StaggerFunction = (index: number, total: number) => number;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Extended options for group FLIP animations.
|
|
44
|
+
*/
|
|
45
|
+
export interface FlipGroupOptions extends FlipOptions {
|
|
46
|
+
/** Optional stagger delay function */
|
|
47
|
+
stagger?: StaggerFunction;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Spring physics configuration.
|
|
52
|
+
*/
|
|
53
|
+
export interface SpringConfig {
|
|
54
|
+
/** Spring stiffness (default: 100) */
|
|
55
|
+
stiffness?: number;
|
|
56
|
+
/** Damping coefficient (default: 10) */
|
|
57
|
+
damping?: number;
|
|
58
|
+
/** Mass of the object (default: 1) */
|
|
59
|
+
mass?: number;
|
|
60
|
+
/** Velocity threshold for completion (default: 0.01) */
|
|
61
|
+
precision?: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Spring instance for animating values.
|
|
66
|
+
*/
|
|
67
|
+
export interface Spring {
|
|
68
|
+
/** Start animating to target value */
|
|
69
|
+
to(target: number): Promise<void>;
|
|
70
|
+
/** Get current animated value */
|
|
71
|
+
current(): number;
|
|
72
|
+
/** Stop the animation */
|
|
73
|
+
stop(): void;
|
|
74
|
+
/** Subscribe to value changes */
|
|
75
|
+
onChange(callback: (value: number) => void): () => void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Web Animations helper configuration.
|
|
80
|
+
*/
|
|
81
|
+
export interface AnimateOptions {
|
|
82
|
+
/** Keyframes to animate */
|
|
83
|
+
keyframes: Keyframe[] | PropertyIndexedKeyframes;
|
|
84
|
+
/** Animation options (duration, easing, etc.) */
|
|
85
|
+
options?: KeyframeAnimationOptions;
|
|
86
|
+
/** Commit final styles to the element (default: true) */
|
|
87
|
+
commitStyles?: boolean;
|
|
88
|
+
/** Respect prefers-reduced-motion (default: true) */
|
|
89
|
+
respectReducedMotion?: boolean;
|
|
90
|
+
/** Callback when animation completes */
|
|
91
|
+
onFinish?: () => void;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Stagger helper configuration.
|
|
96
|
+
*/
|
|
97
|
+
export interface StaggerOptions {
|
|
98
|
+
/** Start delay in milliseconds (default: 0) */
|
|
99
|
+
start?: number;
|
|
100
|
+
/** Origin index or keyword (default: 'start') */
|
|
101
|
+
from?: 'start' | 'center' | 'end' | number;
|
|
102
|
+
/** Optional easing function for normalized distance */
|
|
103
|
+
easing?: EasingFunction;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Easing function signature.
|
|
108
|
+
*/
|
|
109
|
+
export type EasingFunction = (t: number) => number;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Sequence step configuration.
|
|
113
|
+
*/
|
|
114
|
+
export interface SequenceStep extends AnimateOptions {
|
|
115
|
+
/** Target element to animate */
|
|
116
|
+
target: Element;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Sequence run configuration.
|
|
121
|
+
*/
|
|
122
|
+
export interface SequenceOptions {
|
|
123
|
+
/** Optional stagger delay between steps */
|
|
124
|
+
stagger?: StaggerFunction;
|
|
125
|
+
/** Callback when sequence completes */
|
|
126
|
+
onFinish?: () => void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Timeline step configuration.
|
|
131
|
+
*/
|
|
132
|
+
export interface TimelineStep {
|
|
133
|
+
/** Target element to animate */
|
|
134
|
+
target: Element;
|
|
135
|
+
/** Keyframes to animate */
|
|
136
|
+
keyframes: Keyframe[] | PropertyIndexedKeyframes;
|
|
137
|
+
/** Animation options for this step */
|
|
138
|
+
options?: KeyframeAnimationOptions;
|
|
139
|
+
/** Absolute or relative start time in milliseconds */
|
|
140
|
+
at?: number | `+=${number}` | `-=${number}`;
|
|
141
|
+
/** Optional label for debugging */
|
|
142
|
+
label?: string;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Timeline configuration.
|
|
147
|
+
*/
|
|
148
|
+
export interface TimelineConfig {
|
|
149
|
+
/** Commit final styles when timeline completes (default: true) */
|
|
150
|
+
commitStyles?: boolean;
|
|
151
|
+
/** Respect prefers-reduced-motion (default: true) */
|
|
152
|
+
respectReducedMotion?: boolean;
|
|
153
|
+
/** Callback when timeline completes */
|
|
154
|
+
onFinish?: () => void;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Timeline controls.
|
|
159
|
+
*/
|
|
160
|
+
export interface TimelineControls {
|
|
161
|
+
/** Play all steps */
|
|
162
|
+
play(): Promise<void>;
|
|
163
|
+
/** Pause animations */
|
|
164
|
+
pause(): void;
|
|
165
|
+
/** Resume animations */
|
|
166
|
+
resume(): void;
|
|
167
|
+
/** Stop and cancel animations */
|
|
168
|
+
stop(): void;
|
|
169
|
+
/** Seek to a specific time in milliseconds */
|
|
170
|
+
seek(time: number): void;
|
|
171
|
+
/** Add a step to the timeline */
|
|
172
|
+
add(step: TimelineStep): void;
|
|
173
|
+
/** Total timeline duration in milliseconds */
|
|
174
|
+
duration(): number;
|
|
175
|
+
/** Subscribe to finish events */
|
|
176
|
+
onFinish(callback: () => void): () => void;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Scroll animation configuration.
|
|
181
|
+
*/
|
|
182
|
+
export interface ScrollAnimateOptions extends AnimateOptions {
|
|
183
|
+
/** IntersectionObserver root */
|
|
184
|
+
root?: Element | Document | null;
|
|
185
|
+
/** Root margin for observer */
|
|
186
|
+
rootMargin?: string;
|
|
187
|
+
/** Intersection thresholds */
|
|
188
|
+
threshold?: number | number[];
|
|
189
|
+
/** Trigger only once (default: true) */
|
|
190
|
+
once?: boolean;
|
|
191
|
+
/** Callback when element enters the viewport */
|
|
192
|
+
onEnter?: (element: Element) => void;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Cleanup function for scroll animations.
|
|
197
|
+
*/
|
|
198
|
+
export type ScrollAnimateCleanup = () => void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batched reactive updates.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { beginBatch, endBatch } from './internals';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Batches multiple signal updates into a single notification cycle.
|
|
9
|
+
*
|
|
10
|
+
* Updates made inside the batch function are deferred until the batch
|
|
11
|
+
* completes, preventing intermediate re-renders and improving performance.
|
|
12
|
+
*
|
|
13
|
+
* @param fn - Function containing multiple signal updates
|
|
14
|
+
*/
|
|
15
|
+
export const batch = (fn: () => void): void => {
|
|
16
|
+
beginBatch();
|
|
17
|
+
try {
|
|
18
|
+
fn();
|
|
19
|
+
} finally {
|
|
20
|
+
endBatch();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computed reactive values.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
clearDependencies,
|
|
7
|
+
getCurrentObserver,
|
|
8
|
+
registerDependency,
|
|
9
|
+
scheduleObserver,
|
|
10
|
+
track,
|
|
11
|
+
type ReactiveSource,
|
|
12
|
+
} from './internals';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A computed value that derives from other reactive sources.
|
|
16
|
+
*
|
|
17
|
+
* Computed values are lazily evaluated and cached. They only
|
|
18
|
+
* recompute when their dependencies change.
|
|
19
|
+
*
|
|
20
|
+
* @template T - The type of the computed value
|
|
21
|
+
*/
|
|
22
|
+
export class Computed<T> implements ReactiveSource {
|
|
23
|
+
private cachedValue!: T;
|
|
24
|
+
private dirty = true;
|
|
25
|
+
private subscribers = new Set<() => void>();
|
|
26
|
+
private readonly markDirty = () => {
|
|
27
|
+
this.dirty = true;
|
|
28
|
+
// Create snapshot to avoid issues with subscribers modifying the set during iteration
|
|
29
|
+
const subscribersSnapshot = Array.from(this.subscribers);
|
|
30
|
+
for (const subscriber of subscribersSnapshot) {
|
|
31
|
+
scheduleObserver(subscriber);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new computed value.
|
|
37
|
+
* @param compute - Function that computes the value
|
|
38
|
+
*/
|
|
39
|
+
constructor(private readonly compute: () => T) {}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Gets the computed value, recomputing if dependencies changed.
|
|
43
|
+
* During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.
|
|
44
|
+
*/
|
|
45
|
+
get value(): T {
|
|
46
|
+
const current = getCurrentObserver();
|
|
47
|
+
if (current) {
|
|
48
|
+
this.subscribers.add(current);
|
|
49
|
+
registerDependency(current, this);
|
|
50
|
+
}
|
|
51
|
+
if (this.dirty) {
|
|
52
|
+
this.dirty = false;
|
|
53
|
+
// Clear old dependencies before recomputing
|
|
54
|
+
clearDependencies(this.markDirty);
|
|
55
|
+
this.cachedValue = track(this.markDirty, this.compute);
|
|
56
|
+
}
|
|
57
|
+
return this.cachedValue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Reads the current computed value without tracking.
|
|
62
|
+
* Useful when you need the value but don't want to create a dependency.
|
|
63
|
+
*
|
|
64
|
+
* @returns The current cached value (recomputes if dirty)
|
|
65
|
+
*/
|
|
66
|
+
peek(): T {
|
|
67
|
+
if (this.dirty) {
|
|
68
|
+
this.dirty = false;
|
|
69
|
+
// Clear old dependencies before recomputing
|
|
70
|
+
clearDependencies(this.markDirty);
|
|
71
|
+
this.cachedValue = track(this.markDirty, this.compute);
|
|
72
|
+
}
|
|
73
|
+
return this.cachedValue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Removes an observer from this computed's subscriber set.
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
80
|
+
unsubscribe(observer: () => void): void {
|
|
81
|
+
this.subscribers.delete(observer);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Creates a new computed value.
|
|
87
|
+
*
|
|
88
|
+
* @template T - The type of the computed value
|
|
89
|
+
* @param fn - Function that computes the value from reactive sources
|
|
90
|
+
* @returns A new Computed instance
|
|
91
|
+
*/
|
|
92
|
+
export const computed = <T>(fn: () => T): Computed<T> => new Computed(fn);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core reactive signals.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
getCurrentObserver,
|
|
7
|
+
registerDependency,
|
|
8
|
+
scheduleObserver,
|
|
9
|
+
type ReactiveSource,
|
|
10
|
+
} from './internals';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A reactive value container that notifies subscribers on change.
|
|
14
|
+
*
|
|
15
|
+
* Signals are the foundational primitive of the reactive system.
|
|
16
|
+
* Reading a signal's value inside an effect or computed automatically
|
|
17
|
+
* establishes a reactive dependency.
|
|
18
|
+
*
|
|
19
|
+
* @template T - The type of the stored value
|
|
20
|
+
*/
|
|
21
|
+
export class Signal<T> implements ReactiveSource {
|
|
22
|
+
private subscribers = new Set<() => void>();
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new signal with an initial value.
|
|
26
|
+
* @param _value - The initial value
|
|
27
|
+
*/
|
|
28
|
+
constructor(private _value: T) {}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Gets the current value and tracks the read if inside an observer.
|
|
32
|
+
* During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.
|
|
33
|
+
*/
|
|
34
|
+
get value(): T {
|
|
35
|
+
const current = getCurrentObserver();
|
|
36
|
+
if (current) {
|
|
37
|
+
this.subscribers.add(current);
|
|
38
|
+
registerDependency(current, this);
|
|
39
|
+
}
|
|
40
|
+
return this._value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Sets a new value and notifies all subscribers if the value changed.
|
|
45
|
+
* Uses Object.is for equality comparison.
|
|
46
|
+
*/
|
|
47
|
+
set value(next: T) {
|
|
48
|
+
if (Object.is(this._value, next)) return;
|
|
49
|
+
this._value = next;
|
|
50
|
+
// Create snapshot to avoid issues with subscribers modifying the set during iteration
|
|
51
|
+
const subscribersSnapshot = Array.from(this.subscribers);
|
|
52
|
+
for (const subscriber of subscribersSnapshot) {
|
|
53
|
+
scheduleObserver(subscriber);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Reads the current value without tracking.
|
|
59
|
+
* Useful when you need the value but don't want to create a dependency.
|
|
60
|
+
*
|
|
61
|
+
* @returns The current value
|
|
62
|
+
*/
|
|
63
|
+
peek(): T {
|
|
64
|
+
return this._value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Updates the value using a function.
|
|
69
|
+
* Useful for updates based on the current value.
|
|
70
|
+
*
|
|
71
|
+
* @param updater - Function that receives current value and returns new value
|
|
72
|
+
*/
|
|
73
|
+
update(updater: (current: T) => T): void {
|
|
74
|
+
this.value = updater(this._value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Removes an observer from this signal's subscriber set.
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
unsubscribe(observer: () => void): void {
|
|
82
|
+
this.subscribers.delete(observer);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Creates a new reactive signal.
|
|
88
|
+
*
|
|
89
|
+
* @template T - The type of the signal value
|
|
90
|
+
* @param value - The initial value
|
|
91
|
+
* @returns A new Signal instance
|
|
92
|
+
*/
|
|
93
|
+
export const signal = <T>(value: T): Signal<T> => new Signal(value);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive effects.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { CleanupFn, Observer, track, clearDependencies } from './internals';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a side effect that automatically re-runs when dependencies change.
|
|
9
|
+
*
|
|
10
|
+
* The effect runs immediately upon creation and then re-runs whenever
|
|
11
|
+
* any signal or computed value read inside it changes.
|
|
12
|
+
*
|
|
13
|
+
* @param fn - The effect function to run
|
|
14
|
+
* @returns A cleanup function to stop the effect
|
|
15
|
+
*/
|
|
16
|
+
export const effect = (fn: () => void | CleanupFn): CleanupFn => {
|
|
17
|
+
let cleanupFn: CleanupFn | void;
|
|
18
|
+
let isDisposed = false;
|
|
19
|
+
|
|
20
|
+
const observer: Observer = () => {
|
|
21
|
+
if (isDisposed) return;
|
|
22
|
+
|
|
23
|
+
if (cleanupFn) {
|
|
24
|
+
cleanupFn();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Clear old dependencies before running to avoid stale subscriptions
|
|
28
|
+
clearDependencies(observer);
|
|
29
|
+
|
|
30
|
+
cleanupFn = track(observer, fn);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
observer();
|
|
34
|
+
|
|
35
|
+
return () => {
|
|
36
|
+
isDisposed = true;
|
|
37
|
+
if (cleanupFn) {
|
|
38
|
+
cleanupFn();
|
|
39
|
+
}
|
|
40
|
+
// Clean up all dependencies when effect is disposed
|
|
41
|
+
clearDependencies(observer);
|
|
42
|
+
};
|
|
43
|
+
};
|
package/src/reactive/index.ts
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reactive module providing fine-grained reactivity primitives.
|
|
3
|
-
*
|
|
4
|
-
* @module bquery/reactive
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
Computed,
|
|
9
|
-
Signal,
|
|
10
|
-
batch,
|
|
11
|
-
computed,
|
|
12
|
-
effect,
|
|
13
|
-
isComputed,
|
|
14
|
-
isSignal,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Reactive module providing fine-grained reactivity primitives.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/reactive
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
Computed,
|
|
9
|
+
Signal,
|
|
10
|
+
batch,
|
|
11
|
+
computed,
|
|
12
|
+
effect,
|
|
13
|
+
isComputed,
|
|
14
|
+
isSignal,
|
|
15
|
+
linkedSignal,
|
|
16
|
+
persistedSignal,
|
|
17
|
+
readonly,
|
|
18
|
+
signal,
|
|
19
|
+
untrack,
|
|
20
|
+
watch,
|
|
21
|
+
} from './signal';
|
|
22
|
+
|
|
23
|
+
export type { CleanupFn, LinkedSignal, Observer, ReadonlySignal } from './signal';
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal reactive plumbing shared across primitives.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type Observer = () => void;
|
|
7
|
+
export type CleanupFn = () => void;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Interface for reactive sources (Signals, Computed) that can unsubscribe observers.
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export interface ReactiveSource {
|
|
14
|
+
unsubscribe(observer: Observer): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const observerStack: Observer[] = [];
|
|
18
|
+
let batchDepth = 0;
|
|
19
|
+
const pendingObservers = new Set<Observer>();
|
|
20
|
+
|
|
21
|
+
// Track dependencies for each observer to enable cleanup
|
|
22
|
+
const observerDependencies = new WeakMap<Observer, Set<ReactiveSource>>();
|
|
23
|
+
|
|
24
|
+
export const track = <T>(observer: Observer, fn: () => T): T => {
|
|
25
|
+
observerStack.push(observer);
|
|
26
|
+
try {
|
|
27
|
+
return fn();
|
|
28
|
+
} finally {
|
|
29
|
+
observerStack.pop();
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const getCurrentObserver = (): Observer | undefined =>
|
|
34
|
+
observerStack[observerStack.length - 1];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Executes a function without exposing the current observer to dependencies.
|
|
38
|
+
* Unlike disabling tracking globally, this still allows nested reactive internals
|
|
39
|
+
* (e.g., computed recomputation) to track their own dependencies.
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export const withoutCurrentObserver = <T>(fn: () => T): T => {
|
|
43
|
+
// Push undefined to temporarily "hide" the current observer
|
|
44
|
+
// This way, Signal.value reads won't link to the previous observer,
|
|
45
|
+
// but nested track() calls (e.g., computed recompute) still work normally.
|
|
46
|
+
observerStack.push(undefined as unknown as Observer);
|
|
47
|
+
try {
|
|
48
|
+
return fn();
|
|
49
|
+
} finally {
|
|
50
|
+
observerStack.pop();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const scheduleObserver = (observer: Observer): void => {
|
|
55
|
+
if (batchDepth > 0) {
|
|
56
|
+
pendingObservers.add(observer);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
observer();
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const flushObservers = (): void => {
|
|
63
|
+
for (const observer of Array.from(pendingObservers)) {
|
|
64
|
+
pendingObservers.delete(observer);
|
|
65
|
+
observer();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const beginBatch = (): void => {
|
|
70
|
+
batchDepth += 1;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const endBatch = (): void => {
|
|
74
|
+
batchDepth -= 1;
|
|
75
|
+
if (batchDepth === 0) {
|
|
76
|
+
flushObservers();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Registers a dependency between an observer and a reactive source.
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
export const registerDependency = (observer: Observer, source: ReactiveSource): void => {
|
|
85
|
+
let deps = observerDependencies.get(observer);
|
|
86
|
+
if (!deps) {
|
|
87
|
+
deps = new Set();
|
|
88
|
+
observerDependencies.set(observer, deps);
|
|
89
|
+
}
|
|
90
|
+
deps.add(source);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Clears all dependencies for an observer, unsubscribing from all sources.
|
|
95
|
+
* @internal
|
|
96
|
+
*/
|
|
97
|
+
export const clearDependencies = (observer: Observer): void => {
|
|
98
|
+
const deps = observerDependencies.get(observer);
|
|
99
|
+
if (deps) {
|
|
100
|
+
for (const source of deps) {
|
|
101
|
+
source.unsubscribe(observer);
|
|
102
|
+
}
|
|
103
|
+
deps.clear();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linked (writable) computed helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { computed, Computed } from './computed';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A writable computed-like signal.
|
|
9
|
+
*/
|
|
10
|
+
export interface LinkedSignal<T> {
|
|
11
|
+
/** Gets or sets the current value with dependency tracking. */
|
|
12
|
+
value: T;
|
|
13
|
+
/** Gets the current value without dependency tracking. */
|
|
14
|
+
peek(): T;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a writable computed signal by linking a getter and setter.
|
|
19
|
+
*
|
|
20
|
+
* @template T - The derived value type
|
|
21
|
+
* @param getValue - Getter that derives the current value
|
|
22
|
+
* @param setValue - Setter that writes back to underlying signals
|
|
23
|
+
* @returns A writable computed-like signal
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const first = signal('Ada');
|
|
28
|
+
* const last = signal('Lovelace');
|
|
29
|
+
* const fullName = linkedSignal(
|
|
30
|
+
* () => `${first.value} ${last.value}`,
|
|
31
|
+
* (next) => {
|
|
32
|
+
* const [a, b] = next.split(' ');
|
|
33
|
+
* first.value = a ?? '';
|
|
34
|
+
* last.value = b ?? '';
|
|
35
|
+
* }
|
|
36
|
+
* );
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export const linkedSignal = <T>(
|
|
40
|
+
getValue: () => T,
|
|
41
|
+
setValue: (value: T) => void
|
|
42
|
+
): LinkedSignal<T> => {
|
|
43
|
+
const derived: Computed<T> = computed(getValue);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
get value(): T {
|
|
47
|
+
return derived.value;
|
|
48
|
+
},
|
|
49
|
+
set value(next: T) {
|
|
50
|
+
setValue(next);
|
|
51
|
+
},
|
|
52
|
+
peek(): T {
|
|
53
|
+
return derived.peek();
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
};
|