context-scoped-state 0.0.1

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/README.md ADDED
@@ -0,0 +1,204 @@
1
+ # context-scoped-state
2
+
3
+ **State management that respects component boundaries.**
4
+
5
+ Unlike global state libraries (Redux, Zustand), `context-scoped-state` keeps your state where it belongs — scoped to the component tree that needs it. Each context provider creates an independent store instance, making your components truly reusable and your tests truly isolated.
6
+
7
+ ## Why Scoped State?
8
+
9
+ Global state is convenient, but it comes with hidden costs:
10
+
11
+ - **Testing nightmares** — State leaks between tests, requiring complex cleanup
12
+ - **Component coupling** — Reusing components means sharing their global state
13
+ - **Implicit dependencies** — Components magically depend on global singletons
14
+
15
+ `context-scoped-state` solves this by leveraging React's Context API the right way. Same API simplicity, but with proper encapsulation.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install context-scoped-state
21
+ ```
22
+
23
+ ```bash
24
+ yarn add context-scoped-state
25
+ ```
26
+
27
+ ```bash
28
+ pnpm add context-scoped-state
29
+ ```
30
+
31
+ > **Peer Dependencies:** React 18+
32
+
33
+ ## Quick Start
34
+
35
+ ### 1. Define Your Store
36
+
37
+ ```tsx
38
+ import { Store } from 'context-scoped-state';
39
+
40
+ class CounterStore extends Store<{ count: number }> {
41
+ protected getInitialState() {
42
+ return { count: 0 };
43
+ }
44
+
45
+ increment() {
46
+ this.setState({ count: this.getState().count + 1 });
47
+ }
48
+
49
+ decrement() {
50
+ this.setState({ count: this.getState().count - 1 });
51
+ }
52
+ }
53
+ ```
54
+
55
+ ### 2. Create the Hook
56
+
57
+ ```tsx
58
+ import { createStoreHook } from 'context-scoped-state';
59
+
60
+ const useCounterStore = createStoreHook(CounterStore);
61
+ ```
62
+
63
+ ### 3. Use in Components
64
+
65
+ ```tsx
66
+ function Counter() {
67
+ const store = useCounterStore();
68
+
69
+ return (
70
+ <div>
71
+ <span>{store.state.count}</span>
72
+ <button onClick={() => store.increment()}>+</button>
73
+ <button onClick={() => store.decrement()}>-</button>
74
+ </div>
75
+ );
76
+ }
77
+
78
+ // Wrap with Context provider
79
+ function App() {
80
+ return (
81
+ <useCounterStore.Context>
82
+ <Counter />
83
+ </useCounterStore.Context>
84
+ );
85
+ }
86
+ ```
87
+
88
+ That's it. No providers at the root, no selectors, no reducers, no actions, no dispatch.
89
+
90
+ ## Examples
91
+
92
+ ### Independent Nested Stores
93
+
94
+ Each `Context` creates a completely independent store instance. Perfect for reusable widget patterns:
95
+
96
+ ```tsx
97
+ function PlayerScore() {
98
+ const store = useScoreStore();
99
+ return <span>Score: {store.state.score}</span>;
100
+ }
101
+
102
+ function Game() {
103
+ return (
104
+ <div>
105
+ {/* Player 1 has their own score */}
106
+ <useScoreStore.Context>
107
+ <h2>Player 1</h2>
108
+ <PlayerScore />
109
+ </useScoreStore.Context>
110
+
111
+ {/* Player 2 has their own score */}
112
+ <useScoreStore.Context>
113
+ <h2>Player 2</h2>
114
+ <PlayerScore />
115
+ </useScoreStore.Context>
116
+ </div>
117
+ );
118
+ }
119
+ ```
120
+
121
+ Both players have completely independent state — no configuration needed.
122
+
123
+ ### Testing with MockContext
124
+
125
+ Test components in any state without complex setup:
126
+
127
+ ```tsx
128
+ import { render, screen } from '@testing-library/react';
129
+
130
+ test('shows warning when balance is low', () => {
131
+ render(
132
+ <useAccountStore.MockContext state={{ balance: 5, currency: 'USD' }}>
133
+ <AccountStatus />
134
+ </useAccountStore.MockContext>,
135
+ );
136
+
137
+ expect(screen.getByText('Low balance warning')).toBeInTheDocument();
138
+ });
139
+
140
+ test('shows normal status when balance is healthy', () => {
141
+ render(
142
+ <useAccountStore.MockContext state={{ balance: 1000, currency: 'USD' }}>
143
+ <AccountStatus />
144
+ </useAccountStore.MockContext>,
145
+ );
146
+
147
+ expect(screen.queryByText('Low balance warning')).not.toBeInTheDocument();
148
+ });
149
+ ```
150
+
151
+ No mocking libraries. No global state cleanup. Just render with the state you need.
152
+
153
+ ## Why context-scoped-state Over Other Libraries?
154
+
155
+ | Feature | context-scoped-state | Redux | Zustand |
156
+ | ---------------------- | -------------------- | ---------------------------- | -------------- |
157
+ | **Scoped by default** | Yes | No | No |
158
+ | **Multiple instances** | Automatic | Manual wiring | Manual wiring |
159
+ | **Test isolation** | Built-in MockContext | Requires setup | Requires reset |
160
+ | **Boilerplate** | Low | High | Low |
161
+ | **Type safety** | Full | Requires setup | Good |
162
+ | **Learning curve** | Just classes | Actions, reducers, selectors | Simple |
163
+
164
+ ### The Core Difference
165
+
166
+ **Global state libraries** make you fight against React's component model. You end up with:
167
+
168
+ - Selector functions to prevent re-renders
169
+ - Complex test fixtures to reset global state
170
+ - Workarounds for component reusability
171
+
172
+ **context-scoped-state** works _with_ React:
173
+
174
+ - State lives in the component tree, just like React intended
175
+ - Each provider = new instance, automatically
176
+ - Testing is just rendering with different props
177
+
178
+ ### When to Use What
179
+
180
+ **Use context-scoped-state when:**
181
+
182
+ - Building reusable components with internal state
183
+ - You want test isolation without extra setup
184
+ - State naturally belongs to a subtree, not the whole app
185
+ - You prefer OOP patterns (classes, methods)
186
+
187
+ **Need global state?** Just place the Context at your app root — same API, app-wide access.
188
+
189
+ ### Why Not Just Use useState or useReducer?
190
+
191
+ **vs useState:**
192
+
193
+ - `useState` binds state logic directly to the component, making it hard to reuse or test independently
194
+ - With `context-scoped-state`, state logic lives in a separate class — reusable across components and easily testable
195
+
196
+ **vs useReducer:**
197
+
198
+ - No action types, switch statements, or dispatch boilerplate
199
+ - Just call methods directly: `store.increment()` instead of `dispatch({ type: 'INCREMENT' })`
200
+ - Full TypeScript autocomplete for your actions
201
+
202
+ ---
203
+
204
+ **context-scoped-state** — Because not all state needs to be global.
@@ -0,0 +1,3 @@
1
+ export { Store } from './lib/Store';
2
+ export { createStoreHook } from './lib/createStore';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,550 @@
1
+ import { jsx as C } from "react/jsx-runtime";
2
+ import f from "react";
3
+ var _ = function(e, r) {
4
+ return _ = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(t, n) {
5
+ t.__proto__ = n;
6
+ } || function(t, n) {
7
+ for (var o in n) Object.prototype.hasOwnProperty.call(n, o) && (t[o] = n[o]);
8
+ }, _(e, r);
9
+ };
10
+ function h(e, r) {
11
+ if (typeof r != "function" && r !== null)
12
+ throw new TypeError("Class extends value " + String(r) + " is not a constructor or null");
13
+ _(e, r);
14
+ function t() {
15
+ this.constructor = e;
16
+ }
17
+ e.prototype = r === null ? Object.create(r) : (t.prototype = r.prototype, new t());
18
+ }
19
+ function w(e) {
20
+ var r = typeof Symbol == "function" && Symbol.iterator, t = r && e[r], n = 0;
21
+ if (t) return t.call(e);
22
+ if (e && typeof e.length == "number") return {
23
+ next: function() {
24
+ return e && n >= e.length && (e = void 0), { value: e && e[n++], done: !e };
25
+ }
26
+ };
27
+ throw new TypeError(r ? "Object is not iterable." : "Symbol.iterator is not defined.");
28
+ }
29
+ function E(e, r) {
30
+ var t = typeof Symbol == "function" && e[Symbol.iterator];
31
+ if (!t) return e;
32
+ var n = t.call(e), o, i = [], s;
33
+ try {
34
+ for (; (r === void 0 || r-- > 0) && !(o = n.next()).done; ) i.push(o.value);
35
+ } catch (u) {
36
+ s = { error: u };
37
+ } finally {
38
+ try {
39
+ o && !o.done && (t = n.return) && t.call(n);
40
+ } finally {
41
+ if (s) throw s.error;
42
+ }
43
+ }
44
+ return i;
45
+ }
46
+ function x(e, r, t) {
47
+ if (t || arguments.length === 2) for (var n = 0, o = r.length, i; n < o; n++)
48
+ (i || !(n in r)) && (i || (i = Array.prototype.slice.call(r, 0, n)), i[n] = r[n]);
49
+ return e.concat(i || Array.prototype.slice.call(r));
50
+ }
51
+ function l(e) {
52
+ return typeof e == "function";
53
+ }
54
+ function U(e) {
55
+ var r = function(n) {
56
+ Error.call(n), n.stack = new Error().stack;
57
+ }, t = e(r);
58
+ return t.prototype = Object.create(Error.prototype), t.prototype.constructor = t, t;
59
+ }
60
+ var m = U(function(e) {
61
+ return function(t) {
62
+ e(this), this.message = t ? t.length + ` errors occurred during unsubscription:
63
+ ` + t.map(function(n, o) {
64
+ return o + 1 + ") " + n.toString();
65
+ }).join(`
66
+ `) : "", this.name = "UnsubscriptionError", this.errors = t;
67
+ };
68
+ });
69
+ function g(e, r) {
70
+ if (e) {
71
+ var t = e.indexOf(r);
72
+ 0 <= t && e.splice(t, 1);
73
+ }
74
+ }
75
+ var S = (function() {
76
+ function e(r) {
77
+ this.initialTeardown = r, this.closed = !1, this._parentage = null, this._finalizers = null;
78
+ }
79
+ return e.prototype.unsubscribe = function() {
80
+ var r, t, n, o, i;
81
+ if (!this.closed) {
82
+ this.closed = !0;
83
+ var s = this._parentage;
84
+ if (s)
85
+ if (this._parentage = null, Array.isArray(s))
86
+ try {
87
+ for (var u = w(s), c = u.next(); !c.done; c = u.next()) {
88
+ var v = c.value;
89
+ v.remove(this);
90
+ }
91
+ } catch (a) {
92
+ r = { error: a };
93
+ } finally {
94
+ try {
95
+ c && !c.done && (t = u.return) && t.call(u);
96
+ } finally {
97
+ if (r) throw r.error;
98
+ }
99
+ }
100
+ else
101
+ s.remove(this);
102
+ var j = this.initialTeardown;
103
+ if (l(j))
104
+ try {
105
+ j();
106
+ } catch (a) {
107
+ i = a instanceof m ? a.errors : [a];
108
+ }
109
+ var P = this._finalizers;
110
+ if (P) {
111
+ this._finalizers = null;
112
+ try {
113
+ for (var b = w(P), p = b.next(); !p.done; p = b.next()) {
114
+ var V = p.value;
115
+ try {
116
+ A(V);
117
+ } catch (a) {
118
+ i = i ?? [], a instanceof m ? i = x(x([], E(i)), E(a.errors)) : i.push(a);
119
+ }
120
+ }
121
+ } catch (a) {
122
+ n = { error: a };
123
+ } finally {
124
+ try {
125
+ p && !p.done && (o = b.return) && o.call(b);
126
+ } finally {
127
+ if (n) throw n.error;
128
+ }
129
+ }
130
+ }
131
+ if (i)
132
+ throw new m(i);
133
+ }
134
+ }, e.prototype.add = function(r) {
135
+ var t;
136
+ if (r && r !== this)
137
+ if (this.closed)
138
+ A(r);
139
+ else {
140
+ if (r instanceof e) {
141
+ if (r.closed || r._hasParent(this))
142
+ return;
143
+ r._addParent(this);
144
+ }
145
+ (this._finalizers = (t = this._finalizers) !== null && t !== void 0 ? t : []).push(r);
146
+ }
147
+ }, e.prototype._hasParent = function(r) {
148
+ var t = this._parentage;
149
+ return t === r || Array.isArray(t) && t.includes(r);
150
+ }, e.prototype._addParent = function(r) {
151
+ var t = this._parentage;
152
+ this._parentage = Array.isArray(t) ? (t.push(r), t) : t ? [t, r] : r;
153
+ }, e.prototype._removeParent = function(r) {
154
+ var t = this._parentage;
155
+ t === r ? this._parentage = null : Array.isArray(t) && g(t, r);
156
+ }, e.prototype.remove = function(r) {
157
+ var t = this._finalizers;
158
+ t && g(t, r), r instanceof e && r._removeParent(this);
159
+ }, e.EMPTY = (function() {
160
+ var r = new e();
161
+ return r.closed = !0, r;
162
+ })(), e;
163
+ })(), M = S.EMPTY;
164
+ function Y(e) {
165
+ return e instanceof S || e && "closed" in e && l(e.remove) && l(e.add) && l(e.unsubscribe);
166
+ }
167
+ function A(e) {
168
+ l(e) ? e() : e.unsubscribe();
169
+ }
170
+ var H = {
171
+ Promise: void 0
172
+ }, $ = {
173
+ setTimeout: function(e, r) {
174
+ for (var t = [], n = 2; n < arguments.length; n++)
175
+ t[n - 2] = arguments[n];
176
+ return setTimeout.apply(void 0, x([e, r], E(t)));
177
+ },
178
+ clearTimeout: function(e) {
179
+ return clearTimeout(e);
180
+ },
181
+ delegate: void 0
182
+ };
183
+ function q(e) {
184
+ $.setTimeout(function() {
185
+ throw e;
186
+ });
187
+ }
188
+ function I() {
189
+ }
190
+ function y(e) {
191
+ e();
192
+ }
193
+ var F = (function(e) {
194
+ h(r, e);
195
+ function r(t) {
196
+ var n = e.call(this) || this;
197
+ return n.isStopped = !1, t ? (n.destination = t, Y(t) && t.add(n)) : n.destination = J, n;
198
+ }
199
+ return r.create = function(t, n, o) {
200
+ return new O(t, n, o);
201
+ }, r.prototype.next = function(t) {
202
+ this.isStopped || this._next(t);
203
+ }, r.prototype.error = function(t) {
204
+ this.isStopped || (this.isStopped = !0, this._error(t));
205
+ }, r.prototype.complete = function() {
206
+ this.isStopped || (this.isStopped = !0, this._complete());
207
+ }, r.prototype.unsubscribe = function() {
208
+ this.closed || (this.isStopped = !0, e.prototype.unsubscribe.call(this), this.destination = null);
209
+ }, r.prototype._next = function(t) {
210
+ this.destination.next(t);
211
+ }, r.prototype._error = function(t) {
212
+ try {
213
+ this.destination.error(t);
214
+ } finally {
215
+ this.unsubscribe();
216
+ }
217
+ }, r.prototype._complete = function() {
218
+ try {
219
+ this.destination.complete();
220
+ } finally {
221
+ this.unsubscribe();
222
+ }
223
+ }, r;
224
+ })(S), D = (function() {
225
+ function e(r) {
226
+ this.partialObserver = r;
227
+ }
228
+ return e.prototype.next = function(r) {
229
+ var t = this.partialObserver;
230
+ if (t.next)
231
+ try {
232
+ t.next(r);
233
+ } catch (n) {
234
+ d(n);
235
+ }
236
+ }, e.prototype.error = function(r) {
237
+ var t = this.partialObserver;
238
+ if (t.error)
239
+ try {
240
+ t.error(r);
241
+ } catch (n) {
242
+ d(n);
243
+ }
244
+ else
245
+ d(r);
246
+ }, e.prototype.complete = function() {
247
+ var r = this.partialObserver;
248
+ if (r.complete)
249
+ try {
250
+ r.complete();
251
+ } catch (t) {
252
+ d(t);
253
+ }
254
+ }, e;
255
+ })(), O = (function(e) {
256
+ h(r, e);
257
+ function r(t, n, o) {
258
+ var i = e.call(this) || this, s;
259
+ return l(t) || !t ? s = {
260
+ next: t ?? void 0,
261
+ error: n ?? void 0,
262
+ complete: o ?? void 0
263
+ } : s = t, i.destination = new D(s), i;
264
+ }
265
+ return r;
266
+ })(F);
267
+ function d(e) {
268
+ q(e);
269
+ }
270
+ function G(e) {
271
+ throw e;
272
+ }
273
+ var J = {
274
+ closed: !0,
275
+ next: I,
276
+ error: G,
277
+ complete: I
278
+ }, K = (function() {
279
+ return typeof Symbol == "function" && Symbol.observable || "@@observable";
280
+ })();
281
+ function L(e) {
282
+ return e;
283
+ }
284
+ function Q(e) {
285
+ return e.length === 0 ? L : e.length === 1 ? e[0] : function(t) {
286
+ return e.reduce(function(n, o) {
287
+ return o(n);
288
+ }, t);
289
+ };
290
+ }
291
+ var T = (function() {
292
+ function e(r) {
293
+ r && (this._subscribe = r);
294
+ }
295
+ return e.prototype.lift = function(r) {
296
+ var t = new e();
297
+ return t.source = this, t.operator = r, t;
298
+ }, e.prototype.subscribe = function(r, t, n) {
299
+ var o = this, i = X(r) ? r : new O(r, t, n);
300
+ return y(function() {
301
+ var s = o, u = s.operator, c = s.source;
302
+ i.add(u ? u.call(i, c) : c ? o._subscribe(i) : o._trySubscribe(i));
303
+ }), i;
304
+ }, e.prototype._trySubscribe = function(r) {
305
+ try {
306
+ return this._subscribe(r);
307
+ } catch (t) {
308
+ r.error(t);
309
+ }
310
+ }, e.prototype.forEach = function(r, t) {
311
+ var n = this;
312
+ return t = k(t), new t(function(o, i) {
313
+ var s = new O({
314
+ next: function(u) {
315
+ try {
316
+ r(u);
317
+ } catch (c) {
318
+ i(c), s.unsubscribe();
319
+ }
320
+ },
321
+ error: i,
322
+ complete: o
323
+ });
324
+ n.subscribe(s);
325
+ });
326
+ }, e.prototype._subscribe = function(r) {
327
+ var t;
328
+ return (t = this.source) === null || t === void 0 ? void 0 : t.subscribe(r);
329
+ }, e.prototype[K] = function() {
330
+ return this;
331
+ }, e.prototype.pipe = function() {
332
+ for (var r = [], t = 0; t < arguments.length; t++)
333
+ r[t] = arguments[t];
334
+ return Q(r)(this);
335
+ }, e.prototype.toPromise = function(r) {
336
+ var t = this;
337
+ return r = k(r), new r(function(n, o) {
338
+ var i;
339
+ t.subscribe(function(s) {
340
+ return i = s;
341
+ }, function(s) {
342
+ return o(s);
343
+ }, function() {
344
+ return n(i);
345
+ });
346
+ });
347
+ }, e.create = function(r) {
348
+ return new e(r);
349
+ }, e;
350
+ })();
351
+ function k(e) {
352
+ var r;
353
+ return (r = e ?? H.Promise) !== null && r !== void 0 ? r : Promise;
354
+ }
355
+ function W(e) {
356
+ return e && l(e.next) && l(e.error) && l(e.complete);
357
+ }
358
+ function X(e) {
359
+ return e && e instanceof F || W(e) && Y(e);
360
+ }
361
+ var Z = U(function(e) {
362
+ return function() {
363
+ e(this), this.name = "ObjectUnsubscribedError", this.message = "object unsubscribed";
364
+ };
365
+ }), B = (function(e) {
366
+ h(r, e);
367
+ function r() {
368
+ var t = e.call(this) || this;
369
+ return t.closed = !1, t.currentObservers = null, t.observers = [], t.isStopped = !1, t.hasError = !1, t.thrownError = null, t;
370
+ }
371
+ return r.prototype.lift = function(t) {
372
+ var n = new R(this, this);
373
+ return n.operator = t, n;
374
+ }, r.prototype._throwIfClosed = function() {
375
+ if (this.closed)
376
+ throw new Z();
377
+ }, r.prototype.next = function(t) {
378
+ var n = this;
379
+ y(function() {
380
+ var o, i;
381
+ if (n._throwIfClosed(), !n.isStopped) {
382
+ n.currentObservers || (n.currentObservers = Array.from(n.observers));
383
+ try {
384
+ for (var s = w(n.currentObservers), u = s.next(); !u.done; u = s.next()) {
385
+ var c = u.value;
386
+ c.next(t);
387
+ }
388
+ } catch (v) {
389
+ o = { error: v };
390
+ } finally {
391
+ try {
392
+ u && !u.done && (i = s.return) && i.call(s);
393
+ } finally {
394
+ if (o) throw o.error;
395
+ }
396
+ }
397
+ }
398
+ });
399
+ }, r.prototype.error = function(t) {
400
+ var n = this;
401
+ y(function() {
402
+ if (n._throwIfClosed(), !n.isStopped) {
403
+ n.hasError = n.isStopped = !0, n.thrownError = t;
404
+ for (var o = n.observers; o.length; )
405
+ o.shift().error(t);
406
+ }
407
+ });
408
+ }, r.prototype.complete = function() {
409
+ var t = this;
410
+ y(function() {
411
+ if (t._throwIfClosed(), !t.isStopped) {
412
+ t.isStopped = !0;
413
+ for (var n = t.observers; n.length; )
414
+ n.shift().complete();
415
+ }
416
+ });
417
+ }, r.prototype.unsubscribe = function() {
418
+ this.isStopped = this.closed = !0, this.observers = this.currentObservers = null;
419
+ }, Object.defineProperty(r.prototype, "observed", {
420
+ get: function() {
421
+ var t;
422
+ return ((t = this.observers) === null || t === void 0 ? void 0 : t.length) > 0;
423
+ },
424
+ enumerable: !1,
425
+ configurable: !0
426
+ }), r.prototype._trySubscribe = function(t) {
427
+ return this._throwIfClosed(), e.prototype._trySubscribe.call(this, t);
428
+ }, r.prototype._subscribe = function(t) {
429
+ return this._throwIfClosed(), this._checkFinalizedStatuses(t), this._innerSubscribe(t);
430
+ }, r.prototype._innerSubscribe = function(t) {
431
+ var n = this, o = this, i = o.hasError, s = o.isStopped, u = o.observers;
432
+ return i || s ? M : (this.currentObservers = null, u.push(t), new S(function() {
433
+ n.currentObservers = null, g(u, t);
434
+ }));
435
+ }, r.prototype._checkFinalizedStatuses = function(t) {
436
+ var n = this, o = n.hasError, i = n.thrownError, s = n.isStopped;
437
+ o ? t.error(i) : s && t.complete();
438
+ }, r.prototype.asObservable = function() {
439
+ var t = new T();
440
+ return t.source = this, t;
441
+ }, r.create = function(t, n) {
442
+ return new R(t, n);
443
+ }, r;
444
+ })(T), R = (function(e) {
445
+ h(r, e);
446
+ function r(t, n) {
447
+ var o = e.call(this) || this;
448
+ return o.destination = t, o.source = n, o;
449
+ }
450
+ return r.prototype.next = function(t) {
451
+ var n, o;
452
+ (o = (n = this.destination) === null || n === void 0 ? void 0 : n.next) === null || o === void 0 || o.call(n, t);
453
+ }, r.prototype.error = function(t) {
454
+ var n, o;
455
+ (o = (n = this.destination) === null || n === void 0 ? void 0 : n.error) === null || o === void 0 || o.call(n, t);
456
+ }, r.prototype.complete = function() {
457
+ var t, n;
458
+ (n = (t = this.destination) === null || t === void 0 ? void 0 : t.complete) === null || n === void 0 || n.call(t);
459
+ }, r.prototype._subscribe = function(t) {
460
+ var n, o;
461
+ return (o = (n = this.source) === null || n === void 0 ? void 0 : n.subscribe(t)) !== null && o !== void 0 ? o : M;
462
+ }, r;
463
+ })(B), z = (function(e) {
464
+ h(r, e);
465
+ function r(t) {
466
+ var n = e.call(this) || this;
467
+ return n._value = t, n;
468
+ }
469
+ return Object.defineProperty(r.prototype, "value", {
470
+ get: function() {
471
+ return this.getValue();
472
+ },
473
+ enumerable: !1,
474
+ configurable: !0
475
+ }), r.prototype._subscribe = function(t) {
476
+ var n = e.prototype._subscribe.call(this, t);
477
+ return !n.closed && t.next(this._value), n;
478
+ }, r.prototype.getValue = function() {
479
+ var t = this, n = t.hasError, o = t.thrownError, i = t._value;
480
+ if (n)
481
+ throw o;
482
+ return this._throwIfClosed(), i;
483
+ }, r.prototype.next = function(t) {
484
+ e.prototype.next.call(this, this._value = t);
485
+ }, r;
486
+ })(B);
487
+ class rt {
488
+ _stateSubject;
489
+ constructor() {
490
+ this.state = this.getInitialState(), this._stateSubject = new z(this.getInitialState());
491
+ }
492
+ getState() {
493
+ return this._stateSubject.value;
494
+ }
495
+ state$() {
496
+ return this._stateSubject.asObservable();
497
+ }
498
+ state;
499
+ setState(r) {
500
+ this._stateSubject.next(r);
501
+ }
502
+ }
503
+ function et(e) {
504
+ const r = f.createContext(void 0);
505
+ function t() {
506
+ const n = f.useContext(r);
507
+ if (!n)
508
+ throw new Error(
509
+ `Store hook used outside of its Context provider.
510
+
511
+ If you created your hook like:
512
+ const useYourStore = createStoreHook(${e.name});
513
+
514
+ Then wrap your component with:
515
+ <useYourStore.Context>
516
+ <YourComponent />
517
+ </useYourStore.Context>`
518
+ );
519
+ const [o, i] = f.useState(n.getState());
520
+ return f.useEffect(() => {
521
+ const s = n.state$().subscribe(i);
522
+ return () => s.unsubscribe();
523
+ }, []), n.state = o, n;
524
+ }
525
+ return t.Context = function({
526
+ children: o
527
+ }) {
528
+ const i = f.useRef(new e());
529
+ return /* @__PURE__ */ C(r.Provider, { value: i.current, children: o });
530
+ }, t.MockContext = function({
531
+ children: o,
532
+ state: i
533
+ }) {
534
+ const s = () => {
535
+ if (i === void 0)
536
+ return new e();
537
+ class c extends e {
538
+ getInitialState() {
539
+ return i;
540
+ }
541
+ }
542
+ return new c();
543
+ }, u = f.useRef(s());
544
+ return /* @__PURE__ */ C(r.Provider, { value: u.current, children: o });
545
+ }, t;
546
+ }
547
+ export {
548
+ rt as Store,
549
+ et as createStoreHook
550
+ };
@@ -0,0 +1,11 @@
1
+ declare abstract class Store<T> {
2
+ protected abstract getInitialState(): T;
3
+ private readonly _stateSubject;
4
+ constructor();
5
+ getState(): T;
6
+ state$(): import('rxjs').Observable<T>;
7
+ state: T;
8
+ protected setState(newState: T): void;
9
+ }
10
+ export { Store };
11
+ //# sourceMappingURL=Store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../../src/lib/Store.ts"],"names":[],"mappings":"AAEA,uBAAe,KAAK,CAAC,CAAC;IACpB,SAAS,CAAC,QAAQ,CAAC,eAAe,IAAI,CAAC;IAEvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;;IAOnD,QAAQ,IAAI,CAAC;IAIb,MAAM;IAIC,KAAK,EAAE,CAAC,CAAC;IAEhB,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI;CAGtC;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { default as React } from 'react';
2
+ import { Store } from './Store';
3
+ declare function createStoreHook<T extends Store<any>>(storeClass: new () => T): {
4
+ (): T;
5
+ Context({ children, }: {
6
+ children: React.ReactNode;
7
+ }): import("react/jsx-runtime").JSX.Element;
8
+ MockContext({ children, state, }: {
9
+ children: React.ReactNode;
10
+ state?: ReturnType<T["getState"]>;
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ };
13
+ export { createStoreHook };
14
+ //# sourceMappingURL=createStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createStore.d.ts","sourceRoot":"","sources":["../../src/lib/createStore.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,iBAAS,eAAe,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC;QAG/C,CAAC;2BA+BnB;QACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;KAC3B;sCAaE;QACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAC1B,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;KACnC;EAuBF;AACD,OAAO,EAAE,eAAe,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "context-scoped-state",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ ".": {
11
+ "@context-store-react/source": "./src/index.ts",
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "!**/*.tsbuildinfo"
20
+ ],
21
+ "peerDependencies": {
22
+ "react": ">=18.0.0"
23
+ }
24
+ }