f1ow 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,428 +0,0 @@
1
- import * as Y from "yjs";
2
- import { useCanvasStore } from "./f1ow.js";
3
- import { getYElements, getYDoc } from "./yjsProvider-mWrSFiNG.js";
4
- const SYNC_FIELDS = [
5
- "id",
6
- "type",
7
- "x",
8
- "y",
9
- "width",
10
- "height",
11
- "rotation",
12
- "isLocked",
13
- "isVisible",
14
- "sortOrder",
15
- "version"
16
- ];
17
- const STYLE_FIELDS = [
18
- "strokeColor",
19
- "fillColor",
20
- "strokeWidth",
21
- "opacity",
22
- "strokeStyle",
23
- "roughness",
24
- "fontSize",
25
- "fontFamily"
26
- ];
27
- function elementToYMap(el, yMap) {
28
- const elRecord = el;
29
- for (const field of SYNC_FIELDS) {
30
- const value = elRecord[field];
31
- if (value !== void 0) {
32
- yMap.set(field, value);
33
- }
34
- }
35
- if (el.style) {
36
- for (const sf of STYLE_FIELDS) {
37
- yMap.set(`style.${sf}`, el.style[sf]);
38
- }
39
- }
40
- if (el.boundElements) {
41
- yMap.set("boundElements", JSON.stringify(el.boundElements));
42
- } else {
43
- yMap.set("boundElements", null);
44
- }
45
- if (el.ports) {
46
- yMap.set("ports", JSON.stringify(el.ports));
47
- }
48
- if ("lineStyle" in el && el.lineStyle) {
49
- yMap.set("lineStyle", JSON.stringify(el.lineStyle));
50
- }
51
- if (el.ports) {
52
- yMap.set("ports", JSON.stringify(el.ports));
53
- }
54
- if ("lineStyle" in el && el.lineStyle) {
55
- yMap.set("lineStyle", JSON.stringify(el.lineStyle));
56
- }
57
- if (el.groupIds) {
58
- yMap.set("groupIds", JSON.stringify(el.groupIds));
59
- }
60
- switch (el.type) {
61
- case "rectangle":
62
- yMap.set("cornerRadius", el.cornerRadius);
63
- break;
64
- case "line":
65
- case "arrow":
66
- yMap.set("points", JSON.stringify(el.points));
67
- yMap.set("lineType", el.lineType);
68
- if (el.curvature !== void 0) yMap.set("curvature", el.curvature);
69
- yMap.set("startBinding", el.startBinding ? JSON.stringify(el.startBinding) : null);
70
- yMap.set("endBinding", el.endBinding ? JSON.stringify(el.endBinding) : null);
71
- if (el.type === "arrow") {
72
- yMap.set("startArrowhead", el.startArrowhead);
73
- yMap.set("endArrowhead", el.endArrowhead);
74
- }
75
- break;
76
- case "freedraw":
77
- yMap.set("points", JSON.stringify(el.points));
78
- break;
79
- case "text":
80
- yMap.set("text", el.text);
81
- yMap.set("containerId", el.containerId);
82
- yMap.set("textAlign", el.textAlign);
83
- yMap.set("verticalAlign", el.verticalAlign);
84
- break;
85
- case "image":
86
- yMap.set("src", el.src);
87
- yMap.set("naturalWidth", el.naturalWidth);
88
- yMap.set("naturalHeight", el.naturalHeight);
89
- yMap.set("scaleMode", el.scaleMode);
90
- yMap.set("crop", el.crop ? JSON.stringify(el.crop) : null);
91
- yMap.set("cornerRadius", el.cornerRadius);
92
- yMap.set("alt", el.alt);
93
- break;
94
- }
95
- }
96
- function yMapToElement(yMap) {
97
- const type = yMap.get("type");
98
- const id = yMap.get("id");
99
- if (!type || !id) return null;
100
- const style = {};
101
- for (const sf of STYLE_FIELDS) {
102
- const val = yMap.get(`style.${sf}`);
103
- if (val !== void 0) {
104
- style[sf] = val;
105
- }
106
- }
107
- const base = {
108
- id,
109
- type,
110
- x: yMap.get("x") ?? 0,
111
- y: yMap.get("y") ?? 0,
112
- width: yMap.get("width") ?? 100,
113
- height: yMap.get("height") ?? 100,
114
- rotation: yMap.get("rotation") ?? 0,
115
- isLocked: yMap.get("isLocked") ?? false,
116
- isVisible: yMap.get("isVisible") ?? true,
117
- version: yMap.get("version") ?? 0,
118
- style,
119
- boundElements: safeParseJSON(yMap.get("boundElements")) ?? null,
120
- groupIds: safeParseJSON(yMap.get("groupIds")) ?? void 0,
121
- sortOrder: yMap.get("sortOrder") ?? void 0,
122
- ports: safeParseJSON(yMap.get("ports")) ?? void 0
123
- };
124
- switch (type) {
125
- case "rectangle":
126
- base.cornerRadius = yMap.get("cornerRadius") ?? 0;
127
- break;
128
- case "line":
129
- case "arrow":
130
- base.points = safeParseJSON(yMap.get("points")) ?? [0, 0, 100, 0];
131
- base.lineType = yMap.get("lineType") ?? "sharp";
132
- base.curvature = yMap.get("curvature") ?? void 0;
133
- base.startBinding = safeParseJSON(yMap.get("startBinding"));
134
- base.endBinding = safeParseJSON(yMap.get("endBinding"));
135
- if (type === "arrow") {
136
- base.startArrowhead = yMap.get("startArrowhead") ?? null;
137
- base.endArrowhead = yMap.get("endArrowhead") ?? "arrow";
138
- }
139
- {
140
- const ls = safeParseJSON(yMap.get("lineStyle"));
141
- if (ls) base.lineStyle = ls;
142
- }
143
- break;
144
- case "freedraw":
145
- base.points = safeParseJSON(yMap.get("points")) ?? [];
146
- break;
147
- case "text":
148
- base.text = yMap.get("text") ?? "";
149
- base.containerId = yMap.get("containerId") ?? null;
150
- base.textAlign = yMap.get("textAlign") ?? "center";
151
- base.verticalAlign = yMap.get("verticalAlign") ?? "middle";
152
- break;
153
- case "image":
154
- base.src = yMap.get("src") ?? "";
155
- base.naturalWidth = yMap.get("naturalWidth") ?? 0;
156
- base.naturalHeight = yMap.get("naturalHeight") ?? 0;
157
- base.scaleMode = yMap.get("scaleMode") ?? "fit";
158
- base.crop = safeParseJSON(yMap.get("crop")) ?? null;
159
- base.cornerRadius = yMap.get("cornerRadius") ?? 0;
160
- base.alt = yMap.get("alt") ?? "";
161
- break;
162
- }
163
- return base;
164
- }
165
- function safeParseJSON(json) {
166
- if (json == null) return null;
167
- try {
168
- return JSON.parse(json);
169
- } catch {
170
- return null;
171
- }
172
- }
173
- let _isApplyingRemote = false;
174
- let _isApplyingLocal = false;
175
- let _unsubscribe = null;
176
- let _yObserverCleanup = null;
177
- let _syncTimer = null;
178
- let _lastElements = [];
179
- function startSync(debounceMs = 50) {
180
- const doc = getYDoc();
181
- const yElements = getYElements();
182
- if (!doc || !yElements) {
183
- console.warn("[SyncBridge] Cannot start sync — no Yjs doc");
184
- return;
185
- }
186
- stopSync();
187
- if (yElements.size > 0) {
188
- _isApplyingRemote = true;
189
- const elements = yMapCollectionToElements(yElements);
190
- useCanvasStore.getState().setElements(elements);
191
- _lastElements = elements;
192
- _isApplyingRemote = false;
193
- } else {
194
- const localElements = useCanvasStore.getState().elements;
195
- if (localElements.length > 0) {
196
- _isApplyingLocal = true;
197
- doc.transact(() => {
198
- for (const el of localElements) {
199
- const yMap = new Y.Map();
200
- elementToYMap(el, yMap);
201
- yElements.set(el.id, yMap);
202
- }
203
- }, "local-init");
204
- _isApplyingLocal = false;
205
- }
206
- _lastElements = localElements;
207
- }
208
- const yObserver = (events, transaction) => {
209
- if (transaction.origin === "local-sync" || transaction.origin === "local-init") return;
210
- if (_isApplyingLocal) return;
211
- _isApplyingRemote = true;
212
- const store = useCanvasStore.getState();
213
- let elements = [..._lastElements];
214
- let changed = false;
215
- for (const [key, change] of events.keys) {
216
- if (change.action === "add" || change.action === "update") {
217
- const yMap = yElements.get(key);
218
- if (yMap) {
219
- const el = yMapToElement(yMap);
220
- if (el) {
221
- const idx = elements.findIndex((e) => e.id === key);
222
- if (idx >= 0) {
223
- elements[idx] = el;
224
- } else {
225
- elements.push(el);
226
- }
227
- changed = true;
228
- }
229
- }
230
- } else if (change.action === "delete") {
231
- elements = elements.filter((e) => e.id !== key);
232
- changed = true;
233
- }
234
- }
235
- if (changed) {
236
- elements.sort((a, b) => {
237
- if (a.sortOrder && b.sortOrder) {
238
- return a.sortOrder < b.sortOrder ? -1 : a.sortOrder > b.sortOrder ? 1 : 0;
239
- }
240
- return 0;
241
- });
242
- store.setElements(elements);
243
- _lastElements = elements;
244
- }
245
- _isApplyingRemote = false;
246
- };
247
- let _deepObserverTimer = null;
248
- const _dirtyElementIds = /* @__PURE__ */ new Set();
249
- const deepObserver = (events) => {
250
- if (_isApplyingLocal) return;
251
- for (const event of events) {
252
- let target = event.target;
253
- while (target && !(target instanceof Y.Map && target.parent === yElements)) {
254
- target = target.parent;
255
- }
256
- if (target instanceof Y.Map) {
257
- const id = target.get("id");
258
- if (id) _dirtyElementIds.add(id);
259
- }
260
- }
261
- if (_deepObserverTimer) clearTimeout(_deepObserverTimer);
262
- _deepObserverTimer = setTimeout(() => {
263
- if (_dirtyElementIds.size === 0 || _isApplyingLocal) return;
264
- _isApplyingRemote = true;
265
- let elements = [..._lastElements];
266
- let changed = false;
267
- for (const id of _dirtyElementIds) {
268
- const yMap = yElements.get(id);
269
- if (!yMap) continue;
270
- const el = yMapToElement(yMap);
271
- if (!el) continue;
272
- const idx = elements.findIndex((e) => e.id === id);
273
- if (idx >= 0) {
274
- elements[idx] = el;
275
- changed = true;
276
- }
277
- }
278
- _dirtyElementIds.clear();
279
- if (changed) {
280
- useCanvasStore.getState().setElements(elements);
281
- _lastElements = elements;
282
- }
283
- _isApplyingRemote = false;
284
- }, 16);
285
- };
286
- yElements.observe(yObserver);
287
- yElements.observeDeep(deepObserver);
288
- _yObserverCleanup = () => {
289
- yElements.unobserve(yObserver);
290
- yElements.unobserveDeep(deepObserver);
291
- if (_deepObserverTimer) clearTimeout(_deepObserverTimer);
292
- _dirtyElementIds.clear();
293
- };
294
- _unsubscribe = useCanvasStore.subscribe(
295
- (state) => {
296
- if (_isApplyingRemote) return;
297
- if (state.elements === _lastElements) return;
298
- if (_syncTimer) clearTimeout(_syncTimer);
299
- _syncTimer = setTimeout(() => {
300
- syncLocalToYjs(state.elements, yElements, doc);
301
- }, debounceMs);
302
- }
303
- );
304
- }
305
- function stopSync() {
306
- if (_unsubscribe) {
307
- _unsubscribe();
308
- _unsubscribe = null;
309
- }
310
- if (_yObserverCleanup) {
311
- _yObserverCleanup();
312
- _yObserverCleanup = null;
313
- }
314
- if (_syncTimer) {
315
- clearTimeout(_syncTimer);
316
- _syncTimer = null;
317
- }
318
- _lastElements = [];
319
- }
320
- function syncLocalToYjs(elements, yElements, doc) {
321
- _isApplyingLocal = true;
322
- _lastElements = elements;
323
- const localMap = /* @__PURE__ */ new Map();
324
- for (const el of elements) {
325
- localMap.set(el.id, el);
326
- }
327
- doc.transact(() => {
328
- for (const [id] of yElements.entries()) {
329
- if (!localMap.has(id)) {
330
- yElements.delete(id);
331
- }
332
- }
333
- for (const el of elements) {
334
- let yMap = yElements.get(el.id);
335
- if (!yMap) {
336
- yMap = new Y.Map();
337
- elementToYMap(el, yMap);
338
- yElements.set(el.id, yMap);
339
- } else {
340
- updateYMapFromElement(el, yMap);
341
- }
342
- }
343
- }, "local-sync");
344
- _isApplyingLocal = false;
345
- }
346
- function updateYMapFromElement(el, yMap) {
347
- const elRecord = el;
348
- for (const field of SYNC_FIELDS) {
349
- const value = elRecord[field];
350
- if (value !== yMap.get(field)) {
351
- yMap.set(field, value);
352
- }
353
- }
354
- if (el.style) {
355
- for (const sf of STYLE_FIELDS) {
356
- const val = el.style[sf];
357
- if (val !== yMap.get(`style.${sf}`)) {
358
- yMap.set(`style.${sf}`, val);
359
- }
360
- }
361
- }
362
- const beJson = el.boundElements ? JSON.stringify(el.boundElements) : null;
363
- if (beJson !== yMap.get("boundElements")) {
364
- yMap.set("boundElements", beJson);
365
- }
366
- switch (el.type) {
367
- case "rectangle":
368
- if (el.cornerRadius !== yMap.get("cornerRadius")) {
369
- yMap.set("cornerRadius", el.cornerRadius);
370
- }
371
- break;
372
- case "line":
373
- case "arrow": {
374
- const ptsJson = JSON.stringify(el.points);
375
- if (ptsJson !== yMap.get("points")) yMap.set("points", ptsJson);
376
- if (el.lineType !== yMap.get("lineType")) yMap.set("lineType", el.lineType);
377
- if (el.curvature !== yMap.get("curvature")) yMap.set("curvature", el.curvature);
378
- const sbJson = el.startBinding ? JSON.stringify(el.startBinding) : null;
379
- if (sbJson !== yMap.get("startBinding")) yMap.set("startBinding", sbJson);
380
- const ebJson = el.endBinding ? JSON.stringify(el.endBinding) : null;
381
- if (ebJson !== yMap.get("endBinding")) yMap.set("endBinding", ebJson);
382
- if (el.type === "arrow") {
383
- if (el.startArrowhead !== yMap.get("startArrowhead")) yMap.set("startArrowhead", el.startArrowhead);
384
- if (el.endArrowhead !== yMap.get("endArrowhead")) yMap.set("endArrowhead", el.endArrowhead);
385
- }
386
- break;
387
- }
388
- case "freedraw": {
389
- const fpJson = JSON.stringify(el.points);
390
- if (fpJson !== yMap.get("points")) yMap.set("points", fpJson);
391
- break;
392
- }
393
- case "text":
394
- if (el.text !== yMap.get("text")) yMap.set("text", el.text);
395
- if (el.containerId !== yMap.get("containerId")) yMap.set("containerId", el.containerId);
396
- if (el.textAlign !== yMap.get("textAlign")) yMap.set("textAlign", el.textAlign);
397
- if (el.verticalAlign !== yMap.get("verticalAlign")) yMap.set("verticalAlign", el.verticalAlign);
398
- break;
399
- case "image":
400
- if (el.src !== yMap.get("src")) yMap.set("src", el.src);
401
- if (el.naturalWidth !== yMap.get("naturalWidth")) yMap.set("naturalWidth", el.naturalWidth);
402
- if (el.naturalHeight !== yMap.get("naturalHeight")) yMap.set("naturalHeight", el.naturalHeight);
403
- if (el.scaleMode !== yMap.get("scaleMode")) yMap.set("scaleMode", el.scaleMode);
404
- const cropJson = el.crop ? JSON.stringify(el.crop) : null;
405
- if (cropJson !== yMap.get("crop")) yMap.set("crop", cropJson);
406
- if (el.cornerRadius !== yMap.get("cornerRadius")) yMap.set("cornerRadius", el.cornerRadius);
407
- if (el.alt !== yMap.get("alt")) yMap.set("alt", el.alt);
408
- break;
409
- }
410
- }
411
- function yMapCollectionToElements(yElements) {
412
- const elements = [];
413
- for (const [, yMap] of yElements.entries()) {
414
- const el = yMapToElement(yMap);
415
- if (el) elements.push(el);
416
- }
417
- elements.sort((a, b) => {
418
- if (a.sortOrder && b.sortOrder) {
419
- return a.sortOrder < b.sortOrder ? -1 : a.sortOrder > b.sortOrder ? 1 : 0;
420
- }
421
- return 0;
422
- });
423
- return elements;
424
- }
425
- export {
426
- startSync,
427
- stopSync
428
- };
@@ -1,100 +0,0 @@
1
- import * as Y from "yjs";
2
- import { WebsocketProvider } from "y-websocket";
3
- let _doc = null;
4
- let _provider = null;
5
- let _config = null;
6
- let _statusListeners = /* @__PURE__ */ new Set();
7
- function createCollaborationProvider(config) {
8
- if (_provider) {
9
- destroyCollaborationProvider();
10
- }
11
- _config = config;
12
- _doc = new Y.Doc();
13
- _provider = new WebsocketProvider(
14
- config.serverUrl,
15
- config.roomName,
16
- _doc,
17
- {
18
- connect: true,
19
- params: config.authToken ? { token: config.authToken } : void 0
20
- }
21
- );
22
- _provider.awareness.setLocalState({
23
- user: config.user,
24
- cursor: null,
25
- selectedIds: []
26
- });
27
- _provider.on("status", (event) => {
28
- const status = event.status;
29
- for (const listener of _statusListeners) {
30
- listener(status);
31
- }
32
- });
33
- return { doc: _doc, provider: _provider };
34
- }
35
- function destroyCollaborationProvider() {
36
- if (_provider) {
37
- _provider.awareness.setLocalState(null);
38
- _provider.disconnect();
39
- _provider.destroy();
40
- _provider = null;
41
- }
42
- if (_doc) {
43
- _doc.destroy();
44
- _doc = null;
45
- }
46
- _config = null;
47
- }
48
- function getYDoc() {
49
- return _doc;
50
- }
51
- function getYProvider() {
52
- return _provider;
53
- }
54
- function getYElements() {
55
- return _doc == null ? void 0 : _doc.getMap("elements");
56
- }
57
- function getCollaborationConfig() {
58
- return _config;
59
- }
60
- function isCollaborationActive() {
61
- return _provider !== null && _provider.wsconnected;
62
- }
63
- function onStatusChange(listener) {
64
- _statusListeners.add(listener);
65
- return () => {
66
- _statusListeners.delete(listener);
67
- };
68
- }
69
- function updateAwareness(update) {
70
- if (!_provider) return;
71
- const current = _provider.awareness.getLocalState();
72
- _provider.awareness.setLocalState({
73
- ...current,
74
- ...update
75
- });
76
- }
77
- function getRemoteAwareness() {
78
- if (!_provider) return /* @__PURE__ */ new Map();
79
- const all = _provider.awareness.getStates();
80
- const localId = _provider.awareness.clientID;
81
- const remote = /* @__PURE__ */ new Map();
82
- for (const [clientId, state] of all) {
83
- if (clientId !== localId && state && state.user) {
84
- remote.set(clientId, state);
85
- }
86
- }
87
- return remote;
88
- }
89
- export {
90
- createCollaborationProvider,
91
- destroyCollaborationProvider,
92
- getCollaborationConfig,
93
- getRemoteAwareness,
94
- getYDoc,
95
- getYElements,
96
- getYProvider,
97
- isCollaborationActive,
98
- onStatusChange,
99
- updateAwareness
100
- };