@amazon/vinyl-observable 1.0.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/dist/index.cjs +275 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.js +255 -0
- package/dist/index.js.map +7 -0
- package/dist/types/current/index.d.ts +4 -0
- package/dist/types/current/index.d.ts.map +1 -0
- package/dist/types/current/index.js +3 -0
- package/dist/types/current/observable/combineData.d.ts +11 -0
- package/dist/types/current/observable/combineData.d.ts.map +1 -0
- package/dist/types/current/observable/combineData.js +41 -0
- package/dist/types/current/observable/observableValue.d.ts +153 -0
- package/dist/types/current/observable/observableValue.d.ts.map +1 -0
- package/dist/types/current/observable/observableValue.js +224 -0
- package/dist/types/current/tsconfig.tsbuildinfo +1 -0
- package/dist/types/ts3.7/index.d.ts +4 -0
- package/dist/types/ts3.7/observable/combineData.d.ts +11 -0
- package/dist/types/ts3.7/observable/observableValue.d.ts +153 -0
- package/dist/types/ts4.1/index.d.ts +4 -0
- package/dist/types/ts4.1/observable/combineData.d.ts +11 -0
- package/dist/types/ts4.1/observable/observableValue.d.ts +153 -0
- package/dist/types/ts4.7/index.d.ts +4 -0
- package/dist/types/ts4.7/observable/combineData.d.ts +11 -0
- package/dist/types/ts4.7/observable/observableValue.d.ts +153 -0
- package/docs/OBSERVABLE.md +95 -0
- package/package.json +81 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Maybe, Unsubscribe } from '@amazon/vinyl-util';
|
|
2
|
+
export interface ObservableValue<T> {
|
|
3
|
+
/**
|
|
4
|
+
* Invokes a callback immediately and when data has changed.
|
|
5
|
+
* @param callback
|
|
6
|
+
*/
|
|
7
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a data provider transforming this data.
|
|
10
|
+
*/
|
|
11
|
+
map<U>(transform: (value: T) => U): ObservableValue<U>;
|
|
12
|
+
/**
|
|
13
|
+
* Returns a data provider for a property of T.
|
|
14
|
+
*/
|
|
15
|
+
pick<K extends keyof NonNullable<T>>(prop: K): ObservableValue<Picked<T, K>>;
|
|
16
|
+
pick(prop: PropertyKey): ObservableValue<unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* The current value.
|
|
19
|
+
*/
|
|
20
|
+
readonly value: T;
|
|
21
|
+
/**
|
|
22
|
+
* Gets the current value.
|
|
23
|
+
*/
|
|
24
|
+
getValue(): T;
|
|
25
|
+
/**
|
|
26
|
+
* A monotonically increasing id that increments before each change notification.
|
|
27
|
+
*/
|
|
28
|
+
readonly changeId: number;
|
|
29
|
+
}
|
|
30
|
+
export type MaybeObservableValue<T> = ObservableValue<T> | T;
|
|
31
|
+
/**
|
|
32
|
+
* Given an ObservableValue<ValueType>, infers ValueType.
|
|
33
|
+
*/
|
|
34
|
+
export type InferObservableValueType<T extends ObservableValue<any>> = T extends ObservableValue<infer U> ? U : never;
|
|
35
|
+
/**
|
|
36
|
+
* A mutable version of a data provider.
|
|
37
|
+
*/
|
|
38
|
+
export interface MutableValue<T> extends ObservableValue<T> {
|
|
39
|
+
/**
|
|
40
|
+
* The current value, may be set.
|
|
41
|
+
* `onData` callbacks will be invoked if value is not exactly equal to
|
|
42
|
+
* the current value.
|
|
43
|
+
*/
|
|
44
|
+
value: T;
|
|
45
|
+
/**
|
|
46
|
+
* Sets the current value.
|
|
47
|
+
*/
|
|
48
|
+
setValue(value: T): void;
|
|
49
|
+
/**
|
|
50
|
+
* Creates a readonly sub-controller for a transformed value.
|
|
51
|
+
*
|
|
52
|
+
* @param transform Applies a transformation to a single value using a provided function and returns the result.
|
|
53
|
+
* The returned sub controller will use this as its value.
|
|
54
|
+
*/
|
|
55
|
+
map<U>(transform: (value: T) => U): ObservableValue<U>;
|
|
56
|
+
/**
|
|
57
|
+
* Creates a writable sub-controller for a transformed value.
|
|
58
|
+
*
|
|
59
|
+
* @param transform Applies a transformation to a single value using a provided function and returns the result.
|
|
60
|
+
* The returned sub controller will use this as its value.
|
|
61
|
+
* @param setData The reverse of transform; When the sub-controller's data is set, this will convert the
|
|
62
|
+
* transformed value back to what can be saved on `this` controller.
|
|
63
|
+
*/
|
|
64
|
+
map<U>(transform: (value: T) => U, setData: (transformed: U, original: T) => T): MutableValue<U>;
|
|
65
|
+
/**
|
|
66
|
+
* Returns a data controller for a property of T.
|
|
67
|
+
*/
|
|
68
|
+
pick<K extends keyof NonNullable<T>>(prop: K): MutableValue<Picked<T, K>>;
|
|
69
|
+
pick(prop: PropertyKey): MutableValue<unknown>;
|
|
70
|
+
/**
|
|
71
|
+
* Invokes subscribers, can be used to indicate a change without setting
|
|
72
|
+
* a new value.
|
|
73
|
+
*/
|
|
74
|
+
invalidate(): void;
|
|
75
|
+
}
|
|
76
|
+
export type DataChangedCallback<T> = (
|
|
77
|
+
/**
|
|
78
|
+
* The current value.
|
|
79
|
+
*/
|
|
80
|
+
value: T,
|
|
81
|
+
/**
|
|
82
|
+
* The previous value, or undefined if this is the first time calling this callback.
|
|
83
|
+
*/
|
|
84
|
+
previousValue: T | undefined) => void;
|
|
85
|
+
export type Picked<T, K extends keyof NonNullable<T>> = T extends undefined | null ? NonNullable<T>[K] | undefined : NonNullable<T>[K];
|
|
86
|
+
declare abstract class MutableValueBase<T> implements MutableValue<T> {
|
|
87
|
+
abstract value: T;
|
|
88
|
+
abstract readonly changeId: number;
|
|
89
|
+
getValue(): T;
|
|
90
|
+
setValue(value: T): void;
|
|
91
|
+
abstract onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
92
|
+
map<U>(transform: {
|
|
93
|
+
(value: T): U;
|
|
94
|
+
}, setData?: Maybe<(transformed: U, original: T) => T>): MutableValue<U>;
|
|
95
|
+
pick<K extends keyof NonNullable<T>>(prop: K): MutableValue<Picked<T, K>>;
|
|
96
|
+
abstract invalidate(): void;
|
|
97
|
+
}
|
|
98
|
+
export declare class MutableValueImpl<T> extends MutableValueBase<T> {
|
|
99
|
+
private currentValue;
|
|
100
|
+
private _disposed;
|
|
101
|
+
private currentIndex;
|
|
102
|
+
private n;
|
|
103
|
+
private readonly callbacks;
|
|
104
|
+
private _changeId;
|
|
105
|
+
constructor(currentValue: T);
|
|
106
|
+
get changeId(): number;
|
|
107
|
+
hasAnyListeners(): boolean;
|
|
108
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
109
|
+
get value(): T;
|
|
110
|
+
set value(value: T);
|
|
111
|
+
invalidate(): void;
|
|
112
|
+
get disposed(): boolean;
|
|
113
|
+
dispose(): void;
|
|
114
|
+
private notify;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns true if the value is a ObservableValue.
|
|
118
|
+
* @param value
|
|
119
|
+
*/
|
|
120
|
+
export declare function isObservableValue(value: any): value is ObservableValue<any>;
|
|
121
|
+
/**
|
|
122
|
+
* Creates a data provider.
|
|
123
|
+
* @param value
|
|
124
|
+
*/
|
|
125
|
+
export declare function data<T>(value: T): MutableValueImpl<T>;
|
|
126
|
+
/**
|
|
127
|
+
* If the value is a ObservableValue, returns the data provider as is. Otherwise, wraps the value in
|
|
128
|
+
* provider.
|
|
129
|
+
*
|
|
130
|
+
* @param value
|
|
131
|
+
*/
|
|
132
|
+
export declare function asData<T>(value: MaybeObservableValue<T>): ObservableValue<T>;
|
|
133
|
+
export type OnDataRequested<T> = (setData: (value: T) => void) => Unsubscribe;
|
|
134
|
+
export declare class ExternalMutableValue<T> extends MutableValueBase<T> {
|
|
135
|
+
private readonly onDataRequested;
|
|
136
|
+
private _data;
|
|
137
|
+
private externalDataSub;
|
|
138
|
+
constructor(currentValue: T, onDataRequested: OnDataRequested<T>);
|
|
139
|
+
get value(): T;
|
|
140
|
+
get changeId(): number;
|
|
141
|
+
set value(_value: T);
|
|
142
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
143
|
+
invalidate(): void;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Creates a data provider that can observe an external event system when onData is called.
|
|
147
|
+
*
|
|
148
|
+
* @param initialValue
|
|
149
|
+
* @param onDataRequested
|
|
150
|
+
*/
|
|
151
|
+
export declare function externalData<T>(initialValue: T, onDataRequested: (setData: (value: T) => void) => Unsubscribe): ObservableValue<T>;
|
|
152
|
+
export {};
|
|
153
|
+
//# sourceMappingURL=observableValue.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ObservableValue } from './observableValue';
|
|
2
|
+
import type { ReadonlyRecord } from '@amazon/vinyl-util';
|
|
3
|
+
/**
|
|
4
|
+
* Combines a record of data providers into a single provider of a record of values.
|
|
5
|
+
*
|
|
6
|
+
* @param inputs A record of data providers.
|
|
7
|
+
*/
|
|
8
|
+
export declare function combineData<T extends ReadonlyRecord<string, ObservableValue<unknown>>>(inputs: T): ObservableValue<{
|
|
9
|
+
readonly [K in keyof T]: T[K] extends ObservableValue<infer U> ? U : T[K];
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=combineData.d.ts.map
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { Maybe, Unsubscribe } from '@amazon/vinyl-util';
|
|
2
|
+
export interface ObservableValue<T> {
|
|
3
|
+
/**
|
|
4
|
+
* Invokes a callback immediately and when data has changed.
|
|
5
|
+
* @param callback
|
|
6
|
+
*/
|
|
7
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a data provider transforming this data.
|
|
10
|
+
*/
|
|
11
|
+
map<U>(transform: (value: T) => U): ObservableValue<U>;
|
|
12
|
+
/**
|
|
13
|
+
* Returns a data provider for a property of T.
|
|
14
|
+
*/
|
|
15
|
+
pick<K extends keyof NonNullable<T>>(prop: K): ObservableValue<Picked<T, K>>;
|
|
16
|
+
pick(prop: PropertyKey): ObservableValue<unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* The current value.
|
|
19
|
+
*/
|
|
20
|
+
readonly value: T;
|
|
21
|
+
/**
|
|
22
|
+
* Gets the current value.
|
|
23
|
+
*/
|
|
24
|
+
getValue(): T;
|
|
25
|
+
/**
|
|
26
|
+
* A monotonically increasing id that increments before each change notification.
|
|
27
|
+
*/
|
|
28
|
+
readonly changeId: number;
|
|
29
|
+
}
|
|
30
|
+
export type MaybeObservableValue<T> = ObservableValue<T> | T;
|
|
31
|
+
/**
|
|
32
|
+
* Given an ObservableValue<ValueType>, infers ValueType.
|
|
33
|
+
*/
|
|
34
|
+
export type InferObservableValueType<T extends ObservableValue<any>> = T extends ObservableValue<infer U> ? U : never;
|
|
35
|
+
/**
|
|
36
|
+
* A mutable version of a data provider.
|
|
37
|
+
*/
|
|
38
|
+
export interface MutableValue<T> extends ObservableValue<T> {
|
|
39
|
+
/**
|
|
40
|
+
* The current value, may be set.
|
|
41
|
+
* `onData` callbacks will be invoked if value is not exactly equal to
|
|
42
|
+
* the current value.
|
|
43
|
+
*/
|
|
44
|
+
value: T;
|
|
45
|
+
/**
|
|
46
|
+
* Sets the current value.
|
|
47
|
+
*/
|
|
48
|
+
setValue(value: T): void;
|
|
49
|
+
/**
|
|
50
|
+
* Creates a readonly sub-controller for a transformed value.
|
|
51
|
+
*
|
|
52
|
+
* @param transform Applies a transformation to a single value using a provided function and returns the result.
|
|
53
|
+
* The returned sub controller will use this as its value.
|
|
54
|
+
*/
|
|
55
|
+
map<U>(transform: (value: T) => U): ObservableValue<U>;
|
|
56
|
+
/**
|
|
57
|
+
* Creates a writable sub-controller for a transformed value.
|
|
58
|
+
*
|
|
59
|
+
* @param transform Applies a transformation to a single value using a provided function and returns the result.
|
|
60
|
+
* The returned sub controller will use this as its value.
|
|
61
|
+
* @param setData The reverse of transform; When the sub-controller's data is set, this will convert the
|
|
62
|
+
* transformed value back to what can be saved on `this` controller.
|
|
63
|
+
*/
|
|
64
|
+
map<U>(transform: (value: T) => U, setData: (transformed: U, original: T) => T): MutableValue<U>;
|
|
65
|
+
/**
|
|
66
|
+
* Returns a data controller for a property of T.
|
|
67
|
+
*/
|
|
68
|
+
pick<K extends keyof NonNullable<T>>(prop: K): MutableValue<Picked<T, K>>;
|
|
69
|
+
pick(prop: PropertyKey): MutableValue<unknown>;
|
|
70
|
+
/**
|
|
71
|
+
* Invokes subscribers, can be used to indicate a change without setting
|
|
72
|
+
* a new value.
|
|
73
|
+
*/
|
|
74
|
+
invalidate(): void;
|
|
75
|
+
}
|
|
76
|
+
export type DataChangedCallback<T> = (
|
|
77
|
+
/**
|
|
78
|
+
* The current value.
|
|
79
|
+
*/
|
|
80
|
+
value: T,
|
|
81
|
+
/**
|
|
82
|
+
* The previous value, or undefined if this is the first time calling this callback.
|
|
83
|
+
*/
|
|
84
|
+
previousValue: T | undefined) => void;
|
|
85
|
+
export type Picked<T, K extends keyof NonNullable<T>> = T extends undefined | null ? NonNullable<T>[K] | undefined : NonNullable<T>[K];
|
|
86
|
+
declare abstract class MutableValueBase<T> implements MutableValue<T> {
|
|
87
|
+
abstract value: T;
|
|
88
|
+
abstract readonly changeId: number;
|
|
89
|
+
getValue(): T;
|
|
90
|
+
setValue(value: T): void;
|
|
91
|
+
abstract onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
92
|
+
map<U>(transform: {
|
|
93
|
+
(value: T): U;
|
|
94
|
+
}, setData?: Maybe<(transformed: U, original: T) => T>): MutableValue<U>;
|
|
95
|
+
pick<K extends keyof NonNullable<T>>(prop: K): MutableValue<Picked<T, K>>;
|
|
96
|
+
abstract invalidate(): void;
|
|
97
|
+
}
|
|
98
|
+
export declare class MutableValueImpl<T> extends MutableValueBase<T> {
|
|
99
|
+
private currentValue;
|
|
100
|
+
private _disposed;
|
|
101
|
+
private currentIndex;
|
|
102
|
+
private n;
|
|
103
|
+
private readonly callbacks;
|
|
104
|
+
private _changeId;
|
|
105
|
+
constructor(currentValue: T);
|
|
106
|
+
get changeId(): number;
|
|
107
|
+
hasAnyListeners(): boolean;
|
|
108
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
109
|
+
get value(): T;
|
|
110
|
+
set value(value: T);
|
|
111
|
+
invalidate(): void;
|
|
112
|
+
get disposed(): boolean;
|
|
113
|
+
dispose(): void;
|
|
114
|
+
private notify;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns true if the value is a ObservableValue.
|
|
118
|
+
* @param value
|
|
119
|
+
*/
|
|
120
|
+
export declare function isObservableValue(value: any): value is ObservableValue<any>;
|
|
121
|
+
/**
|
|
122
|
+
* Creates a data provider.
|
|
123
|
+
* @param value
|
|
124
|
+
*/
|
|
125
|
+
export declare function data<T>(value: T): MutableValueImpl<T>;
|
|
126
|
+
/**
|
|
127
|
+
* If the value is a ObservableValue, returns the data provider as is. Otherwise, wraps the value in
|
|
128
|
+
* provider.
|
|
129
|
+
*
|
|
130
|
+
* @param value
|
|
131
|
+
*/
|
|
132
|
+
export declare function asData<T>(value: MaybeObservableValue<T>): ObservableValue<T>;
|
|
133
|
+
export type OnDataRequested<T> = (setData: (value: T) => void) => Unsubscribe;
|
|
134
|
+
export declare class ExternalMutableValue<T> extends MutableValueBase<T> {
|
|
135
|
+
private readonly onDataRequested;
|
|
136
|
+
private _data;
|
|
137
|
+
private externalDataSub;
|
|
138
|
+
constructor(currentValue: T, onDataRequested: OnDataRequested<T>);
|
|
139
|
+
get value(): T;
|
|
140
|
+
get changeId(): number;
|
|
141
|
+
set value(_value: T);
|
|
142
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
143
|
+
invalidate(): void;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Creates a data provider that can observe an external event system when onData is called.
|
|
147
|
+
*
|
|
148
|
+
* @param initialValue
|
|
149
|
+
* @param onDataRequested
|
|
150
|
+
*/
|
|
151
|
+
export declare function externalData<T>(initialValue: T, onDataRequested: (setData: (value: T) => void) => Unsubscribe): ObservableValue<T>;
|
|
152
|
+
export {};
|
|
153
|
+
//# sourceMappingURL=observableValue.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ObservableValue } from './observableValue';
|
|
2
|
+
import type { ReadonlyRecord } from '@amazon/vinyl-util';
|
|
3
|
+
/**
|
|
4
|
+
* Combines a record of data providers into a single provider of a record of values.
|
|
5
|
+
*
|
|
6
|
+
* @param inputs A record of data providers.
|
|
7
|
+
*/
|
|
8
|
+
export declare function combineData<T extends ReadonlyRecord<string, ObservableValue<unknown>>>(inputs: T): ObservableValue<{
|
|
9
|
+
readonly [K in keyof T]: T[K] extends ObservableValue<infer U> ? U : T[K];
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=combineData.d.ts.map
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { Maybe, Unsubscribe } from '@amazon/vinyl-util';
|
|
2
|
+
export interface ObservableValue<out T> {
|
|
3
|
+
/**
|
|
4
|
+
* Invokes a callback immediately and when data has changed.
|
|
5
|
+
* @param callback
|
|
6
|
+
*/
|
|
7
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a data provider transforming this data.
|
|
10
|
+
*/
|
|
11
|
+
map<U>(transform: (value: T) => U): ObservableValue<U>;
|
|
12
|
+
/**
|
|
13
|
+
* Returns a data provider for a property of T.
|
|
14
|
+
*/
|
|
15
|
+
pick<K extends keyof NonNullable<T>>(prop: K): ObservableValue<Picked<T, K>>;
|
|
16
|
+
pick(prop: PropertyKey): ObservableValue<unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* The current value.
|
|
19
|
+
*/
|
|
20
|
+
readonly value: T;
|
|
21
|
+
/**
|
|
22
|
+
* Gets the current value.
|
|
23
|
+
*/
|
|
24
|
+
getValue(): T;
|
|
25
|
+
/**
|
|
26
|
+
* A monotonically increasing id that increments before each change notification.
|
|
27
|
+
*/
|
|
28
|
+
readonly changeId: number;
|
|
29
|
+
}
|
|
30
|
+
export type MaybeObservableValue<T> = ObservableValue<T> | T;
|
|
31
|
+
/**
|
|
32
|
+
* Given an ObservableValue<ValueType>, infers ValueType.
|
|
33
|
+
*/
|
|
34
|
+
export type InferObservableValueType<T extends ObservableValue<any>> = T extends ObservableValue<infer U> ? U : never;
|
|
35
|
+
/**
|
|
36
|
+
* A mutable version of a data provider.
|
|
37
|
+
*/
|
|
38
|
+
export interface MutableValue<T> extends ObservableValue<T> {
|
|
39
|
+
/**
|
|
40
|
+
* The current value, may be set.
|
|
41
|
+
* `onData` callbacks will be invoked if value is not exactly equal to
|
|
42
|
+
* the current value.
|
|
43
|
+
*/
|
|
44
|
+
value: T;
|
|
45
|
+
/**
|
|
46
|
+
* Sets the current value.
|
|
47
|
+
*/
|
|
48
|
+
setValue(value: T): void;
|
|
49
|
+
/**
|
|
50
|
+
* Creates a readonly sub-controller for a transformed value.
|
|
51
|
+
*
|
|
52
|
+
* @param transform Applies a transformation to a single value using a provided function and returns the result.
|
|
53
|
+
* The returned sub controller will use this as its value.
|
|
54
|
+
*/
|
|
55
|
+
map<U>(transform: (value: T) => U): ObservableValue<U>;
|
|
56
|
+
/**
|
|
57
|
+
* Creates a writable sub-controller for a transformed value.
|
|
58
|
+
*
|
|
59
|
+
* @param transform Applies a transformation to a single value using a provided function and returns the result.
|
|
60
|
+
* The returned sub controller will use this as its value.
|
|
61
|
+
* @param setData The reverse of transform; When the sub-controller's data is set, this will convert the
|
|
62
|
+
* transformed value back to what can be saved on `this` controller.
|
|
63
|
+
*/
|
|
64
|
+
map<U>(transform: (value: T) => U, setData: (transformed: U, original: T) => T): MutableValue<U>;
|
|
65
|
+
/**
|
|
66
|
+
* Returns a data controller for a property of T.
|
|
67
|
+
*/
|
|
68
|
+
pick<K extends keyof NonNullable<T>>(prop: K): MutableValue<Picked<T, K>>;
|
|
69
|
+
pick(prop: PropertyKey): MutableValue<unknown>;
|
|
70
|
+
/**
|
|
71
|
+
* Invokes subscribers, can be used to indicate a change without setting
|
|
72
|
+
* a new value.
|
|
73
|
+
*/
|
|
74
|
+
invalidate(): void;
|
|
75
|
+
}
|
|
76
|
+
export type DataChangedCallback<T> = (
|
|
77
|
+
/**
|
|
78
|
+
* The current value.
|
|
79
|
+
*/
|
|
80
|
+
value: T,
|
|
81
|
+
/**
|
|
82
|
+
* The previous value, or undefined if this is the first time calling this callback.
|
|
83
|
+
*/
|
|
84
|
+
previousValue: T | undefined) => void;
|
|
85
|
+
export type Picked<T, K extends keyof NonNullable<T>> = T extends undefined | null ? NonNullable<T>[K] | undefined : NonNullable<T>[K];
|
|
86
|
+
declare abstract class MutableValueBase<T> implements MutableValue<T> {
|
|
87
|
+
abstract value: T;
|
|
88
|
+
abstract readonly changeId: number;
|
|
89
|
+
getValue(): T;
|
|
90
|
+
setValue(value: T): void;
|
|
91
|
+
abstract onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
92
|
+
map<U>(transform: {
|
|
93
|
+
(value: T): U;
|
|
94
|
+
}, setData?: Maybe<(transformed: U, original: T) => T>): MutableValue<U>;
|
|
95
|
+
pick<K extends keyof NonNullable<T>>(prop: K): MutableValue<Picked<T, K>>;
|
|
96
|
+
abstract invalidate(): void;
|
|
97
|
+
}
|
|
98
|
+
export declare class MutableValueImpl<T> extends MutableValueBase<T> {
|
|
99
|
+
private currentValue;
|
|
100
|
+
private _disposed;
|
|
101
|
+
private currentIndex;
|
|
102
|
+
private n;
|
|
103
|
+
private readonly callbacks;
|
|
104
|
+
private _changeId;
|
|
105
|
+
constructor(currentValue: T);
|
|
106
|
+
get changeId(): number;
|
|
107
|
+
hasAnyListeners(): boolean;
|
|
108
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
109
|
+
get value(): T;
|
|
110
|
+
set value(value: T);
|
|
111
|
+
invalidate(): void;
|
|
112
|
+
get disposed(): boolean;
|
|
113
|
+
dispose(): void;
|
|
114
|
+
private notify;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns true if the value is a ObservableValue.
|
|
118
|
+
* @param value
|
|
119
|
+
*/
|
|
120
|
+
export declare function isObservableValue(value: any): value is ObservableValue<any>;
|
|
121
|
+
/**
|
|
122
|
+
* Creates a data provider.
|
|
123
|
+
* @param value
|
|
124
|
+
*/
|
|
125
|
+
export declare function data<T>(value: T): MutableValueImpl<T>;
|
|
126
|
+
/**
|
|
127
|
+
* If the value is a ObservableValue, returns the data provider as is. Otherwise, wraps the value in
|
|
128
|
+
* provider.
|
|
129
|
+
*
|
|
130
|
+
* @param value
|
|
131
|
+
*/
|
|
132
|
+
export declare function asData<T>(value: MaybeObservableValue<T>): ObservableValue<T>;
|
|
133
|
+
export type OnDataRequested<T> = (setData: (value: T) => void) => Unsubscribe;
|
|
134
|
+
export declare class ExternalMutableValue<T> extends MutableValueBase<T> {
|
|
135
|
+
private readonly onDataRequested;
|
|
136
|
+
private _data;
|
|
137
|
+
private externalDataSub;
|
|
138
|
+
constructor(currentValue: T, onDataRequested: OnDataRequested<T>);
|
|
139
|
+
get value(): T;
|
|
140
|
+
get changeId(): number;
|
|
141
|
+
set value(_value: T);
|
|
142
|
+
onData(callback: DataChangedCallback<T>): Unsubscribe;
|
|
143
|
+
invalidate(): void;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Creates a data provider that can observe an external event system when onData is called.
|
|
147
|
+
*
|
|
148
|
+
* @param initialValue
|
|
149
|
+
* @param onDataRequested
|
|
150
|
+
*/
|
|
151
|
+
export declare function externalData<T>(initialValue: T, onDataRequested: (setData: (value: T) => void) => Unsubscribe): ObservableValue<T>;
|
|
152
|
+
export {};
|
|
153
|
+
//# sourceMappingURL=observableValue.d.ts.map
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Observable
|
|
2
|
+
|
|
3
|
+
# ObservableValue\<T>
|
|
4
|
+
|
|
5
|
+
An `ObservableValue<T>` represents a reactive, read-only data container that can
|
|
6
|
+
be observed for changes over time. It is designed for simple and efficient state
|
|
7
|
+
tracking without introducing third-party reactivity systems.
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
- Reactive: Subscribers are notified on value changes
|
|
12
|
+
- Composable: You can derive new observable values using `map` and `pick`
|
|
13
|
+
- Typed: Strong type safety for both value and callback arguments
|
|
14
|
+
- Lightweight: Minified and GZipped bundle size is under 1KiB.
|
|
15
|
+
|
|
16
|
+
## Example
|
|
17
|
+
|
|
18
|
+
Use `data` to create a MutableValue for a data type.
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
const user$ = data({ name: 'Alice', age: 30 })
|
|
22
|
+
|
|
23
|
+
const name$ = user$.pick('name')
|
|
24
|
+
name$.onData((name) => {
|
|
25
|
+
console.log('Name changed:', name)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
user$.value = { name: 'Bob', age: 30 }
|
|
29
|
+
// Logs: "Name changed: Bob"
|
|
30
|
+
|
|
31
|
+
age$ = user$.pick('age')
|
|
32
|
+
age$.value = 31
|
|
33
|
+
|
|
34
|
+
user$.value.age // 31
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Utilities
|
|
38
|
+
|
|
39
|
+
### combineData
|
|
40
|
+
|
|
41
|
+
Combines multiple data providers into a single record, notifying observers when
|
|
42
|
+
any have changed.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const a = data(1)
|
|
46
|
+
const b = data('x')
|
|
47
|
+
const combined = combineData({ a, b })
|
|
48
|
+
|
|
49
|
+
combined.onValue((v) => {
|
|
50
|
+
console.log('changed: ', v.a, v.b)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
a.value = 2
|
|
54
|
+
// Logs: "changed: 2 x"
|
|
55
|
+
b.value = 'y'
|
|
56
|
+
// Logs: "changed: 2 y"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Note - combined onValue callback is invoked synchronously; every change from
|
|
60
|
+
every sub-provider will be notified to observers. See `throttle` in vinyl-util
|
|
61
|
+
to handle frequent changes.
|
|
62
|
+
|
|
63
|
+
## externalData
|
|
64
|
+
|
|
65
|
+
Creates an `ObservableValue` that integrates with an external data source. The
|
|
66
|
+
data is only actively fetched or listened to when a subscriber calls `onData`,
|
|
67
|
+
allowing lazy subscription to external event systems such as WebSocket, polling,
|
|
68
|
+
or other push-based updates.
|
|
69
|
+
|
|
70
|
+
Returns An ObservableValue<T> that:
|
|
71
|
+
|
|
72
|
+
- Emits initialValue immediately on subscription.
|
|
73
|
+
- Receives future values from onDataRequested.
|
|
74
|
+
- Automatically unsubscribes from the external source when no listeners remain.
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { externalData } from './data'
|
|
80
|
+
|
|
81
|
+
const timeData = externalData<Date>(new Date(), (setData) => {
|
|
82
|
+
const interval = setInterval(() => {
|
|
83
|
+
setData(new Date())
|
|
84
|
+
}, 1000)
|
|
85
|
+
|
|
86
|
+
return () => clearInterval(interval)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const unsubscribe = timeData.onData((now) => {
|
|
90
|
+
console.log('Current time:', now)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Later, to stop receiving updates
|
|
94
|
+
unsubscribe()
|
|
95
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@amazon/vinyl-observable",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A simple active model",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/amazonmusic/vinyl.git"
|
|
8
|
+
},
|
|
9
|
+
"license": "UNLICENSED",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"main": "./dist/index.cjs",
|
|
12
|
+
"types": "./dist/types/ts3.7/index.d.ts",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"sideEffects": [
|
|
15
|
+
"test/**/*"
|
|
16
|
+
],
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/*",
|
|
19
|
+
"docs/*"
|
|
20
|
+
],
|
|
21
|
+
"typesVersions": {
|
|
22
|
+
">=5.4": {
|
|
23
|
+
"*": [
|
|
24
|
+
"./dist/types/current/index.d.ts"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
">=4.7": {
|
|
28
|
+
"*": [
|
|
29
|
+
"./dist/types/ts4.7/index.d.ts"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
">=4.1": {
|
|
33
|
+
"*": [
|
|
34
|
+
"./dist/types/ts4.1/index.d.ts"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
">=3.7": {
|
|
38
|
+
"*": [
|
|
39
|
+
"./dist/types/ts3.7/index.d.ts"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"exports": {
|
|
44
|
+
".": {
|
|
45
|
+
"types@>=5.4": "./dist/types/current/index.d.ts",
|
|
46
|
+
"types@>=4.7": "./dist/types/ts4.7/index.d.ts",
|
|
47
|
+
"require": "./dist/index.cjs",
|
|
48
|
+
"import": "./dist/index.js"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"analyzeExports": "tsx buildSrc/analyzeExports.ts",
|
|
53
|
+
"analyzeExports:write": "tsx buildSrc/analyzeExports.ts --write",
|
|
54
|
+
"clean": "rimraf --glob dist .eslintcache \"**/*.tsbuildinfo\"",
|
|
55
|
+
"indexFiles:check": "tsx buildSrc/writeIndexFiles.ts --check",
|
|
56
|
+
"indexFiles:write": "tsx buildSrc/writeIndexFiles.ts",
|
|
57
|
+
"build": "tsx buildSrc/build.ts",
|
|
58
|
+
"build:release": "tsx buildSrc/build.ts --release",
|
|
59
|
+
"prettier:check": "prettier . --ignore-path ../../.prettierignore --cache --check",
|
|
60
|
+
"prettier:write": "prettier . --ignore-path ../../.prettierignore --cache --write",
|
|
61
|
+
"eslint:check": "eslint . --cache --max-warnings=0",
|
|
62
|
+
"eslint:write": "eslint . --cache --fix",
|
|
63
|
+
"lint": "npm run indexFiles:check && npm run eslint:check && npm run prettier:check",
|
|
64
|
+
"lint:write": "npm run indexFiles:write && npm run eslint:write && npm run prettier:write",
|
|
65
|
+
"validate": "tsc --project test/unit && npm run lint && npm run test",
|
|
66
|
+
"test": "tsx --tsconfig ../../tsconfig.flat.json ../../node_modules/jasmine/bin/jasmine --config=test/unit/jasmine.config.json",
|
|
67
|
+
"test:coverage": "c8 npm run test",
|
|
68
|
+
"watch": "tsx buildSrc/build.ts --watch",
|
|
69
|
+
"watch:release": "tsx buildSrc/build.ts --watch --release"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@amazon/vinyl-build-utils": "^1.0.0",
|
|
73
|
+
"@amazon/vinyl-jasmine-wrapper": "^1.0.0"
|
|
74
|
+
},
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"@amazon/vinyl-util": "^1.0.0"
|
|
77
|
+
},
|
|
78
|
+
"browserslist": [
|
|
79
|
+
"defaults, chrome 52, firefox 54, edge 15, safari 8"
|
|
80
|
+
]
|
|
81
|
+
}
|