UNPKG

@zag-js/store

Version:

The reactive store package for zag machines

255 lines (253 loc) • 8.5 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/proxy.ts var proxy_exports = {}; __export(proxy_exports, { getVersion: () => getVersion, proxy: () => proxy, ref: () => ref, snapshot: () => snapshot, subscribe: () => subscribe }); module.exports = __toCommonJS(proxy_exports); var import_proxy_compare = require("proxy-compare"); var import_global = require("./global.js"); var import_utils = require("./utils.js"); var proxyStateMap = (0, import_global.globalRef)("__zag__proxyStateMap", () => /* @__PURE__ */ new WeakMap()); var buildProxyFunction = (objectIs = Object.is, newProxy = (target, handler) => new Proxy(target, handler), snapCache = /* @__PURE__ */ new WeakMap(), createSnapshot = (target, version) => { const cache = snapCache.get(target); if (cache?.[0] === version) { return cache[1]; } const snap = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target)); (0, import_proxy_compare.markToTrack)(snap, true); snapCache.set(target, [version, snap]); Reflect.ownKeys(target).forEach((key) => { const value = Reflect.get(target, key); if (import_global.refSet.has(value)) { (0, import_proxy_compare.markToTrack)(value, false); snap[key] = value; } else if (proxyStateMap.has(value)) { snap[key] = snapshot(value); } else { snap[key] = value; } }); return Object.freeze(snap); }, proxyCache = /* @__PURE__ */ new WeakMap(), versionHolder = [1, 1], proxyFunction2 = (initialObject) => { if (!(0, import_utils.isObject)(initialObject)) { throw new Error("object required"); } const found = proxyCache.get(initialObject); if (found) { return found; } let version = versionHolder[0]; const listeners = /* @__PURE__ */ new Set(); const notifyUpdate = (op, nextVersion = ++versionHolder[0]) => { if (version !== nextVersion) { version = nextVersion; listeners.forEach((listener) => listener(op, nextVersion)); } }; let checkVersion = versionHolder[1]; const ensureVersion = (nextCheckVersion = ++versionHolder[1]) => { if (checkVersion !== nextCheckVersion && !listeners.size) { checkVersion = nextCheckVersion; propProxyStates.forEach(([propProxyState]) => { const propVersion = propProxyState[1](nextCheckVersion); if (propVersion > version) { version = propVersion; } }); } return version; }; const createPropListener = (prop) => (op, nextVersion) => { const newOp = [...op]; newOp[1] = [prop, ...newOp[1]]; notifyUpdate(newOp, nextVersion); }; const propProxyStates = /* @__PURE__ */ new Map(); const addPropListener = (prop, propProxyState) => { if ((0, import_utils.isDev)() && propProxyStates.has(prop)) { throw new Error("prop listener already exists"); } if (listeners.size) { const remove = propProxyState[3](createPropListener(prop)); propProxyStates.set(prop, [propProxyState, remove]); } else { propProxyStates.set(prop, [propProxyState]); } }; const removePropListener = (prop) => { const entry = propProxyStates.get(prop); if (entry) { propProxyStates.delete(prop); entry[1]?.(); } }; const addListener = (listener) => { listeners.add(listener); if (listeners.size === 1) { propProxyStates.forEach(([propProxyState, prevRemove], prop) => { if ((0, import_utils.isDev)() && prevRemove) { throw new Error("remove already exists"); } const remove = propProxyState[3](createPropListener(prop)); propProxyStates.set(prop, [propProxyState, remove]); }); } const removeListener = () => { listeners.delete(listener); if (listeners.size === 0) { propProxyStates.forEach(([propProxyState, remove], prop) => { if (remove) { remove(); propProxyStates.set(prop, [propProxyState]); } }); } }; return removeListener; }; const baseObject = Array.isArray(initialObject) ? [] : Object.create(Object.getPrototypeOf(initialObject)); const handler = { deleteProperty(target, prop) { const prevValue = Reflect.get(target, prop); removePropListener(prop); const deleted = Reflect.deleteProperty(target, prop); if (deleted) { notifyUpdate(["delete", [prop], prevValue]); } return deleted; }, set(target, prop, value, receiver) { const hasPrevValue = Reflect.has(target, prop); const prevValue = Reflect.get(target, prop, receiver); if (hasPrevValue && (objectIs(prevValue, value) || proxyCache.has(value) && objectIs(prevValue, proxyCache.get(value)))) { return true; } removePropListener(prop); if ((0, import_utils.isObject)(value)) { value = (0, import_proxy_compare.getUntracked)(value) || value; } let nextValue = value; if (Object.getOwnPropertyDescriptor(target, prop)?.set) { } else { if (!proxyStateMap.has(value) && (0, import_utils.canProxy)(value)) { nextValue = proxy(value); } const childProxyState = !import_global.refSet.has(nextValue) && proxyStateMap.get(nextValue); if (childProxyState) { addPropListener(prop, childProxyState); } } Reflect.set(target, prop, nextValue, receiver); notifyUpdate(["set", [prop], value, prevValue]); return true; } }; const proxyObject = newProxy(baseObject, handler); proxyCache.set(initialObject, proxyObject); const proxyState = [baseObject, ensureVersion, createSnapshot, addListener]; proxyStateMap.set(proxyObject, proxyState); Reflect.ownKeys(initialObject).forEach((key) => { const desc = Object.getOwnPropertyDescriptor(initialObject, key); if (desc.get || desc.set) { Object.defineProperty(baseObject, key, desc); } else { proxyObject[key] = initialObject[key]; } }); return proxyObject; }) => [ // public functions proxyFunction2, // shared state proxyStateMap, import_global.refSet, // internal things objectIs, newProxy, import_utils.canProxy, snapCache, createSnapshot, proxyCache, versionHolder ]; var [proxyFunction] = buildProxyFunction(); function proxy(initialObject = {}) { return proxyFunction(initialObject); } function getVersion(proxyObject) { const proxyState = proxyStateMap.get(proxyObject); return proxyState?.[1](); } function subscribe(proxyObject, callback, notifyInSync) { const proxyState = proxyStateMap.get(proxyObject); if ((0, import_utils.isDev)() && !proxyState) { console.warn("Please use proxy object"); } let promise; const ops = []; const addListener = proxyState[3]; let isListenerActive = false; const listener = (op) => { ops.push(op); if (notifyInSync) { callback(ops.splice(0)); return; } if (!promise) { promise = Promise.resolve().then(() => { promise = void 0; if (isListenerActive) { callback(ops.splice(0)); } }); } }; const removeListener = addListener(listener); isListenerActive = true; return () => { isListenerActive = false; removeListener(); }; } function snapshot(proxyObject) { const proxyState = proxyStateMap.get(proxyObject); if ((0, import_utils.isDev)() && !proxyState) { console.warn("Please use proxy object"); } const [target, ensureVersion, createSnapshot] = proxyState; return createSnapshot(target, ensureVersion()); } function ref(obj) { import_global.refSet.add(obj); return obj; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { getVersion, proxy, ref, snapshot, subscribe });