@liveblocks/react-flow 3.17.0 → 3.18.0-rc2
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.cjs +2 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -20
- package/dist/index.d.ts +8 -20
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/{flow.cjs → lib/flow.cjs} +33 -41
- package/dist/lib/flow.cjs.map +1 -0
- package/dist/{flow.js → lib/flow.js} +26 -34
- package/dist/lib/flow.js.map +1 -0
- package/dist/lib/shared.cjs +77 -0
- package/dist/lib/shared.cjs.map +1 -0
- package/dist/lib/shared.js +68 -0
- package/dist/lib/shared.js.map +1 -0
- package/dist/{version.cjs → lib/version.cjs} +1 -1
- package/dist/lib/version.cjs.map +1 -0
- package/dist/{version.js → lib/version.js} +1 -1
- package/dist/lib/version.js.map +1 -0
- package/dist/node.cjs +151 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +99 -0
- package/dist/node.d.ts +99 -0
- package/dist/node.js +149 -0
- package/dist/node.js.map +1 -0
- package/package.json +25 -5
- package/dist/constants.cjs +0 -35
- package/dist/constants.cjs.map +0 -1
- package/dist/constants.js +0 -31
- package/dist/constants.js.map +0 -1
- package/dist/flow.cjs.map +0 -1
- package/dist/flow.js.map +0 -1
- package/dist/helpers.cjs +0 -35
- package/dist/helpers.cjs.map +0 -1
- package/dist/helpers.js +0 -30
- package/dist/helpers.js.map +0 -1
- package/dist/version.cjs.map +0 -1
- package/dist/version.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var core = require('@liveblocks/core');
|
|
4
|
-
var version = require('./version.cjs');
|
|
4
|
+
var version = require('./lib/version.cjs');
|
|
5
5
|
var cursors = require('./cursors.cjs');
|
|
6
|
-
var flow = require('./flow.cjs');
|
|
7
|
-
var helpers = require('./helpers.cjs');
|
|
6
|
+
var flow = require('./lib/flow.cjs');
|
|
8
7
|
|
|
9
8
|
core.detectDupes(version.PKG_NAME, version.PKG_VERSION, version.PKG_FORMAT);
|
|
10
9
|
|
|
11
10
|
exports.Cursors = cursors.Cursors;
|
|
12
11
|
exports.useLiveblocksFlow = flow.useLiveblocksFlow;
|
|
13
|
-
exports.toLiveblocksEdge = helpers.toLiveblocksEdge;
|
|
14
|
-
exports.toLiveblocksNode = helpers.toLiveblocksNode;
|
|
15
12
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { CursorsCursorProps, CursorsProps } from \"./cursors\";\nexport { Cursors } from \"./cursors\";\nexport { useLiveblocksFlow } from \"./flow\";\nexport
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./lib/version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { CursorsCursorProps, CursorsProps } from \"./cursors\";\nexport { Cursors } from \"./cursors\";\nexport { useLiveblocksFlow } from \"./lib/flow\";\nexport type {\n EdgeSyncConfig,\n LiveblocksEdge,\n LiveblocksFlow,\n LiveblocksNode,\n NodeSyncConfig,\n SyncConfig,\n SyncMode,\n} from \"./lib/types\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;"}
|
package/dist/index.d.cts
CHANGED
|
@@ -41,6 +41,13 @@ interface CursorsProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
41
41
|
*/
|
|
42
42
|
declare const Cursors: react.ForwardRefExoticComponent<CursorsProps & react.RefAttributes<HTMLDivElement>>;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Module with utilities shared between the React Flow frontend and the React
|
|
46
|
+
* Flow Node backend. There are no runtime dependencies on @xyflow/react,
|
|
47
|
+
* react, or any other frontend-specific libraries from this module, and this
|
|
48
|
+
* should stay that way.
|
|
49
|
+
*/
|
|
50
|
+
|
|
44
51
|
declare const NODE_BASE_CONFIG: {
|
|
45
52
|
readonly selected: false;
|
|
46
53
|
readonly dragging: false;
|
|
@@ -244,23 +251,4 @@ declare function useLiveblocksFlow<N extends Node = BuiltInNode, E extends Edge
|
|
|
244
251
|
suspense: true;
|
|
245
252
|
}): Resolve<LiveblocksFlowSuspenseResult<N, E>>;
|
|
246
253
|
|
|
247
|
-
|
|
248
|
-
* @experimental
|
|
249
|
-
*
|
|
250
|
-
* Converts a React Flow `Node` into a Liveblocks Storage version.
|
|
251
|
-
* Keys marked `false` in config are set as local-only (not synced).
|
|
252
|
-
* Keys marked `"atomic"` are stored as plain Json (no deep wrapping).
|
|
253
|
-
* All other keys are deep-liveified (objects→LiveObject, arrays→LiveList).
|
|
254
|
-
*/
|
|
255
|
-
declare function toLiveblocksNode<N extends Node>(node: N, config?: SyncConfig): LiveblocksNode<N>;
|
|
256
|
-
/**
|
|
257
|
-
* @experimental
|
|
258
|
-
*
|
|
259
|
-
* Converts a React Flow `Edge` into a Liveblocks Storage version.
|
|
260
|
-
* Keys marked `false` in config are set as local-only (not synced).
|
|
261
|
-
* Keys marked `"atomic"` are stored as plain Json (no deep wrapping).
|
|
262
|
-
* All other keys are deep-liveified (objects→LiveObject, arrays→LiveList).
|
|
263
|
-
*/
|
|
264
|
-
declare function toLiveblocksEdge<E extends Edge>(edge: E, config?: SyncConfig): LiveblocksEdge<E>;
|
|
265
|
-
|
|
266
|
-
export { Cursors, CursorsCursorProps, CursorsProps, EdgeSyncConfig, LiveblocksEdge, LiveblocksFlow, LiveblocksNode, NodeSyncConfig, toLiveblocksEdge, toLiveblocksNode, useLiveblocksFlow };
|
|
254
|
+
export { Cursors, CursorsCursorProps, CursorsProps, EdgeSyncConfig, LiveblocksEdge, LiveblocksFlow, LiveblocksNode, NodeSyncConfig, useLiveblocksFlow };
|
package/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,13 @@ interface CursorsProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
41
41
|
*/
|
|
42
42
|
declare const Cursors: react.ForwardRefExoticComponent<CursorsProps & react.RefAttributes<HTMLDivElement>>;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Module with utilities shared between the React Flow frontend and the React
|
|
46
|
+
* Flow Node backend. There are no runtime dependencies on @xyflow/react,
|
|
47
|
+
* react, or any other frontend-specific libraries from this module, and this
|
|
48
|
+
* should stay that way.
|
|
49
|
+
*/
|
|
50
|
+
|
|
44
51
|
declare const NODE_BASE_CONFIG: {
|
|
45
52
|
readonly selected: false;
|
|
46
53
|
readonly dragging: false;
|
|
@@ -244,23 +251,4 @@ declare function useLiveblocksFlow<N extends Node = BuiltInNode, E extends Edge
|
|
|
244
251
|
suspense: true;
|
|
245
252
|
}): Resolve<LiveblocksFlowSuspenseResult<N, E>>;
|
|
246
253
|
|
|
247
|
-
|
|
248
|
-
* @experimental
|
|
249
|
-
*
|
|
250
|
-
* Converts a React Flow `Node` into a Liveblocks Storage version.
|
|
251
|
-
* Keys marked `false` in config are set as local-only (not synced).
|
|
252
|
-
* Keys marked `"atomic"` are stored as plain Json (no deep wrapping).
|
|
253
|
-
* All other keys are deep-liveified (objects→LiveObject, arrays→LiveList).
|
|
254
|
-
*/
|
|
255
|
-
declare function toLiveblocksNode<N extends Node>(node: N, config?: SyncConfig): LiveblocksNode<N>;
|
|
256
|
-
/**
|
|
257
|
-
* @experimental
|
|
258
|
-
*
|
|
259
|
-
* Converts a React Flow `Edge` into a Liveblocks Storage version.
|
|
260
|
-
* Keys marked `false` in config are set as local-only (not synced).
|
|
261
|
-
* Keys marked `"atomic"` are stored as plain Json (no deep wrapping).
|
|
262
|
-
* All other keys are deep-liveified (objects→LiveObject, arrays→LiveList).
|
|
263
|
-
*/
|
|
264
|
-
declare function toLiveblocksEdge<E extends Edge>(edge: E, config?: SyncConfig): LiveblocksEdge<E>;
|
|
265
|
-
|
|
266
|
-
export { Cursors, CursorsCursorProps, CursorsProps, EdgeSyncConfig, LiveblocksEdge, LiveblocksFlow, LiveblocksNode, NodeSyncConfig, toLiveblocksEdge, toLiveblocksNode, useLiveblocksFlow };
|
|
254
|
+
export { Cursors, CursorsCursorProps, CursorsProps, EdgeSyncConfig, LiveblocksEdge, LiveblocksFlow, LiveblocksNode, NodeSyncConfig, useLiveblocksFlow };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { detectDupes } from '@liveblocks/core';
|
|
2
|
-
import { PKG_NAME, PKG_VERSION, PKG_FORMAT } from './version.js';
|
|
2
|
+
import { PKG_NAME, PKG_VERSION, PKG_FORMAT } from './lib/version.js';
|
|
3
3
|
export { Cursors } from './cursors.js';
|
|
4
|
-
export { useLiveblocksFlow } from './flow.js';
|
|
5
|
-
export { toLiveblocksEdge, toLiveblocksNode } from './helpers.js';
|
|
4
|
+
export { useLiveblocksFlow } from './lib/flow.js';
|
|
6
5
|
|
|
7
6
|
detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
|
|
8
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { CursorsCursorProps, CursorsProps } from \"./cursors\";\nexport { Cursors } from \"./cursors\";\nexport { useLiveblocksFlow } from \"./flow\";\nexport
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./lib/version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type { CursorsCursorProps, CursorsProps } from \"./cursors\";\nexport { Cursors } from \"./cursors\";\nexport { useLiveblocksFlow } from \"./lib/flow\";\nexport type {\n EdgeSyncConfig,\n LiveblocksEdge,\n LiveblocksFlow,\n LiveblocksNode,\n NodeSyncConfig,\n SyncConfig,\n SyncMode,\n} from \"./lib/types\";\n"],"names":[],"mappings":";;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
|
|
@@ -5,33 +5,9 @@ var react = require('@liveblocks/react');
|
|
|
5
5
|
var _private = require('@liveblocks/react/_private');
|
|
6
6
|
var react$2 = require('@xyflow/react');
|
|
7
7
|
var react$1 = require('react');
|
|
8
|
-
var
|
|
9
|
-
var helpers = require('./helpers.cjs');
|
|
8
|
+
var shared = require('./shared.cjs');
|
|
10
9
|
|
|
11
10
|
const EMPTY_ARRAY = [];
|
|
12
|
-
function mergeAndBuildDataConfigCache(base, data) {
|
|
13
|
-
if (!data)
|
|
14
|
-
return () => base;
|
|
15
|
-
const dataFallback = data["*"];
|
|
16
|
-
const fallback = dataFallback ? { ...base, data: dataFallback } : base;
|
|
17
|
-
const cache = /* @__PURE__ */ new Map();
|
|
18
|
-
for (const type in data) {
|
|
19
|
-
if (type === "*")
|
|
20
|
-
continue;
|
|
21
|
-
const specific = data[type];
|
|
22
|
-
if (!specific)
|
|
23
|
-
continue;
|
|
24
|
-
const dataConfig = { ...dataFallback, ...specific };
|
|
25
|
-
cache.set(type, { ...base, data: dataConfig });
|
|
26
|
-
}
|
|
27
|
-
return (type) => cache.get(type) || fallback;
|
|
28
|
-
}
|
|
29
|
-
function buildNodeConfigCache(nodeDataConfig) {
|
|
30
|
-
return mergeAndBuildDataConfigCache(constants.NODE_BASE_CONFIG, nodeDataConfig);
|
|
31
|
-
}
|
|
32
|
-
function buildEdgeConfigCache(edgeDataConfig) {
|
|
33
|
-
return mergeAndBuildDataConfigCache(constants.EDGE_BASE_CONFIG, edgeDataConfig);
|
|
34
|
-
}
|
|
35
11
|
function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
|
|
36
12
|
for (const change of changes) {
|
|
37
13
|
switch (change.type) {
|
|
@@ -44,7 +20,7 @@ function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
|
|
|
44
20
|
} else {
|
|
45
21
|
nodes.set(
|
|
46
22
|
change.item.id,
|
|
47
|
-
|
|
23
|
+
shared.toLiveblocksInternalNode(change.item, config)
|
|
48
24
|
);
|
|
49
25
|
}
|
|
50
26
|
break;
|
|
@@ -120,7 +96,7 @@ function applyEdgeChanges(changes, edges, getEdgeSyncConfig) {
|
|
|
120
96
|
} else {
|
|
121
97
|
edges.set(
|
|
122
98
|
change.item.id,
|
|
123
|
-
|
|
99
|
+
shared.toLiveblocksInternalEdge(change.item, config)
|
|
124
100
|
);
|
|
125
101
|
}
|
|
126
102
|
break;
|
|
@@ -137,30 +113,46 @@ function applyEdgeChanges(changes, edges, getEdgeSyncConfig) {
|
|
|
137
113
|
}
|
|
138
114
|
}
|
|
139
115
|
}
|
|
116
|
+
function nodeMapToList(nodesMap) {
|
|
117
|
+
if (nodesMap === null)
|
|
118
|
+
return null;
|
|
119
|
+
return Object.values(nodesMap);
|
|
120
|
+
}
|
|
121
|
+
function edgeMapToList(edgesMap) {
|
|
122
|
+
if (edgesMap === null)
|
|
123
|
+
return null;
|
|
124
|
+
return Object.values(edgesMap);
|
|
125
|
+
}
|
|
126
|
+
function useNodesAndEdges(storageKey) {
|
|
127
|
+
const nodesMap = react.useStorage((storage) => {
|
|
128
|
+
const flow = storage[storageKey];
|
|
129
|
+
return flow?.nodes ?? null;
|
|
130
|
+
});
|
|
131
|
+
const edgesMap = react.useStorage((storage) => {
|
|
132
|
+
const flow = storage[storageKey];
|
|
133
|
+
return flow?.edges ?? null;
|
|
134
|
+
});
|
|
135
|
+
const nodes = react$1.useMemo(() => nodeMapToList(nodesMap), [nodesMap]);
|
|
136
|
+
const edges = react$1.useMemo(() => edgeMapToList(edgesMap), [edgesMap]);
|
|
137
|
+
return { nodes, edges };
|
|
138
|
+
}
|
|
140
139
|
function useLiveblocksFlow(options = {}) {
|
|
141
140
|
const history = react.useHistory();
|
|
142
141
|
const isStorageLoaded = react.useStorage(() => true) ?? false;
|
|
143
142
|
const frozenOptions = _private.useInitial({
|
|
144
143
|
nodes: options.nodes,
|
|
145
144
|
edges: options.edges,
|
|
146
|
-
storageKey: options.storageKey ??
|
|
145
|
+
storageKey: options.storageKey ?? shared.DEFAULT_STORAGE_KEY,
|
|
147
146
|
suspense: options.suspense ?? false
|
|
148
147
|
});
|
|
149
148
|
const [getNodeSyncConfig, getEdgeSyncConfig] = react$1.useMemo(
|
|
150
149
|
() => [
|
|
151
|
-
buildNodeConfigCache(frozenOptions.nodes?.sync),
|
|
152
|
-
buildEdgeConfigCache(frozenOptions.edges?.sync)
|
|
150
|
+
shared.buildNodeConfigCache(frozenOptions.nodes?.sync),
|
|
151
|
+
shared.buildEdgeConfigCache(frozenOptions.edges?.sync)
|
|
153
152
|
],
|
|
154
153
|
[frozenOptions]
|
|
155
154
|
);
|
|
156
|
-
const nodes =
|
|
157
|
-
const flow = storage[frozenOptions.storageKey];
|
|
158
|
-
return flow?.nodes ? [...flow.nodes.values()] : null;
|
|
159
|
-
});
|
|
160
|
-
const edges = react.useStorage((storage) => {
|
|
161
|
-
const flow = storage[frozenOptions.storageKey];
|
|
162
|
-
return flow?.edges ? [...flow.edges.values()] : null;
|
|
163
|
-
});
|
|
155
|
+
const { nodes, edges } = useNodesAndEdges(frozenOptions.storageKey);
|
|
164
156
|
const onNodesChange = react.useMutation(
|
|
165
157
|
({ storage }, changes) => {
|
|
166
158
|
const flow = storage.get(frozenOptions.storageKey);
|
|
@@ -193,7 +185,7 @@ function useLiveblocksFlow(options = {}) {
|
|
|
193
185
|
}
|
|
194
186
|
const edges2 = flow.get("edges");
|
|
195
187
|
const config = getEdgeSyncConfig(newEdge.type);
|
|
196
|
-
edges2.set(newEdge.id,
|
|
188
|
+
edges2.set(newEdge.id, shared.toLiveblocksInternalEdge(newEdge, config));
|
|
197
189
|
},
|
|
198
190
|
[frozenOptions.storageKey, getEdgeSyncConfig]
|
|
199
191
|
);
|
|
@@ -227,13 +219,13 @@ function useLiveblocksFlow(options = {}) {
|
|
|
227
219
|
nodes: new core.LiveMap(
|
|
228
220
|
initialNodes.map((node) => [
|
|
229
221
|
node.id,
|
|
230
|
-
|
|
222
|
+
shared.toLiveblocksInternalNode(node, getNodeSyncConfig(node.type))
|
|
231
223
|
])
|
|
232
224
|
),
|
|
233
225
|
edges: new core.LiveMap(
|
|
234
226
|
initialEdges.map((edge) => [
|
|
235
227
|
edge.id,
|
|
236
|
-
|
|
228
|
+
shared.toLiveblocksInternalEdge(edge, getEdgeSyncConfig(edge.type))
|
|
237
229
|
])
|
|
238
230
|
)
|
|
239
231
|
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.cjs","sources":["../../src/lib/flow.ts"],"sourcesContent":["import type {\n History,\n JsonObject,\n ReadonlyJsonObject,\n Resolve,\n ToJson,\n} from \"@liveblocks/core\";\nimport { kInternal, LiveMap, LiveObject } from \"@liveblocks/core\";\nimport { useHistory, useMutation, useStorage } from \"@liveblocks/react\";\nimport {\n useInitial,\n useSuspendUntilStorageReady,\n} from \"@liveblocks/react/_private\";\nimport type {\n BuiltInEdge,\n BuiltInNode,\n Connection,\n Edge,\n EdgeChange,\n Node,\n NodeChange,\n OnConnect,\n OnDelete,\n OnEdgesChange,\n OnNodesChange,\n} from \"@xyflow/react\";\nimport { addEdge as defaultAddEdge } from \"@xyflow/react\";\nimport { useEffect, useMemo } from \"react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksEdge,\n InternalLiveblocksFlow,\n InternalLiveblocksNode,\n NodeSyncConfig,\n SyncConfig,\n} from \"./types\";\n\nconst EMPTY_ARRAY = [] as unknown[];\n\ntype UseLiveblocksFlowResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Resolve<\n (\n | {\n nodes: null;\n edges: null;\n isLoading: true;\n }\n | {\n nodes: N[];\n edges: E[];\n isLoading: false;\n }\n ) & {\n onNodesChange: OnNodesChange<N>;\n onEdgesChange: OnEdgesChange<E>;\n onConnect: OnConnect;\n onDelete: OnDelete<N, E>;\n }\n>;\n\ntype LiveblocksFlowSuspenseResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Extract<UseLiveblocksFlowResult<N, E>, { isLoading: false }>;\n\ntype UseLiveblocksFlowOptions<N extends Node, E extends Edge> = {\n nodes?: {\n /**\n * The initial React Flow nodes.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * initial: [\n * { id: \"1\", position: { x: 0, y: 0 }, data: { label: \"Node 1\" } },\n * { id: \"2\", position: { x: 0, y: 100 }, data: { label: \"Node 2\" } },\n * ],\n * },\n * });\n * ```\n */\n initial?: N[];\n /**\n * Per-type sync configuration for node data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all node types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * sync: {\n * \"*\": {\n * label: false, // Don't sync node.data.label\n * color: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomNode: {\n * showPreview: false, // Don't sync myCustomNode.data.showPreview\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: NodeSyncConfig<N>;\n };\n\n edges?: {\n initial?: E[];\n /**\n * Per-type sync configuration for edge data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all edge types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * edges: {\n * sync: {\n * \"*\": {\n * hovered: false, // Don't sync edge.data.hovered\n * style: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomEdge: {\n * isHighlighted: false, // Don't sync myCustomEdge.data.isHighlighted\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: EdgeSyncConfig<E>;\n };\n\n /**\n * The key used to store the React Flow diagram in Liveblocks Storage.\n * Defaults to `\"flow\"`.\n */\n storageKey?: string;\n\n /**\n * When true, suspends until Storage is ready (use a React `Suspense`\n * boundary). Then `nodes` and `edges` are always arrays and `isLoading` is\n * always false.\n */\n suspense?: boolean;\n};\n\n// Similar to React Flow's `applyNodeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-node-changes\nfunction applyNodeChanges<N extends Node>(\n changes: NodeChange<N>[],\n nodes: LiveMap<string, InternalLiveblocksNode>,\n history: History,\n getNodeSyncConfig: (nodeType: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getNodeSyncConfig(change.item.type);\n const existing = nodes.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n nodes.set(\n change.item.id,\n toLiveblocksInternalNode(change.item, config)\n );\n }\n break;\n }\n\n case \"position\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.dragging === true) {\n history.pause();\n }\n\n if (change.position !== undefined) {\n const prev = node.get(\"position\");\n if (prev?.x !== change.position.x || prev?.y !== change.position.y) {\n node.set(\"position\", change.position);\n }\n }\n\n if (change.dragging !== undefined) {\n if (change.dragging === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `dragging: false`\n node.setLocal(\"dragging\", change.dragging);\n }\n break;\n }\n\n case \"dimensions\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.resizing === true) {\n history.pause();\n }\n\n if (\n change.dimensions !== undefined &&\n change.setAttributes !== undefined\n ) {\n if (\n change.setAttributes === true ||\n change.setAttributes === \"width\"\n ) {\n node.set(\"width\", change.dimensions.width);\n }\n\n if (\n change.setAttributes === true ||\n change.setAttributes === \"height\"\n ) {\n node.set(\"height\", change.dimensions.height);\n }\n }\n\n if (change.dimensions !== undefined) {\n // Must match NODE_BASE_CONFIG's `measured: false`\n node.setLocal(\"measured\", change.dimensions);\n }\n\n if (change.resizing !== undefined) {\n if (change.resizing === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `resizing: false`\n node.setLocal(\"resizing\", change.resizing);\n }\n\n break;\n }\n\n case \"select\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Must match NODE_BASE_CONFIG's `selected: false`\n node.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// Similar to React Flow's `applyEdgeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-edge-changes\nfunction applyEdgeChanges<E extends Edge>(\n changes: EdgeChange<E>[],\n edges: LiveMap<string, InternalLiveblocksEdge>,\n getEdgeSyncConfig: (type: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getEdgeSyncConfig(change.item.type);\n const existing = edges.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n edges.set(\n change.item.id,\n toLiveblocksInternalEdge(change.item, config)\n );\n }\n break;\n }\n\n case \"select\": {\n const edge = edges.get(change.id);\n if (!edge) break;\n // Must match EDGE_BASE_CONFIG's `selected: false`\n edge.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n// in topological order (parents before children), deferring any node with a\n// parentId until its parent has been emitted.\nfunction nodeMapToList<N extends Node>(\n nodesMap: ReadonlyJsonObject | null\n): N[] | null {\n if (nodesMap === null) return null;\n return Object.values(nodesMap) as unknown as N[];\n}\n\nfunction edgeMapToList<E extends Edge>(\n edgesMap: ReadonlyJsonObject | null\n): E[] | null {\n if (edgesMap === null) return null;\n return Object.values(edgesMap) as unknown as E[];\n}\n\nfunction useNodesAndEdges<N extends Node, E extends Edge>(storageKey: string) {\n // Storage already includes local overlays via toJSON(), so no separate local\n // layer is needed. Individual node/edge immutable references are already\n // stable (only change when the underlying LiveObject changes).\n const nodesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.nodes ?? null;\n });\n const edgesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.edges ?? null;\n });\n\n const nodes = useMemo(() => nodeMapToList<N>(nodesMap), [nodesMap]);\n const edges = useMemo(() => edgeMapToList<E>(edgesMap), [edgesMap]);\n return { nodes, edges };\n}\n\n/**\n * Returns a controlled React Flow state backed by Liveblocks Storage.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete, isLoading } = useLiveblocksFlow();\n *\n * if (isLoading) {\n * return <div>Loading…</div>\n * }\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n * Pass `{ suspense: true }` to suspend until Storage is ready, `nodes` and `edges` will never be `null`.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete } =\n * useLiveblocksFlow({ suspense: true });\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n */\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options?: UseLiveblocksFlowOptions<N, E> & { suspense?: false }\n): Resolve<UseLiveblocksFlowResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> & { suspense: true }\n): Resolve<LiveblocksFlowSuspenseResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> = {}\n): Resolve<UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>> {\n const history = useHistory();\n const isStorageLoaded = useStorage(() => true) ?? false;\n\n // These options are not reactive, only their initial values are used.\n const frozenOptions = useInitial({\n nodes: options.nodes,\n edges: options.edges,\n storageKey: options.storageKey ?? DEFAULT_STORAGE_KEY,\n suspense: options.suspense ?? false,\n });\n\n // Pre-compute sync config caches once (not on every render)\n const [getNodeSyncConfig, getEdgeSyncConfig] = useMemo(\n () =>\n [\n buildNodeConfigCache(frozenOptions.nodes?.sync),\n buildEdgeConfigCache(frozenOptions.edges?.sync),\n ] as const,\n [frozenOptions]\n );\n\n const { nodes, edges } = useNodesAndEdges<N, E>(frozenOptions.storageKey);\n\n const onNodesChange = useMutation(\n ({ storage }, changes: NodeChange<N>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyNodeChanges(changes, flow.get(\"nodes\"), history, getNodeSyncConfig);\n },\n [history, frozenOptions, getNodeSyncConfig]\n );\n\n const onEdgesChange = useMutation(\n ({ storage }, changes: EdgeChange<E>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyEdgeChanges(changes, flow.get(\"edges\"), getEdgeSyncConfig);\n },\n [frozenOptions, getEdgeSyncConfig]\n );\n\n const onConnect = useMutation(\n ({ storage }, connection: Connection) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n // Delegate to React Flow's own `addEdge` helper for consistent default\n // edge ID generation, passing an empty array since de-duplication is\n // already handled above.\n const [newEdge] = defaultAddEdge(connection, [] as E[]);\n if (!newEdge) {\n return;\n }\n\n const edges = flow.get(\"edges\");\n const config = getEdgeSyncConfig(newEdge.type);\n edges.set(newEdge.id, toLiveblocksInternalEdge(newEdge, config));\n },\n [frozenOptions.storageKey, getEdgeSyncConfig]\n );\n\n const onDelete = useMutation(\n ({ storage }, params: { nodes: N[]; edges: E[] }) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n const nodesMap = flow.get(\"nodes\");\n const edgesMap = flow.get(\"edges\");\n\n for (const edge of params.edges) {\n edgesMap.delete(edge.id);\n }\n\n for (const node of params.nodes) {\n nodesMap.delete(node.id);\n }\n },\n [frozenOptions.storageKey]\n );\n\n const setInitialStorage = useMutation(\n ({ storage }) => {\n // Similarly to `initialStorage` on `Client.enterRoom` and `RoomProvider`, we only\n // initialize Storage if it doesn't already exist.\n if (storage.get(frozenOptions.storageKey) !== undefined) {\n return;\n }\n\n const initialNodes = frozenOptions.nodes?.initial ?? [];\n const initialEdges = frozenOptions.edges?.initial ?? [];\n\n storage.set(\n frozenOptions.storageKey,\n new LiveObject({\n nodes: new LiveMap(\n initialNodes.map((node) => [\n node.id,\n toLiveblocksInternalNode(node, getNodeSyncConfig(node.type)),\n ])\n ),\n edges: new LiveMap(\n initialEdges.map((edge) => [\n edge.id,\n toLiveblocksInternalEdge(edge, getEdgeSyncConfig(edge.type)),\n ])\n ),\n })\n );\n },\n [frozenOptions, getNodeSyncConfig, getEdgeSyncConfig]\n );\n\n useEffect(() => {\n if (isStorageLoaded) {\n history[kInternal].withoutHistory(() => {\n setInitialStorage();\n });\n }\n }, [isStorageLoaded, setInitialStorage, history]);\n\n if (frozenOptions.suspense) {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- `suspense` is frozen so this branch is stable\n useSuspendUntilStorageReady();\n }\n\n return {\n nodes: frozenOptions.suspense ? (nodes ?? (EMPTY_ARRAY as N[])) : nodes,\n edges: frozenOptions.suspense ? (edges ?? (EMPTY_ARRAY as E[])) : edges,\n isLoading: frozenOptions.suspense ? false : !isStorageLoaded,\n onNodesChange,\n onEdgesChange,\n onConnect,\n onDelete,\n } as UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>;\n}\n"],"names":["toLiveblocksInternalNode","toLiveblocksInternalEdge","useStorage","useMemo","useHistory","useInitial","DEFAULT_STORAGE_KEY","buildNodeConfigCache","buildEdgeConfigCache","useMutation","defaultAddEdge","edges","LiveObject","LiveMap","useEffect","kInternal","useSuspendUntilStorageReady"],"mappings":"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"}
|
|
@@ -1,35 +1,11 @@
|
|
|
1
1
|
import { LiveObject, LiveMap, kInternal } from '@liveblocks/core';
|
|
2
|
-
import {
|
|
2
|
+
import { useStorage, useHistory, useMutation } from '@liveblocks/react';
|
|
3
3
|
import { useInitial, useSuspendUntilStorageReady } from '@liveblocks/react/_private';
|
|
4
4
|
import { addEdge } from '@xyflow/react';
|
|
5
5
|
import { useMemo, useEffect } from 'react';
|
|
6
|
-
import {
|
|
7
|
-
import { toLiveblocksInternalNode, toLiveblocksInternalEdge } from './helpers.js';
|
|
6
|
+
import { toLiveblocksInternalNode, toLiveblocksInternalEdge, DEFAULT_STORAGE_KEY, buildNodeConfigCache, buildEdgeConfigCache } from './shared.js';
|
|
8
7
|
|
|
9
8
|
const EMPTY_ARRAY = [];
|
|
10
|
-
function mergeAndBuildDataConfigCache(base, data) {
|
|
11
|
-
if (!data)
|
|
12
|
-
return () => base;
|
|
13
|
-
const dataFallback = data["*"];
|
|
14
|
-
const fallback = dataFallback ? { ...base, data: dataFallback } : base;
|
|
15
|
-
const cache = /* @__PURE__ */ new Map();
|
|
16
|
-
for (const type in data) {
|
|
17
|
-
if (type === "*")
|
|
18
|
-
continue;
|
|
19
|
-
const specific = data[type];
|
|
20
|
-
if (!specific)
|
|
21
|
-
continue;
|
|
22
|
-
const dataConfig = { ...dataFallback, ...specific };
|
|
23
|
-
cache.set(type, { ...base, data: dataConfig });
|
|
24
|
-
}
|
|
25
|
-
return (type) => cache.get(type) || fallback;
|
|
26
|
-
}
|
|
27
|
-
function buildNodeConfigCache(nodeDataConfig) {
|
|
28
|
-
return mergeAndBuildDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);
|
|
29
|
-
}
|
|
30
|
-
function buildEdgeConfigCache(edgeDataConfig) {
|
|
31
|
-
return mergeAndBuildDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);
|
|
32
|
-
}
|
|
33
9
|
function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
|
|
34
10
|
for (const change of changes) {
|
|
35
11
|
switch (change.type) {
|
|
@@ -135,6 +111,29 @@ function applyEdgeChanges(changes, edges, getEdgeSyncConfig) {
|
|
|
135
111
|
}
|
|
136
112
|
}
|
|
137
113
|
}
|
|
114
|
+
function nodeMapToList(nodesMap) {
|
|
115
|
+
if (nodesMap === null)
|
|
116
|
+
return null;
|
|
117
|
+
return Object.values(nodesMap);
|
|
118
|
+
}
|
|
119
|
+
function edgeMapToList(edgesMap) {
|
|
120
|
+
if (edgesMap === null)
|
|
121
|
+
return null;
|
|
122
|
+
return Object.values(edgesMap);
|
|
123
|
+
}
|
|
124
|
+
function useNodesAndEdges(storageKey) {
|
|
125
|
+
const nodesMap = useStorage((storage) => {
|
|
126
|
+
const flow = storage[storageKey];
|
|
127
|
+
return flow?.nodes ?? null;
|
|
128
|
+
});
|
|
129
|
+
const edgesMap = useStorage((storage) => {
|
|
130
|
+
const flow = storage[storageKey];
|
|
131
|
+
return flow?.edges ?? null;
|
|
132
|
+
});
|
|
133
|
+
const nodes = useMemo(() => nodeMapToList(nodesMap), [nodesMap]);
|
|
134
|
+
const edges = useMemo(() => edgeMapToList(edgesMap), [edgesMap]);
|
|
135
|
+
return { nodes, edges };
|
|
136
|
+
}
|
|
138
137
|
function useLiveblocksFlow(options = {}) {
|
|
139
138
|
const history = useHistory();
|
|
140
139
|
const isStorageLoaded = useStorage(() => true) ?? false;
|
|
@@ -151,14 +150,7 @@ function useLiveblocksFlow(options = {}) {
|
|
|
151
150
|
],
|
|
152
151
|
[frozenOptions]
|
|
153
152
|
);
|
|
154
|
-
const nodes =
|
|
155
|
-
const flow = storage[frozenOptions.storageKey];
|
|
156
|
-
return flow?.nodes ? [...flow.nodes.values()] : null;
|
|
157
|
-
});
|
|
158
|
-
const edges = useStorage((storage) => {
|
|
159
|
-
const flow = storage[frozenOptions.storageKey];
|
|
160
|
-
return flow?.edges ? [...flow.edges.values()] : null;
|
|
161
|
-
});
|
|
153
|
+
const { nodes, edges } = useNodesAndEdges(frozenOptions.storageKey);
|
|
162
154
|
const onNodesChange = useMutation(
|
|
163
155
|
({ storage }, changes) => {
|
|
164
156
|
const flow = storage.get(frozenOptions.storageKey);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.js","sources":["../../src/lib/flow.ts"],"sourcesContent":["import type {\n History,\n JsonObject,\n ReadonlyJsonObject,\n Resolve,\n ToJson,\n} from \"@liveblocks/core\";\nimport { kInternal, LiveMap, LiveObject } from \"@liveblocks/core\";\nimport { useHistory, useMutation, useStorage } from \"@liveblocks/react\";\nimport {\n useInitial,\n useSuspendUntilStorageReady,\n} from \"@liveblocks/react/_private\";\nimport type {\n BuiltInEdge,\n BuiltInNode,\n Connection,\n Edge,\n EdgeChange,\n Node,\n NodeChange,\n OnConnect,\n OnDelete,\n OnEdgesChange,\n OnNodesChange,\n} from \"@xyflow/react\";\nimport { addEdge as defaultAddEdge } from \"@xyflow/react\";\nimport { useEffect, useMemo } from \"react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksEdge,\n InternalLiveblocksFlow,\n InternalLiveblocksNode,\n NodeSyncConfig,\n SyncConfig,\n} from \"./types\";\n\nconst EMPTY_ARRAY = [] as unknown[];\n\ntype UseLiveblocksFlowResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Resolve<\n (\n | {\n nodes: null;\n edges: null;\n isLoading: true;\n }\n | {\n nodes: N[];\n edges: E[];\n isLoading: false;\n }\n ) & {\n onNodesChange: OnNodesChange<N>;\n onEdgesChange: OnEdgesChange<E>;\n onConnect: OnConnect;\n onDelete: OnDelete<N, E>;\n }\n>;\n\ntype LiveblocksFlowSuspenseResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Extract<UseLiveblocksFlowResult<N, E>, { isLoading: false }>;\n\ntype UseLiveblocksFlowOptions<N extends Node, E extends Edge> = {\n nodes?: {\n /**\n * The initial React Flow nodes.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * initial: [\n * { id: \"1\", position: { x: 0, y: 0 }, data: { label: \"Node 1\" } },\n * { id: \"2\", position: { x: 0, y: 100 }, data: { label: \"Node 2\" } },\n * ],\n * },\n * });\n * ```\n */\n initial?: N[];\n /**\n * Per-type sync configuration for node data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all node types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * sync: {\n * \"*\": {\n * label: false, // Don't sync node.data.label\n * color: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomNode: {\n * showPreview: false, // Don't sync myCustomNode.data.showPreview\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: NodeSyncConfig<N>;\n };\n\n edges?: {\n initial?: E[];\n /**\n * Per-type sync configuration for edge data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all edge types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * edges: {\n * sync: {\n * \"*\": {\n * hovered: false, // Don't sync edge.data.hovered\n * style: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomEdge: {\n * isHighlighted: false, // Don't sync myCustomEdge.data.isHighlighted\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: EdgeSyncConfig<E>;\n };\n\n /**\n * The key used to store the React Flow diagram in Liveblocks Storage.\n * Defaults to `\"flow\"`.\n */\n storageKey?: string;\n\n /**\n * When true, suspends until Storage is ready (use a React `Suspense`\n * boundary). Then `nodes` and `edges` are always arrays and `isLoading` is\n * always false.\n */\n suspense?: boolean;\n};\n\n// Similar to React Flow's `applyNodeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-node-changes\nfunction applyNodeChanges<N extends Node>(\n changes: NodeChange<N>[],\n nodes: LiveMap<string, InternalLiveblocksNode>,\n history: History,\n getNodeSyncConfig: (nodeType: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getNodeSyncConfig(change.item.type);\n const existing = nodes.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n nodes.set(\n change.item.id,\n toLiveblocksInternalNode(change.item, config)\n );\n }\n break;\n }\n\n case \"position\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.dragging === true) {\n history.pause();\n }\n\n if (change.position !== undefined) {\n const prev = node.get(\"position\");\n if (prev?.x !== change.position.x || prev?.y !== change.position.y) {\n node.set(\"position\", change.position);\n }\n }\n\n if (change.dragging !== undefined) {\n if (change.dragging === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `dragging: false`\n node.setLocal(\"dragging\", change.dragging);\n }\n break;\n }\n\n case \"dimensions\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.resizing === true) {\n history.pause();\n }\n\n if (\n change.dimensions !== undefined &&\n change.setAttributes !== undefined\n ) {\n if (\n change.setAttributes === true ||\n change.setAttributes === \"width\"\n ) {\n node.set(\"width\", change.dimensions.width);\n }\n\n if (\n change.setAttributes === true ||\n change.setAttributes === \"height\"\n ) {\n node.set(\"height\", change.dimensions.height);\n }\n }\n\n if (change.dimensions !== undefined) {\n // Must match NODE_BASE_CONFIG's `measured: false`\n node.setLocal(\"measured\", change.dimensions);\n }\n\n if (change.resizing !== undefined) {\n if (change.resizing === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `resizing: false`\n node.setLocal(\"resizing\", change.resizing);\n }\n\n break;\n }\n\n case \"select\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Must match NODE_BASE_CONFIG's `selected: false`\n node.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// Similar to React Flow's `applyEdgeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-edge-changes\nfunction applyEdgeChanges<E extends Edge>(\n changes: EdgeChange<E>[],\n edges: LiveMap<string, InternalLiveblocksEdge>,\n getEdgeSyncConfig: (type: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getEdgeSyncConfig(change.item.type);\n const existing = edges.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n edges.set(\n change.item.id,\n toLiveblocksInternalEdge(change.item, config)\n );\n }\n break;\n }\n\n case \"select\": {\n const edge = edges.get(change.id);\n if (!edge) break;\n // Must match EDGE_BASE_CONFIG's `selected: false`\n edge.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n// in topological order (parents before children), deferring any node with a\n// parentId until its parent has been emitted.\nfunction nodeMapToList<N extends Node>(\n nodesMap: ReadonlyJsonObject | null\n): N[] | null {\n if (nodesMap === null) return null;\n return Object.values(nodesMap) as unknown as N[];\n}\n\nfunction edgeMapToList<E extends Edge>(\n edgesMap: ReadonlyJsonObject | null\n): E[] | null {\n if (edgesMap === null) return null;\n return Object.values(edgesMap) as unknown as E[];\n}\n\nfunction useNodesAndEdges<N extends Node, E extends Edge>(storageKey: string) {\n // Storage already includes local overlays via toJSON(), so no separate local\n // layer is needed. Individual node/edge immutable references are already\n // stable (only change when the underlying LiveObject changes).\n const nodesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.nodes ?? null;\n });\n const edgesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.edges ?? null;\n });\n\n const nodes = useMemo(() => nodeMapToList<N>(nodesMap), [nodesMap]);\n const edges = useMemo(() => edgeMapToList<E>(edgesMap), [edgesMap]);\n return { nodes, edges };\n}\n\n/**\n * Returns a controlled React Flow state backed by Liveblocks Storage.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete, isLoading } = useLiveblocksFlow();\n *\n * if (isLoading) {\n * return <div>Loading…</div>\n * }\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n * Pass `{ suspense: true }` to suspend until Storage is ready, `nodes` and `edges` will never be `null`.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete } =\n * useLiveblocksFlow({ suspense: true });\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n */\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options?: UseLiveblocksFlowOptions<N, E> & { suspense?: false }\n): Resolve<UseLiveblocksFlowResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> & { suspense: true }\n): Resolve<LiveblocksFlowSuspenseResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> = {}\n): Resolve<UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>> {\n const history = useHistory();\n const isStorageLoaded = useStorage(() => true) ?? false;\n\n // These options are not reactive, only their initial values are used.\n const frozenOptions = useInitial({\n nodes: options.nodes,\n edges: options.edges,\n storageKey: options.storageKey ?? DEFAULT_STORAGE_KEY,\n suspense: options.suspense ?? false,\n });\n\n // Pre-compute sync config caches once (not on every render)\n const [getNodeSyncConfig, getEdgeSyncConfig] = useMemo(\n () =>\n [\n buildNodeConfigCache(frozenOptions.nodes?.sync),\n buildEdgeConfigCache(frozenOptions.edges?.sync),\n ] as const,\n [frozenOptions]\n );\n\n const { nodes, edges } = useNodesAndEdges<N, E>(frozenOptions.storageKey);\n\n const onNodesChange = useMutation(\n ({ storage }, changes: NodeChange<N>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyNodeChanges(changes, flow.get(\"nodes\"), history, getNodeSyncConfig);\n },\n [history, frozenOptions, getNodeSyncConfig]\n );\n\n const onEdgesChange = useMutation(\n ({ storage }, changes: EdgeChange<E>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyEdgeChanges(changes, flow.get(\"edges\"), getEdgeSyncConfig);\n },\n [frozenOptions, getEdgeSyncConfig]\n );\n\n const onConnect = useMutation(\n ({ storage }, connection: Connection) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n // Delegate to React Flow's own `addEdge` helper for consistent default\n // edge ID generation, passing an empty array since de-duplication is\n // already handled above.\n const [newEdge] = defaultAddEdge(connection, [] as E[]);\n if (!newEdge) {\n return;\n }\n\n const edges = flow.get(\"edges\");\n const config = getEdgeSyncConfig(newEdge.type);\n edges.set(newEdge.id, toLiveblocksInternalEdge(newEdge, config));\n },\n [frozenOptions.storageKey, getEdgeSyncConfig]\n );\n\n const onDelete = useMutation(\n ({ storage }, params: { nodes: N[]; edges: E[] }) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n const nodesMap = flow.get(\"nodes\");\n const edgesMap = flow.get(\"edges\");\n\n for (const edge of params.edges) {\n edgesMap.delete(edge.id);\n }\n\n for (const node of params.nodes) {\n nodesMap.delete(node.id);\n }\n },\n [frozenOptions.storageKey]\n );\n\n const setInitialStorage = useMutation(\n ({ storage }) => {\n // Similarly to `initialStorage` on `Client.enterRoom` and `RoomProvider`, we only\n // initialize Storage if it doesn't already exist.\n if (storage.get(frozenOptions.storageKey) !== undefined) {\n return;\n }\n\n const initialNodes = frozenOptions.nodes?.initial ?? [];\n const initialEdges = frozenOptions.edges?.initial ?? [];\n\n storage.set(\n frozenOptions.storageKey,\n new LiveObject({\n nodes: new LiveMap(\n initialNodes.map((node) => [\n node.id,\n toLiveblocksInternalNode(node, getNodeSyncConfig(node.type)),\n ])\n ),\n edges: new LiveMap(\n initialEdges.map((edge) => [\n edge.id,\n toLiveblocksInternalEdge(edge, getEdgeSyncConfig(edge.type)),\n ])\n ),\n })\n );\n },\n [frozenOptions, getNodeSyncConfig, getEdgeSyncConfig]\n );\n\n useEffect(() => {\n if (isStorageLoaded) {\n history[kInternal].withoutHistory(() => {\n setInitialStorage();\n });\n }\n }, [isStorageLoaded, setInitialStorage, history]);\n\n if (frozenOptions.suspense) {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- `suspense` is frozen so this branch is stable\n useSuspendUntilStorageReady();\n }\n\n return {\n nodes: frozenOptions.suspense ? (nodes ?? (EMPTY_ARRAY as N[])) : nodes,\n edges: frozenOptions.suspense ? (edges ?? (EMPTY_ARRAY as E[])) : edges,\n isLoading: frozenOptions.suspense ? false : !isStorageLoaded,\n onNodesChange,\n onEdgesChange,\n onConnect,\n onDelete,\n } as UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>;\n}\n"],"names":["defaultAddEdge","edges"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@liveblocks/core');
|
|
4
|
+
|
|
5
|
+
const DEFAULT_STORAGE_KEY = "flow";
|
|
6
|
+
const NODE_BASE_CONFIG = {
|
|
7
|
+
// Local-only (not synced)
|
|
8
|
+
selected: false,
|
|
9
|
+
dragging: false,
|
|
10
|
+
measured: false,
|
|
11
|
+
resizing: false,
|
|
12
|
+
// Atomic (synced as plain Json)
|
|
13
|
+
position: "atomic",
|
|
14
|
+
sourcePosition: "atomic",
|
|
15
|
+
targetPosition: "atomic",
|
|
16
|
+
extent: "atomic",
|
|
17
|
+
origin: "atomic",
|
|
18
|
+
handles: "atomic"
|
|
19
|
+
// Note: the `data` key is intentionally left out of this base config, as it
|
|
20
|
+
// is expected to be provided by the end user
|
|
21
|
+
};
|
|
22
|
+
const EDGE_BASE_CONFIG = {
|
|
23
|
+
// Local-only (not synced)
|
|
24
|
+
selected: false,
|
|
25
|
+
// Atomic (synced as plain Json)
|
|
26
|
+
markerStart: "atomic",
|
|
27
|
+
markerEnd: "atomic",
|
|
28
|
+
label: "atomic",
|
|
29
|
+
labelBgPadding: "atomic"
|
|
30
|
+
// Note: the `data` key is intentionally left out of this base config, as it
|
|
31
|
+
// is expected to be provided by the end user
|
|
32
|
+
};
|
|
33
|
+
function buildFlowDataConfigCache(base, data) {
|
|
34
|
+
if (!data)
|
|
35
|
+
return () => base;
|
|
36
|
+
const dataFallback = data["*"];
|
|
37
|
+
const fallback = dataFallback ? { ...base, data: dataFallback } : base;
|
|
38
|
+
const cache = /* @__PURE__ */ new Map();
|
|
39
|
+
for (const type in data) {
|
|
40
|
+
if (type === "*")
|
|
41
|
+
continue;
|
|
42
|
+
const specific = data[type];
|
|
43
|
+
if (!specific)
|
|
44
|
+
continue;
|
|
45
|
+
const dataConfig = { ...dataFallback, ...specific };
|
|
46
|
+
cache.set(type, { ...base, data: dataConfig });
|
|
47
|
+
}
|
|
48
|
+
return (type) => cache.get(type) || fallback;
|
|
49
|
+
}
|
|
50
|
+
function buildNodeConfigCache(nodeDataConfig) {
|
|
51
|
+
return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);
|
|
52
|
+
}
|
|
53
|
+
function buildEdgeConfigCache(edgeDataConfig) {
|
|
54
|
+
return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);
|
|
55
|
+
}
|
|
56
|
+
function toLiveblocksInternalNode(node, config) {
|
|
57
|
+
return core.LiveObject.from(
|
|
58
|
+
node,
|
|
59
|
+
config
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
function toLiveblocksInternalEdge(edge, config) {
|
|
63
|
+
return core.LiveObject.from(
|
|
64
|
+
edge,
|
|
65
|
+
config
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
exports.DEFAULT_STORAGE_KEY = DEFAULT_STORAGE_KEY;
|
|
70
|
+
exports.EDGE_BASE_CONFIG = EDGE_BASE_CONFIG;
|
|
71
|
+
exports.NODE_BASE_CONFIG = NODE_BASE_CONFIG;
|
|
72
|
+
exports.buildEdgeConfigCache = buildEdgeConfigCache;
|
|
73
|
+
exports.buildFlowDataConfigCache = buildFlowDataConfigCache;
|
|
74
|
+
exports.buildNodeConfigCache = buildNodeConfigCache;
|
|
75
|
+
exports.toLiveblocksInternalEdge = toLiveblocksInternalEdge;
|
|
76
|
+
exports.toLiveblocksInternalNode = toLiveblocksInternalNode;
|
|
77
|
+
//# sourceMappingURL=shared.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.cjs","sources":["../../src/lib/shared.ts"],"sourcesContent":["/**\n * Module with utilities shared between the React Flow frontend and the React\n * Flow Node backend. There are no runtime dependencies on @xyflow/react,\n * react, or any other frontend-specific libraries from this module, and this\n * should stay that way.\n */\nimport type { JsonObject, SyncConfig, SyncMode } from \"@liveblocks/core\";\nimport { LiveObject } from \"@liveblocks/core\";\nimport type { Edge, Node } from \"@xyflow/react\";\n\nimport type { InternalLiveblocksEdge, InternalLiveblocksNode } from \"./types\";\n\nexport const DEFAULT_STORAGE_KEY = \"flow\";\n\n// React Flow specific versions of `SyncConfig` that only allow keys that are actually exposed by React Flow.\ntype NodeSyncConfig = { [K in keyof Node]?: SyncMode };\ntype EdgeSyncConfig = { [K in keyof Edge]?: SyncMode };\n\nexport const NODE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n dragging: false,\n measured: false,\n resizing: false,\n\n // Atomic (synced as plain Json)\n position: \"atomic\",\n sourcePosition: \"atomic\",\n targetPosition: \"atomic\",\n extent: \"atomic\",\n origin: \"atomic\",\n handles: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies NodeSyncConfig;\n\nexport const EDGE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n\n // Atomic (synced as plain Json)\n markerStart: \"atomic\",\n markerEnd: \"atomic\",\n label: \"atomic\",\n labelBgPadding: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies EdgeSyncConfig;\n\n/**\n * Merges a base config with per-type user data configs, returning a lookup\n * function that resolves the full SyncConfig for a given type string.\n */\nexport function buildFlowDataConfigCache(\n base: SyncConfig,\n data?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n if (!data) return () => base;\n\n const dataFallback = data[\"*\"];\n const fallback = dataFallback ? { ...base, data: dataFallback } : base;\n\n // Pre-compute full sync configs for all explicitly declared types\n const cache = new Map<string | undefined, SyncConfig>();\n for (const type in data) {\n if (type === \"*\") continue;\n const specific = data[type];\n if (!specific) continue;\n const dataConfig: SyncConfig = { ...dataFallback, ...specific };\n cache.set(type, { ...base, data: dataConfig });\n }\n\n return (type) => cache.get(type) || fallback;\n}\n\nexport function buildNodeConfigCache(\n nodeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);\n}\n\nexport function buildEdgeConfigCache(\n edgeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);\n}\n\nexport function toLiveblocksInternalNode<N extends Node>(\n node: N,\n config: SyncConfig\n): InternalLiveblocksNode {\n return LiveObject.from(\n node as unknown as JsonObject,\n config\n ) as InternalLiveblocksNode;\n}\n\nexport function toLiveblocksInternalEdge<E extends Edge>(\n edge: E,\n config: SyncConfig\n): InternalLiveblocksEdge {\n return LiveObject.from(\n edge as unknown as JsonObject,\n config\n ) as InternalLiveblocksEdge;\n}\n"],"names":["LiveObject"],"mappings":";;;;AAYO,MAAM,mBAAsB,GAAA,OAAA;AAM5B,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,QAAU,EAAA,QAAA;AAAA,EACV,cAAgB,EAAA,QAAA;AAAA,EAChB,cAAgB,EAAA,QAAA;AAAA,EAChB,MAAQ,EAAA,QAAA;AAAA,EACR,MAAQ,EAAA,QAAA;AAAA,EACR,OAAS,EAAA,QAAA;AAAA;AAAA;AAIX,EAAA;AAEO,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,WAAa,EAAA,QAAA;AAAA,EACb,SAAW,EAAA,QAAA;AAAA,EACX,KAAO,EAAA,QAAA;AAAA,EACP,cAAgB,EAAA,QAAA;AAAA;AAAA;AAIlB,EAAA;AAMgB,SAAA,wBAAA,CACd,MACA,IAC0C,EAAA;AAC1C,EAAA,IAAI,CAAC,IAAA;AAAM,IAAA,OAAO,MAAM,IAAA,CAAA;AAExB,EAAM,MAAA,YAAA,GAAe,KAAK,GAAG,CAAA,CAAA;AAC7B,EAAA,MAAM,WAAW,YAAe,GAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,cAAiB,GAAA,IAAA,CAAA;AAGlE,EAAM,MAAA,KAAA,uBAAY,GAAoC,EAAA,CAAA;AACtD,EAAA,KAAA,MAAW,QAAQ,IAAM,EAAA;AACvB,IAAA,IAAI,IAAS,KAAA,GAAA;AAAK,MAAA,SAAA;AAClB,IAAM,MAAA,QAAA,GAAW,KAAK,IAAI,CAAA,CAAA;AAC1B,IAAA,IAAI,CAAC,QAAA;AAAU,MAAA,SAAA;AACf,IAAA,MAAM,UAAyB,GAAA,EAAE,GAAG,YAAA,EAAc,GAAG,QAAS,EAAA,CAAA;AAC9D,IAAA,KAAA,CAAM,IAAI,IAAM,EAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,YAAY,CAAA,CAAA;AAAA,GAC/C;AAEA,EAAA,OAAO,CAAC,IAAA,KAAS,KAAM,CAAA,GAAA,CAAI,IAAI,CAAK,IAAA,QAAA,CAAA;AACtC,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAOA,eAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAOA,eAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF;;;;;;;;;;;"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { LiveObject } from '@liveblocks/core';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_STORAGE_KEY = "flow";
|
|
4
|
+
const NODE_BASE_CONFIG = {
|
|
5
|
+
// Local-only (not synced)
|
|
6
|
+
selected: false,
|
|
7
|
+
dragging: false,
|
|
8
|
+
measured: false,
|
|
9
|
+
resizing: false,
|
|
10
|
+
// Atomic (synced as plain Json)
|
|
11
|
+
position: "atomic",
|
|
12
|
+
sourcePosition: "atomic",
|
|
13
|
+
targetPosition: "atomic",
|
|
14
|
+
extent: "atomic",
|
|
15
|
+
origin: "atomic",
|
|
16
|
+
handles: "atomic"
|
|
17
|
+
// Note: the `data` key is intentionally left out of this base config, as it
|
|
18
|
+
// is expected to be provided by the end user
|
|
19
|
+
};
|
|
20
|
+
const EDGE_BASE_CONFIG = {
|
|
21
|
+
// Local-only (not synced)
|
|
22
|
+
selected: false,
|
|
23
|
+
// Atomic (synced as plain Json)
|
|
24
|
+
markerStart: "atomic",
|
|
25
|
+
markerEnd: "atomic",
|
|
26
|
+
label: "atomic",
|
|
27
|
+
labelBgPadding: "atomic"
|
|
28
|
+
// Note: the `data` key is intentionally left out of this base config, as it
|
|
29
|
+
// is expected to be provided by the end user
|
|
30
|
+
};
|
|
31
|
+
function buildFlowDataConfigCache(base, data) {
|
|
32
|
+
if (!data)
|
|
33
|
+
return () => base;
|
|
34
|
+
const dataFallback = data["*"];
|
|
35
|
+
const fallback = dataFallback ? { ...base, data: dataFallback } : base;
|
|
36
|
+
const cache = /* @__PURE__ */ new Map();
|
|
37
|
+
for (const type in data) {
|
|
38
|
+
if (type === "*")
|
|
39
|
+
continue;
|
|
40
|
+
const specific = data[type];
|
|
41
|
+
if (!specific)
|
|
42
|
+
continue;
|
|
43
|
+
const dataConfig = { ...dataFallback, ...specific };
|
|
44
|
+
cache.set(type, { ...base, data: dataConfig });
|
|
45
|
+
}
|
|
46
|
+
return (type) => cache.get(type) || fallback;
|
|
47
|
+
}
|
|
48
|
+
function buildNodeConfigCache(nodeDataConfig) {
|
|
49
|
+
return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);
|
|
50
|
+
}
|
|
51
|
+
function buildEdgeConfigCache(edgeDataConfig) {
|
|
52
|
+
return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);
|
|
53
|
+
}
|
|
54
|
+
function toLiveblocksInternalNode(node, config) {
|
|
55
|
+
return LiveObject.from(
|
|
56
|
+
node,
|
|
57
|
+
config
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function toLiveblocksInternalEdge(edge, config) {
|
|
61
|
+
return LiveObject.from(
|
|
62
|
+
edge,
|
|
63
|
+
config
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { DEFAULT_STORAGE_KEY, EDGE_BASE_CONFIG, NODE_BASE_CONFIG, buildEdgeConfigCache, buildFlowDataConfigCache, buildNodeConfigCache, toLiveblocksInternalEdge, toLiveblocksInternalNode };
|
|
68
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sources":["../../src/lib/shared.ts"],"sourcesContent":["/**\n * Module with utilities shared between the React Flow frontend and the React\n * Flow Node backend. There are no runtime dependencies on @xyflow/react,\n * react, or any other frontend-specific libraries from this module, and this\n * should stay that way.\n */\nimport type { JsonObject, SyncConfig, SyncMode } from \"@liveblocks/core\";\nimport { LiveObject } from \"@liveblocks/core\";\nimport type { Edge, Node } from \"@xyflow/react\";\n\nimport type { InternalLiveblocksEdge, InternalLiveblocksNode } from \"./types\";\n\nexport const DEFAULT_STORAGE_KEY = \"flow\";\n\n// React Flow specific versions of `SyncConfig` that only allow keys that are actually exposed by React Flow.\ntype NodeSyncConfig = { [K in keyof Node]?: SyncMode };\ntype EdgeSyncConfig = { [K in keyof Edge]?: SyncMode };\n\nexport const NODE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n dragging: false,\n measured: false,\n resizing: false,\n\n // Atomic (synced as plain Json)\n position: \"atomic\",\n sourcePosition: \"atomic\",\n targetPosition: \"atomic\",\n extent: \"atomic\",\n origin: \"atomic\",\n handles: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies NodeSyncConfig;\n\nexport const EDGE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n\n // Atomic (synced as plain Json)\n markerStart: \"atomic\",\n markerEnd: \"atomic\",\n label: \"atomic\",\n labelBgPadding: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies EdgeSyncConfig;\n\n/**\n * Merges a base config with per-type user data configs, returning a lookup\n * function that resolves the full SyncConfig for a given type string.\n */\nexport function buildFlowDataConfigCache(\n base: SyncConfig,\n data?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n if (!data) return () => base;\n\n const dataFallback = data[\"*\"];\n const fallback = dataFallback ? { ...base, data: dataFallback } : base;\n\n // Pre-compute full sync configs for all explicitly declared types\n const cache = new Map<string | undefined, SyncConfig>();\n for (const type in data) {\n if (type === \"*\") continue;\n const specific = data[type];\n if (!specific) continue;\n const dataConfig: SyncConfig = { ...dataFallback, ...specific };\n cache.set(type, { ...base, data: dataConfig });\n }\n\n return (type) => cache.get(type) || fallback;\n}\n\nexport function buildNodeConfigCache(\n nodeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);\n}\n\nexport function buildEdgeConfigCache(\n edgeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);\n}\n\nexport function toLiveblocksInternalNode<N extends Node>(\n node: N,\n config: SyncConfig\n): InternalLiveblocksNode {\n return LiveObject.from(\n node as unknown as JsonObject,\n config\n ) as InternalLiveblocksNode;\n}\n\nexport function toLiveblocksInternalEdge<E extends Edge>(\n edge: E,\n config: SyncConfig\n): InternalLiveblocksEdge {\n return LiveObject.from(\n edge as unknown as JsonObject,\n config\n ) as InternalLiveblocksEdge;\n}\n"],"names":[],"mappings":";;AAYO,MAAM,mBAAsB,GAAA,OAAA;AAM5B,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,QAAU,EAAA,QAAA;AAAA,EACV,cAAgB,EAAA,QAAA;AAAA,EAChB,cAAgB,EAAA,QAAA;AAAA,EAChB,MAAQ,EAAA,QAAA;AAAA,EACR,MAAQ,EAAA,QAAA;AAAA,EACR,OAAS,EAAA,QAAA;AAAA;AAAA;AAIX,EAAA;AAEO,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,WAAa,EAAA,QAAA;AAAA,EACb,SAAW,EAAA,QAAA;AAAA,EACX,KAAO,EAAA,QAAA;AAAA,EACP,cAAgB,EAAA,QAAA;AAAA;AAAA;AAIlB,EAAA;AAMgB,SAAA,wBAAA,CACd,MACA,IAC0C,EAAA;AAC1C,EAAA,IAAI,CAAC,IAAA;AAAM,IAAA,OAAO,MAAM,IAAA,CAAA;AAExB,EAAM,MAAA,YAAA,GAAe,KAAK,GAAG,CAAA,CAAA;AAC7B,EAAA,MAAM,WAAW,YAAe,GAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,cAAiB,GAAA,IAAA,CAAA;AAGlE,EAAM,MAAA,KAAA,uBAAY,GAAoC,EAAA,CAAA;AACtD,EAAA,KAAA,MAAW,QAAQ,IAAM,EAAA;AACvB,IAAA,IAAI,IAAS,KAAA,GAAA;AAAK,MAAA,SAAA;AAClB,IAAM,MAAA,QAAA,GAAW,KAAK,IAAI,CAAA,CAAA;AAC1B,IAAA,IAAI,CAAC,QAAA;AAAU,MAAA,SAAA;AACf,IAAA,MAAM,UAAyB,GAAA,EAAE,GAAG,YAAA,EAAc,GAAG,QAAS,EAAA,CAAA;AAC9D,IAAA,KAAA,CAAM,IAAI,IAAM,EAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,YAAY,CAAA,CAAA;AAAA,GAC/C;AAEA,EAAA,OAAO,CAAC,IAAA,KAAS,KAAM,CAAA,GAAA,CAAI,IAAI,CAAK,IAAA,QAAA,CAAA;AACtC,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAO,UAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAO,UAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF;;;;"}
|