fluids

0.3.0 • Public • Published

fluids

This library is a tiny glue layer for observable events.

  • Create a tree of observable values
  • Let parent nodes send arbitrary events to children (for maximum flexibility)
  • Stay small yet provide helpers for easier integration

 

Observe a value

Any object can be observed, but FluidValue objects have strongly typed events. Observed objects are basically event emitters whose listeners receive every event, and they typically represent a single value.

To start observing:

import { addFluidObserver } from 'fluids'

// You can pass a function:
let observer = addFluidObserver(target, (event) => {
  console.log(event)
})

// or pass an object:
observer = addFluidObserver(target, {
  eventObserved(event) {
    console.log(event)
  },
})

To stop observing:

import { removeFluidObserver } from 'fluids'

removeFluidObserver(target, observer)

Create an observed object

You can extend the FluidValue class for automatic TypeScript support with fluids-compatible libraries.

import { FluidValue, FluidObservable, callFluidObservers } from 'fluids'

// Your class can have multiple event types.
// 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> {
  private _current: T
  constructor(initialValue: T) {
    // Passing a getter to super is only required
    // if your class has no "get" method.
    super(() => this._current)

    this._current = initialValue
  }
  get current() {
    return this._current
  }
  set current(value: T) {
    this._current = value

    // Send the change to all observers.
    callFluidObservers(this, {
      type: 'change',
      value,
      parent: this,
    })
  }
  //
  // These methods are completely optional.
  //
  protected observerAdded(count: number) {
    if (count == 1) {
      // Do something when the first observer is added.
    }
  }
  protected observerRemoved(count: number) {
    if (count == 0) {
      // Do something when the last observer is removed.
    }
  }
}

If extending FluidValue isn't an option, you can outfit an object or prototype with the setFluidGetter function:

import { setFluidGetter, callFluidObservers } from 'fluids'

// This example augments an existing React ref.
let { current } = ref
let get = () => current
setFluidGetter(ref, get)
Object.defineProperty(ref, 'current', {
  get,
  set(value) {
    current = value

    // Remember to notify any observers.
    callFluidObservers(ref, {
      type: 'change',
      value,
      parent: ref,
    })
  },
})

For libraries

The remaining functions are useful when making a fluids-compatible library.

import {
  hasFluidValue,
  getFluidValue,
  getFluidObservers,
  callFluidObserver,
} from 'fluids'

// Check if a value is observable.
hasFluidValue(target)

// Get the current value. Returns `target` if not observable.
getFluidValue(target)

// Get the current observers (or null if none exist).
getFluidObservers(target)

// Call a single observer. Useful for special observation, like waterfalls.
callFluidObserver(observer, event)

Package Sidebar

Install

npm i fluids

Weekly Downloads

12,297

Version

0.3.0

License

MIT

Unpacked Size

38.8 kB

Total Files

12

Last publish

Collaborators

  • aleclarson