UNPKG

jotai

Version:

👻 Next gen state management that will spook you

504 lines (413 loc) • 15.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var react = require('react'); var jotai = require('jotai'); function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var RESTORE_ATOMS = 'h'; var DEV_SUBSCRIBE_STATE = 'n'; var DEV_GET_MOUNTED_ATOMS = 'l'; var DEV_GET_ATOM_STATE = 'a'; var DEV_GET_MOUNTED = 'm'; var atomToPrintable$1 = function atomToPrintable(atom) { return atom.debugLabel || atom.toString(); }; var stateToPrintable = function stateToPrintable(_ref) { var store = _ref[0], atoms = _ref[1]; return Object.fromEntries(atoms.flatMap(function (atom) { var _store$DEV_GET_MOUNTE, _store$DEV_GET_ATOM_S; var mounted = (_store$DEV_GET_MOUNTE = store[DEV_GET_MOUNTED]) == null ? void 0 : _store$DEV_GET_MOUNTE.call(store, atom); if (!mounted) { return []; } var dependents = mounted.t; var atomState = ((_store$DEV_GET_ATOM_S = store[DEV_GET_ATOM_STATE]) == null ? void 0 : _store$DEV_GET_ATOM_S.call(store, atom)) || {}; return [[atomToPrintable$1(atom), _extends({}, 'e' in atomState && { error: atomState.e }, 'p' in atomState && { promise: atomState.p }, 'v' in atomState && { value: atomState.v }, { dependents: Array.from(dependents).map(atomToPrintable$1) })]]; })); }; var useAtomsDebugValue = function useAtomsDebugValue(options) { var _options$enabled; var enabled = (_options$enabled = options == null ? void 0 : options.enabled) != null ? _options$enabled : process.env.NODE_ENV !== "production"; var ScopeContext = jotai.SECRET_INTERNAL_getScopeContext(options == null ? void 0 : options.scope); var _useContext = react.useContext(ScopeContext), store = _useContext.s; var _useState = react.useState([]), atoms = _useState[0], setAtoms = _useState[1]; react.useEffect(function () { var _store$DEV_SUBSCRIBE_; if (!enabled) { return; } var callback = function callback() { var _store$DEV_GET_MOUNTE2; setAtoms(Array.from(((_store$DEV_GET_MOUNTE2 = store[DEV_GET_MOUNTED_ATOMS]) == null ? void 0 : _store$DEV_GET_MOUNTE2.call(store)) || [])); }; var unsubscribe = (_store$DEV_SUBSCRIBE_ = store[DEV_SUBSCRIBE_STATE]) == null ? void 0 : _store$DEV_SUBSCRIBE_.call(store, callback); callback(); return unsubscribe; }, [enabled, store]); react.useDebugValue([store, atoms], stateToPrintable); }; function useAtomDevtools(anAtom, options, deprecatedScope) { if (typeof options === 'string' || typeof deprecatedScope !== 'undefined') { console.warn('DEPRECATED [useAtomDevtools] use DevtoolOptions'); options = { name: options, scope: deprecatedScope }; } var _ref = options || {}, enabled = _ref.enabled, name = _ref.name, scope = _ref.scope; var extension; try { extension = (enabled != null ? enabled : process.env.NODE_ENV !== "production") && window.__REDUX_DEVTOOLS_EXTENSION__; } catch (_unused) {} if (!extension) { if (process.env.NODE_ENV !== "production" && enabled) { console.warn('Please install/enable Redux devtools extension'); } } var _useAtom = jotai.useAtom(anAtom, scope), value = _useAtom[0], setValue = _useAtom[1]; var lastValue = react.useRef(value); var isTimeTraveling = react.useRef(false); var devtools = react.useRef(); var atomName = name || anAtom.debugLabel || anAtom.toString(); react.useEffect(function () { if (!extension) { return; } var setValueIfWritable = function setValueIfWritable(value) { if (typeof setValue === 'function') { setValue(value); return; } console.warn('[Warn] you cannot do write operations (Time-travelling, etc) in read-only atoms\n', anAtom); }; devtools.current = extension.connect({ name: atomName }); var unsubscribe = devtools.current.subscribe(function (message) { var _message$payload3, _message$payload4; if (message.type === 'ACTION' && message.payload) { try { setValueIfWritable(JSON.parse(message.payload)); } catch (e) { console.error('please dispatch a serializable value that JSON.parse() support\n', e); } } else if (message.type === 'DISPATCH' && message.state) { var _message$payload, _message$payload2; if (((_message$payload = message.payload) == null ? void 0 : _message$payload.type) === 'JUMP_TO_ACTION' || ((_message$payload2 = message.payload) == null ? void 0 : _message$payload2.type) === 'JUMP_TO_STATE') { isTimeTraveling.current = true; setValueIfWritable(JSON.parse(message.state)); } } else if (message.type === 'DISPATCH' && ((_message$payload3 = message.payload) == null ? void 0 : _message$payload3.type) === 'COMMIT') { var _devtools$current; (_devtools$current = devtools.current) == null ? void 0 : _devtools$current.init(lastValue.current); } else if (message.type === 'DISPATCH' && ((_message$payload4 = message.payload) == null ? void 0 : _message$payload4.type) === 'IMPORT_STATE') { var _message$payload$next; var computedStates = ((_message$payload$next = message.payload.nextLiftedState) == null ? void 0 : _message$payload$next.computedStates) || []; computedStates.forEach(function (_ref2, index) { var state = _ref2.state; if (index === 0) { var _devtools$current2; (_devtools$current2 = devtools.current) == null ? void 0 : _devtools$current2.init(state); } else { setValueIfWritable(state); } }); } }); devtools.current.shouldInit = true; return unsubscribe; }, [anAtom, extension, atomName, setValue]); react.useEffect(function () { if (!devtools.current) { return; } lastValue.current = value; if (devtools.current.shouldInit) { devtools.current.init(value); devtools.current.shouldInit = false; } else if (isTimeTraveling.current) { isTimeTraveling.current = false; } else { devtools.current.send(atomName + " - " + new Date().toLocaleString(), value); } }, [anAtom, extension, atomName, value]); } var isEqualAtomsValues = function isEqualAtomsValues(left, right) { return left.size === right.size && Array.from(left).every(function (_ref) { var left = _ref[0], v = _ref[1]; return Object.is(right.get(left), v); }); }; var isEqualAtomsDependents = function isEqualAtomsDependents(left, right) { return left.size === right.size && Array.from(left).every(function (_ref2) { var a = _ref2[0], dLeft = _ref2[1]; var dRight = right.get(a); return dRight && dLeft.size === dRight.size && Array.from(dLeft).every(function (d) { return dRight.has(d); }); }); }; function useAtomsSnapshot(scope) { var ScopeContext = jotai.SECRET_INTERNAL_getScopeContext(scope); var scopeContainer = react.useContext(ScopeContext); var store = scopeContainer.s; var _useState = react.useState(function () { return { values: new Map(), dependents: new Map() }; }), atomsSnapshot = _useState[0], setAtomsSnapshot = _useState[1]; react.useEffect(function () { if (!store[DEV_SUBSCRIBE_STATE]) return; var prevValues = new Map(); var prevDependents = new Map(); var invalidatedAtoms = new Set(); var callback = function callback() { var values = new Map(); var dependents = new Map(); var hasNewInvalidatedAtoms = false; for (var _iterator = _createForOfIteratorHelperLoose(store[DEV_GET_MOUNTED_ATOMS]() || []), _step; !(_step = _iterator()).done;) { var atom = _step.value; var atomState = store[DEV_GET_ATOM_STATE](atom); if (atomState) { if (!atomState.y) { if ('p' in atomState) { return; } if (!invalidatedAtoms.has(atom)) { invalidatedAtoms.add(atom); hasNewInvalidatedAtoms = true; } } if ('v' in atomState) { values.set(atom, atomState.v); } } var mounted = store[DEV_GET_MOUNTED](atom); if (mounted) { dependents.set(atom, mounted.t); } } if (hasNewInvalidatedAtoms) { return; } if (isEqualAtomsValues(prevValues, values) && isEqualAtomsDependents(prevDependents, dependents)) { return; } prevValues = values; prevDependents = dependents; invalidatedAtoms.clear(); setAtomsSnapshot({ values: values, dependents: dependents }); }; var unsubscribe = store[DEV_SUBSCRIBE_STATE](callback); callback(); return unsubscribe; }, [store]); return atomsSnapshot; } function useGotoAtomsSnapshot(scope) { var ScopeContext = jotai.SECRET_INTERNAL_getScopeContext(scope); var _useContext = react.useContext(ScopeContext), store = _useContext.s, versionedWrite = _useContext.w; return react.useCallback(function (snapshot) { if (!store[DEV_SUBSCRIBE_STATE]) return; var restoreAtoms = function restoreAtoms(values) { if (versionedWrite) { versionedWrite(function (version) { store[RESTORE_ATOMS](values, version); }); } else { store[RESTORE_ATOMS](values); } }; if (isIterable(snapshot)) { if (process.env.NODE_ENV !== "production") { console.warn('snapshot as iterable is deprecated. use an object instead.'); } restoreAtoms(snapshot); return; } restoreAtoms(snapshot.values); }, [store, versionedWrite]); } var isIterable = function isIterable(item) { return typeof item[Symbol.iterator] === 'function'; }; var atomToPrintable = function atomToPrintable(atom) { return atom.debugLabel ? atom + ":" + atom.debugLabel : "" + atom; }; var getDevtoolsState = function getDevtoolsState(atomsSnapshot) { var values = {}; atomsSnapshot.values.forEach(function (v, atom) { values[atomToPrintable(atom)] = v; }); var dependents = {}; atomsSnapshot.dependents.forEach(function (d, atom) { dependents[atomToPrintable(atom)] = Array.from(d).map(atomToPrintable); }); return { values: values, dependents: dependents }; }; function useAtomsDevtools(name, options) { if (typeof options !== 'undefined' && typeof options !== 'object') { console.warn('DEPRECATED [useAtomsDevtools] use DevtoolsOptions'); options = { scope: options }; } var _ref = options || {}, enabled = _ref.enabled, scope = _ref.scope; var extension; try { extension = (enabled != null ? enabled : process.env.NODE_ENV !== "production") && window.__REDUX_DEVTOOLS_EXTENSION__; } catch (_unused) {} if (!extension) { if (process.env.NODE_ENV !== "production" && enabled) { console.warn('Please install/enable Redux devtools extension'); } } var atomsSnapshot = useAtomsSnapshot(scope); var goToSnapshot = useGotoAtomsSnapshot(scope); var isTimeTraveling = react.useRef(false); var isRecording = react.useRef(true); var devtools = react.useRef(); var snapshots = react.useRef([]); react.useEffect(function () { if (!extension) { return; } var getSnapshotAt = function getSnapshotAt(index) { if (index === void 0) { index = snapshots.current.length - 1; } var snapshot = snapshots.current[index >= 0 ? index : 0]; if (!snapshot) { throw new Error('snaphost index out of bounds'); } return snapshot; }; var connection = extension.connect({ name: name }); var devtoolsUnsubscribe = connection.subscribe(function (message) { var _message$payload; switch (message.type) { case 'DISPATCH': switch ((_message$payload = message.payload) == null ? void 0 : _message$payload.type) { case 'RESET': break; case 'COMMIT': connection.init(getDevtoolsState(getSnapshotAt())); snapshots.current = []; break; case 'JUMP_TO_ACTION': case 'JUMP_TO_STATE': isTimeTraveling.current = true; goToSnapshot(getSnapshotAt(message.payload.actionId - 1)); break; case 'PAUSE_RECORDING': isRecording.current = !isRecording.current; break; } } }); devtools.current = connection; devtools.current.shouldInit = true; return devtoolsUnsubscribe; }, [extension, goToSnapshot, name]); react.useEffect(function () { if (!devtools.current) { return; } if (devtools.current.shouldInit) { devtools.current.init(undefined); devtools.current.shouldInit = false; return; } if (isTimeTraveling.current) { isTimeTraveling.current = false; } else if (isRecording.current) { snapshots.current.push(atomsSnapshot); devtools.current.send({ type: "" + snapshots.current.length, updatedAt: new Date().toLocaleString() }, getDevtoolsState(atomsSnapshot)); } }, [atomsSnapshot]); } exports.useAtomDevtools = useAtomDevtools; exports.useAtomsDebugValue = useAtomsDebugValue; exports.useAtomsDevtools = useAtomsDevtools; exports.useAtomsSnapshot = useAtomsSnapshot; exports.useGotoAtomsSnapshot = useGotoAtomsSnapshot;