@codebelt/classy-store 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,10 +1,8 @@
1
- import { a as subscribe, c as shallowEqual, i as store, n as getInternal, o as PROXYABLE, r as getVersion, t as snapshot } from "./snapshot-fVu34Cr6.mjs";
2
- import { createProxy, isChanged } from "proxy-compare";
3
- import { useCallback, useRef, useSyncExternalStore } from "react";
1
+ import { a as subscribe, i as getVersion, n as createClassyStore, o as PROXYABLE, t as snapshot } from "./snapshot-P0QPV1ER.mjs";
4
2
 
5
- //#region src/collections.ts
3
+ //#region src/collections/collections.ts
6
4
  /**
7
- * A Map-like class backed by a plain array so `store()` can proxy mutations.
5
+ * A Map-like class backed by a plain array so `createClassyStore()` can proxy mutations.
8
6
  *
9
7
  * Native `Map` uses internal slots that ES6 Proxy can't intercept, so mutations
10
8
  * like `.set()` would be invisible to the store. `ReactiveMap` solves this by
@@ -12,7 +10,7 @@ import { useCallback, useRef, useSyncExternalStore } from "react";
12
10
  *
13
11
  * Usage:
14
12
  * ```ts
15
- * const myStore = store({ users: reactiveMap<string, User>() });
13
+ * const myStore = createClassyStore({ users: reactiveMap<string, User>() });
16
14
  * myStore.users.set('id1', { name: 'Alice' }); // reactive
17
15
  * ```
18
16
  */
@@ -81,7 +79,7 @@ var ReactiveMap = class {
81
79
  }
82
80
  };
83
81
  /**
84
- * A Set-like class backed by a plain array so `store()` can proxy mutations.
82
+ * A Set-like class backed by a plain array so `createClassyStore()` can proxy mutations.
85
83
  *
86
84
  * Native `Set` uses internal slots that ES6 Proxy can't intercept, so mutations
87
85
  * like `.add()` would be invisible to the store. `ReactiveSet` solves this by
@@ -89,7 +87,7 @@ var ReactiveMap = class {
89
87
  *
90
88
  * Usage:
91
89
  * ```ts
92
- * const myStore = store({ tags: reactiveSet<string>(['urgent']) });
90
+ * const myStore = createClassyStore({ tags: reactiveSet<string>(['urgent']) });
93
91
  * myStore.tags.add('bug'); // reactive
94
92
  * ```
95
93
  */
@@ -150,7 +148,7 @@ var ReactiveSet = class {
150
148
  };
151
149
  /**
152
150
  * Creates a reactive Map-like collection backed by a plain array.
153
- * Wrap the parent object with `store()` for full reactivity.
151
+ * Wrap the parent object with `createClassyStore()` for full reactivity.
154
152
  *
155
153
  * @param initial - Optional iterable of `[key, value]` pairs.
156
154
  */
@@ -159,7 +157,7 @@ function reactiveMap(initial) {
159
157
  }
160
158
  /**
161
159
  * Creates a reactive Set-like collection backed by a plain array.
162
- * Wrap the parent object with `store()` for full reactivity.
160
+ * Wrap the parent object with `createClassyStore()` for full reactivity.
163
161
  *
164
162
  * @param initial - Optional iterable of values.
165
163
  */
@@ -168,59 +166,30 @@ function reactiveSet(initial) {
168
166
  }
169
167
 
170
168
  //#endregion
171
- //#region src/useStore.ts
172
- function useStore(proxyStore, selector, isEqual) {
173
- getInternal(proxyStore);
174
- const subscribe$1 = useCallback((onStoreChange) => subscribe(proxyStore, onStoreChange), [proxyStore]);
175
- const snapRef = useRef(void 0);
176
- const resultRef = useRef(void 0);
177
- const affected = useRef(/* @__PURE__ */ new WeakMap()).current;
178
- const proxyCache = useRef(/* @__PURE__ */ new WeakMap()).current;
179
- const prevSnapRef = useRef(void 0);
180
- const wrappedRef = useRef(void 0);
181
- const getSnapshot = () => selector ? getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual) : getAutoTrackSnapshot(proxyStore, affected, proxyCache, prevSnapRef, wrappedRef);
182
- return useSyncExternalStore(subscribe$1, getSnapshot, getSnapshot);
183
- }
169
+ //#region src/utils/equality/equality.ts
184
170
  /**
185
- * `getSnapshot` implementation for selector mode.
186
- *
187
- * Fast-paths when the snapshot reference hasn't changed (O(1)). Otherwise
188
- * runs the selector against the new snapshot and compares the result to the
189
- * previous one via `Object.is` (or a custom `isEqual`). Returns the previous
190
- * result reference when equal, preventing unnecessary React re-renders.
171
+ * Shallow-equal comparison for objects and arrays.
172
+ * Useful as a custom `isEqual` for `useStore` selectors that return objects/arrays.
191
173
  *
192
- * Pure function -- no hooks, safe to call from `useSyncExternalStore`.
174
+ * - Primitives compared with `Object.is`.
175
+ * - Arrays: length + element-wise `Object.is`.
176
+ * - Objects: key count + value-wise `Object.is`.
193
177
  */
194
- function getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual) {
195
- const nextSnap = snapshot(proxyStore);
196
- if (snapRef.current === nextSnap && resultRef.current !== void 0) return resultRef.current;
197
- const nextResult = selector(nextSnap);
198
- snapRef.current = nextSnap;
199
- if (resultRef.current !== void 0 && (isEqual ? isEqual(resultRef.current, nextResult) : Object.is(resultRef.current, nextResult))) return resultRef.current;
200
- resultRef.current = nextResult;
201
- return nextResult;
202
- }
203
- /**
204
- * `getSnapshot` implementation for auto-tracked (selectorless) mode.
205
- *
206
- * Uses `proxy-compare` to diff only the properties the component actually read.
207
- * If the snapshot reference is the same, returns the cached tracking proxy.
208
- * If the snapshot changed but no tracked property differs (`isChanged` returns
209
- * false), also returns the cached proxy -- avoiding re-render. Only when a
210
- * relevant property changed does it create a new `createProxy` wrapper.
211
- *
212
- * Pure function -- no hooks, safe to call from `useSyncExternalStore`.
213
- */
214
- function getAutoTrackSnapshot(proxyStore, affected, proxyCache, prevSnapRef, wrappedRef) {
215
- const nextSnap = snapshot(proxyStore);
216
- if (prevSnapRef.current === nextSnap) return wrappedRef.current;
217
- if (prevSnapRef.current !== void 0 && !isChanged(prevSnapRef.current, nextSnap, affected)) return wrappedRef.current;
218
- prevSnapRef.current = nextSnap;
219
- const wrapped = createProxy(nextSnap, affected, proxyCache);
220
- wrappedRef.current = wrapped;
221
- return wrapped;
178
+ function shallowEqual(a, b) {
179
+ if (Object.is(a, b)) return true;
180
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
181
+ if (Array.isArray(a) && Array.isArray(b)) {
182
+ if (a.length !== b.length) return false;
183
+ for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false;
184
+ return true;
185
+ }
186
+ const keysA = Object.keys(a);
187
+ const keysB = Object.keys(b);
188
+ if (keysA.length !== keysB.length) return false;
189
+ for (const key of keysA) if (!Object.hasOwn(b, key) || !Object.is(a[key], b[key])) return false;
190
+ return true;
222
191
  }
223
192
 
224
193
  //#endregion
225
- export { getVersion, reactiveMap, reactiveSet, shallowEqual, snapshot, store, subscribe, useStore };
194
+ export { createClassyStore, getVersion, reactiveMap, reactiveSet, shallowEqual, snapshot, subscribe };
226
195
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["subscribe","coreSubscribe"],"sources":["../src/collections.ts","../src/useStore.ts"],"sourcesContent":["import {PROXYABLE} from './utils';\n\n// ── ReactiveMap ───────────────────────────────────────────────────────────────\n\n/**\n * A Map-like class backed by a plain array so `store()` can proxy mutations.\n *\n * Native `Map` uses internal slots that ES6 Proxy can't intercept, so mutations\n * like `.set()` would be invisible to the store. `ReactiveMap` solves this by\n * storing entries in a plain array (`_entries`) that the proxy can track.\n *\n * Usage:\n * ```ts\n * const myStore = store({ users: reactiveMap<string, User>() });\n * myStore.users.set('id1', { name: 'Alice' }); // reactive\n * ```\n */\nexport class ReactiveMap<K, V> {\n static [PROXYABLE] = true;\n\n /** @internal Backing storage — proxied by store(). */\n _entries: [K, V][] = [];\n\n /** Deduplicates initial entries by key (last value wins, matching native `Map`). */\n constructor(initial?: Iterable<[K, V]>) {\n if (initial) {\n for (const [k, v] of initial) {\n const index = this._entries.findIndex(([ek]) => Object.is(ek, k));\n if (index !== -1) {\n this._entries[index] = [k, v];\n } else {\n this._entries.push([k, v]);\n }\n }\n }\n }\n\n /** Returns the number of entries. */\n get size(): number {\n return this._entries.length;\n }\n\n /** Returns the value for `key`, or `undefined`. O(n) linear scan. */\n get(key: K): V | undefined {\n const entry = this._entries.find(([k]) => Object.is(k, key));\n return entry ? entry[1] : undefined;\n }\n\n /** Returns `true` if `key` exists. O(n) linear scan. */\n has(key: K): boolean {\n return this._entries.some(([k]) => Object.is(k, key));\n }\n\n /** Sets `key` to `value`. Updates in-place if key exists, appends otherwise. */\n set(key: K, value: V): this {\n const index = this._entries.findIndex(([k]) => Object.is(k, key));\n if (index !== -1) {\n this._entries[index] = [key, value];\n } else {\n this._entries.push([key, value]);\n }\n return this;\n }\n\n /** Removes the entry for `key`. Returns `true` if found. */\n delete(key: K): boolean {\n const index = this._entries.findIndex(([k]) => Object.is(k, key));\n if (index === -1) return false;\n this._entries.splice(index, 1);\n return true;\n }\n\n /** Removes all entries. Uses splice to trigger proxy notification. */\n clear(): void {\n this._entries.splice(0, this._entries.length);\n }\n\n /** Returns an iterator over the keys. */\n keys(): IterableIterator<K> {\n return this._entries.map(([k]) => k)[Symbol.iterator]();\n }\n\n /** Returns an iterator over the values. */\n values(): IterableIterator<V> {\n return this._entries.map(([, v]) => v)[Symbol.iterator]();\n }\n\n /** Returns an iterator over [key, value] pairs. */\n entries(): IterableIterator<[K, V]> {\n return this._entries.map(([k, v]) => [k, v] as [K, V])[Symbol.iterator]();\n }\n\n /** Calls `callback` for each entry, matching the native `Map.forEach` signature. */\n forEach(callback: (value: V, key: K, map: ReactiveMap<K, V>) => void): void {\n for (const [k, v] of this._entries) {\n callback(v, k, this);\n }\n }\n\n /** Enables `for...of` iteration over [key, value] pairs. */\n [Symbol.iterator](): IterableIterator<[K, V]> {\n return this.entries();\n }\n}\n\n// ── ReactiveSet ───────────────────────────────────────────────────────────────\n\n/**\n * A Set-like class backed by a plain array so `store()` can proxy mutations.\n *\n * Native `Set` uses internal slots that ES6 Proxy can't intercept, so mutations\n * like `.add()` would be invisible to the store. `ReactiveSet` solves this by\n * storing items in a plain array (`_items`) that the proxy can track.\n *\n * Usage:\n * ```ts\n * const myStore = store({ tags: reactiveSet<string>(['urgent']) });\n * myStore.tags.add('bug'); // reactive\n * ```\n */\nexport class ReactiveSet<T> {\n static [PROXYABLE] = true;\n\n /** @internal Backing storage — proxied by store(). */\n _items: T[] = [];\n\n /** Deduplicates initial values using `Object.is` comparison. */\n constructor(initial?: Iterable<T>) {\n if (initial) {\n for (const v of initial) {\n if (!this._items.some((item) => Object.is(item, v))) {\n this._items.push(v);\n }\n }\n }\n }\n\n /** Returns the number of unique items. */\n get size(): number {\n return this._items.length;\n }\n\n /** Returns `true` if `value` exists. O(n) linear scan. */\n has(value: T): boolean {\n return this._items.some((item) => Object.is(item, value));\n }\n\n /** Adds `value` if not already present (no-op for duplicates). */\n add(value: T): this {\n if (!this.has(value)) {\n this._items.push(value);\n }\n return this;\n }\n\n /** Removes `value`. Returns `true` if found. */\n delete(value: T): boolean {\n const index = this._items.findIndex((item) => Object.is(item, value));\n if (index === -1) return false;\n this._items.splice(index, 1);\n return true;\n }\n\n /** Removes all items. Uses splice to trigger proxy notification. */\n clear(): void {\n this._items.splice(0, this._items.length);\n }\n\n /** Returns an iterator over the values (same as `values()`, matching Set API). */\n keys(): IterableIterator<T> {\n return this._items[Symbol.iterator]();\n }\n\n /** Returns an iterator over the values. */\n values(): IterableIterator<T> {\n return this._items[Symbol.iterator]();\n }\n\n /** Returns an iterator over [value, value] pairs, matching the native Set API. */\n entries(): IterableIterator<[T, T]> {\n return this._items.map((v) => [v, v] as [T, T])[Symbol.iterator]();\n }\n\n /** Calls `callback` for each item, matching the native `Set.forEach` signature. */\n forEach(callback: (value: T, key: T, set: ReactiveSet<T>) => void): void {\n for (const v of this._items) {\n callback(v, v, this);\n }\n }\n\n /** Enables `for...of` iteration over values. */\n [Symbol.iterator](): IterableIterator<T> {\n return this.values();\n }\n}\n\n// ── Factory functions ─────────────────────────────────────────────────────────\n\n/**\n * Creates a reactive Map-like collection backed by a plain array.\n * Wrap the parent object with `store()` for full reactivity.\n *\n * @param initial - Optional iterable of `[key, value]` pairs.\n */\nexport function reactiveMap<K, V>(\n initial?: Iterable<[K, V]>,\n): ReactiveMap<K, V> {\n return new ReactiveMap(initial);\n}\n\n/**\n * Creates a reactive Set-like collection backed by a plain array.\n * Wrap the parent object with `store()` for full reactivity.\n *\n * @param initial - Optional iterable of values.\n */\nexport function reactiveSet<T>(initial?: Iterable<T>): ReactiveSet<T> {\n return new ReactiveSet(initial);\n}\n","import {createProxy, isChanged} from 'proxy-compare';\nimport {useCallback, useRef, useSyncExternalStore} from 'react';\nimport {subscribe as coreSubscribe, getInternal} from './core';\nimport {snapshot} from './snapshot';\nimport type {Snapshot} from './types';\n\n// ── Overloads ─────────────────────────────────────────────────────────────────\n\n/**\n * Subscribe to a store proxy with an explicit selector.\n *\n * Re-renders only when the selected value changes (compared via `Object.is`\n * by default, or a custom `isEqual`).\n *\n * @param proxyStore - A reactive proxy created by `store()`.\n * @param selector - Picks data from the immutable snapshot.\n * @param isEqual - Optional custom equality function (default: `Object.is`).\n */\nexport function useStore<T extends object, S>(\n proxyStore: T,\n selector: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): S;\n\n/**\n * Subscribe to a store proxy **without** a selector (auto-tracked mode).\n *\n * Returns a `proxy-compare` tracking proxy over the immutable snapshot.\n * The component only re-renders when a property it actually read changes.\n *\n * @param proxyStore - A reactive proxy created by `store()`.\n */\nexport function useStore<T extends object>(proxyStore: T): Snapshot<T>;\n\n// ── Implementation ────────────────────────────────────────────────────────────\n\nexport function useStore<T extends object, S>(\n proxyStore: T,\n selector?: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Snapshot<T> | S {\n // Validate that the argument is actually a store proxy (throws if not).\n getInternal(proxyStore);\n\n // Stable subscribe function (internal identity never changes for a given store).\n const subscribe = useCallback(\n (onStoreChange: () => void) => coreSubscribe(proxyStore, onStoreChange),\n [proxyStore],\n );\n\n // ── Refs used by both modes (always allocated to satisfy Rules of Hooks) ──\n\n // Selector mode refs\n const snapRef = useRef<Snapshot<T> | undefined>(undefined);\n const resultRef = useRef<S | undefined>(undefined);\n\n // Auto-track mode refs\n const affected = useRef(new WeakMap<object, unknown>()).current;\n const proxyCache = useRef(new WeakMap<object, unknown>()).current;\n const prevSnapRef = useRef<Snapshot<T> | undefined>(undefined);\n const wrappedRef = useRef<Snapshot<T> | undefined>(undefined);\n\n // ── Single getSnapshot for useSyncExternalStore ───────────────────────────\n\n const getSnapshot = (): Snapshot<T> | S =>\n selector\n ? getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual)\n : getAutoTrackSnapshot(\n proxyStore,\n affected,\n proxyCache,\n prevSnapRef,\n wrappedRef,\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n// ── Selector mode logic (pure function, no hooks) ─────────────────────────────\n\n/**\n * `getSnapshot` implementation for selector mode.\n *\n * Fast-paths when the snapshot reference hasn't changed (O(1)). Otherwise\n * runs the selector against the new snapshot and compares the result to the\n * previous one via `Object.is` (or a custom `isEqual`). Returns the previous\n * result reference when equal, preventing unnecessary React re-renders.\n *\n * Pure function -- no hooks, safe to call from `useSyncExternalStore`.\n */\nfunction getSelectorSnapshot<T extends object, S>(\n proxyStore: T,\n snapRef: React.RefObject<Snapshot<T> | undefined>,\n resultRef: React.RefObject<S | undefined>,\n selector: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): S {\n const nextSnap = snapshot(proxyStore);\n\n // Fast path: same snapshot reference → same result.\n if (snapRef.current === nextSnap && resultRef.current !== undefined) {\n return resultRef.current;\n }\n\n const nextResult = selector(nextSnap);\n snapRef.current = nextSnap;\n\n // Check equality with previous result.\n if (\n resultRef.current !== undefined &&\n (isEqual\n ? isEqual(resultRef.current, nextResult)\n : Object.is(resultRef.current, nextResult))\n ) {\n return resultRef.current;\n }\n\n resultRef.current = nextResult;\n return nextResult;\n}\n\n// ── Auto-tracked (selectorless) mode logic (pure function, no hooks) ──────────\n\n/**\n * `getSnapshot` implementation for auto-tracked (selectorless) mode.\n *\n * Uses `proxy-compare` to diff only the properties the component actually read.\n * If the snapshot reference is the same, returns the cached tracking proxy.\n * If the snapshot changed but no tracked property differs (`isChanged` returns\n * false), also returns the cached proxy -- avoiding re-render. Only when a\n * relevant property changed does it create a new `createProxy` wrapper.\n *\n * Pure function -- no hooks, safe to call from `useSyncExternalStore`.\n */\nfunction getAutoTrackSnapshot<T extends object>(\n proxyStore: T,\n affected: WeakMap<object, unknown>,\n proxyCache: WeakMap<object, unknown>,\n prevSnapRef: React.RefObject<Snapshot<T> | undefined>,\n wrappedRef: React.RefObject<Snapshot<T> | undefined>,\n): Snapshot<T> {\n const nextSnap = snapshot(proxyStore);\n\n // If the raw snapshot is the same reference, nothing changed.\n if (prevSnapRef.current === nextSnap) {\n return wrappedRef.current as Snapshot<T>;\n }\n\n // Check if any property the component actually read has changed.\n if (\n prevSnapRef.current !== undefined &&\n !isChanged(prevSnapRef.current, nextSnap, affected)\n ) {\n // No property the component cares about changed → return same wrapped proxy.\n return wrappedRef.current as Snapshot<T>;\n }\n\n // Something relevant changed — create a new tracking proxy.\n prevSnapRef.current = nextSnap;\n const wrapped = createProxy(nextSnap, affected, proxyCache) as Snapshot<T>;\n wrappedRef.current = wrapped;\n return wrapped;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/collections/collections.ts","../src/utils/equality/equality.ts"],"sourcesContent":["import {PROXYABLE} from '../utils/internal/internal';\n\n// ── ReactiveMap ───────────────────────────────────────────────────────────────\n\n/**\n * A Map-like class backed by a plain array so `createClassyStore()` can proxy mutations.\n *\n * Native `Map` uses internal slots that ES6 Proxy can't intercept, so mutations\n * like `.set()` would be invisible to the store. `ReactiveMap` solves this by\n * storing entries in a plain array (`_entries`) that the proxy can track.\n *\n * Usage:\n * ```ts\n * const myStore = createClassyStore({ users: reactiveMap<string, User>() });\n * myStore.users.set('id1', { name: 'Alice' }); // reactive\n * ```\n */\nexport class ReactiveMap<K, V> {\n static [PROXYABLE] = true;\n\n /** @internal Backing storage — proxied by store(). */\n _entries: [K, V][] = [];\n\n /** Deduplicates initial entries by key (last value wins, matching native `Map`). */\n constructor(initial?: Iterable<[K, V]>) {\n if (initial) {\n for (const [k, v] of initial) {\n const index = this._entries.findIndex(([ek]) => Object.is(ek, k));\n if (index !== -1) {\n this._entries[index] = [k, v];\n } else {\n this._entries.push([k, v]);\n }\n }\n }\n }\n\n /** Returns the number of entries. */\n get size(): number {\n return this._entries.length;\n }\n\n /** Returns the value for `key`, or `undefined`. O(n) linear scan. */\n get(key: K): V | undefined {\n const entry = this._entries.find(([k]) => Object.is(k, key));\n return entry ? entry[1] : undefined;\n }\n\n /** Returns `true` if `key` exists. O(n) linear scan. */\n has(key: K): boolean {\n return this._entries.some(([k]) => Object.is(k, key));\n }\n\n /** Sets `key` to `value`. Updates in-place if key exists, appends otherwise. */\n set(key: K, value: V): this {\n const index = this._entries.findIndex(([k]) => Object.is(k, key));\n if (index !== -1) {\n this._entries[index] = [key, value];\n } else {\n this._entries.push([key, value]);\n }\n return this;\n }\n\n /** Removes the entry for `key`. Returns `true` if found. */\n delete(key: K): boolean {\n const index = this._entries.findIndex(([k]) => Object.is(k, key));\n if (index === -1) return false;\n this._entries.splice(index, 1);\n return true;\n }\n\n /** Removes all entries. Uses splice to trigger proxy notification. */\n clear(): void {\n this._entries.splice(0, this._entries.length);\n }\n\n /** Returns an iterator over the keys. */\n keys(): IterableIterator<K> {\n return this._entries.map(([k]) => k)[Symbol.iterator]();\n }\n\n /** Returns an iterator over the values. */\n values(): IterableIterator<V> {\n return this._entries.map(([, v]) => v)[Symbol.iterator]();\n }\n\n /** Returns an iterator over [key, value] pairs. */\n entries(): IterableIterator<[K, V]> {\n return this._entries.map(([k, v]) => [k, v] as [K, V])[Symbol.iterator]();\n }\n\n /** Calls `callback` for each entry, matching the native `Map.forEach` signature. */\n forEach(callback: (value: V, key: K, map: ReactiveMap<K, V>) => void): void {\n for (const [k, v] of this._entries) {\n callback(v, k, this);\n }\n }\n\n /** Enables `for...of` iteration over [key, value] pairs. */\n [Symbol.iterator](): IterableIterator<[K, V]> {\n return this.entries();\n }\n}\n\n// ── ReactiveSet ───────────────────────────────────────────────────────────────\n\n/**\n * A Set-like class backed by a plain array so `createClassyStore()` can proxy mutations.\n *\n * Native `Set` uses internal slots that ES6 Proxy can't intercept, so mutations\n * like `.add()` would be invisible to the store. `ReactiveSet` solves this by\n * storing items in a plain array (`_items`) that the proxy can track.\n *\n * Usage:\n * ```ts\n * const myStore = createClassyStore({ tags: reactiveSet<string>(['urgent']) });\n * myStore.tags.add('bug'); // reactive\n * ```\n */\nexport class ReactiveSet<T> {\n static [PROXYABLE] = true;\n\n /** @internal Backing storage — proxied by store(). */\n _items: T[] = [];\n\n /** Deduplicates initial values using `Object.is` comparison. */\n constructor(initial?: Iterable<T>) {\n if (initial) {\n for (const v of initial) {\n if (!this._items.some((item) => Object.is(item, v))) {\n this._items.push(v);\n }\n }\n }\n }\n\n /** Returns the number of unique items. */\n get size(): number {\n return this._items.length;\n }\n\n /** Returns `true` if `value` exists. O(n) linear scan. */\n has(value: T): boolean {\n return this._items.some((item) => Object.is(item, value));\n }\n\n /** Adds `value` if not already present (no-op for duplicates). */\n add(value: T): this {\n if (!this.has(value)) {\n this._items.push(value);\n }\n return this;\n }\n\n /** Removes `value`. Returns `true` if found. */\n delete(value: T): boolean {\n const index = this._items.findIndex((item) => Object.is(item, value));\n if (index === -1) return false;\n this._items.splice(index, 1);\n return true;\n }\n\n /** Removes all items. Uses splice to trigger proxy notification. */\n clear(): void {\n this._items.splice(0, this._items.length);\n }\n\n /** Returns an iterator over the values (same as `values()`, matching Set API). */\n keys(): IterableIterator<T> {\n return this._items[Symbol.iterator]();\n }\n\n /** Returns an iterator over the values. */\n values(): IterableIterator<T> {\n return this._items[Symbol.iterator]();\n }\n\n /** Returns an iterator over [value, value] pairs, matching the native Set API. */\n entries(): IterableIterator<[T, T]> {\n return this._items.map((v) => [v, v] as [T, T])[Symbol.iterator]();\n }\n\n /** Calls `callback` for each item, matching the native `Set.forEach` signature. */\n forEach(callback: (value: T, key: T, set: ReactiveSet<T>) => void): void {\n for (const v of this._items) {\n callback(v, v, this);\n }\n }\n\n /** Enables `for...of` iteration over values. */\n [Symbol.iterator](): IterableIterator<T> {\n return this.values();\n }\n}\n\n// ── Factory functions ─────────────────────────────────────────────────────────\n\n/**\n * Creates a reactive Map-like collection backed by a plain array.\n * Wrap the parent object with `createClassyStore()` for full reactivity.\n *\n * @param initial - Optional iterable of `[key, value]` pairs.\n */\nexport function reactiveMap<K, V>(\n initial?: Iterable<[K, V]>,\n): ReactiveMap<K, V> {\n return new ReactiveMap(initial);\n}\n\n/**\n * Creates a reactive Set-like collection backed by a plain array.\n * Wrap the parent object with `createClassyStore()` for full reactivity.\n *\n * @param initial - Optional iterable of values.\n */\nexport function reactiveSet<T>(initial?: Iterable<T>): ReactiveSet<T> {\n return new ReactiveSet(initial);\n}\n","/**\n * Shallow-equal comparison for objects and arrays.\n * Useful as a custom `isEqual` for `useStore` selectors that return objects/arrays.\n *\n * - Primitives compared with `Object.is`.\n * - Arrays: length + element-wise `Object.is`.\n * - Objects: key count + value-wise `Object.is`.\n */\nexport function shallowEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== 'object' ||\n a === null ||\n typeof b !== 'object' ||\n b === null\n ) {\n return false;\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!Object.is(a[i], b[i])) return false;\n }\n return true;\n }\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (\n !Object.hasOwn(b, key) ||\n !Object.is(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n )\n ) {\n return false;\n }\n }\n return true;\n}\n"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_snapshot = require('../snapshot-BKVFJLuo.cjs');
3
+ let proxy_compare = require("proxy-compare");
4
+ let react = require("react");
5
+
6
+ //#region src/react/react.ts
7
+ function useStore(proxyStore, selector, isEqual) {
8
+ require_snapshot.getInternal(proxyStore);
9
+ const subscribe$1 = (0, react.useCallback)((onStoreChange) => require_snapshot.subscribe(proxyStore, onStoreChange), [proxyStore]);
10
+ const snapRef = (0, react.useRef)(void 0);
11
+ const resultRef = (0, react.useRef)(void 0);
12
+ const affected = (0, react.useRef)(/* @__PURE__ */ new WeakMap()).current;
13
+ const proxyCache = (0, react.useRef)(/* @__PURE__ */ new WeakMap()).current;
14
+ const prevSnapRef = (0, react.useRef)(void 0);
15
+ const wrappedRef = (0, react.useRef)(void 0);
16
+ const getSnapshot = () => selector ? getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual) : getAutoTrackSnapshot(proxyStore, affected, proxyCache, prevSnapRef, wrappedRef);
17
+ return (0, react.useSyncExternalStore)(subscribe$1, getSnapshot, getSnapshot);
18
+ }
19
+ /**
20
+ * `getSnapshot` implementation for selector mode.
21
+ *
22
+ * Fast-paths when the snapshot reference hasn't changed (O(1)). Otherwise
23
+ * runs the selector against the new snapshot and compares the result to the
24
+ * previous one via `Object.is` (or a custom `isEqual`). Returns the previous
25
+ * result reference when equal, preventing unnecessary React re-renders.
26
+ *
27
+ * Pure function -- no hooks, safe to call from `useSyncExternalStore`.
28
+ */
29
+ function getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual) {
30
+ const nextSnap = require_snapshot.snapshot(proxyStore);
31
+ if (snapRef.current === nextSnap && resultRef.current !== void 0) return resultRef.current;
32
+ const nextResult = selector(nextSnap);
33
+ snapRef.current = nextSnap;
34
+ if (resultRef.current !== void 0 && (isEqual ? isEqual(resultRef.current, nextResult) : Object.is(resultRef.current, nextResult))) return resultRef.current;
35
+ resultRef.current = nextResult;
36
+ return nextResult;
37
+ }
38
+ /**
39
+ * `getSnapshot` implementation for auto-tracked (selectorless) mode.
40
+ *
41
+ * Uses `proxy-compare` to diff only the properties the component actually read.
42
+ * If the snapshot reference is the same, returns the cached tracking proxy.
43
+ * If the snapshot changed but no tracked property differs (`isChanged` returns
44
+ * false), also returns the cached proxy -- avoiding re-render. Only when a
45
+ * relevant property changed does it create a new `createProxy` wrapper.
46
+ *
47
+ * Pure function -- no hooks, safe to call from `useSyncExternalStore`.
48
+ */
49
+ function getAutoTrackSnapshot(proxyStore, affected, proxyCache, prevSnapRef, wrappedRef) {
50
+ const nextSnap = require_snapshot.snapshot(proxyStore);
51
+ if (prevSnapRef.current === nextSnap) return wrappedRef.current;
52
+ if (prevSnapRef.current !== void 0 && !(0, proxy_compare.isChanged)(prevSnapRef.current, nextSnap, affected)) return wrappedRef.current;
53
+ prevSnapRef.current = nextSnap;
54
+ const wrapped = (0, proxy_compare.createProxy)(nextSnap, affected, proxyCache);
55
+ wrappedRef.current = wrapped;
56
+ return wrapped;
57
+ }
58
+
59
+ //#endregion
60
+ exports.useStore = useStore;
61
+ //# sourceMappingURL=react.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.cjs","names":["subscribe","coreSubscribe","snapshot"],"sources":["../../src/react/react.ts"],"sourcesContent":["import {createProxy, isChanged} from 'proxy-compare';\nimport {useCallback, useRef, useSyncExternalStore} from 'react';\nimport {subscribe as coreSubscribe, getInternal} from '../core/core';\nimport {snapshot} from '../snapshot/snapshot';\nimport type {Snapshot} from '../types';\n\n// ── Overloads ─────────────────────────────────────────────────────────────────\n\n/**\n * Subscribe to a store proxy with an explicit selector.\n *\n * Re-renders only when the selected value changes (compared via `Object.is`\n * by default, or a custom `isEqual`).\n *\n * @param proxyStore - A reactive proxy created by `store()`.\n * @param selector - Picks data from the immutable snapshot.\n * @param isEqual - Optional custom equality function (default: `Object.is`).\n */\nexport function useStore<T extends object, S>(\n proxyStore: T,\n selector: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): S;\n\n/**\n * Subscribe to a store proxy **without** a selector (auto-tracked mode).\n *\n * Returns a `proxy-compare` tracking proxy over the immutable snapshot.\n * The component only re-renders when a property it actually read changes.\n *\n * @param proxyStore - A reactive proxy created by `store()`.\n */\nexport function useStore<T extends object>(proxyStore: T): Snapshot<T>;\n\n// ── Implementation ────────────────────────────────────────────────────────────\n\nexport function useStore<T extends object, S>(\n proxyStore: T,\n selector?: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Snapshot<T> | S {\n // Validate that the argument is actually a store proxy (throws if not).\n getInternal(proxyStore);\n\n // Stable subscribe function (internal identity never changes for a given store).\n const subscribe = useCallback(\n (onStoreChange: () => void) => coreSubscribe(proxyStore, onStoreChange),\n [proxyStore],\n );\n\n // ── Refs used by both modes (always allocated to satisfy Rules of Hooks) ──\n\n // Selector mode refs\n const snapRef = useRef<Snapshot<T> | undefined>(undefined);\n const resultRef = useRef<S | undefined>(undefined);\n\n // Auto-track mode refs\n const affected = useRef(new WeakMap<object, unknown>()).current;\n const proxyCache = useRef(new WeakMap<object, unknown>()).current;\n const prevSnapRef = useRef<Snapshot<T> | undefined>(undefined);\n const wrappedRef = useRef<Snapshot<T> | undefined>(undefined);\n\n // ── Single getSnapshot for useSyncExternalStore ───────────────────────────\n\n const getSnapshot = (): Snapshot<T> | S =>\n selector\n ? getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual)\n : getAutoTrackSnapshot(\n proxyStore,\n affected,\n proxyCache,\n prevSnapRef,\n wrappedRef,\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n// ── Selector mode logic (pure function, no hooks) ─────────────────────────────\n\n/**\n * `getSnapshot` implementation for selector mode.\n *\n * Fast-paths when the snapshot reference hasn't changed (O(1)). Otherwise\n * runs the selector against the new snapshot and compares the result to the\n * previous one via `Object.is` (or a custom `isEqual`). Returns the previous\n * result reference when equal, preventing unnecessary React re-renders.\n *\n * Pure function -- no hooks, safe to call from `useSyncExternalStore`.\n */\nfunction getSelectorSnapshot<T extends object, S>(\n proxyStore: T,\n snapRef: React.RefObject<Snapshot<T> | undefined>,\n resultRef: React.RefObject<S | undefined>,\n selector: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): S {\n const nextSnap = snapshot(proxyStore);\n\n // Fast path: same snapshot reference → same result.\n if (snapRef.current === nextSnap && resultRef.current !== undefined) {\n return resultRef.current;\n }\n\n const nextResult = selector(nextSnap);\n snapRef.current = nextSnap;\n\n // Check equality with previous result.\n if (\n resultRef.current !== undefined &&\n (isEqual\n ? isEqual(resultRef.current, nextResult)\n : Object.is(resultRef.current, nextResult))\n ) {\n return resultRef.current;\n }\n\n resultRef.current = nextResult;\n return nextResult;\n}\n\n// ── Auto-tracked (selectorless) mode logic (pure function, no hooks) ──────────\n\n/**\n * `getSnapshot` implementation for auto-tracked (selectorless) mode.\n *\n * Uses `proxy-compare` to diff only the properties the component actually read.\n * If the snapshot reference is the same, returns the cached tracking proxy.\n * If the snapshot changed but no tracked property differs (`isChanged` returns\n * false), also returns the cached proxy -- avoiding re-render. Only when a\n * relevant property changed does it create a new `createProxy` wrapper.\n *\n * Pure function -- no hooks, safe to call from `useSyncExternalStore`.\n */\nfunction getAutoTrackSnapshot<T extends object>(\n proxyStore: T,\n affected: WeakMap<object, unknown>,\n proxyCache: WeakMap<object, unknown>,\n prevSnapRef: React.RefObject<Snapshot<T> | undefined>,\n wrappedRef: React.RefObject<Snapshot<T> | undefined>,\n): Snapshot<T> {\n const nextSnap = snapshot(proxyStore);\n\n // If the raw snapshot is the same reference, nothing changed.\n if (prevSnapRef.current === nextSnap) {\n return wrappedRef.current as Snapshot<T>;\n }\n\n // Check if any property the component actually read has changed.\n if (\n prevSnapRef.current !== undefined &&\n !isChanged(prevSnapRef.current, nextSnap, affected)\n ) {\n // No property the component cares about changed → return same wrapped proxy.\n return wrappedRef.current as Snapshot<T>;\n }\n\n // Something relevant changed — create a new tracking proxy.\n prevSnapRef.current = nextSnap;\n const wrapped = createProxy(nextSnap, affected, proxyCache) as Snapshot<T>;\n wrappedRef.current = wrapped;\n return wrapped;\n}\n"],"mappings":";;;;;;AAoCA,SAAgB,SACd,YACA,UACA,SACiB;AAEjB,8BAAY,WAAW;CAGvB,MAAMA,sCACH,kBAA8BC,2BAAc,YAAY,cAAc,EACvE,CAAC,WAAW,CACb;CAKD,MAAM,4BAA0C,OAAU;CAC1D,MAAM,8BAAkC,OAAU;CAGlD,MAAM,6CAAkB,IAAI,SAA0B,CAAC,CAAC;CACxD,MAAM,+CAAoB,IAAI,SAA0B,CAAC,CAAC;CAC1D,MAAM,gCAA8C,OAAU;CAC9D,MAAM,+BAA6C,OAAU;CAI7D,MAAM,oBACJ,WACI,oBAAoB,YAAY,SAAS,WAAW,UAAU,QAAQ,GACtE,qBACE,YACA,UACA,YACA,aACA,WACD;AAEP,wCAA4BD,aAAW,aAAa,YAAY;;;;;;;;;;;;AAelE,SAAS,oBACP,YACA,SACA,WACA,UACA,SACG;CACH,MAAM,WAAWE,0BAAS,WAAW;AAGrC,KAAI,QAAQ,YAAY,YAAY,UAAU,YAAY,OACxD,QAAO,UAAU;CAGnB,MAAM,aAAa,SAAS,SAAS;AACrC,SAAQ,UAAU;AAGlB,KACE,UAAU,YAAY,WACrB,UACG,QAAQ,UAAU,SAAS,WAAW,GACtC,OAAO,GAAG,UAAU,SAAS,WAAW,EAE5C,QAAO,UAAU;AAGnB,WAAU,UAAU;AACpB,QAAO;;;;;;;;;;;;;AAgBT,SAAS,qBACP,YACA,UACA,YACA,aACA,YACa;CACb,MAAM,WAAWA,0BAAS,WAAW;AAGrC,KAAI,YAAY,YAAY,SAC1B,QAAO,WAAW;AAIpB,KACE,YAAY,YAAY,UACxB,8BAAW,YAAY,SAAS,UAAU,SAAS,CAGnD,QAAO,WAAW;AAIpB,aAAY,UAAU;CACtB,MAAM,yCAAsB,UAAU,UAAU,WAAW;AAC3D,YAAW,UAAU;AACrB,QAAO"}
@@ -0,0 +1,26 @@
1
+ import { t as Snapshot } from "../types-B6RZUB86.cjs";
2
+
3
+ //#region src/react/react.d.ts
4
+ /**
5
+ * Subscribe to a store proxy with an explicit selector.
6
+ *
7
+ * Re-renders only when the selected value changes (compared via `Object.is`
8
+ * by default, or a custom `isEqual`).
9
+ *
10
+ * @param proxyStore - A reactive proxy created by `store()`.
11
+ * @param selector - Picks data from the immutable snapshot.
12
+ * @param isEqual - Optional custom equality function (default: `Object.is`).
13
+ */
14
+ declare function useStore<T extends object, S>(proxyStore: T, selector: (snap: Snapshot<T>) => S, isEqual?: (a: S, b: S) => boolean): S;
15
+ /**
16
+ * Subscribe to a store proxy **without** a selector (auto-tracked mode).
17
+ *
18
+ * Returns a `proxy-compare` tracking proxy over the immutable snapshot.
19
+ * The component only re-renders when a property it actually read changes.
20
+ *
21
+ * @param proxyStore - A reactive proxy created by `store()`.
22
+ */
23
+ declare function useStore<T extends object>(proxyStore: T): Snapshot<T>;
24
+ //#endregion
25
+ export { useStore };
26
+ //# sourceMappingURL=react.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.cts","names":[],"sources":["../../src/react/react.ts"],"mappings":";;;;;AAkBA;;;;;;;;iBAAgB,QAAA,qBAAA,CACd,UAAA,EAAY,CAAA,EACZ,QAAA,GAAW,IAAA,EAAM,QAAA,CAAS,CAAA,MAAO,CAAA,EACjC,OAAA,IAAW,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,eACnB,CAAA;;;;;;;;;iBAUa,QAAA,kBAAA,CAA2B,UAAA,EAAY,CAAA,GAAI,QAAA,CAAS,CAAA"}
@@ -0,0 +1,26 @@
1
+ import { t as Snapshot } from "../types-vWYkF3tH.mjs";
2
+
3
+ //#region src/react/react.d.ts
4
+ /**
5
+ * Subscribe to a store proxy with an explicit selector.
6
+ *
7
+ * Re-renders only when the selected value changes (compared via `Object.is`
8
+ * by default, or a custom `isEqual`).
9
+ *
10
+ * @param proxyStore - A reactive proxy created by `store()`.
11
+ * @param selector - Picks data from the immutable snapshot.
12
+ * @param isEqual - Optional custom equality function (default: `Object.is`).
13
+ */
14
+ declare function useStore<T extends object, S>(proxyStore: T, selector: (snap: Snapshot<T>) => S, isEqual?: (a: S, b: S) => boolean): S;
15
+ /**
16
+ * Subscribe to a store proxy **without** a selector (auto-tracked mode).
17
+ *
18
+ * Returns a `proxy-compare` tracking proxy over the immutable snapshot.
19
+ * The component only re-renders when a property it actually read changes.
20
+ *
21
+ * @param proxyStore - A reactive proxy created by `store()`.
22
+ */
23
+ declare function useStore<T extends object>(proxyStore: T): Snapshot<T>;
24
+ //#endregion
25
+ export { useStore };
26
+ //# sourceMappingURL=react.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.mts","names":[],"sources":["../../src/react/react.ts"],"mappings":";;;;;AAkBA;;;;;;;;iBAAgB,QAAA,qBAAA,CACd,UAAA,EAAY,CAAA,EACZ,QAAA,GAAW,IAAA,EAAM,QAAA,CAAS,CAAA,MAAO,CAAA,EACjC,OAAA,IAAW,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,eACnB,CAAA;;;;;;;;;iBAUa,QAAA,kBAAA,CAA2B,UAAA,EAAY,CAAA,GAAI,QAAA,CAAS,CAAA"}
@@ -0,0 +1,60 @@
1
+ import { a as subscribe, r as getInternal, t as snapshot } from "../snapshot-P0QPV1ER.mjs";
2
+ import { createProxy, isChanged } from "proxy-compare";
3
+ import { useCallback, useRef, useSyncExternalStore } from "react";
4
+
5
+ //#region src/react/react.ts
6
+ function useStore(proxyStore, selector, isEqual) {
7
+ getInternal(proxyStore);
8
+ const subscribe$1 = useCallback((onStoreChange) => subscribe(proxyStore, onStoreChange), [proxyStore]);
9
+ const snapRef = useRef(void 0);
10
+ const resultRef = useRef(void 0);
11
+ const affected = useRef(/* @__PURE__ */ new WeakMap()).current;
12
+ const proxyCache = useRef(/* @__PURE__ */ new WeakMap()).current;
13
+ const prevSnapRef = useRef(void 0);
14
+ const wrappedRef = useRef(void 0);
15
+ const getSnapshot = () => selector ? getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual) : getAutoTrackSnapshot(proxyStore, affected, proxyCache, prevSnapRef, wrappedRef);
16
+ return useSyncExternalStore(subscribe$1, getSnapshot, getSnapshot);
17
+ }
18
+ /**
19
+ * `getSnapshot` implementation for selector mode.
20
+ *
21
+ * Fast-paths when the snapshot reference hasn't changed (O(1)). Otherwise
22
+ * runs the selector against the new snapshot and compares the result to the
23
+ * previous one via `Object.is` (or a custom `isEqual`). Returns the previous
24
+ * result reference when equal, preventing unnecessary React re-renders.
25
+ *
26
+ * Pure function -- no hooks, safe to call from `useSyncExternalStore`.
27
+ */
28
+ function getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual) {
29
+ const nextSnap = snapshot(proxyStore);
30
+ if (snapRef.current === nextSnap && resultRef.current !== void 0) return resultRef.current;
31
+ const nextResult = selector(nextSnap);
32
+ snapRef.current = nextSnap;
33
+ if (resultRef.current !== void 0 && (isEqual ? isEqual(resultRef.current, nextResult) : Object.is(resultRef.current, nextResult))) return resultRef.current;
34
+ resultRef.current = nextResult;
35
+ return nextResult;
36
+ }
37
+ /**
38
+ * `getSnapshot` implementation for auto-tracked (selectorless) mode.
39
+ *
40
+ * Uses `proxy-compare` to diff only the properties the component actually read.
41
+ * If the snapshot reference is the same, returns the cached tracking proxy.
42
+ * If the snapshot changed but no tracked property differs (`isChanged` returns
43
+ * false), also returns the cached proxy -- avoiding re-render. Only when a
44
+ * relevant property changed does it create a new `createProxy` wrapper.
45
+ *
46
+ * Pure function -- no hooks, safe to call from `useSyncExternalStore`.
47
+ */
48
+ function getAutoTrackSnapshot(proxyStore, affected, proxyCache, prevSnapRef, wrappedRef) {
49
+ const nextSnap = snapshot(proxyStore);
50
+ if (prevSnapRef.current === nextSnap) return wrappedRef.current;
51
+ if (prevSnapRef.current !== void 0 && !isChanged(prevSnapRef.current, nextSnap, affected)) return wrappedRef.current;
52
+ prevSnapRef.current = nextSnap;
53
+ const wrapped = createProxy(nextSnap, affected, proxyCache);
54
+ wrappedRef.current = wrapped;
55
+ return wrapped;
56
+ }
57
+
58
+ //#endregion
59
+ export { useStore };
60
+ //# sourceMappingURL=react.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.mjs","names":["subscribe","coreSubscribe"],"sources":["../../src/react/react.ts"],"sourcesContent":["import {createProxy, isChanged} from 'proxy-compare';\nimport {useCallback, useRef, useSyncExternalStore} from 'react';\nimport {subscribe as coreSubscribe, getInternal} from '../core/core';\nimport {snapshot} from '../snapshot/snapshot';\nimport type {Snapshot} from '../types';\n\n// ── Overloads ─────────────────────────────────────────────────────────────────\n\n/**\n * Subscribe to a store proxy with an explicit selector.\n *\n * Re-renders only when the selected value changes (compared via `Object.is`\n * by default, or a custom `isEqual`).\n *\n * @param proxyStore - A reactive proxy created by `store()`.\n * @param selector - Picks data from the immutable snapshot.\n * @param isEqual - Optional custom equality function (default: `Object.is`).\n */\nexport function useStore<T extends object, S>(\n proxyStore: T,\n selector: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): S;\n\n/**\n * Subscribe to a store proxy **without** a selector (auto-tracked mode).\n *\n * Returns a `proxy-compare` tracking proxy over the immutable snapshot.\n * The component only re-renders when a property it actually read changes.\n *\n * @param proxyStore - A reactive proxy created by `store()`.\n */\nexport function useStore<T extends object>(proxyStore: T): Snapshot<T>;\n\n// ── Implementation ────────────────────────────────────────────────────────────\n\nexport function useStore<T extends object, S>(\n proxyStore: T,\n selector?: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Snapshot<T> | S {\n // Validate that the argument is actually a store proxy (throws if not).\n getInternal(proxyStore);\n\n // Stable subscribe function (internal identity never changes for a given store).\n const subscribe = useCallback(\n (onStoreChange: () => void) => coreSubscribe(proxyStore, onStoreChange),\n [proxyStore],\n );\n\n // ── Refs used by both modes (always allocated to satisfy Rules of Hooks) ──\n\n // Selector mode refs\n const snapRef = useRef<Snapshot<T> | undefined>(undefined);\n const resultRef = useRef<S | undefined>(undefined);\n\n // Auto-track mode refs\n const affected = useRef(new WeakMap<object, unknown>()).current;\n const proxyCache = useRef(new WeakMap<object, unknown>()).current;\n const prevSnapRef = useRef<Snapshot<T> | undefined>(undefined);\n const wrappedRef = useRef<Snapshot<T> | undefined>(undefined);\n\n // ── Single getSnapshot for useSyncExternalStore ───────────────────────────\n\n const getSnapshot = (): Snapshot<T> | S =>\n selector\n ? getSelectorSnapshot(proxyStore, snapRef, resultRef, selector, isEqual)\n : getAutoTrackSnapshot(\n proxyStore,\n affected,\n proxyCache,\n prevSnapRef,\n wrappedRef,\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n// ── Selector mode logic (pure function, no hooks) ─────────────────────────────\n\n/**\n * `getSnapshot` implementation for selector mode.\n *\n * Fast-paths when the snapshot reference hasn't changed (O(1)). Otherwise\n * runs the selector against the new snapshot and compares the result to the\n * previous one via `Object.is` (or a custom `isEqual`). Returns the previous\n * result reference when equal, preventing unnecessary React re-renders.\n *\n * Pure function -- no hooks, safe to call from `useSyncExternalStore`.\n */\nfunction getSelectorSnapshot<T extends object, S>(\n proxyStore: T,\n snapRef: React.RefObject<Snapshot<T> | undefined>,\n resultRef: React.RefObject<S | undefined>,\n selector: (snap: Snapshot<T>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): S {\n const nextSnap = snapshot(proxyStore);\n\n // Fast path: same snapshot reference → same result.\n if (snapRef.current === nextSnap && resultRef.current !== undefined) {\n return resultRef.current;\n }\n\n const nextResult = selector(nextSnap);\n snapRef.current = nextSnap;\n\n // Check equality with previous result.\n if (\n resultRef.current !== undefined &&\n (isEqual\n ? isEqual(resultRef.current, nextResult)\n : Object.is(resultRef.current, nextResult))\n ) {\n return resultRef.current;\n }\n\n resultRef.current = nextResult;\n return nextResult;\n}\n\n// ── Auto-tracked (selectorless) mode logic (pure function, no hooks) ──────────\n\n/**\n * `getSnapshot` implementation for auto-tracked (selectorless) mode.\n *\n * Uses `proxy-compare` to diff only the properties the component actually read.\n * If the snapshot reference is the same, returns the cached tracking proxy.\n * If the snapshot changed but no tracked property differs (`isChanged` returns\n * false), also returns the cached proxy -- avoiding re-render. Only when a\n * relevant property changed does it create a new `createProxy` wrapper.\n *\n * Pure function -- no hooks, safe to call from `useSyncExternalStore`.\n */\nfunction getAutoTrackSnapshot<T extends object>(\n proxyStore: T,\n affected: WeakMap<object, unknown>,\n proxyCache: WeakMap<object, unknown>,\n prevSnapRef: React.RefObject<Snapshot<T> | undefined>,\n wrappedRef: React.RefObject<Snapshot<T> | undefined>,\n): Snapshot<T> {\n const nextSnap = snapshot(proxyStore);\n\n // If the raw snapshot is the same reference, nothing changed.\n if (prevSnapRef.current === nextSnap) {\n return wrappedRef.current as Snapshot<T>;\n }\n\n // Check if any property the component actually read has changed.\n if (\n prevSnapRef.current !== undefined &&\n !isChanged(prevSnapRef.current, nextSnap, affected)\n ) {\n // No property the component cares about changed → return same wrapped proxy.\n return wrappedRef.current as Snapshot<T>;\n }\n\n // Something relevant changed — create a new tracking proxy.\n prevSnapRef.current = nextSnap;\n const wrapped = createProxy(nextSnap, affected, proxyCache) as Snapshot<T>;\n wrappedRef.current = wrapped;\n return wrapped;\n}\n"],"mappings":";;;;;AAoCA,SAAgB,SACd,YACA,UACA,SACiB;AAEjB,aAAY,WAAW;CAGvB,MAAMA,cAAY,aACf,kBAA8BC,UAAc,YAAY,cAAc,EACvE,CAAC,WAAW,CACb;CAKD,MAAM,UAAU,OAAgC,OAAU;CAC1D,MAAM,YAAY,OAAsB,OAAU;CAGlD,MAAM,WAAW,uBAAO,IAAI,SAA0B,CAAC,CAAC;CACxD,MAAM,aAAa,uBAAO,IAAI,SAA0B,CAAC,CAAC;CAC1D,MAAM,cAAc,OAAgC,OAAU;CAC9D,MAAM,aAAa,OAAgC,OAAU;CAI7D,MAAM,oBACJ,WACI,oBAAoB,YAAY,SAAS,WAAW,UAAU,QAAQ,GACtE,qBACE,YACA,UACA,YACA,aACA,WACD;AAEP,QAAO,qBAAqBD,aAAW,aAAa,YAAY;;;;;;;;;;;;AAelE,SAAS,oBACP,YACA,SACA,WACA,UACA,SACG;CACH,MAAM,WAAW,SAAS,WAAW;AAGrC,KAAI,QAAQ,YAAY,YAAY,UAAU,YAAY,OACxD,QAAO,UAAU;CAGnB,MAAM,aAAa,SAAS,SAAS;AACrC,SAAQ,UAAU;AAGlB,KACE,UAAU,YAAY,WACrB,UACG,QAAQ,UAAU,SAAS,WAAW,GACtC,OAAO,GAAG,UAAU,SAAS,WAAW,EAE5C,QAAO,UAAU;AAGnB,WAAU,UAAU;AACpB,QAAO;;;;;;;;;;;;;AAgBT,SAAS,qBACP,YACA,UACA,YACA,aACA,YACa;CACb,MAAM,WAAW,SAAS,WAAW;AAGrC,KAAI,YAAY,YAAY,SAC1B,QAAO,WAAW;AAIpB,KACE,YAAY,YAAY,UACxB,CAAC,UAAU,YAAY,SAAS,UAAU,SAAS,CAGnD,QAAO,WAAW;AAIpB,aAAY,UAAU;CACtB,MAAM,UAAU,YAAY,UAAU,UAAU,WAAW;AAC3D,YAAW,UAAU;AACrB,QAAO"}
@@ -1,5 +1,5 @@
1
1
 
2
- //#region src/utils.ts
2
+ //#region src/utils/internal/internal.ts
3
3
  const objectProto = Object.getPrototypeOf({});
4
4
  /**
5
5
  * Symbol that class instances can use to opt-in to deep proxying.
@@ -47,31 +47,9 @@ function findGetterDescriptor(target, prop) {
47
47
  proto = Object.getPrototypeOf(proto);
48
48
  }
49
49
  }
50
- /**
51
- * Shallow-equal comparison for objects and arrays.
52
- * Useful as a custom `isEqual` for `useStore` selectors that return objects/arrays.
53
- *
54
- * - Primitives compared with `Object.is`.
55
- * - Arrays: length + element-wise `Object.is`.
56
- * - Objects: key count + value-wise `Object.is`.
57
- */
58
- function shallowEqual(a, b) {
59
- if (Object.is(a, b)) return true;
60
- if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
61
- if (Array.isArray(a) && Array.isArray(b)) {
62
- if (a.length !== b.length) return false;
63
- for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false;
64
- return true;
65
- }
66
- const keysA = Object.keys(a);
67
- const keysB = Object.keys(b);
68
- if (keysA.length !== keysB.length) return false;
69
- for (const key of keysA) if (!Object.hasOwn(b, key) || !Object.is(a[key], b[key])) return false;
70
- return true;
71
- }
72
50
 
73
51
  //#endregion
74
- //#region src/core.ts
52
+ //#region src/core/core.ts
75
53
  /** Global version counter shared across all stores. */
76
54
  let globalVersion = 0;
77
55
  /** Maps every store proxy → its internal bookkeeping. */
@@ -148,7 +126,7 @@ function evaluateComputed(internal, prop, getterFn, receiver) {
148
126
  }
149
127
  /**
150
128
  * Retrieve the internal bookkeeping for a store proxy.
151
- * Throws if the object was not created with `store()`.
129
+ * Throws if the object was not created with `createClassyStore()`.
152
130
  */
153
131
  function getInternal(proxy) {
154
132
  const internal = internalsMap.get(proxy);
@@ -270,15 +248,20 @@ function createStoreProxy(target, parent) {
270
248
  *
271
249
  * @param instance - A class instance (or plain object) to make reactive.
272
250
  * @returns The same object wrapped in a reactive Proxy.
251
+ *
252
+ * @example
253
+ * ```ts
254
+ * const myStore = createClassyStore(new MyClass());
255
+ * ```
273
256
  */
274
- function store(instance) {
257
+ function createClassyStore(instance) {
275
258
  return createStoreProxy(instance, null);
276
259
  }
277
260
  /**
278
261
  * Subscribe to store changes. The callback fires once per batched mutation
279
262
  * (coalesced via `queueMicrotask`), not once per individual property write.
280
263
  *
281
- * @param proxy - A reactive proxy created by `store()`.
264
+ * @param proxy - A reactive proxy created by `createClassyStore()`.
282
265
  * @param callback - Invoked after each batched mutation.
283
266
  * @returns An unsubscribe function. Call it to stop receiving notifications.
284
267
  */
@@ -301,12 +284,12 @@ function getVersion(proxy) {
301
284
  }
302
285
 
303
286
  //#endregion
304
- //#region src/snapshot.ts
287
+ //#region src/snapshot/snapshot.ts
305
288
  /**
306
289
  * Version-stamped snapshot cache for tracked (proxied) sub-trees.
307
290
  * Key: raw target object → [version, frozen snapshot].
308
291
  */
309
- const snapCache = /* @__PURE__ */ new WeakMap();
292
+ const snapshotCache = /* @__PURE__ */ new WeakMap();
310
293
  /**
311
294
  * Cache for untracked nested objects (never accessed through the proxy).
312
295
  * Key: the raw mutable object → frozen deep clone.
@@ -325,7 +308,7 @@ const snapshotGetterCache = /* @__PURE__ */ new WeakMap();
325
308
  * boundaries: if `this.items` hasn't changed between snapshots (same
326
309
  * reference via structural sharing), the getter returns the same result.
327
310
  */
328
- const crossSnapMemo = /* @__PURE__ */ new WeakMap();
311
+ const crossSnapshotMemo = /* @__PURE__ */ new WeakMap();
329
312
  /**
330
313
  * Run a getter against the snapshot with dependency tracking.
331
314
  *
@@ -359,7 +342,7 @@ function computeWithTracking(snap, getterFn) {
359
342
  * guarantees stable refs for unchanged sub-trees). For getter properties
360
343
  * this invokes the getter (which is itself memoized), then compares.
361
344
  */
362
- function areMemoedDepsValid(currentSnap, deps) {
345
+ function areMemoizedDepsValid(currentSnap, deps) {
363
346
  for (const dep of deps) {
364
347
  const currentValue = Reflect.get(currentSnap, dep.prop, currentSnap);
365
348
  if (!Object.is(currentValue, dep.value)) return false;
@@ -378,16 +361,16 @@ function areMemoedDepsValid(currentSnap, deps) {
378
361
  function evaluateSnapshotGetter(currentSnap, target, key, getterFn) {
379
362
  const perSnapCache = snapshotGetterCache.get(currentSnap);
380
363
  if (perSnapCache?.has(key)) return perSnapCache.get(key);
381
- let memoMap = crossSnapMemo.get(target);
364
+ let memoMap = crossSnapshotMemo.get(target);
382
365
  const prev = memoMap?.get(key);
383
366
  let result;
384
- if (prev && areMemoedDepsValid(currentSnap, prev.deps)) result = prev.result;
367
+ if (prev && areMemoizedDepsValid(currentSnap, prev.deps)) result = prev.result;
385
368
  else {
386
369
  const computation = computeWithTracking(currentSnap, getterFn);
387
370
  result = computation.result;
388
371
  if (!memoMap) {
389
372
  memoMap = /* @__PURE__ */ new Map();
390
- crossSnapMemo.set(target, memoMap);
373
+ crossSnapshotMemo.set(target, memoMap);
391
374
  }
392
375
  memoMap.set(key, {
393
376
  deps: computation.deps,
@@ -501,7 +484,7 @@ function installMemoizedGetters(snap, target) {
501
484
  * are installed as lazy-memoizing accessors via `installMemoizedGetters`.
502
485
  */
503
486
  function createSnapshotRecursive(target, internal) {
504
- const cached = snapCache.get(target);
487
+ const cached = snapshotCache.get(target);
505
488
  if (cached && cached[0] === internal.version) return cached[1];
506
489
  let snap;
507
490
  if (Array.isArray(target)) {
@@ -518,7 +501,7 @@ function createSnapshotRecursive(target, internal) {
518
501
  installMemoizedGetters(snap, target);
519
502
  }
520
503
  Object.freeze(snap);
521
- snapCache.set(target, [internal.version, snap]);
504
+ snapshotCache.set(target, [internal.version, snap]);
522
505
  return snap;
523
506
  }
524
507
  /**
@@ -534,7 +517,7 @@ function createSnapshotRecursive(target, internal) {
534
517
  * per snapshot and their results are stable across snapshots when dependencies
535
518
  * haven't changed (cross-snapshot memoization).
536
519
  *
537
- * @param proxyStore - A reactive proxy created by `store()`.
520
+ * @param proxyStore - A reactive proxy created by `createClassyStore()`.
538
521
  * @returns A deeply frozen plain-JS object (Snapshot<T>).
539
522
  */
540
523
  function snapshot(proxyStore) {
@@ -549,6 +532,12 @@ Object.defineProperty(exports, 'PROXYABLE', {
549
532
  return PROXYABLE;
550
533
  }
551
534
  });
535
+ Object.defineProperty(exports, 'createClassyStore', {
536
+ enumerable: true,
537
+ get: function () {
538
+ return createClassyStore;
539
+ }
540
+ });
552
541
  Object.defineProperty(exports, 'findGetterDescriptor', {
553
542
  enumerable: true,
554
543
  get: function () {
@@ -567,28 +556,16 @@ Object.defineProperty(exports, 'getVersion', {
567
556
  return getVersion;
568
557
  }
569
558
  });
570
- Object.defineProperty(exports, 'shallowEqual', {
571
- enumerable: true,
572
- get: function () {
573
- return shallowEqual;
574
- }
575
- });
576
559
  Object.defineProperty(exports, 'snapshot', {
577
560
  enumerable: true,
578
561
  get: function () {
579
562
  return snapshot;
580
563
  }
581
564
  });
582
- Object.defineProperty(exports, 'store', {
583
- enumerable: true,
584
- get: function () {
585
- return store;
586
- }
587
- });
588
565
  Object.defineProperty(exports, 'subscribe', {
589
566
  enumerable: true,
590
567
  get: function () {
591
568
  return subscribe;
592
569
  }
593
570
  });
594
- //# sourceMappingURL=snapshot-TbHIUjvP.cjs.map
571
+ //# sourceMappingURL=snapshot-BKVFJLuo.cjs.map