Comparing version
@@ -1,6 +0,5 @@ | ||
declare const $get: unique symbol; | ||
declare const $observers: unique symbol; | ||
export { FluidValue, hasFluidValue, getFluidValue, getFluidObservers, callFluidObserver, callFluidObservers, setFluidGetter, addFluidObserver, removeFluidObserver, }; | ||
/** Returns true if `arg` can be observed. */ | ||
declare const hasFluidValue: (arg: any) => arg is FluidValue<any, UnknownFluidEvent<any>>; | ||
declare const hasFluidValue: (arg: any) => arg is FluidValue<any>; | ||
/** | ||
@@ -17,3 +16,3 @@ * Get the current value. | ||
/** Send an event to all observers. */ | ||
declare function callFluidObservers<E extends FluidEvent>(target: FluidValue<any, E>, event: E): void; | ||
declare function callFluidObservers<E extends FluidEvent>(target: FluidObservable<E>, event: E): void; | ||
declare function callFluidObservers(target: object, event: UnsafeFluidEvent): void; | ||
@@ -24,27 +23,38 @@ declare type GetFluidValue = { | ||
declare type GetFluidObservers = { | ||
<E extends FluidEvent>(target: FluidValue<any, E>): ReadonlySet<FluidObserver<E>> | null; | ||
<E extends FluidEvent>(target: FluidObservable<E>): ReadonlySet<FluidObserver<E>> | null; | ||
(target: object): ReadonlySet<FluidObserver> | null; | ||
}; | ||
/** An event from a `FluidValue` instance */ | ||
export interface FluidEvent<T = any> { | ||
/** An event from a `fluids` compatible object */ | ||
export interface FluidEvent<T extends object = any> { | ||
type: string; | ||
parent: FluidValue<T>; | ||
parent: T; | ||
} | ||
/** An event from any `FluidValue` instance */ | ||
export interface UnknownFluidEvent<T = any> extends FluidEvent<T> { | ||
/** An unknown event from a `fluids` compatible object */ | ||
export interface UnsafeFluidEvent<T extends object = any> extends FluidEvent<T> { | ||
[key: string]: any; | ||
} | ||
/** An untyped event from a `fluids` compatible object */ | ||
export interface UnsafeFluidEvent { | ||
type: string; | ||
parent: object; | ||
[key: string]: any; | ||
/** | ||
* A source of `FluidEvent` objects that can be observed with | ||
* the `addFluidObserver` function. | ||
* | ||
* Use "interface merging" to mark your class as observable: | ||
* | ||
* class Foo {} | ||
* interface Foo extends FluidObservable<FooEvent> {} | ||
* | ||
* Once that's done, you get the following benefits: | ||
* - observers added with `addFluidObserver` are type-checked | ||
* - events passed to `callFluidObservers` are type-checked | ||
*/ | ||
export interface FluidObservable<E extends FluidEvent = any> { | ||
[$observers]?: E | null; | ||
} | ||
/** | ||
* Extend this class for automatic TypeScript support when passing | ||
* an object to a `fluids` compatible function. | ||
* `FluidValue` objects can be unwrapped with `getFluidValue` to access | ||
* their current value. | ||
* | ||
* Libraries may support observable values by handling `FluidValue` objects | ||
* in their functions and classes. | ||
*/ | ||
declare abstract class FluidValue<T = any, E extends FluidEvent<T> = UnknownFluidEvent<T>> { | ||
protected [$get]: () => T; | ||
protected [$observers]?: Set<FluidObserver<E>>; | ||
declare abstract class FluidValue<T = any> { | ||
constructor(get?: () => T); | ||
@@ -54,5 +64,5 @@ /** Get the current value. */ | ||
/** Called after an observer is added. */ | ||
protected observerAdded?(count: number, observer: FluidObserver): void; | ||
protected observerAdded?(count: number, observer: FluidObserver<any>): void; | ||
/** Called after an observer is removed. */ | ||
protected observerRemoved?(count: number, observer: FluidObserver): void; | ||
protected observerRemoved?(count: number, observer: FluidObserver<any>): void; | ||
} | ||
@@ -76,6 +86,6 @@ /** An observer of `FluidValue` objects. */ | ||
/** Observe a `fluids`-compatible object. */ | ||
declare function addFluidObserver<T, E extends FluidEvent>(target: FluidValue<T, E>, observer: FluidObserver<E>): typeof observer; | ||
declare function addFluidObserver<E extends FluidEvent>(target: FluidObservable<E>, observer: FluidObserver<E>): typeof observer; | ||
declare function addFluidObserver<E extends UnsafeFluidEvent>(target: object, observer: FluidObserver<E>): typeof observer; | ||
/** Stop observing a `fluids`-compatible object. */ | ||
declare function removeFluidObserver<E extends FluidEvent>(target: FluidValue<any, E>, observer: FluidObserver<E>): void; | ||
declare function removeFluidObserver<E extends FluidEvent>(target: FluidObservable<E>, observer: FluidObserver<E>): void; | ||
declare function removeFluidObserver<E extends UnsafeFluidEvent>(target: object, observer: FluidObserver<E>): void; |
@@ -41,4 +41,7 @@ "use strict"; | ||
/** | ||
* Extend this class for automatic TypeScript support when passing | ||
* an object to a `fluids` compatible function. | ||
* `FluidValue` objects can be unwrapped with `getFluidValue` to access | ||
* their current value. | ||
* | ||
* Libraries may support observable values by handling `FluidValue` objects | ||
* in their functions and classes. | ||
*/ | ||
@@ -61,13 +64,11 @@ var FluidValue = /** @class */ (function () { | ||
function addFluidObserver(target, observer) { | ||
if (target[$get]) { | ||
var observers = target[$observers]; | ||
if (!observers) { | ||
setHidden(target, $observers, (observers = new Set())); | ||
var observers = target[$observers]; | ||
if (!observers) { | ||
setHidden(target, $observers, (observers = new Set())); | ||
} | ||
if (!observers.has(observer)) { | ||
observers.add(observer); | ||
if (target.observerAdded) { | ||
target.observerAdded(observers.size, observer); | ||
} | ||
if (!observers.has(observer)) { | ||
observers.add(observer); | ||
if (target.observerAdded) { | ||
target.observerAdded(observers.size, observer); | ||
} | ||
} | ||
} | ||
@@ -74,0 +75,0 @@ return observer; |
@@ -1,6 +0,5 @@ | ||
declare const $get: unique symbol; | ||
declare const $observers: unique symbol; | ||
export { FluidValue, hasFluidValue, getFluidValue, getFluidObservers, callFluidObserver, callFluidObservers, setFluidGetter, addFluidObserver, removeFluidObserver, }; | ||
/** Returns true if `arg` can be observed. */ | ||
declare const hasFluidValue: (arg: any) => arg is FluidValue<any, UnknownFluidEvent<any>>; | ||
declare const hasFluidValue: (arg: any) => arg is FluidValue<any>; | ||
/** | ||
@@ -17,3 +16,3 @@ * Get the current value. | ||
/** Send an event to all observers. */ | ||
declare function callFluidObservers<E extends FluidEvent>(target: FluidValue<any, E>, event: E): void; | ||
declare function callFluidObservers<E extends FluidEvent>(target: FluidObservable<E>, event: E): void; | ||
declare function callFluidObservers(target: object, event: UnsafeFluidEvent): void; | ||
@@ -24,27 +23,38 @@ declare type GetFluidValue = { | ||
declare type GetFluidObservers = { | ||
<E extends FluidEvent>(target: FluidValue<any, E>): ReadonlySet<FluidObserver<E>> | null; | ||
<E extends FluidEvent>(target: FluidObservable<E>): ReadonlySet<FluidObserver<E>> | null; | ||
(target: object): ReadonlySet<FluidObserver> | null; | ||
}; | ||
/** An event from a `FluidValue` instance */ | ||
export interface FluidEvent<T = any> { | ||
/** An event from a `fluids` compatible object */ | ||
export interface FluidEvent<T extends object = any> { | ||
type: string; | ||
parent: FluidValue<T>; | ||
parent: T; | ||
} | ||
/** An event from any `FluidValue` instance */ | ||
export interface UnknownFluidEvent<T = any> extends FluidEvent<T> { | ||
/** An unknown event from a `fluids` compatible object */ | ||
export interface UnsafeFluidEvent<T extends object = any> extends FluidEvent<T> { | ||
[key: string]: any; | ||
} | ||
/** An untyped event from a `fluids` compatible object */ | ||
export interface UnsafeFluidEvent { | ||
type: string; | ||
parent: object; | ||
[key: string]: any; | ||
/** | ||
* A source of `FluidEvent` objects that can be observed with | ||
* the `addFluidObserver` function. | ||
* | ||
* Use "interface merging" to mark your class as observable: | ||
* | ||
* class Foo {} | ||
* interface Foo extends FluidObservable<FooEvent> {} | ||
* | ||
* Once that's done, you get the following benefits: | ||
* - observers added with `addFluidObserver` are type-checked | ||
* - events passed to `callFluidObservers` are type-checked | ||
*/ | ||
export interface FluidObservable<E extends FluidEvent = any> { | ||
[$observers]?: E | null; | ||
} | ||
/** | ||
* Extend this class for automatic TypeScript support when passing | ||
* an object to a `fluids` compatible function. | ||
* `FluidValue` objects can be unwrapped with `getFluidValue` to access | ||
* their current value. | ||
* | ||
* Libraries may support observable values by handling `FluidValue` objects | ||
* in their functions and classes. | ||
*/ | ||
declare abstract class FluidValue<T = any, E extends FluidEvent<T> = UnknownFluidEvent<T>> { | ||
protected [$get]: () => T; | ||
protected [$observers]?: Set<FluidObserver<E>>; | ||
declare abstract class FluidValue<T = any> { | ||
constructor(get?: () => T); | ||
@@ -54,5 +64,5 @@ /** Get the current value. */ | ||
/** Called after an observer is added. */ | ||
protected observerAdded?(count: number, observer: FluidObserver): void; | ||
protected observerAdded?(count: number, observer: FluidObserver<any>): void; | ||
/** Called after an observer is removed. */ | ||
protected observerRemoved?(count: number, observer: FluidObserver): void; | ||
protected observerRemoved?(count: number, observer: FluidObserver<any>): void; | ||
} | ||
@@ -76,6 +86,6 @@ /** An observer of `FluidValue` objects. */ | ||
/** Observe a `fluids`-compatible object. */ | ||
declare function addFluidObserver<T, E extends FluidEvent>(target: FluidValue<T, E>, observer: FluidObserver<E>): typeof observer; | ||
declare function addFluidObserver<E extends FluidEvent>(target: FluidObservable<E>, observer: FluidObserver<E>): typeof observer; | ||
declare function addFluidObserver<E extends UnsafeFluidEvent>(target: object, observer: FluidObserver<E>): typeof observer; | ||
/** Stop observing a `fluids`-compatible object. */ | ||
declare function removeFluidObserver<E extends FluidEvent>(target: FluidValue<any, E>, observer: FluidObserver<E>): void; | ||
declare function removeFluidObserver<E extends FluidEvent>(target: FluidObservable<E>, observer: FluidObserver<E>): void; | ||
declare function removeFluidObserver<E extends UnsafeFluidEvent>(target: object, observer: FluidObserver<E>): void; |
@@ -36,4 +36,7 @@ var $get = Symbol.for('FluidValue.get'); | ||
/** | ||
* Extend this class for automatic TypeScript support when passing | ||
* an object to a `fluids` compatible function. | ||
* `FluidValue` objects can be unwrapped with `getFluidValue` to access | ||
* their current value. | ||
* | ||
* Libraries may support observable values by handling `FluidValue` objects | ||
* in their functions and classes. | ||
*/ | ||
@@ -54,13 +57,11 @@ var FluidValue = /** @class */ (function () { | ||
function addFluidObserver(target, observer) { | ||
if (target[$get]) { | ||
var observers = target[$observers]; | ||
if (!observers) { | ||
setHidden(target, $observers, (observers = new Set())); | ||
var observers = target[$observers]; | ||
if (!observers) { | ||
setHidden(target, $observers, (observers = new Set())); | ||
} | ||
if (!observers.has(observer)) { | ||
observers.add(observer); | ||
if (target.observerAdded) { | ||
target.observerAdded(observers.size, observer); | ||
} | ||
if (!observers.has(observer)) { | ||
observers.add(observer); | ||
if (target.observerAdded) { | ||
target.observerAdded(observers.size, observer); | ||
} | ||
} | ||
} | ||
@@ -67,0 +68,0 @@ return observer; |
{ | ||
"name": "fluids", | ||
"version": "0.2.9", | ||
"version": "0.3.0-rc.0", | ||
"description": "Glue layer for reactivity", | ||
@@ -5,0 +5,0 @@ "main": "dist/cjs/index", |
@@ -13,3 +13,3 @@ # fluids | ||
Any object can be observed, but `FluidValue` objects have strongly typed | ||
Any object can be observed, but `FluidValue` objects have strongly typed | ||
events. Observed objects are basically event emitters whose listeners | ||
@@ -24,3 +24,3 @@ receive every event, and they typically represent a single value. | ||
// You can pass a function: | ||
let observer = addFluidObserver(target, event => { | ||
let observer = addFluidObserver(target, (event) => { | ||
console.log(event) | ||
@@ -33,3 +33,3 @@ }) | ||
console.log(event) | ||
} | ||
}, | ||
}) | ||
@@ -52,9 +52,13 @@ ``` | ||
```ts | ||
import { FluidValue, callFluidObservers } from 'fluids' | ||
import { FluidValue, FluidObservable, callFluidObservers } from 'fluids' | ||
// Your class can have multiple event types. | ||
type RefEvent<T> = { type: 'change', value: T, parent: Ref<T> } | ||
// The `type` and `parent` properties are required. | ||
type RefEvent<T> = { type: 'change'; value: T; parent: Ref<T> } | ||
// Use "interface merging" to attach the event types. | ||
interface Ref<T> extends FluidObservable<RefEvent<T>> {} | ||
// This example is an observable React ref. | ||
class Ref<T> extends FluidValue<T, RefEvent<T>> { | ||
class Ref<T> extends FluidValue<T> { | ||
private _current: T | ||
@@ -118,3 +122,3 @@ constructor(initialValue: T) { | ||
}) | ||
} | ||
}, | ||
}) | ||
@@ -128,3 +132,8 @@ ``` | ||
```ts | ||
import { hasFluidValue, getFluidValue, getFluidObservers, callFluidObserver } from 'fluids' | ||
import { | ||
hasFluidValue, | ||
getFluidValue, | ||
getFluidObservers, | ||
callFluidObserver, | ||
} from 'fluids' | ||
@@ -131,0 +140,0 @@ // Check if a value is observable. |
@@ -55,3 +55,3 @@ const $get = Symbol.for('FluidValue.get') | ||
function callFluidObservers<E extends FluidEvent>( | ||
target: FluidValue<any, E>, | ||
target: FluidObservable<E>, | ||
event: E | ||
@@ -76,3 +76,3 @@ ): void | ||
type GetFluidObservers = { | ||
<E extends FluidEvent>(target: FluidValue<any, E>): ReadonlySet< | ||
<E extends FluidEvent>(target: FluidObservable<E>): ReadonlySet< | ||
FluidObserver<E> | ||
@@ -83,31 +83,40 @@ > | null | ||
/** An event from a `FluidValue` instance */ | ||
export interface FluidEvent<T = any> { | ||
/** An event from a `fluids` compatible object */ | ||
export interface FluidEvent<T extends object = any> { | ||
type: string | ||
parent: FluidValue<T> | ||
parent: T | ||
} | ||
/** An event from any `FluidValue` instance */ | ||
export interface UnknownFluidEvent<T = any> extends FluidEvent<T> { | ||
/** An unknown event from a `fluids` compatible object */ | ||
export interface UnsafeFluidEvent<T extends object = any> | ||
extends FluidEvent<T> { | ||
[key: string]: any | ||
} | ||
/** An untyped event from a `fluids` compatible object */ | ||
export interface UnsafeFluidEvent { | ||
type: string | ||
parent: object | ||
[key: string]: any | ||
/** | ||
* A source of `FluidEvent` objects that can be observed with | ||
* the `addFluidObserver` function. | ||
* | ||
* Use "interface merging" to mark your class as observable: | ||
* | ||
* class Foo {} | ||
* interface Foo extends FluidObservable<FooEvent> {} | ||
* | ||
* Once that's done, you get the following benefits: | ||
* - observers added with `addFluidObserver` are type-checked | ||
* - events passed to `callFluidObservers` are type-checked | ||
*/ | ||
export interface FluidObservable<E extends FluidEvent = any> { | ||
// Never access this directly. Its only purpose is to enforce type safety. | ||
[$observers]?: E | null | ||
} | ||
/** | ||
* Extend this class for automatic TypeScript support when passing | ||
* an object to a `fluids` compatible function. | ||
* `FluidValue` objects can be unwrapped with `getFluidValue` to access | ||
* their current value. | ||
* | ||
* Libraries may support observable values by handling `FluidValue` objects | ||
* in their functions and classes. | ||
*/ | ||
abstract class FluidValue< | ||
T = any, | ||
E extends FluidEvent<T> = UnknownFluidEvent<T> | ||
> { | ||
protected [$get]: () => T | ||
protected [$observers]?: Set<FluidObserver<E>> | ||
abstract class FluidValue<T = any> { | ||
constructor(get?: () => T) { | ||
@@ -124,6 +133,6 @@ if (!get && !(get = this.get)) { | ||
/** Called after an observer is added. */ | ||
protected observerAdded?(count: number, observer: FluidObserver): void | ||
protected observerAdded?(count: number, observer: FluidObserver<any>): void | ||
/** Called after an observer is removed. */ | ||
protected observerRemoved?(count: number, observer: FluidObserver): void | ||
protected observerRemoved?(count: number, observer: FluidObserver<any>): void | ||
} | ||
@@ -151,4 +160,4 @@ | ||
/** Observe a `fluids`-compatible object. */ | ||
function addFluidObserver<T, E extends FluidEvent>( | ||
target: FluidValue<T, E>, | ||
function addFluidObserver<E extends FluidEvent>( | ||
target: FluidObservable<E>, | ||
observer: FluidObserver<E> | ||
@@ -163,13 +172,11 @@ ): typeof observer | ||
function addFluidObserver(target: any, observer: FluidObserver) { | ||
if (target[$get]) { | ||
let observers: Set<FluidObserver> = target[$observers] | ||
if (!observers) { | ||
setHidden(target, $observers, (observers = new Set())) | ||
let observers: Set<FluidObserver> = target[$observers] | ||
if (!observers) { | ||
setHidden(target, $observers, (observers = new Set())) | ||
} | ||
if (!observers.has(observer)) { | ||
observers.add(observer) | ||
if (target.observerAdded) { | ||
target.observerAdded(observers.size, observer) | ||
} | ||
if (!observers.has(observer)) { | ||
observers.add(observer) | ||
if (target.observerAdded) { | ||
target.observerAdded(observers.size, observer) | ||
} | ||
} | ||
} | ||
@@ -181,3 +188,3 @@ return observer | ||
function removeFluidObserver<E extends FluidEvent>( | ||
target: FluidValue<any, E>, | ||
target: FluidObservable<E>, | ||
observer: FluidObserver<E> | ||
@@ -184,0 +191,0 @@ ): void |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
28876
4.3%542
5.86%146
6.57%