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 +204 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +550 -0
- package/dist/lib/Store.d.ts +11 -0
- package/dist/lib/Store.d.ts.map +1 -0
- package/dist/lib/createStore.d.ts +14 -0
- package/dist/lib/createStore.d.ts.map +1 -0
- package/package.json +24 -0
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.
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|