@bromscandium/core 1.0.0 → 1.0.2
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/LICENSE +20 -20
- package/README.md +59 -59
- package/package.json +38 -38
- package/src/dep.ts +148 -148
- package/src/effect.ts +263 -263
- package/src/index.ts +38 -38
- package/src/reactive.ts +162 -162
- package/src/ref.ts +243 -243
package/src/ref.ts
CHANGED
|
@@ -1,243 +1,243 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ref implementation for wrapping primitive and object values in reactive containers.
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { track, trigger, getActiveEffect } from './dep.js';
|
|
7
|
-
import { reactive, toRaw } from './reactive.js';
|
|
8
|
-
|
|
9
|
-
/** Internal flag used to identify ref objects */
|
|
10
|
-
export const RefFlag = '__b_isRef';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A reactive reference that wraps a value and tracks access to its `.value` property.
|
|
14
|
-
*/
|
|
15
|
-
export interface Ref<T = any> {
|
|
16
|
-
value: T;
|
|
17
|
-
readonly [RefFlag]: true;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A computed ref with a read-only value that is derived from other reactive state.
|
|
22
|
-
*/
|
|
23
|
-
export interface ComputedRef<T = any> extends Ref<T> {
|
|
24
|
-
readonly value: T;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
class RefImpl<T> {
|
|
28
|
-
private _value: T;
|
|
29
|
-
private _rawValue: T;
|
|
30
|
-
public readonly [RefFlag] = true;
|
|
31
|
-
|
|
32
|
-
constructor(value: T) {
|
|
33
|
-
this._rawValue = toRaw(value) as T;
|
|
34
|
-
this._value = toReactive(value);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
get value(): T {
|
|
38
|
-
trackRefValue(this);
|
|
39
|
-
return this._value;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
set value(newValue: T) {
|
|
43
|
-
const rawNewValue = toRaw(newValue) as T;
|
|
44
|
-
if (!Object.is(rawNewValue, this._rawValue)) {
|
|
45
|
-
this._rawValue = rawNewValue;
|
|
46
|
-
this._value = toReactive(newValue);
|
|
47
|
-
triggerRefValue(this);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function toReactive<T>(value: T): T {
|
|
53
|
-
return typeof value === 'object' && value !== null
|
|
54
|
-
? reactive(value as object) as T
|
|
55
|
-
: value;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function trackRefValue(ref: any): void {
|
|
59
|
-
if (getActiveEffect()) {
|
|
60
|
-
track(ref, 'value');
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function triggerRefValue(ref: any): void {
|
|
65
|
-
trigger(ref, 'value');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Creates a reactive reference for a value.
|
|
70
|
-
* Object values are automatically made deeply reactive.
|
|
71
|
-
*
|
|
72
|
-
* @param value - The initial value for the ref
|
|
73
|
-
* @returns A reactive ref containing the value
|
|
74
|
-
*
|
|
75
|
-
* @example
|
|
76
|
-
* ```ts
|
|
77
|
-
* const count = ref(0);
|
|
78
|
-
* console.log(count.value); // 0
|
|
79
|
-
* count.value++; // Triggers effects
|
|
80
|
-
*
|
|
81
|
-
* const obj = ref({ nested: 1 });
|
|
82
|
-
* obj.value.nested++; // Also triggers effects (deep reactivity)
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
export function ref<T>(value: T): Ref<T>;
|
|
86
|
-
export function ref<T = any>(): Ref<T | undefined>;
|
|
87
|
-
export function ref<T>(value?: T): Ref<T> {
|
|
88
|
-
if (isRef(value)) {
|
|
89
|
-
return value as Ref<T>;
|
|
90
|
-
}
|
|
91
|
-
return new RefImpl(value) as Ref<T>;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Checks if a value is a ref created by `ref()` or `computed()`.
|
|
96
|
-
*
|
|
97
|
-
* @param value - The value to check
|
|
98
|
-
* @returns True if the value is a ref
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```ts
|
|
102
|
-
* isRef(ref(0)); // true
|
|
103
|
-
* isRef(0); // false
|
|
104
|
-
* isRef(computed(() => 1)); // true
|
|
105
|
-
* ```
|
|
106
|
-
*/
|
|
107
|
-
export function isRef<T>(value: Ref<T> | unknown): value is Ref<T> {
|
|
108
|
-
return !!(value && (value as any)[RefFlag] === true);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Unwraps a ref to get its inner value. Returns the value directly if not a ref.
|
|
113
|
-
*
|
|
114
|
-
* @param ref - A ref or plain value to unwrap
|
|
115
|
-
* @returns The unwrapped value
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* ```ts
|
|
119
|
-
* unref(ref(1)); // 1
|
|
120
|
-
* unref(1); // 1
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
export function unref<T>(ref: T | Ref<T>): T {
|
|
124
|
-
return isRef(ref) ? ref.value : ref;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Creates a ref that syncs with a property of a reactive object.
|
|
129
|
-
* The ref stays connected to the source object.
|
|
130
|
-
*
|
|
131
|
-
* @param object - The source reactive object
|
|
132
|
-
* @param key - The property key to create a ref for
|
|
133
|
-
* @returns A ref linked to the specified property
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* ```ts
|
|
137
|
-
* const state = reactive({ count: 0 });
|
|
138
|
-
* const countRef = toRef(state, 'count');
|
|
139
|
-
* countRef.value++; // Also updates state.count
|
|
140
|
-
* ```
|
|
141
|
-
*/
|
|
142
|
-
export function toRef<T extends object, K extends keyof T>(
|
|
143
|
-
object: T,
|
|
144
|
-
key: K
|
|
145
|
-
): Ref<T[K]> {
|
|
146
|
-
const val = object[key];
|
|
147
|
-
if (isRef(val)) {
|
|
148
|
-
return val as Ref<T[K]>;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
get value() {
|
|
153
|
-
return object[key];
|
|
154
|
-
},
|
|
155
|
-
set value(newValue) {
|
|
156
|
-
object[key] = newValue;
|
|
157
|
-
},
|
|
158
|
-
[RefFlag]: true,
|
|
159
|
-
} as Ref<T[K]>;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Converts all properties of a reactive object into refs.
|
|
164
|
-
* Each ref is linked to the corresponding property on the source object.
|
|
165
|
-
*
|
|
166
|
-
* @param object - The source reactive object
|
|
167
|
-
* @returns An object with the same keys, where each value is a ref
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* ```ts
|
|
171
|
-
* const state = reactive({ count: 0, name: 'test' });
|
|
172
|
-
* const { count, name } = toRefs(state);
|
|
173
|
-
* count.value++; // Updates state.count
|
|
174
|
-
* ```
|
|
175
|
-
*/
|
|
176
|
-
export function toRefs<T extends object>(object: T): { [K in keyof T]: Ref<T[K]> } {
|
|
177
|
-
const result: any = {};
|
|
178
|
-
for (const key in object) {
|
|
179
|
-
result[key] = toRef(object, key);
|
|
180
|
-
}
|
|
181
|
-
return result;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* A shallow ref type (same interface as Ref but without deep reactivity).
|
|
186
|
-
*/
|
|
187
|
-
export type ShallowRef<T = any> = Ref<T>;
|
|
188
|
-
|
|
189
|
-
class ShallowRefImpl<T> {
|
|
190
|
-
private _value: T;
|
|
191
|
-
public readonly [RefFlag] = true;
|
|
192
|
-
|
|
193
|
-
constructor(value: T) {
|
|
194
|
-
this._value = value;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
get value(): T {
|
|
198
|
-
trackRefValue(this);
|
|
199
|
-
return this._value;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
set value(newValue: T) {
|
|
203
|
-
if (!Object.is(newValue, this._value)) {
|
|
204
|
-
this._value = newValue;
|
|
205
|
-
triggerRefValue(this);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Creates a ref that does not make its value deeply reactive.
|
|
212
|
-
* Only reassigning `.value` will trigger effects, not mutations to nested properties.
|
|
213
|
-
*
|
|
214
|
-
* @param value - The initial value for the shallow ref
|
|
215
|
-
* @returns A shallow ref containing the value
|
|
216
|
-
*
|
|
217
|
-
* @example
|
|
218
|
-
* ```ts
|
|
219
|
-
* const state = shallowRef({ nested: 0 });
|
|
220
|
-
* state.value.nested++; // Does NOT trigger effects
|
|
221
|
-
* state.value = { nested: 1 }; // Triggers effects
|
|
222
|
-
* ```
|
|
223
|
-
*/
|
|
224
|
-
export function shallowRef<T>(value: T): ShallowRef<T> {
|
|
225
|
-
return new ShallowRefImpl(value) as ShallowRef<T>;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Manually triggers effects that depend on a ref.
|
|
230
|
-
* Useful after mutating the inner value of a shallow ref.
|
|
231
|
-
*
|
|
232
|
-
* @param ref - The ref to trigger
|
|
233
|
-
*
|
|
234
|
-
* @example
|
|
235
|
-
* ```ts
|
|
236
|
-
* const state = shallowRef({ count: 0 });
|
|
237
|
-
* state.value.count++; // No automatic trigger
|
|
238
|
-
* triggerRef(state); // Manually trigger effects
|
|
239
|
-
* ```
|
|
240
|
-
*/
|
|
241
|
-
export function triggerRef(ref: Ref): void {
|
|
242
|
-
triggerRefValue(ref);
|
|
243
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Ref implementation for wrapping primitive and object values in reactive containers.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { track, trigger, getActiveEffect } from './dep.js';
|
|
7
|
+
import { reactive, toRaw } from './reactive.js';
|
|
8
|
+
|
|
9
|
+
/** Internal flag used to identify ref objects */
|
|
10
|
+
export const RefFlag = '__b_isRef';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A reactive reference that wraps a value and tracks access to its `.value` property.
|
|
14
|
+
*/
|
|
15
|
+
export interface Ref<T = any> {
|
|
16
|
+
value: T;
|
|
17
|
+
readonly [RefFlag]: true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A computed ref with a read-only value that is derived from other reactive state.
|
|
22
|
+
*/
|
|
23
|
+
export interface ComputedRef<T = any> extends Ref<T> {
|
|
24
|
+
readonly value: T;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class RefImpl<T> {
|
|
28
|
+
private _value: T;
|
|
29
|
+
private _rawValue: T;
|
|
30
|
+
public readonly [RefFlag] = true;
|
|
31
|
+
|
|
32
|
+
constructor(value: T) {
|
|
33
|
+
this._rawValue = toRaw(value) as T;
|
|
34
|
+
this._value = toReactive(value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get value(): T {
|
|
38
|
+
trackRefValue(this);
|
|
39
|
+
return this._value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
set value(newValue: T) {
|
|
43
|
+
const rawNewValue = toRaw(newValue) as T;
|
|
44
|
+
if (!Object.is(rawNewValue, this._rawValue)) {
|
|
45
|
+
this._rawValue = rawNewValue;
|
|
46
|
+
this._value = toReactive(newValue);
|
|
47
|
+
triggerRefValue(this);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function toReactive<T>(value: T): T {
|
|
53
|
+
return typeof value === 'object' && value !== null
|
|
54
|
+
? reactive(value as object) as T
|
|
55
|
+
: value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function trackRefValue(ref: any): void {
|
|
59
|
+
if (getActiveEffect()) {
|
|
60
|
+
track(ref, 'value');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function triggerRefValue(ref: any): void {
|
|
65
|
+
trigger(ref, 'value');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Creates a reactive reference for a value.
|
|
70
|
+
* Object values are automatically made deeply reactive.
|
|
71
|
+
*
|
|
72
|
+
* @param value - The initial value for the ref
|
|
73
|
+
* @returns A reactive ref containing the value
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const count = ref(0);
|
|
78
|
+
* console.log(count.value); // 0
|
|
79
|
+
* count.value++; // Triggers effects
|
|
80
|
+
*
|
|
81
|
+
* const obj = ref({ nested: 1 });
|
|
82
|
+
* obj.value.nested++; // Also triggers effects (deep reactivity)
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export function ref<T>(value: T): Ref<T>;
|
|
86
|
+
export function ref<T = any>(): Ref<T | undefined>;
|
|
87
|
+
export function ref<T>(value?: T): Ref<T> {
|
|
88
|
+
if (isRef(value)) {
|
|
89
|
+
return value as Ref<T>;
|
|
90
|
+
}
|
|
91
|
+
return new RefImpl(value) as Ref<T>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Checks if a value is a ref created by `ref()` or `computed()`.
|
|
96
|
+
*
|
|
97
|
+
* @param value - The value to check
|
|
98
|
+
* @returns True if the value is a ref
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* isRef(ref(0)); // true
|
|
103
|
+
* isRef(0); // false
|
|
104
|
+
* isRef(computed(() => 1)); // true
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export function isRef<T>(value: Ref<T> | unknown): value is Ref<T> {
|
|
108
|
+
return !!(value && (value as any)[RefFlag] === true);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Unwraps a ref to get its inner value. Returns the value directly if not a ref.
|
|
113
|
+
*
|
|
114
|
+
* @param ref - A ref or plain value to unwrap
|
|
115
|
+
* @returns The unwrapped value
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* unref(ref(1)); // 1
|
|
120
|
+
* unref(1); // 1
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export function unref<T>(ref: T | Ref<T>): T {
|
|
124
|
+
return isRef(ref) ? ref.value : ref;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Creates a ref that syncs with a property of a reactive object.
|
|
129
|
+
* The ref stays connected to the source object.
|
|
130
|
+
*
|
|
131
|
+
* @param object - The source reactive object
|
|
132
|
+
* @param key - The property key to create a ref for
|
|
133
|
+
* @returns A ref linked to the specified property
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* const state = reactive({ count: 0 });
|
|
138
|
+
* const countRef = toRef(state, 'count');
|
|
139
|
+
* countRef.value++; // Also updates state.count
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export function toRef<T extends object, K extends keyof T>(
|
|
143
|
+
object: T,
|
|
144
|
+
key: K
|
|
145
|
+
): Ref<T[K]> {
|
|
146
|
+
const val = object[key];
|
|
147
|
+
if (isRef(val)) {
|
|
148
|
+
return val as Ref<T[K]>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
get value() {
|
|
153
|
+
return object[key];
|
|
154
|
+
},
|
|
155
|
+
set value(newValue) {
|
|
156
|
+
object[key] = newValue;
|
|
157
|
+
},
|
|
158
|
+
[RefFlag]: true,
|
|
159
|
+
} as Ref<T[K]>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Converts all properties of a reactive object into refs.
|
|
164
|
+
* Each ref is linked to the corresponding property on the source object.
|
|
165
|
+
*
|
|
166
|
+
* @param object - The source reactive object
|
|
167
|
+
* @returns An object with the same keys, where each value is a ref
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* const state = reactive({ count: 0, name: 'test' });
|
|
172
|
+
* const { count, name } = toRefs(state);
|
|
173
|
+
* count.value++; // Updates state.count
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export function toRefs<T extends object>(object: T): { [K in keyof T]: Ref<T[K]> } {
|
|
177
|
+
const result: any = {};
|
|
178
|
+
for (const key in object) {
|
|
179
|
+
result[key] = toRef(object, key);
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* A shallow ref type (same interface as Ref but without deep reactivity).
|
|
186
|
+
*/
|
|
187
|
+
export type ShallowRef<T = any> = Ref<T>;
|
|
188
|
+
|
|
189
|
+
class ShallowRefImpl<T> {
|
|
190
|
+
private _value: T;
|
|
191
|
+
public readonly [RefFlag] = true;
|
|
192
|
+
|
|
193
|
+
constructor(value: T) {
|
|
194
|
+
this._value = value;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
get value(): T {
|
|
198
|
+
trackRefValue(this);
|
|
199
|
+
return this._value;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
set value(newValue: T) {
|
|
203
|
+
if (!Object.is(newValue, this._value)) {
|
|
204
|
+
this._value = newValue;
|
|
205
|
+
triggerRefValue(this);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Creates a ref that does not make its value deeply reactive.
|
|
212
|
+
* Only reassigning `.value` will trigger effects, not mutations to nested properties.
|
|
213
|
+
*
|
|
214
|
+
* @param value - The initial value for the shallow ref
|
|
215
|
+
* @returns A shallow ref containing the value
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* const state = shallowRef({ nested: 0 });
|
|
220
|
+
* state.value.nested++; // Does NOT trigger effects
|
|
221
|
+
* state.value = { nested: 1 }; // Triggers effects
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
export function shallowRef<T>(value: T): ShallowRef<T> {
|
|
225
|
+
return new ShallowRefImpl(value) as ShallowRef<T>;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Manually triggers effects that depend on a ref.
|
|
230
|
+
* Useful after mutating the inner value of a shallow ref.
|
|
231
|
+
*
|
|
232
|
+
* @param ref - The ref to trigger
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* const state = shallowRef({ count: 0 });
|
|
237
|
+
* state.value.count++; // No automatic trigger
|
|
238
|
+
* triggerRef(state); // Manually trigger effects
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
export function triggerRef(ref: Ref): void {
|
|
242
|
+
triggerRefValue(ref);
|
|
243
|
+
}
|