bunja 2.0.0-alpha.6 → 2.0.0-alpha.9
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 +277 -0
- package/bunja.ts +133 -2
- package/deno.json +1 -1
- package/dist/{bunja-bhXTtuLY.cjs → bunja-DO4Cr7x-.cjs} +78 -3
- package/dist/{bunja-CqyhNWOx.d.ts → bunja-DXtbhAmJ.d.cts} +57 -1
- package/dist/{bunja-P0kiwZQC.d.cts → bunja-D_SKFBCD.d.ts} +57 -1
- package/dist/{bunja-BB7ru8D0.js → bunja-DxIUFo_M.js} +78 -3
- package/dist/bunja.cjs +1 -1
- package/dist/bunja.d.cts +2 -2
- package/dist/bunja.d.ts +2 -2
- package/dist/bunja.js +1 -1
- package/dist/react.cjs +21 -15
- package/dist/react.d.cts +2 -6
- package/dist/react.d.ts +2 -6
- package/dist/react.js +23 -16
- package/dist/solid.cjs +2 -5
- package/dist/solid.d.cts +1 -1
- package/dist/solid.d.ts +1 -1
- package/dist/solid.js +2 -5
- package/package.json +2 -1
- package/react.ts +19 -16
- package/solid.ts +1 -4
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Bunja
|
|
2
|
+
|
|
3
|
+
Bunja is lightweight State Lifetime Manager.\
|
|
4
|
+
Heavily inspired by [Bunshi](https://github.com/saasquatch/bunshi).
|
|
5
|
+
|
|
6
|
+
> Definition: Bunja (分子 / 분자) - Korean for molecule, member or element.
|
|
7
|
+
|
|
8
|
+
## Why is managing the lifetime of state necessary?
|
|
9
|
+
|
|
10
|
+
Global state managers like jotai or signals offer the advantage of declaratively
|
|
11
|
+
describing state and effectively reducing render counts, but they lack suitable
|
|
12
|
+
methods for managing resources with a defined start and end.\
|
|
13
|
+
For example, consider establishing and closing a WebSocket connection or a modal
|
|
14
|
+
form UI that appears temporarily and then disappears.
|
|
15
|
+
|
|
16
|
+
Bunja is a library designed to address these weaknesses.\
|
|
17
|
+
Each state defined with Bunja has a lifetime that begins when it is first
|
|
18
|
+
depended on somewhere in the render tree and ends when all dependencies
|
|
19
|
+
disappear.
|
|
20
|
+
|
|
21
|
+
Therefore, when writing a state to manage a WebSocket, you only need to create a
|
|
22
|
+
function that establishes the WebSocket connection and an dispose handler that
|
|
23
|
+
terminates the connection.\
|
|
24
|
+
The library automatically tracks the actual usage period and calls the init and
|
|
25
|
+
dispose as needed.
|
|
26
|
+
|
|
27
|
+
## So, do I no longer need jotai or other state management libraries?
|
|
28
|
+
|
|
29
|
+
No. Bunja focuses solely on managing the lifetime of state, so jotai and other
|
|
30
|
+
state management libraries are still valuable.\
|
|
31
|
+
You can typically use jotai or something, and when lifetime management becomes
|
|
32
|
+
necessary, you can wrap those states with bunja.
|
|
33
|
+
|
|
34
|
+
## How to use
|
|
35
|
+
|
|
36
|
+
Bunja basically provides two functions: `bunja` and `useBunja`.\
|
|
37
|
+
You can use `bunja` to define a state with a finite lifetime and use the
|
|
38
|
+
`useBunja` hook to access that state.
|
|
39
|
+
|
|
40
|
+
### Defining a Bunja
|
|
41
|
+
|
|
42
|
+
You can define a bunja using the `bunja` function. When you access the defined
|
|
43
|
+
bunja with the `useBunja` hook, a bunja instance is created.\
|
|
44
|
+
If all components in the render tree that refer to the bunja disappear, the
|
|
45
|
+
bunja instance is automatically destroyed.
|
|
46
|
+
|
|
47
|
+
If you want to trigger effects when the lifetime of a bunja starts and ends, you
|
|
48
|
+
can use the `bunja.effect` function.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { bunja } from "bunja";
|
|
52
|
+
import { useBunja } from "bunja/react";
|
|
53
|
+
|
|
54
|
+
const countBunja = bunja(() => {
|
|
55
|
+
const countAtom = atom(0);
|
|
56
|
+
|
|
57
|
+
bunja.effect(() => {
|
|
58
|
+
console.log("mounted");
|
|
59
|
+
return () => console.log("unmounted");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return { countAtom };
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
function MyComponent() {
|
|
66
|
+
const { countAtom } = useBunja(countBunja);
|
|
67
|
+
const [count, setCount] = useAtom(countAtom);
|
|
68
|
+
// Your component logic here
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Defining a Bunja that relies on other Bunja
|
|
73
|
+
|
|
74
|
+
If you want to manage a state with a broad lifetime and another state with a
|
|
75
|
+
narrower lifetime, you can create a (narrower) bunja that depends on a (broader)
|
|
76
|
+
bunja. For example, you can think of a bunja that manages the WebSocket
|
|
77
|
+
connection and disconnection, and another bunja that subscribes to a specific
|
|
78
|
+
resource over the connected WebSocket.
|
|
79
|
+
|
|
80
|
+
In an application composed of multiple pages, you might want to subscribe to the
|
|
81
|
+
Foo resource on page A and the Bar resource on page B, while using the same
|
|
82
|
+
WebSocket connection regardless of which page you're on. In such a case, you can
|
|
83
|
+
write the following code.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
// To simplify the example, code for buffering and reconnection has been omitted.
|
|
87
|
+
const websocketBunja = bunja(() => {
|
|
88
|
+
let socket;
|
|
89
|
+
const send = (message) => socket.send(JSON.stringify(message));
|
|
90
|
+
|
|
91
|
+
const emitter = new EventEmitter();
|
|
92
|
+
const on = (handler) => {
|
|
93
|
+
emitter.on("message", handler);
|
|
94
|
+
return () => emitter.off("message", handler);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
bunja.effect(() => {
|
|
98
|
+
socket = new WebSocket("...");
|
|
99
|
+
socket.onmessage = (e) => emitter.emit("message", JSON.parse(e.data));
|
|
100
|
+
return () => socket.close();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return { send, on };
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const resourceFooBunja = bunja(() => {
|
|
107
|
+
const { send, on } = bunja.use(websocketBunja);
|
|
108
|
+
const resourceFooAtom = atom();
|
|
109
|
+
|
|
110
|
+
bunja.effect(() => {
|
|
111
|
+
const off = on((message) => {
|
|
112
|
+
if (message.type === "foo") store.set(resourceAtom, message.value);
|
|
113
|
+
});
|
|
114
|
+
send("subscribe-foo");
|
|
115
|
+
return () => {
|
|
116
|
+
send("unsubscribe-foo");
|
|
117
|
+
off();
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return { resourceFooAtom };
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const resourceBarBunja = bunja(() => {
|
|
125
|
+
const { send, on } = bunja.use(websocketBunja);
|
|
126
|
+
const resourceBarAtom = atom();
|
|
127
|
+
// ...
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
function PageA() {
|
|
131
|
+
const { resourceFooAtom } = useBunja(resourceFooBunja);
|
|
132
|
+
const resourceFoo = useAtomValue(resourceFooAtom);
|
|
133
|
+
// ...
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function PageB() {
|
|
137
|
+
const { resourceBarAtom } = useBunja(resourceBarBunja);
|
|
138
|
+
const resourceBar = useAtomValue(resourceBarAtom);
|
|
139
|
+
// ...
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Notice that `websocketBunja` is not directly `useBunja`-ed. When you `useBunja`
|
|
144
|
+
either `resourceFooBunja` or `resourceBarBunja`, since they depend on
|
|
145
|
+
`websocketBunja`, it has the same effect as if `websocketBunja` were also
|
|
146
|
+
`useBunja`-ed.
|
|
147
|
+
|
|
148
|
+
> [!NOTE]
|
|
149
|
+
> When a bunja starts, the initialization effect of the bunja with a broader
|
|
150
|
+
> lifetime is called first.\
|
|
151
|
+
> Similarly, when a bunja ends, the cleanup effect of the bunja with the broader
|
|
152
|
+
> lifetime is called first.\
|
|
153
|
+
> This behavior is aligned with how React's `useEffect` cleanup function is
|
|
154
|
+
> invoked, where the parent’s cleanup is executed before the child’s in the
|
|
155
|
+
> render tree.
|
|
156
|
+
>
|
|
157
|
+
> See: <https://github.com/facebook/react/issues/16728>
|
|
158
|
+
|
|
159
|
+
### Dependency injection using Scope
|
|
160
|
+
|
|
161
|
+
You can use a bunja for local state management.\
|
|
162
|
+
When you specify a scope as a dependency of the bunja, separate bunja instances
|
|
163
|
+
are created based on the values injected into the scope.
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { bunja, createScope } from "bunja";
|
|
167
|
+
|
|
168
|
+
const UrlScope = createScope();
|
|
169
|
+
|
|
170
|
+
const fetchBunja = bunja(() => {
|
|
171
|
+
const url = bunja.use(UrlScope);
|
|
172
|
+
|
|
173
|
+
const queryAtom = atomWithQuery((get) => ({
|
|
174
|
+
queryKey: [url],
|
|
175
|
+
queryFn: async () => (await fetch(url)).json(),
|
|
176
|
+
}));
|
|
177
|
+
|
|
178
|
+
return { queryAtom };
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Injecting dependencies via React context
|
|
183
|
+
|
|
184
|
+
If you bind a scope to a React context, bunjas that depend on the scope can
|
|
185
|
+
retrieve values from the corresponding React context.
|
|
186
|
+
|
|
187
|
+
In the example below, there are two React instances (`<ChildComponent />`) that
|
|
188
|
+
reference the same `fetchBunja`, but since each looks at a different context
|
|
189
|
+
value, two separate bunja instances are also created.
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
import { createContext } from "react";
|
|
193
|
+
import { bunja, createScope } from "bunja";
|
|
194
|
+
import { bindScope } from "bunja/react";
|
|
195
|
+
|
|
196
|
+
const UrlContext = createContext("https://example.com/");
|
|
197
|
+
const UrlScope = createScope();
|
|
198
|
+
bindScope(UrlScope, UrlContext);
|
|
199
|
+
|
|
200
|
+
const fetchBunja = bunja(() => {
|
|
201
|
+
const url = bunja.use(UrlScope);
|
|
202
|
+
|
|
203
|
+
const queryAtom = atomWithQuery((get) => ({
|
|
204
|
+
queryKey: [url],
|
|
205
|
+
queryFn: async () => (await fetch(url)).json(),
|
|
206
|
+
}));
|
|
207
|
+
|
|
208
|
+
return { queryAtom };
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
function ParentComponent() {
|
|
212
|
+
return (
|
|
213
|
+
<>
|
|
214
|
+
<UrlContext value="https://example.com/foo">
|
|
215
|
+
<ChildComponent />
|
|
216
|
+
</UrlContext>
|
|
217
|
+
<UrlContext value="https://example.com/bar">
|
|
218
|
+
<ChildComponent />
|
|
219
|
+
</UrlContext>
|
|
220
|
+
</>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function ChildComponent() {
|
|
225
|
+
const { queryAtom } = useBunja(fetchBunja);
|
|
226
|
+
const { data, isPending, isError } = useAtomValue(queryAtom);
|
|
227
|
+
// Your component logic here
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
You can use the `createScopeFromContext` function to handle both the creation of
|
|
232
|
+
the scope and the binding to the context in one step.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
import { createContext } from "react";
|
|
236
|
+
import { createScopeFromContext } from "bunja/react";
|
|
237
|
+
|
|
238
|
+
const UrlContext = createContext("https://example.com/");
|
|
239
|
+
const UrlScope = createScopeFromContext(UrlContext);
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### Injecting dependencies directly into the scope
|
|
243
|
+
|
|
244
|
+
You might want to use a bunja directly within a React component where the values
|
|
245
|
+
to be injected into the scope are created.
|
|
246
|
+
|
|
247
|
+
In such cases, you can use the second parameter of `useBunja` hook to inject
|
|
248
|
+
values into the scope without wrapping the context separately.
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
function MyComponent() {
|
|
252
|
+
const { queryAtom } = useBunja(
|
|
253
|
+
fetchBunja,
|
|
254
|
+
[UrlScope.bind("https://example.com/")],
|
|
255
|
+
);
|
|
256
|
+
const { data, isPending, isError } = useAtomValue(queryAtom);
|
|
257
|
+
// Your component logic here
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
##### Doing the same thing inside a bunja
|
|
262
|
+
|
|
263
|
+
You can use `bunja.fork` to inject scope values from within a bunja
|
|
264
|
+
initialization function.
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
const myBunja = bunja(() => {
|
|
268
|
+
const fooData = bunja.fork(fetchBunja, [
|
|
269
|
+
UrlScope.bind("https://example.com/foo"),
|
|
270
|
+
]);
|
|
271
|
+
const barData = bunja.fork(fetchBunja, [
|
|
272
|
+
UrlScope.bind("https://example.com/bar"),
|
|
273
|
+
]);
|
|
274
|
+
|
|
275
|
+
return { fooData, barData };
|
|
276
|
+
});
|
|
277
|
+
```
|
package/bunja.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// @ts-ignore dev
|
|
2
|
+
// deno-lint-ignore no-process-global
|
|
3
|
+
const __DEV__ = process.env.NODE_ENV !== "production";
|
|
4
|
+
|
|
1
5
|
export interface BunjaFn {
|
|
2
6
|
<T>(init: () => T): Bunja<T>;
|
|
3
7
|
use: BunjaUseFn;
|
|
@@ -61,6 +65,11 @@ interface BunjaStoreGetContext {
|
|
|
61
65
|
type BunjaInstanceMap = Map<Bunja<unknown>, BunjaInstance>;
|
|
62
66
|
type ScopeInstanceMap = Map<Scope<unknown>, ScopeInstance>;
|
|
63
67
|
|
|
68
|
+
interface InternalState {
|
|
69
|
+
bunjas: Record<string, BunjaInstance>;
|
|
70
|
+
scopes: Map<Scope<unknown>, Map<unknown, ScopeInstance>>;
|
|
71
|
+
}
|
|
72
|
+
|
|
64
73
|
interface BunjaBakingContext {
|
|
65
74
|
currentBunja: Bunja<unknown>;
|
|
66
75
|
}
|
|
@@ -69,10 +78,22 @@ export type WrapInstanceFn = <T>(fn: (dispose: () => void) => T) => T;
|
|
|
69
78
|
const defaultWrapInstanceFn: WrapInstanceFn = (fn) => fn(noop);
|
|
70
79
|
|
|
71
80
|
export class BunjaStore {
|
|
81
|
+
private static counter: number = 0;
|
|
82
|
+
readonly id: string = String(BunjaStore.counter++);
|
|
72
83
|
#bunjas: Record<string, BunjaInstance> = {};
|
|
73
84
|
#scopes: Map<Scope<unknown>, Map<unknown, ScopeInstance>> = new Map();
|
|
74
85
|
#bakingContext: BunjaBakingContext | undefined;
|
|
75
86
|
wrapInstance: WrapInstanceFn = defaultWrapInstanceFn;
|
|
87
|
+
constructor() {
|
|
88
|
+
if (__DEV__) {
|
|
89
|
+
devtoolsGlobalHook.stores[this.id] = this;
|
|
90
|
+
devtoolsGlobalHook.emit("storeCreated", { storeId: this.id });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
get _internalState(): InternalState | undefined {
|
|
94
|
+
if (__DEV__) return { bunjas: this.#bunjas, scopes: this.#scopes };
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
76
97
|
dispose(): void {
|
|
77
98
|
for (const instance of Object.values(this.#bunjas)) instance.dispose();
|
|
78
99
|
for (const instanceMap of Object.values(this.#scopes)) {
|
|
@@ -80,6 +101,10 @@ export class BunjaStore {
|
|
|
80
101
|
}
|
|
81
102
|
this.#bunjas = {};
|
|
82
103
|
this.#scopes = new Map();
|
|
104
|
+
if (__DEV__) {
|
|
105
|
+
devtoolsGlobalHook.emit("storeDisposed", { storeId: this.id });
|
|
106
|
+
delete devtoolsGlobalHook.stores[this.id];
|
|
107
|
+
}
|
|
83
108
|
}
|
|
84
109
|
get<T>(bunja: Bunja<T>, readScope: ReadScope): BunjaStoreGetResult<T> {
|
|
85
110
|
const originalUse = bunjaFn.use;
|
|
@@ -87,7 +112,7 @@ export class BunjaStore {
|
|
|
87
112
|
const { bunjaInstance, bunjaInstanceMap, scopeInstanceMap } = bunja.baked
|
|
88
113
|
? this.#getBaked(bunja, readScope)
|
|
89
114
|
: this.#getUnbaked(bunja, readScope);
|
|
90
|
-
|
|
115
|
+
const result: BunjaStoreGetResult<T> = {
|
|
91
116
|
value: bunjaInstance.value as T,
|
|
92
117
|
mount: () => {
|
|
93
118
|
bunjaInstanceMap.forEach((instance) => instance.add());
|
|
@@ -102,6 +127,14 @@ export class BunjaStore {
|
|
|
102
127
|
},
|
|
103
128
|
deps: Array.from(scopeInstanceMap.values()).map(({ value }) => value),
|
|
104
129
|
};
|
|
130
|
+
if (__DEV__) {
|
|
131
|
+
result.bunjaInstance = bunjaInstance;
|
|
132
|
+
devtoolsGlobalHook.emit("getCalled", {
|
|
133
|
+
storeId: this.id,
|
|
134
|
+
bunjaInstanceId: bunjaInstance.id,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
105
138
|
} finally {
|
|
106
139
|
bunjaFn.use = originalUse;
|
|
107
140
|
}
|
|
@@ -225,7 +258,16 @@ export class BunjaStore {
|
|
|
225
258
|
return instanceMap.get(key) ??
|
|
226
259
|
instanceMap.set(
|
|
227
260
|
key,
|
|
228
|
-
|
|
261
|
+
this.#createScopeInstance(scope, key, value, () => {
|
|
262
|
+
instanceMap.delete(key);
|
|
263
|
+
if (__DEV__) {
|
|
264
|
+
devtoolsGlobalHook.emit("scopeInstanceUnmounted", {
|
|
265
|
+
storeId: this.id,
|
|
266
|
+
scope,
|
|
267
|
+
key,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}),
|
|
229
271
|
).get(key)!;
|
|
230
272
|
}
|
|
231
273
|
#createBunjaInstance(
|
|
@@ -241,12 +283,39 @@ export class BunjaStore {
|
|
|
241
283
|
return () => cleanups.forEach((cleanup) => cleanup());
|
|
242
284
|
};
|
|
243
285
|
const bunjaInstance = new BunjaInstance(id, value, effect, () => {
|
|
286
|
+
if (__DEV__) {
|
|
287
|
+
devtoolsGlobalHook.emit("bunjaInstanceUnmounted", {
|
|
288
|
+
storeId: this.id,
|
|
289
|
+
bunjaInstanceId: id,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
244
292
|
dispose();
|
|
245
293
|
delete this.#bunjas[id];
|
|
246
294
|
});
|
|
247
295
|
this.#bunjas[id] = bunjaInstance;
|
|
296
|
+
if (__DEV__) {
|
|
297
|
+
devtoolsGlobalHook.emit("bunjaInstanceMounted", {
|
|
298
|
+
storeId: this.id,
|
|
299
|
+
bunjaInstanceId: id,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
248
302
|
return bunjaInstance;
|
|
249
303
|
}
|
|
304
|
+
#createScopeInstance(
|
|
305
|
+
scope: Scope<unknown>,
|
|
306
|
+
key: unknown,
|
|
307
|
+
value: unknown,
|
|
308
|
+
dispose: () => void,
|
|
309
|
+
): ScopeInstance {
|
|
310
|
+
if (__DEV__) {
|
|
311
|
+
devtoolsGlobalHook.emit("scopeInstanceMounted", {
|
|
312
|
+
storeId: this.id,
|
|
313
|
+
scope,
|
|
314
|
+
key,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
return new ScopeInstance(value, dispose);
|
|
318
|
+
}
|
|
250
319
|
}
|
|
251
320
|
|
|
252
321
|
export type ReadScope = <T>(scope: Scope<T>) => T;
|
|
@@ -267,6 +336,7 @@ export interface BunjaStoreGetResult<T> {
|
|
|
267
336
|
value: T;
|
|
268
337
|
mount: () => () => void;
|
|
269
338
|
deps: unknown[];
|
|
339
|
+
bunjaInstance?: BunjaInstance;
|
|
270
340
|
}
|
|
271
341
|
|
|
272
342
|
export function delayUnmount(
|
|
@@ -431,3 +501,64 @@ function toposort<T extends Toposortable>(nodes: T[]): T[] {
|
|
|
431
501
|
}
|
|
432
502
|
|
|
433
503
|
const noop = () => {};
|
|
504
|
+
|
|
505
|
+
export interface BunjaDevtoolsGlobalHook {
|
|
506
|
+
stores: Record<string, BunjaStore>;
|
|
507
|
+
listeners: Record<
|
|
508
|
+
BunjaDevtoolsEventType,
|
|
509
|
+
Set<(event: any) => void>
|
|
510
|
+
>;
|
|
511
|
+
emit<T extends BunjaDevtoolsEventType>(
|
|
512
|
+
type: T,
|
|
513
|
+
event: BunjaDevtoolsEvent[T],
|
|
514
|
+
): void;
|
|
515
|
+
on<T extends BunjaDevtoolsEventType>(
|
|
516
|
+
type: T,
|
|
517
|
+
listener: (event: BunjaDevtoolsEvent[T]) => void,
|
|
518
|
+
): () => void;
|
|
519
|
+
}
|
|
520
|
+
export interface BunjaDevtoolsEvent {
|
|
521
|
+
storeCreated: { storeId: string };
|
|
522
|
+
storeDisposed: { storeId: string };
|
|
523
|
+
getCalled: { storeId: string; bunjaInstanceId: string };
|
|
524
|
+
bunjaInstanceMounted: { storeId: string; bunjaInstanceId: string };
|
|
525
|
+
bunjaInstanceUnmounted: { storeId: string; bunjaInstanceId: string };
|
|
526
|
+
scopeInstanceMounted: {
|
|
527
|
+
storeId: string;
|
|
528
|
+
scope: Scope<unknown>;
|
|
529
|
+
key: unknown;
|
|
530
|
+
};
|
|
531
|
+
scopeInstanceUnmounted: {
|
|
532
|
+
storeId: string;
|
|
533
|
+
scope: Scope<unknown>;
|
|
534
|
+
key: unknown;
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
export type BunjaDevtoolsEventType = keyof BunjaDevtoolsEvent;
|
|
538
|
+
let devtoolsGlobalHook: BunjaDevtoolsGlobalHook;
|
|
539
|
+
if (__DEV__) {
|
|
540
|
+
if ((globalThis as any).__BUNJA_DEVTOOLS_GLOBAL_HOOK__) {
|
|
541
|
+
devtoolsGlobalHook = (globalThis as any).__BUNJA_DEVTOOLS_GLOBAL_HOOK__;
|
|
542
|
+
} else {
|
|
543
|
+
devtoolsGlobalHook = {
|
|
544
|
+
stores: {},
|
|
545
|
+
listeners: {
|
|
546
|
+
storeCreated: new Set(),
|
|
547
|
+
storeDisposed: new Set(),
|
|
548
|
+
getCalled: new Set(),
|
|
549
|
+
bunjaInstanceMounted: new Set(),
|
|
550
|
+
bunjaInstanceUnmounted: new Set(),
|
|
551
|
+
scopeInstanceMounted: new Set(),
|
|
552
|
+
scopeInstanceUnmounted: new Set(),
|
|
553
|
+
},
|
|
554
|
+
emit: (type, event) => {
|
|
555
|
+
for (const fn of devtoolsGlobalHook.listeners[type]) fn(event);
|
|
556
|
+
},
|
|
557
|
+
on: (type, listener) => {
|
|
558
|
+
devtoolsGlobalHook.listeners[type].add(listener);
|
|
559
|
+
return () => devtoolsGlobalHook.listeners[type].delete(listener);
|
|
560
|
+
},
|
|
561
|
+
};
|
|
562
|
+
(globalThis as any).__BUNJA_DEVTOOLS_GLOBAL_HOOK__ = devtoolsGlobalHook;
|
|
563
|
+
}
|
|
564
|
+
}
|
package/deno.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
//#region bunja.ts
|
|
3
|
+
const __DEV__ = process.env.NODE_ENV !== "production";
|
|
3
4
|
const bunja = bunjaFn;
|
|
4
5
|
function bunjaFn(init) {
|
|
5
6
|
return new Bunja(init);
|
|
@@ -26,22 +27,41 @@ function invalidEffect() {
|
|
|
26
27
|
throw new Error("`bunja.effect` can only be used inside a bunja init function.");
|
|
27
28
|
}
|
|
28
29
|
const defaultWrapInstanceFn = (fn) => fn(noop);
|
|
29
|
-
var BunjaStore = class {
|
|
30
|
+
var BunjaStore = class BunjaStore {
|
|
31
|
+
static counter = 0;
|
|
32
|
+
id = String(BunjaStore.counter++);
|
|
30
33
|
#bunjas = {};
|
|
31
34
|
#scopes = /* @__PURE__ */ new Map();
|
|
32
35
|
#bakingContext;
|
|
33
36
|
wrapInstance = defaultWrapInstanceFn;
|
|
37
|
+
constructor() {
|
|
38
|
+
if (__DEV__) {
|
|
39
|
+
devtoolsGlobalHook.stores[this.id] = this;
|
|
40
|
+
devtoolsGlobalHook.emit("storeCreated", { storeId: this.id });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
get _internalState() {
|
|
44
|
+
if (__DEV__) return {
|
|
45
|
+
bunjas: this.#bunjas,
|
|
46
|
+
scopes: this.#scopes
|
|
47
|
+
};
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
34
50
|
dispose() {
|
|
35
51
|
for (const instance of Object.values(this.#bunjas)) instance.dispose();
|
|
36
52
|
for (const instanceMap of Object.values(this.#scopes)) for (const instance of instanceMap.values()) instance.dispose();
|
|
37
53
|
this.#bunjas = {};
|
|
38
54
|
this.#scopes = /* @__PURE__ */ new Map();
|
|
55
|
+
if (__DEV__) {
|
|
56
|
+
devtoolsGlobalHook.emit("storeDisposed", { storeId: this.id });
|
|
57
|
+
delete devtoolsGlobalHook.stores[this.id];
|
|
58
|
+
}
|
|
39
59
|
}
|
|
40
60
|
get(bunja$1, readScope) {
|
|
41
61
|
const originalUse = bunjaFn.use;
|
|
42
62
|
try {
|
|
43
63
|
const { bunjaInstance, bunjaInstanceMap, scopeInstanceMap } = bunja$1.baked ? this.#getBaked(bunja$1, readScope) : this.#getUnbaked(bunja$1, readScope);
|
|
44
|
-
|
|
64
|
+
const result = {
|
|
45
65
|
value: bunjaInstance.value,
|
|
46
66
|
mount: () => {
|
|
47
67
|
bunjaInstanceMap.forEach((instance) => instance.add());
|
|
@@ -56,6 +76,14 @@ var BunjaStore = class {
|
|
|
56
76
|
},
|
|
57
77
|
deps: Array.from(scopeInstanceMap.values()).map(({ value }) => value)
|
|
58
78
|
};
|
|
79
|
+
if (__DEV__) {
|
|
80
|
+
result.bunjaInstance = bunjaInstance;
|
|
81
|
+
devtoolsGlobalHook.emit("getCalled", {
|
|
82
|
+
storeId: this.id,
|
|
83
|
+
bunjaInstanceId: bunjaInstance.id
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
59
87
|
} finally {
|
|
60
88
|
bunjaFn.use = originalUse;
|
|
61
89
|
}
|
|
@@ -150,7 +178,14 @@ var BunjaStore = class {
|
|
|
150
178
|
#getScopeInstance(scope, value) {
|
|
151
179
|
const key = scope.hash(value);
|
|
152
180
|
const instanceMap = this.#scopes.get(scope) ?? this.#scopes.set(scope, /* @__PURE__ */ new Map()).get(scope);
|
|
153
|
-
return instanceMap.get(key) ?? instanceMap.set(key,
|
|
181
|
+
return instanceMap.get(key) ?? instanceMap.set(key, this.#createScopeInstance(scope, key, value, () => {
|
|
182
|
+
instanceMap.delete(key);
|
|
183
|
+
if (__DEV__) devtoolsGlobalHook.emit("scopeInstanceUnmounted", {
|
|
184
|
+
storeId: this.id,
|
|
185
|
+
scope,
|
|
186
|
+
key
|
|
187
|
+
});
|
|
188
|
+
})).get(key);
|
|
154
189
|
}
|
|
155
190
|
#createBunjaInstance(id, value, effects, dispose) {
|
|
156
191
|
const effect = () => {
|
|
@@ -158,12 +193,28 @@ var BunjaStore = class {
|
|
|
158
193
|
return () => cleanups.forEach((cleanup) => cleanup());
|
|
159
194
|
};
|
|
160
195
|
const bunjaInstance = new BunjaInstance(id, value, effect, () => {
|
|
196
|
+
if (__DEV__) devtoolsGlobalHook.emit("bunjaInstanceUnmounted", {
|
|
197
|
+
storeId: this.id,
|
|
198
|
+
bunjaInstanceId: id
|
|
199
|
+
});
|
|
161
200
|
dispose();
|
|
162
201
|
delete this.#bunjas[id];
|
|
163
202
|
});
|
|
164
203
|
this.#bunjas[id] = bunjaInstance;
|
|
204
|
+
if (__DEV__) devtoolsGlobalHook.emit("bunjaInstanceMounted", {
|
|
205
|
+
storeId: this.id,
|
|
206
|
+
bunjaInstanceId: id
|
|
207
|
+
});
|
|
165
208
|
return bunjaInstance;
|
|
166
209
|
}
|
|
210
|
+
#createScopeInstance(scope, key, value, dispose) {
|
|
211
|
+
if (__DEV__) devtoolsGlobalHook.emit("scopeInstanceMounted", {
|
|
212
|
+
storeId: this.id,
|
|
213
|
+
scope,
|
|
214
|
+
key
|
|
215
|
+
});
|
|
216
|
+
return new ScopeInstance(value, dispose);
|
|
217
|
+
}
|
|
167
218
|
};
|
|
168
219
|
function createReadScopeFn(scopeValuePairs, readScope) {
|
|
169
220
|
const map = new Map(scopeValuePairs);
|
|
@@ -306,6 +357,30 @@ function toposort(nodes) {
|
|
|
306
357
|
return result;
|
|
307
358
|
}
|
|
308
359
|
const noop = () => {};
|
|
360
|
+
let devtoolsGlobalHook;
|
|
361
|
+
if (__DEV__) if (globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__) devtoolsGlobalHook = globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__;
|
|
362
|
+
else {
|
|
363
|
+
devtoolsGlobalHook = {
|
|
364
|
+
stores: {},
|
|
365
|
+
listeners: {
|
|
366
|
+
storeCreated: /* @__PURE__ */ new Set(),
|
|
367
|
+
storeDisposed: /* @__PURE__ */ new Set(),
|
|
368
|
+
getCalled: /* @__PURE__ */ new Set(),
|
|
369
|
+
bunjaInstanceMounted: /* @__PURE__ */ new Set(),
|
|
370
|
+
bunjaInstanceUnmounted: /* @__PURE__ */ new Set(),
|
|
371
|
+
scopeInstanceMounted: /* @__PURE__ */ new Set(),
|
|
372
|
+
scopeInstanceUnmounted: /* @__PURE__ */ new Set()
|
|
373
|
+
},
|
|
374
|
+
emit: (type, event) => {
|
|
375
|
+
for (const fn of devtoolsGlobalHook.listeners[type]) fn(event);
|
|
376
|
+
},
|
|
377
|
+
on: (type, listener) => {
|
|
378
|
+
devtoolsGlobalHook.listeners[type].add(listener);
|
|
379
|
+
return () => devtoolsGlobalHook.listeners[type].delete(listener);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__ = devtoolsGlobalHook;
|
|
383
|
+
}
|
|
309
384
|
|
|
310
385
|
//#endregion
|
|
311
386
|
Object.defineProperty(exports, 'Bunja', {
|
|
@@ -16,10 +16,18 @@ interface CreateBunjaStoreConfig {
|
|
|
16
16
|
}
|
|
17
17
|
declare function createBunjaStore(config?: CreateBunjaStoreConfig): BunjaStore;
|
|
18
18
|
type Dep<T> = Bunja<T> | Scope<T>;
|
|
19
|
+
interface InternalState {
|
|
20
|
+
bunjas: Record<string, BunjaInstance>;
|
|
21
|
+
scopes: Map<Scope<unknown>, Map<unknown, ScopeInstance>>;
|
|
22
|
+
}
|
|
19
23
|
type WrapInstanceFn = <T>(fn: (dispose: () => void) => T) => T;
|
|
20
24
|
declare class BunjaStore {
|
|
21
25
|
#private;
|
|
26
|
+
private static counter;
|
|
27
|
+
readonly id: string;
|
|
22
28
|
wrapInstance: WrapInstanceFn;
|
|
29
|
+
constructor();
|
|
30
|
+
get _internalState(): InternalState | undefined;
|
|
23
31
|
dispose(): void;
|
|
24
32
|
get<T>(bunja: Bunja<T>, readScope: ReadScope): BunjaStoreGetResult<T>;
|
|
25
33
|
}
|
|
@@ -29,6 +37,7 @@ interface BunjaStoreGetResult<T> {
|
|
|
29
37
|
value: T;
|
|
30
38
|
mount: () => () => void;
|
|
31
39
|
deps: unknown[];
|
|
40
|
+
bunjaInstance?: BunjaInstance;
|
|
32
41
|
}
|
|
33
42
|
declare function delayUnmount(mount: () => () => void, ms?: number): () => () => void;
|
|
34
43
|
declare class Bunja<T> {
|
|
@@ -66,6 +75,16 @@ declare abstract class RefCounter {
|
|
|
66
75
|
add(): void;
|
|
67
76
|
sub(): void;
|
|
68
77
|
}
|
|
78
|
+
declare class BunjaInstance extends RefCounter {
|
|
79
|
+
#private;
|
|
80
|
+
readonly id: string;
|
|
81
|
+
readonly value: unknown;
|
|
82
|
+
readonly effect: BunjaEffectCallback;
|
|
83
|
+
private readonly _dispose;
|
|
84
|
+
constructor(id: string, value: unknown, effect: BunjaEffectCallback, _dispose: () => void);
|
|
85
|
+
dispose(): void;
|
|
86
|
+
add(): void;
|
|
87
|
+
}
|
|
69
88
|
declare class ScopeInstance extends RefCounter {
|
|
70
89
|
readonly value: unknown;
|
|
71
90
|
readonly dispose: () => void;
|
|
@@ -73,5 +92,42 @@ declare class ScopeInstance extends RefCounter {
|
|
|
73
92
|
readonly id: string;
|
|
74
93
|
constructor(value: unknown, dispose: () => void);
|
|
75
94
|
}
|
|
95
|
+
interface BunjaDevtoolsGlobalHook {
|
|
96
|
+
stores: Record<string, BunjaStore>;
|
|
97
|
+
listeners: Record<BunjaDevtoolsEventType, Set<(event: any) => void>>;
|
|
98
|
+
emit<T extends BunjaDevtoolsEventType>(type: T, event: BunjaDevtoolsEvent[T]): void;
|
|
99
|
+
on<T extends BunjaDevtoolsEventType>(type: T, listener: (event: BunjaDevtoolsEvent[T]) => void): () => void;
|
|
100
|
+
}
|
|
101
|
+
interface BunjaDevtoolsEvent {
|
|
102
|
+
storeCreated: {
|
|
103
|
+
storeId: string;
|
|
104
|
+
};
|
|
105
|
+
storeDisposed: {
|
|
106
|
+
storeId: string;
|
|
107
|
+
};
|
|
108
|
+
getCalled: {
|
|
109
|
+
storeId: string;
|
|
110
|
+
bunjaInstanceId: string;
|
|
111
|
+
};
|
|
112
|
+
bunjaInstanceMounted: {
|
|
113
|
+
storeId: string;
|
|
114
|
+
bunjaInstanceId: string;
|
|
115
|
+
};
|
|
116
|
+
bunjaInstanceUnmounted: {
|
|
117
|
+
storeId: string;
|
|
118
|
+
bunjaInstanceId: string;
|
|
119
|
+
};
|
|
120
|
+
scopeInstanceMounted: {
|
|
121
|
+
storeId: string;
|
|
122
|
+
scope: Scope<unknown>;
|
|
123
|
+
key: unknown;
|
|
124
|
+
};
|
|
125
|
+
scopeInstanceUnmounted: {
|
|
126
|
+
storeId: string;
|
|
127
|
+
scope: Scope<unknown>;
|
|
128
|
+
key: unknown;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
type BunjaDevtoolsEventType = keyof BunjaDevtoolsEvent;
|
|
76
132
|
//#endregion
|
|
77
|
-
export { Bunja, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
|
133
|
+
export { Bunja, BunjaDevtoolsEvent, BunjaDevtoolsEventType, BunjaDevtoolsGlobalHook, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
|
@@ -16,10 +16,18 @@ interface CreateBunjaStoreConfig {
|
|
|
16
16
|
}
|
|
17
17
|
declare function createBunjaStore(config?: CreateBunjaStoreConfig): BunjaStore;
|
|
18
18
|
type Dep<T> = Bunja<T> | Scope<T>;
|
|
19
|
+
interface InternalState {
|
|
20
|
+
bunjas: Record<string, BunjaInstance>;
|
|
21
|
+
scopes: Map<Scope<unknown>, Map<unknown, ScopeInstance>>;
|
|
22
|
+
}
|
|
19
23
|
type WrapInstanceFn = <T>(fn: (dispose: () => void) => T) => T;
|
|
20
24
|
declare class BunjaStore {
|
|
21
25
|
#private;
|
|
26
|
+
private static counter;
|
|
27
|
+
readonly id: string;
|
|
22
28
|
wrapInstance: WrapInstanceFn;
|
|
29
|
+
constructor();
|
|
30
|
+
get _internalState(): InternalState | undefined;
|
|
23
31
|
dispose(): void;
|
|
24
32
|
get<T>(bunja: Bunja<T>, readScope: ReadScope): BunjaStoreGetResult<T>;
|
|
25
33
|
}
|
|
@@ -29,6 +37,7 @@ interface BunjaStoreGetResult<T> {
|
|
|
29
37
|
value: T;
|
|
30
38
|
mount: () => () => void;
|
|
31
39
|
deps: unknown[];
|
|
40
|
+
bunjaInstance?: BunjaInstance;
|
|
32
41
|
}
|
|
33
42
|
declare function delayUnmount(mount: () => () => void, ms?: number): () => () => void;
|
|
34
43
|
declare class Bunja<T> {
|
|
@@ -66,6 +75,16 @@ declare abstract class RefCounter {
|
|
|
66
75
|
add(): void;
|
|
67
76
|
sub(): void;
|
|
68
77
|
}
|
|
78
|
+
declare class BunjaInstance extends RefCounter {
|
|
79
|
+
#private;
|
|
80
|
+
readonly id: string;
|
|
81
|
+
readonly value: unknown;
|
|
82
|
+
readonly effect: BunjaEffectCallback;
|
|
83
|
+
private readonly _dispose;
|
|
84
|
+
constructor(id: string, value: unknown, effect: BunjaEffectCallback, _dispose: () => void);
|
|
85
|
+
dispose(): void;
|
|
86
|
+
add(): void;
|
|
87
|
+
}
|
|
69
88
|
declare class ScopeInstance extends RefCounter {
|
|
70
89
|
readonly value: unknown;
|
|
71
90
|
readonly dispose: () => void;
|
|
@@ -73,5 +92,42 @@ declare class ScopeInstance extends RefCounter {
|
|
|
73
92
|
readonly id: string;
|
|
74
93
|
constructor(value: unknown, dispose: () => void);
|
|
75
94
|
}
|
|
95
|
+
interface BunjaDevtoolsGlobalHook {
|
|
96
|
+
stores: Record<string, BunjaStore>;
|
|
97
|
+
listeners: Record<BunjaDevtoolsEventType, Set<(event: any) => void>>;
|
|
98
|
+
emit<T extends BunjaDevtoolsEventType>(type: T, event: BunjaDevtoolsEvent[T]): void;
|
|
99
|
+
on<T extends BunjaDevtoolsEventType>(type: T, listener: (event: BunjaDevtoolsEvent[T]) => void): () => void;
|
|
100
|
+
}
|
|
101
|
+
interface BunjaDevtoolsEvent {
|
|
102
|
+
storeCreated: {
|
|
103
|
+
storeId: string;
|
|
104
|
+
};
|
|
105
|
+
storeDisposed: {
|
|
106
|
+
storeId: string;
|
|
107
|
+
};
|
|
108
|
+
getCalled: {
|
|
109
|
+
storeId: string;
|
|
110
|
+
bunjaInstanceId: string;
|
|
111
|
+
};
|
|
112
|
+
bunjaInstanceMounted: {
|
|
113
|
+
storeId: string;
|
|
114
|
+
bunjaInstanceId: string;
|
|
115
|
+
};
|
|
116
|
+
bunjaInstanceUnmounted: {
|
|
117
|
+
storeId: string;
|
|
118
|
+
bunjaInstanceId: string;
|
|
119
|
+
};
|
|
120
|
+
scopeInstanceMounted: {
|
|
121
|
+
storeId: string;
|
|
122
|
+
scope: Scope<unknown>;
|
|
123
|
+
key: unknown;
|
|
124
|
+
};
|
|
125
|
+
scopeInstanceUnmounted: {
|
|
126
|
+
storeId: string;
|
|
127
|
+
scope: Scope<unknown>;
|
|
128
|
+
key: unknown;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
type BunjaDevtoolsEventType = keyof BunjaDevtoolsEvent;
|
|
76
132
|
//#endregion
|
|
77
|
-
export { Bunja, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
|
133
|
+
export { Bunja, BunjaDevtoolsEvent, BunjaDevtoolsEventType, BunjaDevtoolsGlobalHook, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//#region bunja.ts
|
|
2
|
+
const __DEV__ = process.env.NODE_ENV !== "production";
|
|
2
3
|
const bunja = bunjaFn;
|
|
3
4
|
function bunjaFn(init) {
|
|
4
5
|
return new Bunja(init);
|
|
@@ -25,22 +26,41 @@ function invalidEffect() {
|
|
|
25
26
|
throw new Error("`bunja.effect` can only be used inside a bunja init function.");
|
|
26
27
|
}
|
|
27
28
|
const defaultWrapInstanceFn = (fn) => fn(noop);
|
|
28
|
-
var BunjaStore = class {
|
|
29
|
+
var BunjaStore = class BunjaStore {
|
|
30
|
+
static counter = 0;
|
|
31
|
+
id = String(BunjaStore.counter++);
|
|
29
32
|
#bunjas = {};
|
|
30
33
|
#scopes = /* @__PURE__ */ new Map();
|
|
31
34
|
#bakingContext;
|
|
32
35
|
wrapInstance = defaultWrapInstanceFn;
|
|
36
|
+
constructor() {
|
|
37
|
+
if (__DEV__) {
|
|
38
|
+
devtoolsGlobalHook.stores[this.id] = this;
|
|
39
|
+
devtoolsGlobalHook.emit("storeCreated", { storeId: this.id });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
get _internalState() {
|
|
43
|
+
if (__DEV__) return {
|
|
44
|
+
bunjas: this.#bunjas,
|
|
45
|
+
scopes: this.#scopes
|
|
46
|
+
};
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
33
49
|
dispose() {
|
|
34
50
|
for (const instance of Object.values(this.#bunjas)) instance.dispose();
|
|
35
51
|
for (const instanceMap of Object.values(this.#scopes)) for (const instance of instanceMap.values()) instance.dispose();
|
|
36
52
|
this.#bunjas = {};
|
|
37
53
|
this.#scopes = /* @__PURE__ */ new Map();
|
|
54
|
+
if (__DEV__) {
|
|
55
|
+
devtoolsGlobalHook.emit("storeDisposed", { storeId: this.id });
|
|
56
|
+
delete devtoolsGlobalHook.stores[this.id];
|
|
57
|
+
}
|
|
38
58
|
}
|
|
39
59
|
get(bunja$1, readScope) {
|
|
40
60
|
const originalUse = bunjaFn.use;
|
|
41
61
|
try {
|
|
42
62
|
const { bunjaInstance, bunjaInstanceMap, scopeInstanceMap } = bunja$1.baked ? this.#getBaked(bunja$1, readScope) : this.#getUnbaked(bunja$1, readScope);
|
|
43
|
-
|
|
63
|
+
const result = {
|
|
44
64
|
value: bunjaInstance.value,
|
|
45
65
|
mount: () => {
|
|
46
66
|
bunjaInstanceMap.forEach((instance) => instance.add());
|
|
@@ -55,6 +75,14 @@ var BunjaStore = class {
|
|
|
55
75
|
},
|
|
56
76
|
deps: Array.from(scopeInstanceMap.values()).map(({ value }) => value)
|
|
57
77
|
};
|
|
78
|
+
if (__DEV__) {
|
|
79
|
+
result.bunjaInstance = bunjaInstance;
|
|
80
|
+
devtoolsGlobalHook.emit("getCalled", {
|
|
81
|
+
storeId: this.id,
|
|
82
|
+
bunjaInstanceId: bunjaInstance.id
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
58
86
|
} finally {
|
|
59
87
|
bunjaFn.use = originalUse;
|
|
60
88
|
}
|
|
@@ -149,7 +177,14 @@ var BunjaStore = class {
|
|
|
149
177
|
#getScopeInstance(scope, value) {
|
|
150
178
|
const key = scope.hash(value);
|
|
151
179
|
const instanceMap = this.#scopes.get(scope) ?? this.#scopes.set(scope, /* @__PURE__ */ new Map()).get(scope);
|
|
152
|
-
return instanceMap.get(key) ?? instanceMap.set(key,
|
|
180
|
+
return instanceMap.get(key) ?? instanceMap.set(key, this.#createScopeInstance(scope, key, value, () => {
|
|
181
|
+
instanceMap.delete(key);
|
|
182
|
+
if (__DEV__) devtoolsGlobalHook.emit("scopeInstanceUnmounted", {
|
|
183
|
+
storeId: this.id,
|
|
184
|
+
scope,
|
|
185
|
+
key
|
|
186
|
+
});
|
|
187
|
+
})).get(key);
|
|
153
188
|
}
|
|
154
189
|
#createBunjaInstance(id, value, effects, dispose) {
|
|
155
190
|
const effect = () => {
|
|
@@ -157,12 +192,28 @@ var BunjaStore = class {
|
|
|
157
192
|
return () => cleanups.forEach((cleanup) => cleanup());
|
|
158
193
|
};
|
|
159
194
|
const bunjaInstance = new BunjaInstance(id, value, effect, () => {
|
|
195
|
+
if (__DEV__) devtoolsGlobalHook.emit("bunjaInstanceUnmounted", {
|
|
196
|
+
storeId: this.id,
|
|
197
|
+
bunjaInstanceId: id
|
|
198
|
+
});
|
|
160
199
|
dispose();
|
|
161
200
|
delete this.#bunjas[id];
|
|
162
201
|
});
|
|
163
202
|
this.#bunjas[id] = bunjaInstance;
|
|
203
|
+
if (__DEV__) devtoolsGlobalHook.emit("bunjaInstanceMounted", {
|
|
204
|
+
storeId: this.id,
|
|
205
|
+
bunjaInstanceId: id
|
|
206
|
+
});
|
|
164
207
|
return bunjaInstance;
|
|
165
208
|
}
|
|
209
|
+
#createScopeInstance(scope, key, value, dispose) {
|
|
210
|
+
if (__DEV__) devtoolsGlobalHook.emit("scopeInstanceMounted", {
|
|
211
|
+
storeId: this.id,
|
|
212
|
+
scope,
|
|
213
|
+
key
|
|
214
|
+
});
|
|
215
|
+
return new ScopeInstance(value, dispose);
|
|
216
|
+
}
|
|
166
217
|
};
|
|
167
218
|
function createReadScopeFn(scopeValuePairs, readScope) {
|
|
168
219
|
const map = new Map(scopeValuePairs);
|
|
@@ -305,6 +356,30 @@ function toposort(nodes) {
|
|
|
305
356
|
return result;
|
|
306
357
|
}
|
|
307
358
|
const noop = () => {};
|
|
359
|
+
let devtoolsGlobalHook;
|
|
360
|
+
if (__DEV__) if (globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__) devtoolsGlobalHook = globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__;
|
|
361
|
+
else {
|
|
362
|
+
devtoolsGlobalHook = {
|
|
363
|
+
stores: {},
|
|
364
|
+
listeners: {
|
|
365
|
+
storeCreated: /* @__PURE__ */ new Set(),
|
|
366
|
+
storeDisposed: /* @__PURE__ */ new Set(),
|
|
367
|
+
getCalled: /* @__PURE__ */ new Set(),
|
|
368
|
+
bunjaInstanceMounted: /* @__PURE__ */ new Set(),
|
|
369
|
+
bunjaInstanceUnmounted: /* @__PURE__ */ new Set(),
|
|
370
|
+
scopeInstanceMounted: /* @__PURE__ */ new Set(),
|
|
371
|
+
scopeInstanceUnmounted: /* @__PURE__ */ new Set()
|
|
372
|
+
},
|
|
373
|
+
emit: (type, event) => {
|
|
374
|
+
for (const fn of devtoolsGlobalHook.listeners[type]) fn(event);
|
|
375
|
+
},
|
|
376
|
+
on: (type, listener) => {
|
|
377
|
+
devtoolsGlobalHook.listeners[type].add(listener);
|
|
378
|
+
return () => devtoolsGlobalHook.listeners[type].delete(listener);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__ = devtoolsGlobalHook;
|
|
382
|
+
}
|
|
308
383
|
|
|
309
384
|
//#endregion
|
|
310
385
|
export { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
package/dist/bunja.cjs
CHANGED
package/dist/bunja.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Bunja, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-
|
|
2
|
-
export { Bunja, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
|
1
|
+
import { Bunja, BunjaDevtoolsEvent, BunjaDevtoolsEventType, BunjaDevtoolsGlobalHook, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-DXtbhAmJ.cjs";
|
|
2
|
+
export { Bunja, BunjaDevtoolsEvent, BunjaDevtoolsEventType, BunjaDevtoolsGlobalHook, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
package/dist/bunja.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Bunja, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-
|
|
2
|
-
export { Bunja, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
|
1
|
+
import { Bunja, BunjaDevtoolsEvent, BunjaDevtoolsEventType, BunjaDevtoolsGlobalHook, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-D_SKFBCD.js";
|
|
2
|
+
export { Bunja, BunjaDevtoolsEvent, BunjaDevtoolsEventType, BunjaDevtoolsGlobalHook, BunjaEffectCallback, BunjaEffectFn, BunjaFn, BunjaForkFn, BunjaStore, BunjaStoreGetResult, BunjaUseFn, CreateBunjaStoreConfig, Dep, HashFn, ReadScope, Scope, ScopeValuePair, WrapInstanceFn, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
package/dist/bunja.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-
|
|
1
|
+
import { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-DxIUFo_M.js";
|
|
2
2
|
|
|
3
3
|
export { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|
package/dist/react.cjs
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
5
|
-
const require_bunja = require('./bunja-
|
|
5
|
+
const require_bunja = require('./bunja-DO4Cr7x-.cjs');
|
|
6
6
|
const react = require_chunk.__toESM(require("react"));
|
|
7
7
|
|
|
8
8
|
//#region react.ts
|
|
9
|
+
const __DEV__ = process.env.NODE_ENV !== "production";
|
|
9
10
|
const BunjaStoreContext = (0, react.createContext)(require_bunja.createBunjaStore());
|
|
10
11
|
function BunjaStoreProvider({ children }) {
|
|
11
12
|
const [value] = (0, react.useState)(require_bunja.createBunjaStore);
|
|
@@ -30,19 +31,25 @@ const defaultReadScope = (scope) => {
|
|
|
30
31
|
};
|
|
31
32
|
function useBunja(bunja, scopeValuePairs) {
|
|
32
33
|
const store = (0, react.use)(BunjaStoreContext);
|
|
33
|
-
const readScope = scopeValuePairs ? require_bunja.createReadScopeFn(scopeValuePairs,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
const readScope = scopeValuePairs ? require_bunja.createReadScopeFn(scopeValuePairs, defaultReadScope) : defaultReadScope;
|
|
35
|
+
if (__DEV__) {
|
|
36
|
+
const { value, mount, deps, bunjaInstance } = store.get(bunja, readScope);
|
|
37
|
+
(0, react.useEffect)(require_bunja.delayUnmount(mount), deps);
|
|
38
|
+
(0, react.useMemo)(() => ({
|
|
39
|
+
bunja,
|
|
40
|
+
scopeValuePairs,
|
|
41
|
+
bunjaInstance
|
|
42
|
+
}), [
|
|
43
|
+
bunja,
|
|
44
|
+
scopeValuePairs,
|
|
45
|
+
bunjaInstance
|
|
46
|
+
]);
|
|
47
|
+
return value;
|
|
48
|
+
} else {
|
|
49
|
+
const { value, mount, deps } = store.get(bunja, readScope);
|
|
50
|
+
(0, react.useEffect)(require_bunja.delayUnmount(mount), deps);
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
//#endregion
|
|
@@ -50,6 +57,5 @@ exports.BunjaStoreContext = BunjaStoreContext;
|
|
|
50
57
|
exports.BunjaStoreProvider = BunjaStoreProvider;
|
|
51
58
|
exports.bindScope = bindScope;
|
|
52
59
|
exports.createScopeFromContext = createScopeFromContext;
|
|
53
|
-
exports.inject = inject;
|
|
54
60
|
exports.scopeContextMap = scopeContextMap;
|
|
55
61
|
exports.useBunja = useBunja;
|
package/dist/react.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bunja, BunjaStore, HashFn, Scope, ScopeValuePair } from "./bunja-
|
|
1
|
+
import { Bunja, BunjaStore, HashFn, Scope, ScopeValuePair } from "./bunja-DXtbhAmJ.cjs";
|
|
2
2
|
import { Context, PropsWithChildren } from "react";
|
|
3
3
|
|
|
4
4
|
//#region react.d.ts
|
|
@@ -10,9 +10,5 @@ declare const scopeContextMap: Map<Scope<unknown>, Context<unknown>>;
|
|
|
10
10
|
declare function bindScope<T>(scope: Scope<T>, context: Context<T>): void;
|
|
11
11
|
declare function createScopeFromContext<T>(context: Context<T>, hash?: HashFn<T>): Scope<T>;
|
|
12
12
|
declare function useBunja<T>(bunja: Bunja<T>, scopeValuePairs?: ScopeValuePair<any>[]): T;
|
|
13
|
-
/**
|
|
14
|
-
* @deprecated use `scopeValuePairs` parameter directly in `useBunja` instead.
|
|
15
|
-
*/
|
|
16
|
-
declare function inject(scopeValuePairs: ScopeValuePair<any>[]): ScopeValuePair<any>[];
|
|
17
13
|
//#endregion
|
|
18
|
-
export { BunjaStoreContext, BunjaStoreProvider, bindScope, createScopeFromContext,
|
|
14
|
+
export { BunjaStoreContext, BunjaStoreProvider, bindScope, createScopeFromContext, scopeContextMap, useBunja };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bunja, BunjaStore, HashFn, Scope, ScopeValuePair } from "./bunja-
|
|
1
|
+
import { Bunja, BunjaStore, HashFn, Scope, ScopeValuePair } from "./bunja-D_SKFBCD.js";
|
|
2
2
|
import { Context, PropsWithChildren } from "react";
|
|
3
3
|
|
|
4
4
|
//#region react.d.ts
|
|
@@ -10,9 +10,5 @@ declare const scopeContextMap: Map<Scope<unknown>, Context<unknown>>;
|
|
|
10
10
|
declare function bindScope<T>(scope: Scope<T>, context: Context<T>): void;
|
|
11
11
|
declare function createScopeFromContext<T>(context: Context<T>, hash?: HashFn<T>): Scope<T>;
|
|
12
12
|
declare function useBunja<T>(bunja: Bunja<T>, scopeValuePairs?: ScopeValuePair<any>[]): T;
|
|
13
|
-
/**
|
|
14
|
-
* @deprecated use `scopeValuePairs` parameter directly in `useBunja` instead.
|
|
15
|
-
*/
|
|
16
|
-
declare function inject(scopeValuePairs: ScopeValuePair<any>[]): ScopeValuePair<any>[];
|
|
17
13
|
//#endregion
|
|
18
|
-
export { BunjaStoreContext, BunjaStoreProvider, bindScope, createScopeFromContext,
|
|
14
|
+
export { BunjaStoreContext, BunjaStoreProvider, bindScope, createScopeFromContext, scopeContextMap, useBunja };
|
package/dist/react.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
import { createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-
|
|
5
|
-
import { createContext, createElement, use, useEffect, useState } from "react";
|
|
4
|
+
import { createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-DxIUFo_M.js";
|
|
5
|
+
import { createContext, createElement, use, useEffect, useMemo, useState } from "react";
|
|
6
6
|
|
|
7
7
|
//#region react.ts
|
|
8
|
+
const __DEV__ = process.env.NODE_ENV !== "production";
|
|
8
9
|
const BunjaStoreContext = createContext(createBunjaStore());
|
|
9
10
|
function BunjaStoreProvider({ children }) {
|
|
10
11
|
const [value] = useState(createBunjaStore);
|
|
@@ -29,20 +30,26 @@ const defaultReadScope = (scope) => {
|
|
|
29
30
|
};
|
|
30
31
|
function useBunja(bunja, scopeValuePairs) {
|
|
31
32
|
const store = use(BunjaStoreContext);
|
|
32
|
-
const readScope = scopeValuePairs ? createReadScopeFn(scopeValuePairs,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
const readScope = scopeValuePairs ? createReadScopeFn(scopeValuePairs, defaultReadScope) : defaultReadScope;
|
|
34
|
+
if (__DEV__) {
|
|
35
|
+
const { value, mount, deps, bunjaInstance } = store.get(bunja, readScope);
|
|
36
|
+
useEffect(delayUnmount(mount), deps);
|
|
37
|
+
useMemo(() => ({
|
|
38
|
+
bunja,
|
|
39
|
+
scopeValuePairs,
|
|
40
|
+
bunjaInstance
|
|
41
|
+
}), [
|
|
42
|
+
bunja,
|
|
43
|
+
scopeValuePairs,
|
|
44
|
+
bunjaInstance
|
|
45
|
+
]);
|
|
46
|
+
return value;
|
|
47
|
+
} else {
|
|
48
|
+
const { value, mount, deps } = store.get(bunja, readScope);
|
|
49
|
+
useEffect(delayUnmount(mount), deps);
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
//#endregion
|
|
48
|
-
export { BunjaStoreContext, BunjaStoreProvider, bindScope, createScopeFromContext,
|
|
55
|
+
export { BunjaStoreContext, BunjaStoreProvider, bindScope, createScopeFromContext, scopeContextMap, useBunja };
|
package/dist/solid.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
-
const require_bunja = require('./bunja-
|
|
2
|
+
const require_bunja = require('./bunja-DO4Cr7x-.cjs');
|
|
3
3
|
const solid_js = require_chunk.__toESM(require("solid-js"));
|
|
4
4
|
|
|
5
5
|
//#region solid.ts
|
|
@@ -36,10 +36,7 @@ const defaultReadScope = (scope) => {
|
|
|
36
36
|
};
|
|
37
37
|
function useBunja(bunja, scopeValuePairs) {
|
|
38
38
|
const store = (0, solid_js.useContext)(BunjaStoreContext);
|
|
39
|
-
const readScope = scopeValuePairs ? require_bunja.createReadScopeFn(scopeValuePairs,
|
|
40
|
-
const context = scopeContextMap.get(scope);
|
|
41
|
-
return access((0, solid_js.useContext)(context));
|
|
42
|
-
}) : defaultReadScope;
|
|
39
|
+
const readScope = scopeValuePairs ? require_bunja.createReadScopeFn(scopeValuePairs, defaultReadScope) : defaultReadScope;
|
|
43
40
|
const entry = (0, solid_js.createMemo)(() => store.get(access(bunja), readScope));
|
|
44
41
|
(0, solid_js.createEffect)(() => {
|
|
45
42
|
const cleanup = entry().mount();
|
package/dist/solid.d.cts
CHANGED
package/dist/solid.d.ts
CHANGED
package/dist/solid.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createBunjaStore, createReadScopeFn, createScope } from "./bunja-
|
|
1
|
+
import { createBunjaStore, createReadScopeFn, createScope } from "./bunja-DxIUFo_M.js";
|
|
2
2
|
import { createComponent, createContext, createEffect, createMemo, createRoot, getOwner, onCleanup, useContext } from "solid-js";
|
|
3
3
|
|
|
4
4
|
//#region solid.ts
|
|
@@ -35,10 +35,7 @@ const defaultReadScope = (scope) => {
|
|
|
35
35
|
};
|
|
36
36
|
function useBunja(bunja, scopeValuePairs) {
|
|
37
37
|
const store = useContext(BunjaStoreContext);
|
|
38
|
-
const readScope = scopeValuePairs ? createReadScopeFn(scopeValuePairs,
|
|
39
|
-
const context = scopeContextMap.get(scope);
|
|
40
|
-
return access(useContext(context));
|
|
41
|
-
}) : defaultReadScope;
|
|
38
|
+
const readScope = scopeValuePairs ? createReadScopeFn(scopeValuePairs, defaultReadScope) : defaultReadScope;
|
|
42
39
|
const entry = createMemo(() => store.get(access(bunja), readScope));
|
|
43
40
|
createEffect(() => {
|
|
44
41
|
const cleanup = entry().mount();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunja",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-alpha.
|
|
4
|
+
"version": "2.0.0-alpha.9",
|
|
5
5
|
"description": "State Lifetime Manager",
|
|
6
6
|
"main": "dist/bunja.cjs",
|
|
7
7
|
"module": "dist/bunja.js",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
|
+
"clean": "rm -rf ./dist",
|
|
55
56
|
"build": "tsdown"
|
|
56
57
|
},
|
|
57
58
|
"keywords": [
|
package/react.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type PropsWithChildren,
|
|
8
8
|
use,
|
|
9
9
|
useEffect,
|
|
10
|
+
useMemo,
|
|
10
11
|
useState,
|
|
11
12
|
} from "react";
|
|
12
13
|
import {
|
|
@@ -22,6 +23,10 @@ import {
|
|
|
22
23
|
type ScopeValuePair,
|
|
23
24
|
} from "./bunja.ts";
|
|
24
25
|
|
|
26
|
+
// @ts-ignore dev
|
|
27
|
+
// deno-lint-ignore no-process-global
|
|
28
|
+
const __DEV__ = process.env.NODE_ENV !== "production";
|
|
29
|
+
|
|
25
30
|
export const BunjaStoreContext: Context<BunjaStore> = createContext(
|
|
26
31
|
createBunjaStore(),
|
|
27
32
|
);
|
|
@@ -59,21 +64,19 @@ export function useBunja<T>(
|
|
|
59
64
|
): T {
|
|
60
65
|
const store = use(BunjaStoreContext);
|
|
61
66
|
const readScope = scopeValuePairs
|
|
62
|
-
? createReadScopeFn(scopeValuePairs,
|
|
63
|
-
const context = scopeContextMap.get(scope as Scope<unknown>)!;
|
|
64
|
-
return use(context) as T;
|
|
65
|
-
})
|
|
67
|
+
? createReadScopeFn(scopeValuePairs, defaultReadScope)
|
|
66
68
|
: defaultReadScope;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
|
|
69
|
+
if (__DEV__) {
|
|
70
|
+
const { value, mount, deps, bunjaInstance } = store.get(bunja, readScope);
|
|
71
|
+
useEffect(delayUnmount(mount), deps);
|
|
72
|
+
useMemo(
|
|
73
|
+
() => ({ bunja, scopeValuePairs, bunjaInstance }),
|
|
74
|
+
[bunja, scopeValuePairs, bunjaInstance],
|
|
75
|
+
);
|
|
76
|
+
return value;
|
|
77
|
+
} else {
|
|
78
|
+
const { value, mount, deps } = store.get(bunja, readScope);
|
|
79
|
+
useEffect(delayUnmount(mount), deps);
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
79
82
|
}
|
package/solid.ts
CHANGED
|
@@ -87,10 +87,7 @@ export function useBunja<T>(
|
|
|
87
87
|
): Accessor<T> {
|
|
88
88
|
const store = useContext(BunjaStoreContext);
|
|
89
89
|
const readScope = scopeValuePairs
|
|
90
|
-
? createReadScopeFn(scopeValuePairs,
|
|
91
|
-
const context = scopeContextMap.get(scope as Scope<unknown>)!;
|
|
92
|
-
return access(useContext(context)) as T;
|
|
93
|
-
})
|
|
90
|
+
? createReadScopeFn(scopeValuePairs, defaultReadScope)
|
|
94
91
|
: defaultReadScope;
|
|
95
92
|
const entry = createMemo(() => store.get(access(bunja), readScope));
|
|
96
93
|
createEffect(() => {
|