@virtuoso.dev/reactive-engine-react 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +70 -16
- package/dist/index.js +131 -76
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -56,8 +56,16 @@ export declare interface EngineProviderProps {
|
|
|
56
56
|
children: React_2.ReactNode;
|
|
57
57
|
/**
|
|
58
58
|
* Optional stable ID for storage namespacing. Use this for multi-engine apps to prevent storage key conflicts.
|
|
59
|
+
* Also registers the engine in the global registry for access via `useRemote*` hooks with a string ID.
|
|
59
60
|
*/
|
|
60
61
|
engineId?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Optional reactive ref to expose the engine instance. Created by {@link useEngineRef}.
|
|
64
|
+
* Pass to `useRemote*` hooks to access the engine from sibling or ancestor components.
|
|
65
|
+
*
|
|
66
|
+
* @remarks An `EngineRef` should only be used with a single `EngineProvider`.
|
|
67
|
+
*/
|
|
68
|
+
engineRef?: EngineRef;
|
|
61
69
|
/**
|
|
62
70
|
* A callback invoked once when the engine is created. Use this to register nodes and set up subscriptions.
|
|
63
71
|
*/
|
|
@@ -76,6 +84,29 @@ export declare interface EngineProviderProps {
|
|
|
76
84
|
updateFn?: (engine: Engine) => void;
|
|
77
85
|
}
|
|
78
86
|
|
|
87
|
+
/**
|
|
88
|
+
* A reactive ref that holds an engine instance. Created by {@link useEngineRef}.
|
|
89
|
+
* Pass it to {@link EngineProvider} via the `engineRef` prop, then use it with
|
|
90
|
+
* the `useRemote*` hooks to access the engine from anywhere in the component tree.
|
|
91
|
+
*
|
|
92
|
+
* @remarks An `EngineRef` should only be used with a single `EngineProvider`.
|
|
93
|
+
* Using the same ref with multiple providers is unsupported.
|
|
94
|
+
*
|
|
95
|
+
* @category React Hooks and Components
|
|
96
|
+
*/
|
|
97
|
+
export declare interface EngineRef {
|
|
98
|
+
/** The current engine instance, or null if not yet available. */
|
|
99
|
+
readonly current: Engine | null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Union type for the engine source parameter accepted by `useRemote*` hooks.
|
|
104
|
+
* Can be either a string engine ID (for global registry lookup) or an {@link EngineRef}.
|
|
105
|
+
*
|
|
106
|
+
* @category React Hooks and Components
|
|
107
|
+
*/
|
|
108
|
+
export declare type EngineSource = EngineRef | string;
|
|
109
|
+
|
|
79
110
|
/**
|
|
80
111
|
* Options for the {@link useRemoteCellValues} hook.
|
|
81
112
|
* @category React Hooks and Components
|
|
@@ -84,7 +115,7 @@ export declare interface RemoteCellValuesOptions<T extends unknown[]> {
|
|
|
84
115
|
cells: {
|
|
85
116
|
[K in keyof T]: Out<T[K]>;
|
|
86
117
|
};
|
|
87
|
-
|
|
118
|
+
engineSource: EngineSource;
|
|
88
119
|
}
|
|
89
120
|
|
|
90
121
|
/**
|
|
@@ -198,6 +229,29 @@ declare function useCellValueWithStore<T>(cell: Out<T>): T;
|
|
|
198
229
|
*/
|
|
199
230
|
export declare function useEngine(): Engine;
|
|
200
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Creates a stable, memoized {@link EngineRef} for use inside a component.
|
|
234
|
+
* Pass the returned ref to an {@link EngineProvider} via the `engineRef` prop,
|
|
235
|
+
* and to `useRemote*` hooks to access the engine reactively.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```tsx
|
|
239
|
+
* function App() {
|
|
240
|
+
* const engineRef = useEngineRef()
|
|
241
|
+
* return (
|
|
242
|
+
* <>
|
|
243
|
+
* <SiblingComponent engineRef={engineRef} />
|
|
244
|
+
* <EngineProvider engineRef={engineRef} initFn={initFn}>
|
|
245
|
+
* <NestedComponent />
|
|
246
|
+
* </EngineProvider>
|
|
247
|
+
* </>
|
|
248
|
+
* )
|
|
249
|
+
* }
|
|
250
|
+
* ```
|
|
251
|
+
* @category React Hooks and Components
|
|
252
|
+
*/
|
|
253
|
+
export declare function useEngineRef(): EngineRef;
|
|
254
|
+
|
|
201
255
|
export declare const useIsomorphicLayoutEffect: typeof React_2.useLayoutEffect;
|
|
202
256
|
|
|
203
257
|
/**
|
|
@@ -225,11 +279,11 @@ export declare const useIsomorphicLayoutEffect: typeof React_2.useLayoutEffect;
|
|
|
225
279
|
export declare function usePublisher<T>(node$: Inp<T>): (value: T) => void;
|
|
226
280
|
|
|
227
281
|
/**
|
|
228
|
-
* Returns a tuple of the current value and a publisher function for a cell in an engine identified by `
|
|
282
|
+
* Returns a tuple of the current value and a publisher function for a cell in an engine identified by `engineSource`.
|
|
229
283
|
* Returns `[undefined, noop]` when the engine is not available yet.
|
|
230
284
|
*
|
|
231
285
|
* @param cell - The cell to use.
|
|
232
|
-
* @param
|
|
286
|
+
* @param engineSource - A string engine ID or an {@link EngineRef}.
|
|
233
287
|
* @returns A tuple of the current value (or undefined) and a publisher function.
|
|
234
288
|
* @typeParam T - The type of values that the cell emits/accepts.
|
|
235
289
|
*
|
|
@@ -237,22 +291,22 @@ export declare function usePublisher<T>(node$: Inp<T>): (value: T) => void;
|
|
|
237
291
|
* ```tsx
|
|
238
292
|
* const cell$ = Cell(0)
|
|
239
293
|
* // ...
|
|
240
|
-
* function SiblingComponent() {
|
|
241
|
-
* const [value, setValue] = useRemoteCell(cell$,
|
|
294
|
+
* function SiblingComponent({ engineRef }: { engineRef: EngineRef }) {
|
|
295
|
+
* const [value, setValue] = useRemoteCell(cell$, engineRef)
|
|
242
296
|
* if (value === undefined) return <div>Loading...</div>
|
|
243
297
|
* return <button onClick={() => setValue(value + 1)}>{value}</button>
|
|
244
298
|
* }
|
|
245
299
|
* ```
|
|
246
300
|
* @category React Hooks and Components
|
|
247
301
|
*/
|
|
248
|
-
export declare function useRemoteCell<T>(cell: NodeRef<T>,
|
|
302
|
+
export declare function useRemoteCell<T>(cell: NodeRef<T>, engineSource: EngineSource): [T | undefined, (value: T) => void];
|
|
249
303
|
|
|
250
304
|
/**
|
|
251
|
-
* Gets the current value of the cell from an engine identified by `
|
|
305
|
+
* Gets the current value of the cell from an engine identified by `engineSource`.
|
|
252
306
|
* Returns `undefined` when the engine is not available yet.
|
|
253
307
|
*
|
|
254
308
|
* @param cell - The cell to read from.
|
|
255
|
-
* @param
|
|
309
|
+
* @param engineSource - A string engine ID or an {@link EngineRef} to read from.
|
|
256
310
|
* @returns The current value of the cell, or `undefined` if the engine is not available.
|
|
257
311
|
* @typeParam T - The type of the value that the cell carries.
|
|
258
312
|
*
|
|
@@ -260,15 +314,15 @@ export declare function useRemoteCell<T>(cell: NodeRef<T>, engineId: string): [T
|
|
|
260
314
|
* ```tsx
|
|
261
315
|
* const cell$ = Cell(0)
|
|
262
316
|
* // ...
|
|
263
|
-
* function SiblingComponent() {
|
|
264
|
-
* const value = useRemoteCellValue(cell$,
|
|
317
|
+
* function SiblingComponent({ engineRef }: { engineRef: EngineRef }) {
|
|
318
|
+
* const value = useRemoteCellValue(cell$, engineRef)
|
|
265
319
|
* if (value === undefined) return <div>Loading...</div>
|
|
266
320
|
* return <div>{value}</div>
|
|
267
321
|
* }
|
|
268
322
|
* ```
|
|
269
323
|
* @category React Hooks and Components
|
|
270
324
|
*/
|
|
271
|
-
export declare function useRemoteCellValue<T>(cell: Out<T>,
|
|
325
|
+
export declare function useRemoteCellValue<T>(cell: Out<T>, engineSource: EngineSource): T | undefined;
|
|
272
326
|
|
|
273
327
|
/**
|
|
274
328
|
* Returns the up-to-date values of the passed cells from an engine identified by `engineId`.
|
|
@@ -334,11 +388,11 @@ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6, T7, T8, T9,
|
|
|
334
388
|
export declare function useRemoteCellValues(options: RemoteCellValuesOptions<unknown[]>): undefined | unknown[];
|
|
335
389
|
|
|
336
390
|
/**
|
|
337
|
-
* Returns a function that publishes values to a node in an engine identified by `
|
|
391
|
+
* Returns a function that publishes values to a node in an engine identified by `engineSource`.
|
|
338
392
|
* Returns a no-op function when the engine is not available yet.
|
|
339
393
|
*
|
|
340
394
|
* @param node$ - The node to publish to.
|
|
341
|
-
* @param
|
|
395
|
+
* @param engineSource - A string engine ID or an {@link EngineRef} to publish to.
|
|
342
396
|
* @returns A publisher function that accepts values of type T.
|
|
343
397
|
* @typeParam T - The type of values that the node accepts.
|
|
344
398
|
*
|
|
@@ -346,13 +400,13 @@ export declare function useRemoteCellValues(options: RemoteCellValuesOptions<unk
|
|
|
346
400
|
* ```tsx
|
|
347
401
|
* const trigger$ = Trigger()
|
|
348
402
|
* // ...
|
|
349
|
-
* function SiblingComponent() {
|
|
350
|
-
* const publish = useRemotePublisher(trigger$,
|
|
403
|
+
* function SiblingComponent({ engineRef }: { engineRef: EngineRef }) {
|
|
404
|
+
* const publish = useRemotePublisher(trigger$, engineRef)
|
|
351
405
|
* return <button onClick={() => publish()}>Trigger</button>
|
|
352
406
|
* }
|
|
353
407
|
* ```
|
|
354
408
|
* @category React Hooks and Components
|
|
355
409
|
*/
|
|
356
|
-
export declare function useRemotePublisher<T>(node$: Inp<T>,
|
|
410
|
+
export declare function useRemotePublisher<T>(node$: Inp<T>, engineSource: EngineSource): (value: T) => void;
|
|
357
411
|
|
|
358
412
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,55 +1,84 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { Engine as
|
|
1
|
+
import { jsx as p } from "react/jsx-runtime";
|
|
2
|
+
import { Engine as d } from "@virtuoso.dev/reactive-engine-core";
|
|
3
3
|
import * as s from "react";
|
|
4
|
-
import
|
|
5
|
-
const
|
|
6
|
-
function
|
|
7
|
-
let
|
|
8
|
-
|
|
4
|
+
import h from "tiny-invariant";
|
|
5
|
+
const c = typeof document < "u" ? s.useLayoutEffect : s.useEffect, y = Symbol("engineRefInternal");
|
|
6
|
+
function x() {
|
|
7
|
+
let e = null;
|
|
8
|
+
const n = /* @__PURE__ */ new Set();
|
|
9
|
+
return {
|
|
10
|
+
get current() {
|
|
11
|
+
return e;
|
|
12
|
+
},
|
|
13
|
+
[y]: {
|
|
14
|
+
set(r) {
|
|
15
|
+
e = r, n.forEach((u) => {
|
|
16
|
+
u();
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
subscribe(r) {
|
|
20
|
+
return n.add(r), () => {
|
|
21
|
+
n.delete(r);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function j() {
|
|
28
|
+
const [e] = s.useState(() => x());
|
|
29
|
+
return e;
|
|
9
30
|
}
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
t.engine = n, t.subscribers.forEach((u) => {
|
|
13
|
-
u();
|
|
14
|
-
}), t.subscribers.size === 0 && n === null && l.delete(e);
|
|
31
|
+
function E(e) {
|
|
32
|
+
return e[y];
|
|
15
33
|
}
|
|
16
|
-
|
|
17
|
-
|
|
34
|
+
const f = /* @__PURE__ */ new Map();
|
|
35
|
+
function S(e) {
|
|
36
|
+
let n = f.get(e);
|
|
37
|
+
return n || (n = { engine: null, subscribers: /* @__PURE__ */ new Set() }, f.set(e, n)), n;
|
|
38
|
+
}
|
|
39
|
+
function R(e, n) {
|
|
40
|
+
const t = S(e);
|
|
41
|
+
t.engine = n, t.subscribers.forEach((r) => {
|
|
42
|
+
r();
|
|
43
|
+
}), t.subscribers.size === 0 && n === null && f.delete(e);
|
|
44
|
+
}
|
|
45
|
+
function I(e, n) {
|
|
46
|
+
const t = S(e);
|
|
18
47
|
return t.subscribers.add(n), () => {
|
|
19
|
-
t.subscribers.delete(n), t.subscribers.size === 0 && t.engine === null &&
|
|
48
|
+
t.subscribers.delete(n), t.subscribers.size === 0 && t.engine === null && f.delete(e);
|
|
20
49
|
};
|
|
21
50
|
}
|
|
22
|
-
function
|
|
51
|
+
function m(e) {
|
|
23
52
|
var n;
|
|
24
|
-
return ((n =
|
|
53
|
+
return ((n = f.get(e)) == null ? void 0 : n.engine) ?? null;
|
|
25
54
|
}
|
|
26
|
-
const
|
|
55
|
+
const V = s.createContext(null);
|
|
27
56
|
function a() {
|
|
28
|
-
const e = s.useContext(
|
|
29
|
-
return
|
|
57
|
+
const e = s.useContext(V);
|
|
58
|
+
return h(e !== null, "useEngine must be used within an EngineProvider"), e;
|
|
30
59
|
}
|
|
31
|
-
function
|
|
60
|
+
function w(e) {
|
|
32
61
|
const n = a();
|
|
33
62
|
n.register(e);
|
|
34
|
-
const t = s.useCallback((
|
|
63
|
+
const t = s.useCallback((r) => n.sub(e, r), [n, e]);
|
|
35
64
|
return s.useSyncExternalStore(
|
|
36
65
|
t,
|
|
37
66
|
() => n.getValue(e),
|
|
38
67
|
() => n.getValue(e)
|
|
39
68
|
);
|
|
40
69
|
}
|
|
41
|
-
function
|
|
70
|
+
function P(e) {
|
|
42
71
|
const n = a();
|
|
43
72
|
n.register(e);
|
|
44
|
-
const [t,
|
|
45
|
-
return
|
|
73
|
+
const [t, r] = s.useState(() => n.getValue(e));
|
|
74
|
+
return c(() => n.sub(e, r), [n, e]), t;
|
|
46
75
|
}
|
|
47
|
-
const
|
|
48
|
-
function
|
|
76
|
+
const v = "useSyncExternalStore" in s ? w : P;
|
|
77
|
+
function k(...e) {
|
|
49
78
|
const n = a(), t = s.useMemo(() => n.combineCells(e), [n, ...e]);
|
|
50
|
-
return
|
|
79
|
+
return v(t);
|
|
51
80
|
}
|
|
52
|
-
function
|
|
81
|
+
function N(e) {
|
|
53
82
|
const n = a();
|
|
54
83
|
return n.register(e), s.useCallback(
|
|
55
84
|
(t) => {
|
|
@@ -58,73 +87,99 @@ function P(e) {
|
|
|
58
87
|
[n, e]
|
|
59
88
|
);
|
|
60
89
|
}
|
|
61
|
-
function
|
|
62
|
-
return [
|
|
90
|
+
function A(e) {
|
|
91
|
+
return [v(e), N(e)];
|
|
63
92
|
}
|
|
64
|
-
function
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
t
|
|
68
|
-
|
|
93
|
+
function C(e) {
|
|
94
|
+
const n = typeof e != "string", t = n ? null : e, r = n ? e : null, [u, l] = s.useState(() => t ? m(t) : null);
|
|
95
|
+
c(() => {
|
|
96
|
+
if (!t) {
|
|
97
|
+
l(null);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
return l(m(t)), I(t, () => {
|
|
101
|
+
l(m(t));
|
|
102
|
+
});
|
|
103
|
+
}, [t]);
|
|
104
|
+
const [i, o] = s.useState(() => r ? r.current : null);
|
|
105
|
+
return c(() => {
|
|
106
|
+
if (!r) {
|
|
107
|
+
o(null);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const b = E(r);
|
|
111
|
+
return o(r.current), b.subscribe(() => {
|
|
112
|
+
o(r.current);
|
|
113
|
+
});
|
|
114
|
+
}, [r]), n ? i : u;
|
|
69
115
|
}
|
|
70
|
-
function
|
|
71
|
-
const t =
|
|
72
|
-
return
|
|
116
|
+
function L(e, n) {
|
|
117
|
+
const t = C(n), [r, u] = s.useState(() => t ? t.getValue(e) : void 0);
|
|
118
|
+
return c(() => {
|
|
73
119
|
if (!t) {
|
|
74
|
-
|
|
120
|
+
u(void 0);
|
|
75
121
|
return;
|
|
76
122
|
}
|
|
77
|
-
return t.register(e),
|
|
78
|
-
}, [t, e]),
|
|
123
|
+
return t.register(e), u(t.getValue(e)), t.sub(e, u);
|
|
124
|
+
}, [t, e]), r;
|
|
79
125
|
}
|
|
80
126
|
function M(e, n) {
|
|
81
|
-
const t =
|
|
82
|
-
return
|
|
127
|
+
const t = C(n);
|
|
128
|
+
return c(() => {
|
|
83
129
|
t && t.register(e);
|
|
84
130
|
}, [t, e]), s.useCallback(
|
|
85
|
-
(
|
|
86
|
-
t && t.pub(e,
|
|
131
|
+
(r) => {
|
|
132
|
+
t && t.pub(e, r);
|
|
87
133
|
},
|
|
88
134
|
[t, e]
|
|
89
135
|
);
|
|
90
136
|
}
|
|
91
|
-
function
|
|
92
|
-
return [
|
|
137
|
+
function G(e, n) {
|
|
138
|
+
return [L(e, n), M(e, n)];
|
|
93
139
|
}
|
|
94
|
-
function
|
|
95
|
-
const { cells: n,
|
|
96
|
-
() =>
|
|
140
|
+
function O(e) {
|
|
141
|
+
const { cells: n, engineSource: t } = e, r = C(t), u = s.useMemo(() => r ? r.combineCells(n) : null, [r, ...n]), [l, i] = s.useState(
|
|
142
|
+
() => r && u ? r.getValue(u) : void 0
|
|
97
143
|
);
|
|
98
|
-
return
|
|
99
|
-
if (!
|
|
100
|
-
|
|
144
|
+
return c(() => {
|
|
145
|
+
if (!r || !u) {
|
|
146
|
+
i(void 0);
|
|
101
147
|
return;
|
|
102
148
|
}
|
|
103
|
-
return
|
|
104
|
-
}, [
|
|
105
|
-
}
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
149
|
+
return r.register(u), i(r.getValue(u)), r.sub(u, i);
|
|
150
|
+
}, [r, u]), l;
|
|
151
|
+
}
|
|
152
|
+
const W = ({
|
|
153
|
+
children: e,
|
|
154
|
+
engineId: n,
|
|
155
|
+
engineRef: t,
|
|
156
|
+
initFn: r,
|
|
157
|
+
initWith: u,
|
|
158
|
+
updateDeps: l,
|
|
159
|
+
updateFn: i
|
|
160
|
+
}) => {
|
|
161
|
+
const [o, b] = s.useState(null);
|
|
162
|
+
return c(() => {
|
|
163
|
+
const g = new d(u, n);
|
|
164
|
+
return b(g), r == null || r(g), n && R(n, g), t && E(t).set(g), () => {
|
|
165
|
+
n && R(n, null), t && E(t).set(null), g.dispose();
|
|
112
166
|
};
|
|
113
|
-
}, [u, n]),
|
|
114
|
-
o && (
|
|
115
|
-
}, [o, ...
|
|
167
|
+
}, [u, n, t]), c(() => {
|
|
168
|
+
o && (i == null || i(o));
|
|
169
|
+
}, [o, ...l ?? []]), o && /* @__PURE__ */ p(V.Provider, { value: o, children: e });
|
|
116
170
|
};
|
|
117
171
|
export {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
172
|
+
V as EngineContext,
|
|
173
|
+
W as EngineProvider,
|
|
174
|
+
A as useCell,
|
|
175
|
+
v as useCellValue,
|
|
176
|
+
k as useCellValues,
|
|
123
177
|
a as useEngine,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
178
|
+
j as useEngineRef,
|
|
179
|
+
c as useIsomorphicLayoutEffect,
|
|
180
|
+
N as usePublisher,
|
|
181
|
+
G as useRemoteCell,
|
|
182
|
+
L as useRemoteCellValue,
|
|
183
|
+
O as useRemoteCellValues,
|
|
129
184
|
M as useRemotePublisher
|
|
130
185
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": false,
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.2.0",
|
|
7
7
|
"module": "dist/index.js",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"vite-plugin-dts": "^4.5.4",
|
|
43
43
|
"vitest": "^4.0.16",
|
|
44
44
|
"vitest-browser-react": "^2.0.2",
|
|
45
|
-
"@virtuoso.dev/
|
|
46
|
-
"@virtuoso.dev/
|
|
45
|
+
"@virtuoso.dev/tooling": "0.1.0",
|
|
46
|
+
"@virtuoso.dev/reactive-engine-core": "0.0.4"
|
|
47
47
|
},
|
|
48
48
|
"files": [
|
|
49
49
|
"dist"
|