UNPKG

js-draw

Version:

Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript.

185 lines (184 loc) 7.63 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _ReactiveValueImpl_value, _ReactiveValueImpl_onUpdateListeners; Object.defineProperty(exports, "__esModule", { value: true }); exports.MutableReactiveValue = exports.ReactiveValue = void 0; const noOpUpdateListenerResult = { remove() { }, }; /** * An update listener that does nothing. Useful for reactive values * that will never change. */ const noOpSetUpdateListener = () => { return noOpUpdateListenerResult; }; /** * A `ReactiveValue` is a value that * - updates periodically, * - can fire listeners when it updates, * - and can be chanined together with other `ReactiveValue`s. * * A `ReactiveValue` is a read-only view. See {@link MutableReactiveValue} for a * read-write view. * * Static methods in the `ReactiveValue` and `MutableReactiveValue` classes are * constructors (e.g. `fromImmutable`). * * Avoid extending this class from an external library, as that may not be stable. */ class ReactiveValue { /** Returns a promise that resolves when this value is next changed. */ waitForNextUpdate() { return new Promise((resolve) => { const listener = this.onUpdate((value) => { listener.remove(); resolve(value); }); }); } /** Creates a `ReactiveValue` with an initial value, `initialValue`. */ static fromInitialValue(initialValue) { return new ReactiveValueImpl(initialValue); } /** Returns a `ReactiveValue` that is **known** will never change. */ static fromImmutable(value) { return { get: () => value, onUpdate: noOpSetUpdateListener, onUpdateAndNow: (callback) => { callback(value); return noOpUpdateListenerResult; }, // Never resolves -- immutable. waitForNextUpdate: () => new Promise(() => { }), }; } /** * Creates a `ReactiveValue` whose values come from `callback`. * * `callback` is called whenever any of `sourceValues` are updated and initially to * set the initial value of the result. */ static fromCallback(callback, sourceValues) { const result = new ReactiveValueImpl(callback()); const resultRef = typeof WeakRef !== 'undefined' ? new WeakRef(result) : { deref: () => result }; for (const value of sourceValues) { const listener = value.onUpdate(() => { // Use resultRef to allow `result` to be garbage collected // despite this listener. const value = resultRef.deref(); if (value) { value.set(callback()); } else { listener.remove(); } }); } return result; } static map(source, map, inverseMap) { const result = ReactiveValue.fromInitialValue(map(source.get())); let expectedResultValue = result.get(); source.onUpdate((newValue) => { expectedResultValue = map(newValue); result.set(expectedResultValue); }); if (inverseMap) { result.onUpdate((newValue) => { // Prevent infinite loops if inverseMap is not a true // inverse. if (newValue !== expectedResultValue) { source.set(inverseMap(newValue)); } }); } return result; } static union(values) { return ReactiveValue.fromCallback(() => { return values.map((value) => value.get()); }, values); } } exports.ReactiveValue = ReactiveValue; class MutableReactiveValue extends ReactiveValue { static fromProperty(sourceValue, propertyName) { const child = ReactiveValue.fromInitialValue(sourceValue.get()[propertyName]); const childRef = typeof WeakRef !== 'undefined' ? new WeakRef(child) : { deref: () => child }; // When the source is updated... const sourceListener = sourceValue.onUpdate((newValue) => { const childValue = childRef.deref(); if (childValue) { childValue.set(newValue[propertyName]); } else { // TODO: What if `sourceValue` would be dropped before // the child value? sourceListener.remove(); } }); // When the child is updated, also apply the update to the // parent. child.onUpdate((newValue) => { sourceValue.set({ ...sourceValue.get(), [propertyName]: newValue, }); }); return child; } } exports.MutableReactiveValue = MutableReactiveValue; // @internal class ReactiveValueImpl extends MutableReactiveValue { constructor(initialValue) { super(); _ReactiveValueImpl_value.set(this, void 0); _ReactiveValueImpl_onUpdateListeners.set(this, void 0); __classPrivateFieldSet(this, _ReactiveValueImpl_value, initialValue, "f"); __classPrivateFieldSet(this, _ReactiveValueImpl_onUpdateListeners, [], "f"); } set(newValue) { if (__classPrivateFieldGet(this, _ReactiveValueImpl_value, "f") === newValue) { return; } __classPrivateFieldSet(this, _ReactiveValueImpl_value, newValue, "f"); for (const listener of __classPrivateFieldGet(this, _ReactiveValueImpl_onUpdateListeners, "f")) { listener(newValue); } } get() { return __classPrivateFieldGet(this, _ReactiveValueImpl_value, "f"); } onUpdate(listener) { // **Note**: If memory is a concern, listeners should avoid referencing this // reactive value directly. Doing so allows the value to be garbage collected when // no longer referenced. __classPrivateFieldGet(this, _ReactiveValueImpl_onUpdateListeners, "f").push(listener); return { remove: () => { __classPrivateFieldSet(this, _ReactiveValueImpl_onUpdateListeners, __classPrivateFieldGet(this, _ReactiveValueImpl_onUpdateListeners, "f").filter((otherListener) => { return otherListener !== listener; }), "f"); }, }; } onUpdateAndNow(callback) { callback(this.get()); return this.onUpdate(callback); } } _ReactiveValueImpl_value = new WeakMap(), _ReactiveValueImpl_onUpdateListeners = new WeakMap(); exports.default = ReactiveValue;