react-transition-state
Version:
Zero dependency React transition state machine.
120 lines (119 loc) • 3.57 kB
JavaScript
;
const require_internal = require("./internal.cjs");
let react = require("react");
//#region src/useTransitionMap.ts
const updateState = (key, status, setStateMap, ref, config, onChange) => {
if (config) {
clearTimeout(config.t);
cancelAnimationFrame(config.r);
}
const state = require_internal.getState(status);
const stateMap = new Map(ref.m);
stateMap.set(key, state);
setStateMap(stateMap);
ref.m = stateMap;
onChange?.({
key,
current: state
});
};
const useTransitionMap = ({ allowMultiple, enter = true, exit = true, preEnter, preExit, timeout, initialEntered, mountOnEnter, unmountOnExit, onStateChange: onChange } = {}) => {
const [stateMap, setStateMap] = (0, react.useState)(/* @__PURE__ */ new Map());
const [ref] = (0, react.useState)({
m: stateMap,
c: /* @__PURE__ */ new Map()
});
const [enterTimeout, exitTimeout] = require_internal.getTimeout(timeout);
const setItem = (0, react.useCallback)((key, options) => {
const { initialEntered: _initialEntered = initialEntered } = options || {};
updateState(key, _initialEntered ? 2 : require_internal.startOrEnd(mountOnEnter), setStateMap, ref);
ref.c.set(key, { r: 0 });
}, [
initialEntered,
mountOnEnter,
ref
]);
const deleteItem = (0, react.useCallback)((key) => {
const newStateMap = new Map(ref.m);
if (newStateMap.delete(key)) {
setStateMap(newStateMap);
ref.m = newStateMap;
ref.c.delete(key);
return true;
}
return false;
}, [ref]);
const endTransition = (0, react.useCallback)((key) => {
const state = ref.m.get(key);
if (!state) {
if (process.env.NODE_ENV !== "production") console.error(`[React-Transition-State] cannot call endTransition: invalid key — ${key}`);
return;
}
const status = require_internal.getEndStatus(state.$, unmountOnExit);
if (status) updateState(key, status, setStateMap, ref, ref.c.get(key), onChange);
}, [
onChange,
unmountOnExit,
ref
]);
const toggle = (0, react.useCallback)((key, toEnter) => {
const state = ref.m.get(key);
if (!state) {
if (process.env.NODE_ENV !== "production") console.error(`[React-Transition-State] cannot call toggle: invalid key — ${key}`);
return;
}
const config = ref.c.get(key);
const transitState = (status) => {
updateState(key, status, setStateMap, ref, config, onChange);
switch (status) {
case 1:
if (enterTimeout >= 0) config.t = setTimeout(() => endTransition(key), enterTimeout);
break;
case 4:
if (exitTimeout >= 0) config.t = setTimeout(() => endTransition(key), exitTimeout);
break;
case 0:
case 3:
require_internal.nextTick(() => transitState(status + 1), config);
break;
}
};
const enterStage = state.isEnter;
if (typeof toEnter !== "boolean") toEnter = !enterStage;
if (toEnter) {
if (!enterStage) {
transitState(enter ? preEnter ? 0 : 1 : 2);
if (!allowMultiple) ref.m.forEach((_, _key) => _key !== key && toggle(_key, false));
}
} else if (enterStage) transitState(exit ? preExit ? 3 : 4 : require_internal.startOrEnd(unmountOnExit));
}, [
ref,
onChange,
endTransition,
allowMultiple,
enter,
exit,
preEnter,
preExit,
enterTimeout,
exitTimeout,
unmountOnExit
]);
return {
stateMap,
toggle,
toggleAll: (0, react.useCallback)((toEnter) => {
if (!allowMultiple && toEnter !== false) return;
for (const key of ref.m.keys()) toggle(key, toEnter);
}, [
allowMultiple,
toggle,
ref
]),
endTransition,
setItem,
deleteItem
};
};
//#endregion
exports.useTransitionMap = useTransitionMap;