@bitstillery/mithril 3.9.2 → 3.9.3
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/package.json +1 -1
- package/signal.ts +2 -2
- package/state.ts +73 -11
- package/store.ts +2 -1
package/package.json
CHANGED
package/signal.ts
CHANGED
|
@@ -188,7 +188,7 @@ export class ComputedSignal<T> extends Signal<T> {
|
|
|
188
188
|
this._compute = compute
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
get value(): T {
|
|
191
|
+
override get value(): T {
|
|
192
192
|
// Track access by other computed signals - this enables computed-to-computed dependency chains
|
|
193
193
|
// When computed B accesses computed A, A should notify B when A's dependencies change
|
|
194
194
|
if (currentEffect) {
|
|
@@ -259,7 +259,7 @@ export class ComputedSignal<T> extends Signal<T> {
|
|
|
259
259
|
this._markDirty()
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
set value(_newValue: T) {
|
|
262
|
+
override set value(_newValue: T) {
|
|
263
263
|
throw new Error('Computed signals are read-only')
|
|
264
264
|
}
|
|
265
265
|
}
|
package/state.ts
CHANGED
|
@@ -60,12 +60,37 @@ function isState(value: any): boolean {
|
|
|
60
60
|
return value && typeof value === 'object' && (value as any).__isState === true
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Built-ins whose methods need their internal slots. A proxy has none, and the get trap calls a
|
|
65
|
+
* function-valued property with the proxy as `this`, so a proxied Date or Map throws on every method
|
|
66
|
+
* call (and a Map's `get`/`set` read as a get/set descriptor). They are held as a signal's value
|
|
67
|
+
* instead, and replaced wholesale to notify.
|
|
68
|
+
*/
|
|
69
|
+
function isOpaqueObject(value: object): boolean {
|
|
70
|
+
return (
|
|
71
|
+
value instanceof Date ||
|
|
72
|
+
value instanceof Map ||
|
|
73
|
+
value instanceof Set ||
|
|
74
|
+
value instanceof WeakMap ||
|
|
75
|
+
value instanceof WeakSet ||
|
|
76
|
+
value instanceof RegExp ||
|
|
77
|
+
value instanceof Promise ||
|
|
78
|
+
value instanceof ArrayBuffer ||
|
|
79
|
+
ArrayBuffer.isView(value)
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
63
83
|
/**
|
|
64
84
|
* Check if a value is a get/set descriptor object (like JavaScript property descriptors)
|
|
65
85
|
* Used to detect computed properties defined as { get: () => T, set?: (value: T) => void }
|
|
66
86
|
*/
|
|
67
87
|
function isGetSetDescriptor(value: any): boolean {
|
|
68
|
-
return
|
|
88
|
+
return (
|
|
89
|
+
value &&
|
|
90
|
+
typeof value === 'object' &&
|
|
91
|
+
!isOpaqueObject(value) &&
|
|
92
|
+
(typeof value.get === 'function' || typeof value.set === 'function')
|
|
93
|
+
)
|
|
69
94
|
}
|
|
70
95
|
|
|
71
96
|
/**
|
|
@@ -203,7 +228,7 @@ export function state<T extends Record<string, any>>(initial: T, name?: string,
|
|
|
203
228
|
parentSignalMap?: Map<string, Signal<any> | ComputedSignal<any>>,
|
|
204
229
|
context?: InitContext,
|
|
205
230
|
): any {
|
|
206
|
-
if (obj === null || typeof obj !== 'object') {
|
|
231
|
+
if (obj === null || typeof obj !== 'object' || isOpaqueObject(obj)) {
|
|
207
232
|
return obj
|
|
208
233
|
}
|
|
209
234
|
|
|
@@ -863,6 +888,48 @@ export function state<T extends Record<string, any>>(initial: T, name?: string,
|
|
|
863
888
|
return wrapped
|
|
864
889
|
}
|
|
865
890
|
|
|
891
|
+
/** The built-ins `isOpaqueObject` keeps out of the proxy: state holds them as they are. */
|
|
892
|
+
type OpaqueObject =
|
|
893
|
+
| Date
|
|
894
|
+
| Map<any, any>
|
|
895
|
+
| Set<any>
|
|
896
|
+
| WeakMap<any, any>
|
|
897
|
+
| WeakSet<any>
|
|
898
|
+
| RegExp
|
|
899
|
+
| Promise<any>
|
|
900
|
+
| ArrayBuffer
|
|
901
|
+
| ArrayBufferView
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* A value as state hands it out: a function reads as its computed result, an object (or array) as its
|
|
905
|
+
* own State. Distributes over a union, so a nullable object (`Foo | null`) is still a State with its
|
|
906
|
+
* `$` signals once it is set.
|
|
907
|
+
*/
|
|
908
|
+
type StateValue<V> = V extends (...args: any[]) => infer R
|
|
909
|
+
? R
|
|
910
|
+
: V extends OpaqueObject
|
|
911
|
+
? V
|
|
912
|
+
: V extends Record<string, any>
|
|
913
|
+
? State<V>
|
|
914
|
+
: V
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* A property as state hands it out. Unlike an array element it doesn't distribute over a union, so a
|
|
918
|
+
* nullable object (`Foo | null`) stays its plain shape and a plain `Foo` can be written to it, as in 3.9.
|
|
919
|
+
* A `{get, set}` descriptor reads as its computed value.
|
|
920
|
+
*/
|
|
921
|
+
type StateProp<V> = [V] extends [never]
|
|
922
|
+
? V
|
|
923
|
+
: [V] extends [(...args: any[]) => infer R]
|
|
924
|
+
? R
|
|
925
|
+
: [V] extends [{get: () => infer R; set: (value: never) => void}]
|
|
926
|
+
? R
|
|
927
|
+
: [V] extends [OpaqueObject]
|
|
928
|
+
? V
|
|
929
|
+
: [V] extends [Record<string, any>]
|
|
930
|
+
? State<V>
|
|
931
|
+
: V
|
|
932
|
+
|
|
866
933
|
/**
|
|
867
934
|
* Mapped type that adds $prop for each key, returning the Signal for that property.
|
|
868
935
|
* - Primitives: $prop => Signal<T[K]>
|
|
@@ -874,24 +941,19 @@ export type StateSignals<T extends Record<string, any>> = {
|
|
|
874
941
|
// lookup by a `string` key would read as `Value | Signal<Value>`.
|
|
875
942
|
[K in keyof T as K extends string ? (string extends K ? never : `$${K}`) : never]: T[K] extends (...args: any[]) => infer R
|
|
876
943
|
? ComputedSignal<R>
|
|
877
|
-
: T[K]
|
|
878
|
-
? Signal<State<T[K]>>
|
|
879
|
-
: Signal<T[K]>
|
|
944
|
+
: Signal<StateProp<T[K]>>
|
|
880
945
|
}
|
|
881
|
-
type StateElem<E> = E extends Record<string, any> ? State<E> : E
|
|
882
946
|
|
|
883
|
-
export type StateArray<Elem> = Omit<Array<
|
|
947
|
+
export type StateArray<Elem> = Omit<Array<StateValue<Elem>>, 'fill' | 'push' | 'splice' | 'unshift'> & {
|
|
884
948
|
fill(value: Elem, start?: number, end?: number): StateArray<Elem>
|
|
885
949
|
push(...items: Elem[]): number
|
|
886
|
-
splice(start: number, deleteCount?: number, ...items: Elem[]):
|
|
950
|
+
splice(start: number, deleteCount?: number, ...items: Elem[]): StateValue<Elem>[]
|
|
887
951
|
unshift(...items: Elem[]): number
|
|
888
952
|
}
|
|
889
953
|
|
|
890
954
|
export type State<T extends Record<string, any>> = T extends (infer Elem)[]
|
|
891
955
|
? StateArray<Elem>
|
|
892
|
-
: {
|
|
893
|
-
[K in keyof T]: T[K] extends (...args: any[]) => infer R ? R : T[K] extends Record<string, any> ? State<T[K]> : T[K]
|
|
894
|
-
} & StateSignals<T>
|
|
956
|
+
: {[K in keyof T]: StateProp<T[K]>} & StateSignals<T>
|
|
895
957
|
|
|
896
958
|
/**
|
|
897
959
|
* A partial of a state shape at every depth, for the persistence tiers of a Store: each tier fills in
|
package/store.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {allowComputed, state,
|
|
1
|
+
import {allowComputed, state, updateStateRegistry} from './state'
|
|
2
|
+
import type {State, DeepPartial} from './state'
|
|
2
3
|
import {serializeStore, deserializeStore} from './render/ssrState'
|
|
3
4
|
|
|
4
5
|
// Helper function to restore computed properties (same as in ssrState.ts)
|