@zag-js/preact
Version:
The preact wrapper for zag
63 lines (62 loc) • 1.76 kB
JavaScript
// src/bindable.ts
import { isEqual, isFunction } from "@zag-js/utils";
import { flushSync } from "preact/compat";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
var identity = (v) => v();
function useBindable(props) {
const initial = props().value ?? props().defaultValue;
const eq = props().isEqual ?? isEqual;
const [initialValue] = useState(initial);
const [value, setValue] = useState(initialValue);
const controlled = props().value !== void 0;
const valueRef = useRef(value);
valueRef.current = controlled ? props().value : value;
const prevValue = useRef(valueRef.current);
useLayoutEffect(() => {
prevValue.current = valueRef.current;
}, [value, props().value]);
const setFn = (value2) => {
const prev = prevValue.current;
const next = isFunction(value2) ? value2(prev) : value2;
if (props().debug) {
console.log(`[bindable > ${props().debug}] setValue`, { next, prev });
}
if (!controlled) setValue(next);
if (!eq(next, prev)) {
props().onChange?.(next, prev);
}
};
function get() {
return controlled ? props().value : value;
}
return {
initial: initialValue,
ref: valueRef,
get,
set(value2) {
const exec = props().sync ? flushSync : identity;
exec(() => setFn(value2));
},
invoke(nextValue, prevValue2) {
props().onChange?.(nextValue, prevValue2);
},
hash(value2) {
return props().hash?.(value2) ?? String(value2);
}
};
}
useBindable.cleanup = (fn) => {
useLayoutEffect(() => fn, []);
};
useBindable.ref = (defaultValue) => {
const value = useRef(defaultValue);
return {
get: () => value.current,
set: (next) => {
value.current = next;
}
};
};
export {
useBindable
};