src/MapProperty.js
import { assert } from "akutils";
import createPropertyClass from "./createPropertyClass";
import KeyedApi from "./KeyedApi";
import ObjectShadowImpl from "./ObjectShadowImpl";
import MapShadow from "./MapShadow";
import Property from "./Property";
import StateType from "./StateType";
/**
Exposes a Map interface on a shadow property. The f.lux auto-shadowing process maps `objects` using
this {@link Property} subclass.
The default shadow class is {@link MapShadow}.
Use `MapProperty` when you want to shadow an `object` and provide a
[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) interface
for manipulating and accessing `object` properties.
The `_keyed` instance variable exposes a {@link KeyedApi} instance for working with properties.
Readonly properties cannot be updated using the shadow so the `this._keyed` is used set the value
or remove it from the object. For example,
```js
this._keyed.set("updated", Date());
```
would set the `updated` shadow property with a string value for the current time.
@see {@link KeyedApi}
@see {@link MapShadow}
*/
export default class MapProperty extends Property {
/**
If a {@link StateType} is not passed to this constructor then one is located using
{@link StateType.from} thus ensuring the f.lux shadowing process is defined for this
property.
@param {StateType} [stateType] - a specialized {@link StateType} instance describing how f.lux should
shadow this property.
*/
constructor(stateType) {
super(stateType);
this._keyed = new KeyedApi(this);
this.setImplementationClass(ObjectShadowImpl);
this.setShadowClass(MapShadow)
}
/**
Factory function for creating an `MapProperty` subclass suitable for using with new. The generated
class will have the `type` {@link StateType} descriptor set upon return.
Example usage:
```
class SomeShadow extends MapShadow {
// definition here
}
export default MapProperty.createClass(SomeShadow, type => {
// configure type variable
});
```
@param {Object|MapShadow} [shadowType={}] - `MapShadow` subclass or object literal api definition.
If object literal specified, each property and function is mapped onto a Shadow subclass.
@param {function(type: StateType)} [typeCallback] - a callback function that will be passed the
{@link StateType} spec for additional customization, such as setting autoshadow, initial state,
or readonly.
@param {Object} [initialState={}] - the initial state for the new property.
@return {MapProperty} newly defined `MapProperty` subclass.
*/
static createClass(shadowType={}, typeCallback, initialState={}) {
return createPropertyClass(shadowType, initialState, typeCallback, MapProperty);
}
/**
Factory function for setting up the {@link StateType} `type` class variable with an appropriately
configured intial state.
Example usage:
```
export default class SomeProperty extends MapProperty {
// implement property here
}
class SomeShadow extends MapShadow {
// implement shadow api here
}
MapProperty.defineType(SomeProperty, SomeShadow, type => {
// configure type variable
});
```
@param {MapProperty} PropClass - MapProperty subclass
@param {Object|MapShadow} [ShadowType] - `MapShadow` subclass or object literal api definition.
If object literal specified, each property and function is mapped onto a Shadow subclass.
@param {function(type: StateType)} [typeCallback] - a callback function that will be passed the
{@link StateType} spec for additional customization, such as setting autoshadow, initial state, or
readonly.
@param {Object} [initialState={}] - the initial state for the new property.
*/
static defineType(PropClass, ShadowType, typeCallback, initialState={}) {
assert( a => a.is(MapProperty.isPrototypeOf(PropClass), "PropClass must subclass MapProperty") );
StateType.defineTypeEx(PropClass, ShadowType, typeCallback, initialState);
}
/**
Used by {@link StateType} to determine if a keyed property type.
@ignore
*/
static supportsKeyedChildProperties() { return true }
}
StateType.defineType(MapProperty, spec => spec.initialState({}).typeName("MapProperty") );