Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| import type { MaybeGetter } from "$lib/types.js"; | |
| import { isFunction } from "$lib/utils/is.js"; | |
| import { extract } from "./extract.svelte"; | |
| type SyncedArgs<T> = | |
| | { | |
| value: MaybeGetter<T>; | |
| onChange?: (value: T) => void; | |
| } | |
| | { | |
| value: MaybeGetter<T | undefined>; | |
| onChange?: (value: T) => void; | |
| defaultValue: T; | |
| }; | |
| /** | |
| * Setting `current` calls the `onChange` callback with the new value. | |
| * | |
| * If the value arg is static, it will be used as the default value, | |
| * and subsequent sets will set an internal state that gets read as `current`. | |
| * | |
| * Otherwise, if it is a getter, it will be called every time `current` is read, | |
| * and no internal state is used. | |
| */ | |
| export class Synced<T> { | |
| #internalValue = $state<T>() as T; | |
| #valueArg: SyncedArgs<T>["value"]; | |
| #onChange?: SyncedArgs<T>["onChange"]; | |
| #defaultValue?: T; | |
| constructor({ value, onChange, ...args }: SyncedArgs<T>) { | |
| this.#valueArg = value; | |
| this.#onChange = onChange; | |
| this.#defaultValue = "defaultValue" in args ? args?.defaultValue : undefined; | |
| this.#internalValue = extract(value, this.#defaultValue) as T; | |
| } | |
| get current() { | |
| return isFunction(this.#valueArg) | |
| ? (this.#valueArg() ?? this.#defaultValue ?? this.#internalValue) | |
| : this.#internalValue; | |
| } | |
| set current(value: T) { | |
| if (this.current === value) return; | |
| if (isFunction(this.#valueArg)) { | |
| this.#onChange?.(value); | |
| return; | |
| } | |
| this.#internalValue = value; | |
| this.#onChange?.(value); | |
| } | |
| } | |