@virtuoso.dev/reactive-engine-react 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -76,6 +76,17 @@ export declare interface EngineProviderProps {
76
76
  updateFn?: (engine: Engine) => void;
77
77
  }
78
78
 
79
+ /**
80
+ * Options for the {@link useRemoteCellValues} hook.
81
+ * @category React Hooks and Components
82
+ */
83
+ export declare interface RemoteCellValuesOptions<T extends unknown[]> {
84
+ cells: {
85
+ [K in keyof T]: Out<T[K]>;
86
+ };
87
+ engineId: string;
88
+ }
89
+
79
90
  /**
80
91
  * Returns a tuple of the current value of a cell and a publisher function (similar to `useState`).
81
92
  * The component re-renderes when the cell value changes.
@@ -134,8 +145,6 @@ export declare const useCellValue: typeof useCellValueWithStore;
134
145
  * }
135
146
  * ```
136
147
  */
137
- export declare function useCellValues(...cells: Out[]): unknown[];
138
-
139
148
  /** @hidden */
140
149
  export declare function useCellValues<T1>(...cells: [Out<T1>]): [T1];
141
150
 
@@ -175,6 +184,9 @@ export declare function useCellValues<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T
175
184
  /** @hidden */
176
185
  export declare function useCellValues<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(...cells: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>, Out<T6>, Out<T7>, Out<T8>, Out<T9>, Out<T10>, Out<T11>, Out<T12>, Out<T13>]): [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13];
177
186
 
187
+ /** @hidden */
188
+ export declare function useCellValues(...cells: Out[]): unknown[];
189
+
178
190
  declare function useCellValueWithStore<T>(cell: Out<T>): T;
179
191
 
180
192
  /**
@@ -212,4 +224,135 @@ export declare const useIsomorphicLayoutEffect: typeof React_2.useLayoutEffect;
212
224
  */
213
225
  export declare function usePublisher<T>(node$: Inp<T>): (value: T) => void;
214
226
 
227
+ /**
228
+ * Returns a tuple of the current value and a publisher function for a cell in an engine identified by `engineId`.
229
+ * Returns `[undefined, noop]` when the engine is not available yet.
230
+ *
231
+ * @param cell - The cell to use.
232
+ * @param engineId - The ID of the engine (must match the `engineId` prop of an EngineProvider).
233
+ * @returns A tuple of the current value (or undefined) and a publisher function.
234
+ * @typeParam T - The type of values that the cell emits/accepts.
235
+ *
236
+ * @example
237
+ * ```tsx
238
+ * const cell$ = Cell(0)
239
+ * // ...
240
+ * function SiblingComponent() {
241
+ * const [value, setValue] = useRemoteCell(cell$, 'my-engine')
242
+ * if (value === undefined) return <div>Loading...</div>
243
+ * return <button onClick={() => setValue(value + 1)}>{value}</button>
244
+ * }
245
+ * ```
246
+ * @category React Hooks and Components
247
+ */
248
+ export declare function useRemoteCell<T>(cell: NodeRef<T>, engineId: string): [T | undefined, (value: T) => void];
249
+
250
+ /**
251
+ * Gets the current value of the cell from an engine identified by `engineId`.
252
+ * Returns `undefined` when the engine is not available yet.
253
+ *
254
+ * @param cell - The cell to read from.
255
+ * @param engineId - The ID of the engine to read from (must match the `engineId` prop of an EngineProvider).
256
+ * @returns The current value of the cell, or `undefined` if the engine is not available.
257
+ * @typeParam T - The type of the value that the cell carries.
258
+ *
259
+ * @example
260
+ * ```tsx
261
+ * const cell$ = Cell(0)
262
+ * // ...
263
+ * function SiblingComponent() {
264
+ * const value = useRemoteCellValue(cell$, 'my-engine')
265
+ * if (value === undefined) return <div>Loading...</div>
266
+ * return <div>{value}</div>
267
+ * }
268
+ * ```
269
+ * @category React Hooks and Components
270
+ */
271
+ export declare function useRemoteCellValue<T>(cell: Out<T>, engineId: string): T | undefined;
272
+
273
+ /**
274
+ * Returns the up-to-date values of the passed cells from an engine identified by `engineId`.
275
+ * Returns `undefined` when the engine is not available yet.
276
+ *
277
+ * @param options - An object containing the cells array and engineId.
278
+ * @returns An array with the current values of the cells, or `undefined` if the engine is not available.
279
+ *
280
+ * @example
281
+ * ```tsx
282
+ * const foo$ = Cell('foo')
283
+ * const bar$ = Cell('bar')
284
+ * // ...
285
+ * function SiblingComponent() {
286
+ * const values = useRemoteCellValues({ cells: [foo$, bar$], engineId: 'my-engine' })
287
+ * if (values === undefined) return <div>Loading...</div>
288
+ * const [foo, bar] = values
289
+ * return <div>{foo} - {bar}</div>
290
+ * }
291
+ * ```
292
+ * @category React Hooks and Components
293
+ */
294
+ /** @hidden */
295
+ export declare function useRemoteCellValues<T1>(options: RemoteCellValuesOptions<[T1]>): [T1] | undefined;
296
+
297
+ /** @hidden */
298
+ export declare function useRemoteCellValues<T1, T2>(options: RemoteCellValuesOptions<[T1, T2]>): [T1, T2] | undefined;
299
+
300
+ /** @hidden */
301
+ export declare function useRemoteCellValues<T1, T2, T3>(options: RemoteCellValuesOptions<[T1, T2, T3]>): [T1, T2, T3] | undefined;
302
+
303
+ /** @hidden */
304
+ export declare function useRemoteCellValues<T1, T2, T3, T4>(options: RemoteCellValuesOptions<[T1, T2, T3, T4]>): [T1, T2, T3, T4] | undefined;
305
+
306
+ /** @hidden */
307
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5]>): [T1, T2, T3, T4, T5] | undefined;
308
+
309
+ /** @hidden */
310
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5, T6]>): [T1, T2, T3, T4, T5, T6] | undefined;
311
+
312
+ /** @hidden */
313
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6, T7>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5, T6, T7]>): [T1, T2, T3, T4, T5, T6, T7] | undefined;
314
+
315
+ /** @hidden */
316
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6, T7, T8>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5, T6, T7, T8]>): [T1, T2, T3, T4, T5, T6, T7, T8] | undefined;
317
+
318
+ /** @hidden */
319
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6, T7, T8, T9>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>): [T1, T2, T3, T4, T5, T6, T7, T8, T9] | undefined;
320
+
321
+ /** @hidden */
322
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>): [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] | undefined;
323
+
324
+ /** @hidden */
325
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]>): [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11] | undefined;
326
+
327
+ /** @hidden */
328
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]>): [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12] | undefined;
329
+
330
+ /** @hidden */
331
+ export declare function useRemoteCellValues<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(options: RemoteCellValuesOptions<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]>): [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13] | undefined;
332
+
333
+ /** @hidden */
334
+ export declare function useRemoteCellValues(options: RemoteCellValuesOptions<unknown[]>): undefined | unknown[];
335
+
336
+ /**
337
+ * Returns a function that publishes values to a node in an engine identified by `engineId`.
338
+ * Returns a no-op function when the engine is not available yet.
339
+ *
340
+ * @param node$ - The node to publish to.
341
+ * @param engineId - The ID of the engine to publish to (must match the `engineId` prop of an EngineProvider).
342
+ * @returns A publisher function that accepts values of type T.
343
+ * @typeParam T - The type of values that the node accepts.
344
+ *
345
+ * @example
346
+ * ```tsx
347
+ * const trigger$ = Trigger()
348
+ * // ...
349
+ * function SiblingComponent() {
350
+ * const publish = useRemotePublisher(trigger$, 'my-engine')
351
+ * return <button onClick={() => publish()}>Trigger</button>
352
+ * }
353
+ * ```
354
+ * @category React Hooks and Components
355
+ */
356
+ export declare function useRemotePublisher<T>(node$: Inp<T>, engineId: string): (value: T) => void;
357
+
215
358
  export { }
package/dist/index.js CHANGED
@@ -1,63 +1,130 @@
1
- import { jsx as C } from "react/jsx-runtime";
2
- import { Engine as E } from "@virtuoso.dev/reactive-engine-core";
3
- import * as u from "react";
4
- import b from "tiny-invariant";
5
- const a = typeof document < "u" ? u.useLayoutEffect : u.useEffect, g = u.createContext(null);
6
- function o() {
7
- const e = u.useContext(g);
8
- return b(e !== null, "useEngine must be used within an EngineProvider"), e;
9
- }
10
- function S(e) {
11
- const n = o();
1
+ import { jsx as v } from "react/jsx-runtime";
2
+ import { Engine as S } from "@virtuoso.dev/reactive-engine-core";
3
+ import * as s from "react";
4
+ import R from "tiny-invariant";
5
+ const i = typeof document < "u" ? s.useLayoutEffect : s.useEffect, l = /* @__PURE__ */ new Map();
6
+ function C(e) {
7
+ let n = l.get(e);
8
+ return n || (n = { engine: null, subscribers: /* @__PURE__ */ new Set() }, l.set(e, n)), n;
9
+ }
10
+ function m(e, n) {
11
+ const t = C(e);
12
+ t.engine = n, t.subscribers.forEach((u) => {
13
+ u();
14
+ }), t.subscribers.size === 0 && n === null && l.delete(e);
15
+ }
16
+ function p(e, n) {
17
+ const t = C(e);
18
+ return t.subscribers.add(n), () => {
19
+ t.subscribers.delete(n), t.subscribers.size === 0 && t.engine === null && l.delete(e);
20
+ };
21
+ }
22
+ function f(e) {
23
+ var n;
24
+ return ((n = l.get(e)) == null ? void 0 : n.engine) ?? null;
25
+ }
26
+ const E = s.createContext(null);
27
+ function a() {
28
+ const e = s.useContext(E);
29
+ return R(e !== null, "useEngine must be used within an EngineProvider"), e;
30
+ }
31
+ function x(e) {
32
+ const n = a();
12
33
  n.register(e);
13
- const t = u.useCallback((r) => n.sub(e, r), [n, e]);
14
- return u.useSyncExternalStore(
34
+ const t = s.useCallback((u) => n.sub(e, u), [n, e]);
35
+ return s.useSyncExternalStore(
15
36
  t,
16
37
  () => n.getValue(e),
17
38
  () => n.getValue(e)
18
39
  );
19
40
  }
20
- function V(e) {
21
- const n = o();
41
+ function h(e) {
42
+ const n = a();
22
43
  n.register(e);
23
- const [t, r] = u.useState(() => n.getValue(e));
24
- return a(() => n.sub(e, r), [n, e]), t;
44
+ const [t, u] = s.useState(() => n.getValue(e));
45
+ return i(() => n.sub(e, u), [n, e]), t;
25
46
  }
26
- const f = "useSyncExternalStore" in u ? S : V;
27
- function h(...e) {
28
- const n = o(), t = u.useMemo(() => n.combineCells(e), [n, ...e]);
29
- return f(t);
47
+ const V = "useSyncExternalStore" in s ? x : h;
48
+ function j(...e) {
49
+ const n = a(), t = s.useMemo(() => n.combineCells(e), [n, ...e]);
50
+ return V(t);
30
51
  }
31
- function x(e) {
32
- const n = o();
33
- return n.register(e), u.useCallback(
52
+ function P(e) {
53
+ const n = a();
54
+ return n.register(e), s.useCallback(
34
55
  (t) => {
35
56
  n.pub(e, t);
36
57
  },
37
58
  [n, e]
38
59
  );
39
60
  }
40
- function P(e) {
41
- return [f(e), x(e)];
42
- }
43
- const d = ({ children: e, engineId: n, initFn: t, initWith: r, updateDeps: l, updateFn: i }) => {
44
- const [s, m] = u.useState(null);
45
- return a(() => {
46
- const c = new E(r, n);
47
- return m(c), t == null || t(c), () => {
48
- c.dispose();
61
+ function O(e) {
62
+ return [V(e), P(e)];
63
+ }
64
+ function b(e) {
65
+ const [n, t] = s.useState(() => f(e));
66
+ return i(() => (t(f(e)), p(e, () => {
67
+ t(f(e));
68
+ })), [e]), n;
69
+ }
70
+ function w(e, n) {
71
+ const t = b(n), [u, r] = s.useState(() => t ? t.getValue(e) : void 0);
72
+ return i(() => {
73
+ if (!t) {
74
+ r(void 0);
75
+ return;
76
+ }
77
+ return t.register(e), r(t.getValue(e)), t.sub(e, r);
78
+ }, [t, e]), u;
79
+ }
80
+ function M(e, n) {
81
+ const t = b(n);
82
+ return i(() => {
83
+ t && t.register(e);
84
+ }, [t, e]), s.useCallback(
85
+ (u) => {
86
+ t && t.pub(e, u);
87
+ },
88
+ [t, e]
89
+ );
90
+ }
91
+ function T(e, n) {
92
+ return [w(e, n), M(e, n)];
93
+ }
94
+ function W(e) {
95
+ const { cells: n, engineId: t } = e, u = b(t), r = s.useMemo(() => u ? u.combineCells(n) : null, [u, ...n]), [c, o] = s.useState(
96
+ () => u && r ? u.getValue(r) : void 0
97
+ );
98
+ return i(() => {
99
+ if (!u || !r) {
100
+ o(void 0);
101
+ return;
102
+ }
103
+ return u.register(r), o(u.getValue(r)), u.sub(r, o);
104
+ }, [u, r]), c;
105
+ }
106
+ const q = ({ children: e, engineId: n, initFn: t, initWith: u, updateDeps: r, updateFn: c }) => {
107
+ const [o, y] = s.useState(null);
108
+ return i(() => {
109
+ const g = new S(u, n);
110
+ return y(g), t == null || t(g), n && m(n, g), () => {
111
+ n && m(n, null), g.dispose();
49
112
  };
50
- }, [r, n]), a(() => {
51
- s && (i == null || i(s));
52
- }, [s, ...l ?? []]), s && /* @__PURE__ */ C(g.Provider, { value: s, children: e });
113
+ }, [u, n]), i(() => {
114
+ o && (c == null || c(o));
115
+ }, [o, ...r ?? []]), o && /* @__PURE__ */ v(E.Provider, { value: o, children: e });
53
116
  };
54
117
  export {
55
- g as EngineContext,
56
- d as EngineProvider,
57
- P as useCell,
58
- f as useCellValue,
59
- h as useCellValues,
60
- o as useEngine,
61
- a as useIsomorphicLayoutEffect,
62
- x as usePublisher
118
+ E as EngineContext,
119
+ q as EngineProvider,
120
+ O as useCell,
121
+ V as useCellValue,
122
+ j as useCellValues,
123
+ a as useEngine,
124
+ i as useIsomorphicLayoutEffect,
125
+ P as usePublisher,
126
+ T as useRemoteCell,
127
+ w as useRemoteCellValue,
128
+ W as useRemoteCellValues,
129
+ M as useRemotePublisher
63
130
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "private": false,
4
4
  "sideEffects": false,
5
5
  "type": "module",
6
- "version": "0.0.3",
6
+ "version": "0.1.0",
7
7
  "module": "dist/index.js",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
@@ -21,13 +21,11 @@
21
21
  "tiny-invariant": "^1.3.3"
22
22
  },
23
23
  "peerDependencies": {
24
- "@virtuoso.dev/reactive-engine-core": ">=0.0.3",
24
+ "@virtuoso.dev/reactive-engine-core": ">=0.0.4",
25
25
  "react": ">= 18",
26
26
  "react-dom": ">= 18"
27
27
  },
28
28
  "devDependencies": {
29
- "@testing-library/jest-dom": "^6.9.1",
30
- "@testing-library/react": "^16.3.0",
31
29
  "@types/node": "^22.10.1",
32
30
  "@types/react": "^19.2.7",
33
31
  "@types/react-dom": "^19.2.3",
@@ -35,7 +33,6 @@
35
33
  "@vitest/browser-playwright": "^4.0.16",
36
34
  "@vitejs/plugin-react": "^4.5.0",
37
35
  "eslint": "^9.24.0",
38
- "jsdom": "^27.4.0",
39
36
  "playwright": "^1.33.0",
40
37
  "prettier": "^3.5.3",
41
38
  "react": "^19.2.3",
@@ -45,7 +42,7 @@
45
42
  "vite-plugin-dts": "^4.5.4",
46
43
  "vitest": "^4.0.16",
47
44
  "vitest-browser-react": "^2.0.2",
48
- "@virtuoso.dev/reactive-engine-core": "0.0.3",
45
+ "@virtuoso.dev/reactive-engine-core": "0.0.4",
49
46
  "@virtuoso.dev/tooling": "0.1.0"
50
47
  },
51
48
  "files": [