{"version":3,"file":"MotionValueState.mjs","sources":["../../../src/effects/MotionValueState.ts"],"sourcesContent":["import { frame } from \"../frameloop/frame\"\nimport { Schedule } from \"../frameloop/types\"\nimport { MotionValue } from \"../value\"\n\ninterface Entry {\n    value: MotionValue\n    render?: VoidFunction\n    onRemove: VoidFunction\n}\n\nexport class MotionValueState {\n    /**\n     * Transform keys bound to this state, in `transformPropOrder`, and\n     * the value bound to each. Lets the transform builder visit only\n     * bound transforms, reading each value directly.\n     */\n    transformKeys?: string[]\n    transformValues?: Record<string, MotionValue>\n\n    private values = new Map<string, Entry>()\n\n    /**\n     * Renders scheduled for the next flush, usually one or two (values\n     * bound to the same computed render, e.g. `x` and `y` to `transform`,\n     * share an entry). Tracked with a count rather than truncating the\n     * array so no backing store is reallocated every frame. Kept per\n     * state so pending writes can be flushed synchronously before the\n     * subject is measured.\n     */\n    private pending: VoidFunction[] = []\n    private numPending = 0\n\n    /**\n     * @param step - The frameloop step renders are scheduled in. Defaults\n     * to `frame.render`. Effects that feed a render loop running in\n     * `frame.render` (GPU scenes) should write in `frame.preRender`.\n     */\n    constructor(private step: Schedule = frame.render) {}\n\n    /**\n     * @param render - Writes the value to the subject. Renders read the\n     * motion value directly rather than a cached copy, so there is one\n     * place a value lives.\n     * @param computed - A value already in this state (e.g. `transform`)\n     * whose render should run whenever `value` changes.\n     */\n    set(\n        name: string,\n        value: MotionValue,\n        render?: VoidFunction,\n        computed?: MotionValue\n    ): VoidFunction {\n        this.values.get(name)?.onRemove()\n\n        if (computed) {\n            for (const entry of this.values.values()) {\n                if (entry.value === computed) render = entry.render\n            }\n        }\n\n        const onChange = () => render && this.schedule(render)\n\n        /**\n         * Values created ahead of a DOM read start out undefined and\n         * have nothing to render until they're set.\n         */\n        value.get() !== undefined && onChange()\n\n        const cancelOnChange = value.on(\"change\", onChange)\n\n        const onRemove = () => {\n            cancelOnChange()\n            render && !computed && this.cancel(render)\n            this.values.delete(name)\n        }\n\n        this.values.set(name, {\n            value,\n            render: computed ? undefined : render,\n            onRemove,\n        })\n\n        return onRemove\n    }\n\n    get(name: string): MotionValue | undefined {\n        return this.values.get(name)?.value\n    }\n\n    /**\n     * Detach every value from this state and return them, so another\n     * renderer can take them over. The state stays cached by its effect,\n     * so the bound transforms are reset too rather than leaking into\n     * values bound later.\n     */\n    release() {\n        const values = new Map<string, MotionValue>()\n        this.values.forEach((entry, name) => {\n            values.set(name, entry.value)\n            entry.onRemove()\n        })\n        this.transformKeys = this.transformValues = undefined\n        return values\n    }\n\n    private schedule(render: VoidFunction) {\n        const { pending, numPending } = this\n\n        for (let i = 0; i < numPending; i++) {\n            if (pending[i] === render) return\n        }\n\n        numPending || this.step(this.flush)\n\n        pending[this.numPending++] = render\n    }\n\n    private cancel(render: VoidFunction) {\n        const { pending } = this\n\n        for (let i = 0; i < this.numPending; i++) {\n            if (pending[i] === render) {\n                pending[i] = pending[--this.numPending]\n                return\n            }\n        }\n    }\n\n    /**\n     * Run the pending renders. Resetting the count first means a render\n     * scheduled while flushing lands in the next frame, as with the\n     * frameloop itself.\n     */\n    flush = () => {\n        const { pending, numPending } = this\n        this.numPending = 0\n        for (let i = 0; i < numPending; i++) pending[i]()\n    }\n}\n"],"names":[],"mappings":"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"}