@fieldnotes/react 0.14.0 → 0.14.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.
- package/README.md +1 -1
- package/dist/index.cjs +60 -255
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -8
- package/dist/index.d.ts +3 -8
- package/dist/index.js +95 -290
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ React bindings for the [Field Notes](https://github.com/IrakliDevelop/fieldnotes
|
|
|
8
8
|
npm install @fieldnotes/core @fieldnotes/react
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Requires React 18+.
|
|
11
|
+
Requires React 18+. Using Vue or Svelte? See [`@fieldnotes/vue`](../vue) and [`@fieldnotes/svelte`](../svelte).
|
|
12
12
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
package/dist/index.cjs
CHANGED
|
@@ -193,12 +193,11 @@ function CanvasElement({ position, size, children }) {
|
|
|
193
193
|
};
|
|
194
194
|
elementIdRef.current = register();
|
|
195
195
|
setPortalTarget(container);
|
|
196
|
-
let disposed = false;
|
|
197
196
|
const handleStoreReplacement = () => {
|
|
198
197
|
const clearedId = elementIdRef.current;
|
|
199
198
|
if (clearedId === null) return;
|
|
200
199
|
queueMicrotask(() => {
|
|
201
|
-
if (
|
|
200
|
+
if (elementIdRef.current !== clearedId) return;
|
|
202
201
|
if (viewport.store.getById(clearedId)?.type === "html") {
|
|
203
202
|
viewport.updateHtmlElement(clearedId, container);
|
|
204
203
|
} else {
|
|
@@ -210,7 +209,6 @@ function CanvasElement({ position, size, children }) {
|
|
|
210
209
|
const unsubscribeClear = viewport.store.on("clear", handleStoreReplacement);
|
|
211
210
|
const unsubscribeBatch = viewport.store.on("batch", handleStoreReplacement);
|
|
212
211
|
return () => {
|
|
213
|
-
disposed = true;
|
|
214
212
|
unsubscribeClear();
|
|
215
213
|
unsubscribeBatch();
|
|
216
214
|
if (elementIdRef.current) {
|
|
@@ -235,65 +233,40 @@ function CanvasElement({ position, size, children }) {
|
|
|
235
233
|
|
|
236
234
|
// src/hooks/use-active-tool.ts
|
|
237
235
|
var import_react5 = require("react");
|
|
236
|
+
var import_core2 = require("@fieldnotes/core");
|
|
238
237
|
function useActiveTool() {
|
|
239
238
|
const viewport = useViewport();
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
[viewport]
|
|
243
|
-
);
|
|
244
|
-
const getSnapshot = (0, import_react5.useCallback)(() => viewport.toolManager.activeTool?.name ?? "", [viewport]);
|
|
245
|
-
const toolName = (0, import_react5.useSyncExternalStore)(subscribe, getSnapshot);
|
|
239
|
+
const source = (0, import_react5.useMemo)(() => (0, import_core2.createActiveToolSource)(viewport), [viewport]);
|
|
240
|
+
const toolName = (0, import_react5.useSyncExternalStore)(source.subscribe, source.getSnapshot);
|
|
246
241
|
const setTool = (0, import_react5.useCallback)((name) => viewport.setTool(name), [viewport]);
|
|
247
242
|
return [toolName, setTool];
|
|
248
243
|
}
|
|
249
244
|
|
|
250
245
|
// src/hooks/use-camera.ts
|
|
251
246
|
var import_react6 = require("react");
|
|
247
|
+
var import_core3 = require("@fieldnotes/core");
|
|
252
248
|
function useCamera() {
|
|
253
249
|
const viewport = useViewport();
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
(onStoreChange) => viewport.camera.onChange(onStoreChange),
|
|
257
|
-
[viewport]
|
|
258
|
-
);
|
|
259
|
-
const getSnapshot = (0, import_react6.useCallback)(() => {
|
|
260
|
-
const { position, zoom } = viewport.camera;
|
|
261
|
-
const cached = cachedRef.current;
|
|
262
|
-
if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {
|
|
263
|
-
return cached;
|
|
264
|
-
}
|
|
265
|
-
const next = { x: position.x, y: position.y, zoom };
|
|
266
|
-
cachedRef.current = next;
|
|
267
|
-
return next;
|
|
268
|
-
}, [viewport]);
|
|
269
|
-
return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot);
|
|
250
|
+
const source = (0, import_react6.useMemo)(() => (0, import_core3.createCameraSource)(viewport), [viewport]);
|
|
251
|
+
return (0, import_react6.useSyncExternalStore)(source.subscribe, source.getSnapshot);
|
|
270
252
|
}
|
|
271
253
|
|
|
272
254
|
// src/hooks/use-tool-options.ts
|
|
273
255
|
var import_react7 = require("react");
|
|
274
|
-
|
|
275
|
-
}
|
|
256
|
+
var import_core4 = require("@fieldnotes/core");
|
|
276
257
|
function useToolOptions(toolName) {
|
|
277
258
|
const viewport = useViewport();
|
|
278
|
-
const
|
|
259
|
+
const nameRef = (0, import_react7.useRef)(toolName);
|
|
260
|
+
nameRef.current = toolName;
|
|
261
|
+
const source = (0, import_react7.useMemo)(
|
|
262
|
+
() => (0, import_core4.createToolOptionsSource)(viewport, () => nameRef.current),
|
|
263
|
+
[viewport]
|
|
264
|
+
);
|
|
279
265
|
const subscribe = (0, import_react7.useCallback)(
|
|
280
|
-
(onStoreChange) =>
|
|
281
|
-
|
|
282
|
-
if (!tool?.onOptionsChange) return noop;
|
|
283
|
-
return tool.onOptionsChange(onStoreChange);
|
|
284
|
-
},
|
|
285
|
-
[viewport, toolName]
|
|
266
|
+
(onStoreChange) => source.subscribe(onStoreChange),
|
|
267
|
+
[source, toolName]
|
|
286
268
|
);
|
|
287
|
-
const
|
|
288
|
-
const tool = viewport.toolManager.getTool(toolName);
|
|
289
|
-
if (!tool?.getOptions) return null;
|
|
290
|
-
const next = tool.getOptions();
|
|
291
|
-
const cached = cachedRef.current;
|
|
292
|
-
if (cached && shallowEqual(cached, next)) return cached;
|
|
293
|
-
cachedRef.current = next;
|
|
294
|
-
return next;
|
|
295
|
-
}, [viewport, toolName]);
|
|
296
|
-
const options = (0, import_react7.useSyncExternalStore)(subscribe, getSnapshot);
|
|
269
|
+
const options = (0, import_react7.useSyncExternalStore)(subscribe, source.getSnapshot);
|
|
297
270
|
const setOptions = (0, import_react7.useCallback)(
|
|
298
271
|
(partial) => {
|
|
299
272
|
const tool = viewport.toolManager.getTool(toolName);
|
|
@@ -303,51 +276,14 @@ function useToolOptions(toolName) {
|
|
|
303
276
|
);
|
|
304
277
|
return [options, setOptions];
|
|
305
278
|
}
|
|
306
|
-
function shallowEqual(a, b) {
|
|
307
|
-
const keysA = Object.keys(a);
|
|
308
|
-
const keysB = Object.keys(b);
|
|
309
|
-
if (keysA.length !== keysB.length) return false;
|
|
310
|
-
for (const key of keysA) {
|
|
311
|
-
const valA = a[key];
|
|
312
|
-
const valB = b[key];
|
|
313
|
-
if (valA === valB) continue;
|
|
314
|
-
if (typeof valA === "object" && valA !== null && typeof valB === "object" && valB !== null && !Array.isArray(valA) && !Array.isArray(valB)) {
|
|
315
|
-
const objA = valA;
|
|
316
|
-
const objB = valB;
|
|
317
|
-
const innerKeys = Object.keys(objA);
|
|
318
|
-
if (innerKeys.length === Object.keys(objB).length && innerKeys.every((k) => objA[k] === objB[k])) {
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return false;
|
|
323
|
-
}
|
|
324
|
-
return true;
|
|
325
|
-
}
|
|
326
279
|
|
|
327
280
|
// src/hooks/use-layers.ts
|
|
328
281
|
var import_react8 = require("react");
|
|
282
|
+
var import_core5 = require("@fieldnotes/core");
|
|
329
283
|
function useLayers() {
|
|
330
284
|
const viewport = useViewport();
|
|
331
|
-
const
|
|
332
|
-
const
|
|
333
|
-
(onStoreChange) => viewport.layerManager.on("change", onStoreChange),
|
|
334
|
-
[viewport]
|
|
335
|
-
);
|
|
336
|
-
const getSnapshot = (0, import_react8.useCallback)(() => {
|
|
337
|
-
const layers = viewport.layerManager.getLayers();
|
|
338
|
-
const activeLayerId = viewport.layerManager.activeLayerId;
|
|
339
|
-
const cached = cachedRef.current;
|
|
340
|
-
if (cached.activeLayerId === activeLayerId && cached.layers.length === layers.length && cached.layers.every((l, i) => {
|
|
341
|
-
const next2 = layers[i];
|
|
342
|
-
return next2 !== void 0 && l.id === next2.id && l.name === next2.name && l.visible === next2.visible && l.locked === next2.locked && l.order === next2.order && l.opacity === next2.opacity;
|
|
343
|
-
})) {
|
|
344
|
-
return cached;
|
|
345
|
-
}
|
|
346
|
-
const next = { layers, activeLayerId };
|
|
347
|
-
cachedRef.current = next;
|
|
348
|
-
return next;
|
|
349
|
-
}, [viewport]);
|
|
350
|
-
const snapshot = (0, import_react8.useSyncExternalStore)(subscribe, getSnapshot);
|
|
285
|
+
const source = (0, import_react8.useMemo)(() => (0, import_core5.createLayersSource)(viewport), [viewport]);
|
|
286
|
+
const snapshot = (0, import_react8.useSyncExternalStore)(source.subscribe, source.getSnapshot);
|
|
351
287
|
const createLayer = (0, import_react8.useCallback)(
|
|
352
288
|
(name) => viewport.layerManager.createLayer(name),
|
|
353
289
|
[viewport]
|
|
@@ -401,25 +337,11 @@ function useLayers() {
|
|
|
401
337
|
|
|
402
338
|
// src/hooks/use-history.ts
|
|
403
339
|
var import_react9 = require("react");
|
|
340
|
+
var import_core6 = require("@fieldnotes/core");
|
|
404
341
|
function useHistory() {
|
|
405
342
|
const viewport = useViewport();
|
|
406
|
-
const
|
|
407
|
-
const
|
|
408
|
-
(onStoreChange) => viewport.history.onChange(onStoreChange),
|
|
409
|
-
[viewport]
|
|
410
|
-
);
|
|
411
|
-
const getSnapshot = (0, import_react9.useCallback)(() => {
|
|
412
|
-
const canUndo = viewport.history.canUndo;
|
|
413
|
-
const canRedo = viewport.history.canRedo;
|
|
414
|
-
const cached = cachedRef.current;
|
|
415
|
-
if (cached.canUndo === canUndo && cached.canRedo === canRedo) {
|
|
416
|
-
return cached;
|
|
417
|
-
}
|
|
418
|
-
const next = { canUndo, canRedo };
|
|
419
|
-
cachedRef.current = next;
|
|
420
|
-
return next;
|
|
421
|
-
}, [viewport]);
|
|
422
|
-
const snapshot = (0, import_react9.useSyncExternalStore)(subscribe, getSnapshot);
|
|
343
|
+
const source = (0, import_react9.useMemo)(() => (0, import_core6.createHistorySource)(viewport), [viewport]);
|
|
344
|
+
const snapshot = (0, import_react9.useSyncExternalStore)(source.subscribe, source.getSnapshot);
|
|
423
345
|
const undo = (0, import_react9.useCallback)(() => viewport.undo(), [viewport]);
|
|
424
346
|
const redo = (0, import_react9.useCallback)(() => viewport.redo(), [viewport]);
|
|
425
347
|
return {
|
|
@@ -432,186 +354,69 @@ function useHistory() {
|
|
|
432
354
|
|
|
433
355
|
// src/hooks/use-elements.ts
|
|
434
356
|
var import_react10 = require("react");
|
|
435
|
-
|
|
436
|
-
if (Object.is(a, b)) return true;
|
|
437
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
438
|
-
return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));
|
|
439
|
-
}
|
|
440
|
-
if (typeof a === "object" && a !== null && typeof b === "object" && b !== null && !Array.isArray(a) && !Array.isArray(b)) {
|
|
441
|
-
const ka = Object.keys(a);
|
|
442
|
-
const kb = Object.keys(b);
|
|
443
|
-
return ka.length === kb.length && ka.every(
|
|
444
|
-
(k) => k in b && Object.is(a[k], b[k])
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
return false;
|
|
448
|
-
}
|
|
357
|
+
var import_core7 = require("@fieldnotes/core");
|
|
449
358
|
function useElements(arg, isEqual) {
|
|
450
359
|
const viewport = useViewport();
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
(
|
|
360
|
+
const latest = (0, import_react10.useRef)({ arg, isEqual });
|
|
361
|
+
latest.current = { arg, isEqual };
|
|
362
|
+
const elementsSource = (0, import_react10.useMemo)(
|
|
363
|
+
() => (0, import_core7.createElementsSource)(viewport, () => {
|
|
364
|
+
const a = latest.current.arg;
|
|
365
|
+
return typeof a === "function" ? void 0 : a;
|
|
366
|
+
}),
|
|
455
367
|
[viewport]
|
|
456
368
|
);
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();
|
|
469
|
-
const cached = cachedRef.current;
|
|
470
|
-
if (cached.length === next.length && cached.every((el, i) => el === next[i])) {
|
|
471
|
-
return cached;
|
|
472
|
-
}
|
|
473
|
-
cachedRef.current = next;
|
|
474
|
-
return next;
|
|
475
|
-
}, [viewport, arg, isEqual]);
|
|
476
|
-
return (0, import_react10.useSyncExternalStore)(subscribe, getSnapshot);
|
|
369
|
+
const selectorSource = (0, import_react10.useMemo)(
|
|
370
|
+
() => (0, import_core7.createElementsSelectorSource)(
|
|
371
|
+
viewport,
|
|
372
|
+
// Only read while `arg` is a selector: the source is picked below by `typeof arg`.
|
|
373
|
+
() => latest.current.arg,
|
|
374
|
+
() => latest.current.isEqual
|
|
375
|
+
),
|
|
376
|
+
[viewport]
|
|
377
|
+
);
|
|
378
|
+
const source = typeof arg === "function" ? selectorSource : elementsSource;
|
|
379
|
+
return (0, import_react10.useSyncExternalStore)(source.subscribe, source.getSnapshot);
|
|
477
380
|
}
|
|
478
381
|
|
|
479
382
|
// src/hooks/use-selection.ts
|
|
480
383
|
var import_react11 = require("react");
|
|
384
|
+
var import_core8 = require("@fieldnotes/core");
|
|
481
385
|
function useSelection() {
|
|
482
386
|
const viewport = useViewport();
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
[viewport]
|
|
486
|
-
);
|
|
487
|
-
const getSnapshot = (0, import_react11.useCallback)(() => viewport.getSelectedIds(), [viewport]);
|
|
488
|
-
return (0, import_react11.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
387
|
+
const source = (0, import_react11.useMemo)(() => (0, import_core8.createSelectionSource)(viewport), [viewport]);
|
|
388
|
+
return (0, import_react11.useSyncExternalStore)(source.subscribe, source.getSnapshot, source.getSnapshot);
|
|
489
389
|
}
|
|
490
390
|
|
|
491
391
|
// src/hooks/use-selection-style.ts
|
|
492
392
|
var import_react12 = require("react");
|
|
493
|
-
|
|
494
|
-
// src/hooks/style-keys.ts
|
|
495
|
-
var STYLE_KEYS = [
|
|
496
|
-
"color",
|
|
497
|
-
"fillColor",
|
|
498
|
-
"strokeWidth",
|
|
499
|
-
"opacity",
|
|
500
|
-
"fontSize",
|
|
501
|
-
"strokeStyle"
|
|
502
|
-
];
|
|
503
|
-
|
|
504
|
-
// src/hooks/use-selection-style.ts
|
|
505
|
-
function styleEqual(a, b) {
|
|
506
|
-
if (a === b) return true;
|
|
507
|
-
if (a === null || b === null) return false;
|
|
508
|
-
return STYLE_KEYS.every((k) => a[k] === b[k]);
|
|
509
|
-
}
|
|
393
|
+
var import_core9 = require("@fieldnotes/core");
|
|
510
394
|
function useSelectionStyle() {
|
|
511
395
|
const viewport = useViewport();
|
|
512
|
-
const
|
|
513
|
-
const
|
|
514
|
-
(onChange) => {
|
|
515
|
-
const offSel = viewport.onSelectionChange(onChange);
|
|
516
|
-
const offStore = viewport.store.onChange(onChange);
|
|
517
|
-
return () => {
|
|
518
|
-
offSel();
|
|
519
|
-
offStore();
|
|
520
|
-
};
|
|
521
|
-
},
|
|
522
|
-
[viewport]
|
|
523
|
-
);
|
|
524
|
-
const getSnapshot = (0, import_react12.useCallback)(() => {
|
|
525
|
-
const next = viewport.getSelectionStyle();
|
|
526
|
-
if (styleEqual(cacheRef.current, next)) return cacheRef.current;
|
|
527
|
-
cacheRef.current = next;
|
|
528
|
-
return next;
|
|
529
|
-
}, [viewport]);
|
|
530
|
-
const style = (0, import_react12.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
396
|
+
const source = (0, import_react12.useMemo)(() => (0, import_core9.createSelectionStyleSource)(viewport), [viewport]);
|
|
397
|
+
const style = (0, import_react12.useSyncExternalStore)(source.subscribe, source.getSnapshot, source.getSnapshot);
|
|
531
398
|
const apply = (0, import_react12.useCallback)((s) => viewport.applyStyleToSelection(s), [viewport]);
|
|
532
399
|
return [style, apply];
|
|
533
400
|
}
|
|
534
401
|
|
|
535
402
|
// src/hooks/use-selection-style-details.ts
|
|
536
403
|
var import_react13 = require("react");
|
|
537
|
-
|
|
538
|
-
return a.length === b.length && a.every((k, i) => k === b[i]);
|
|
539
|
-
}
|
|
540
|
-
function detailsEqual(a, b) {
|
|
541
|
-
if (a === b) return true;
|
|
542
|
-
if (a === null || b === null) return false;
|
|
543
|
-
return keysEqual(a.applicable, b.applicable) && keysEqual(a.mixed, b.mixed) && STYLE_KEYS.every((k) => a.common[k] === b.common[k]);
|
|
544
|
-
}
|
|
404
|
+
var import_core10 = require("@fieldnotes/core");
|
|
545
405
|
function useSelectionStyleDetails() {
|
|
546
406
|
const viewport = useViewport();
|
|
547
|
-
const
|
|
548
|
-
const
|
|
549
|
-
(onChange) => {
|
|
550
|
-
const offSel = viewport.onSelectionChange(onChange);
|
|
551
|
-
const offStore = viewport.store.onChange(onChange);
|
|
552
|
-
return () => {
|
|
553
|
-
offSel();
|
|
554
|
-
offStore();
|
|
555
|
-
};
|
|
556
|
-
},
|
|
557
|
-
[viewport]
|
|
558
|
-
);
|
|
559
|
-
const getSnapshot = (0, import_react13.useCallback)(() => {
|
|
560
|
-
const next = viewport.getSelectionStyleDetails();
|
|
561
|
-
if (detailsEqual(cacheRef.current, next)) return cacheRef.current;
|
|
562
|
-
cacheRef.current = next;
|
|
563
|
-
return next;
|
|
564
|
-
}, [viewport]);
|
|
565
|
-
const details = (0, import_react13.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
407
|
+
const source = (0, import_react13.useMemo)(() => (0, import_core10.createSelectionStyleDetailsSource)(viewport), [viewport]);
|
|
408
|
+
const details = (0, import_react13.useSyncExternalStore)(source.subscribe, source.getSnapshot, source.getSnapshot);
|
|
566
409
|
const apply = (0, import_react13.useCallback)((s) => viewport.applyStyleToSelection(s), [viewport]);
|
|
567
410
|
return [details, apply];
|
|
568
411
|
}
|
|
569
412
|
|
|
570
413
|
// src/hooks/use-selection-ops.ts
|
|
571
414
|
var import_react14 = require("react");
|
|
572
|
-
|
|
573
|
-
return a.selectedIds === b.selectedIds && a.canGroup === b.canGroup && a.canUngroup === b.canUngroup && a.canAlign === b.canAlign && a.canDistribute === b.canDistribute && a.isLocked === b.isLocked;
|
|
574
|
-
}
|
|
415
|
+
var import_core11 = require("@fieldnotes/core");
|
|
575
416
|
function useSelectionOps() {
|
|
576
417
|
const viewport = useViewport();
|
|
577
|
-
const
|
|
578
|
-
const
|
|
579
|
-
(onChange) => {
|
|
580
|
-
const offSel = viewport.onSelectionChange(onChange);
|
|
581
|
-
const offStore = viewport.store.onChange(onChange);
|
|
582
|
-
return () => {
|
|
583
|
-
offSel();
|
|
584
|
-
offStore();
|
|
585
|
-
};
|
|
586
|
-
},
|
|
587
|
-
[viewport]
|
|
588
|
-
);
|
|
589
|
-
const getSnapshot = (0, import_react14.useCallback)(() => {
|
|
590
|
-
const ids = viewport.getSelectedIds();
|
|
591
|
-
const n = ids.length;
|
|
592
|
-
let canUngroup = false;
|
|
593
|
-
let lockedCount = 0;
|
|
594
|
-
for (const id of ids) {
|
|
595
|
-
const el = viewport.store.getById(id);
|
|
596
|
-
if (!el) continue;
|
|
597
|
-
if (el.groupId !== void 0) canUngroup = true;
|
|
598
|
-
if (el.locked) lockedCount++;
|
|
599
|
-
}
|
|
600
|
-
const isLocked = n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;
|
|
601
|
-
const next = {
|
|
602
|
-
selectedIds: ids,
|
|
603
|
-
canGroup: n >= 2,
|
|
604
|
-
canUngroup,
|
|
605
|
-
canAlign: n >= 2,
|
|
606
|
-
canDistribute: n >= 3,
|
|
607
|
-
isLocked
|
|
608
|
-
};
|
|
609
|
-
const prev = cacheRef.current;
|
|
610
|
-
if (prev && snapshotEqual(prev, next)) return prev;
|
|
611
|
-
cacheRef.current = next;
|
|
612
|
-
return next;
|
|
613
|
-
}, [viewport]);
|
|
614
|
-
const snap = (0, import_react14.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
418
|
+
const source = (0, import_react14.useMemo)(() => (0, import_core11.createSelectionOpsSource)(viewport), [viewport]);
|
|
419
|
+
const snap = (0, import_react14.useSyncExternalStore)(source.subscribe, source.getSnapshot, source.getSnapshot);
|
|
615
420
|
const group = (0, import_react14.useCallback)(() => viewport.groupSelection(), [viewport]);
|
|
616
421
|
const ungroup = (0, import_react14.useCallback)(() => viewport.ungroupSelection(), [viewport]);
|
|
617
422
|
const toggleLock = (0, import_react14.useCallback)(() => viewport.toggleLockSelection(), [viewport]);
|
|
@@ -642,7 +447,7 @@ function useSelectionOps() {
|
|
|
642
447
|
|
|
643
448
|
// src/hooks/use-element-rects.ts
|
|
644
449
|
var import_react15 = require("react");
|
|
645
|
-
var
|
|
450
|
+
var import_core12 = require("@fieldnotes/core");
|
|
646
451
|
function useElementRects(match) {
|
|
647
452
|
const viewport = useViewport();
|
|
648
453
|
const matchRef = (0, import_react15.useRef)(match);
|
|
@@ -652,11 +457,11 @@ function useElementRects(match) {
|
|
|
652
457
|
const trackerRef = (0, import_react15.useRef)(null);
|
|
653
458
|
const subscribe = (0, import_react15.useCallback)(
|
|
654
459
|
(onStoreChange) => {
|
|
655
|
-
const tracker = new
|
|
460
|
+
const tracker = new import_core12.ElementRectTracker(viewport, { match: stableMatch });
|
|
656
461
|
trackerRef.current = tracker;
|
|
657
462
|
const next = tracker.getRects();
|
|
658
463
|
const previous = cacheRef.current;
|
|
659
|
-
if (previous === null || !(0,
|
|
464
|
+
if (previous === null || !(0, import_core12.elementRectsEqual)(previous, next)) {
|
|
660
465
|
cacheRef.current = next;
|
|
661
466
|
onStoreChange();
|
|
662
467
|
}
|
|
@@ -674,7 +479,7 @@ function useElementRects(match) {
|
|
|
674
479
|
);
|
|
675
480
|
const getSnapshot = (0, import_react15.useCallback)(() => {
|
|
676
481
|
if (cacheRef.current === null) {
|
|
677
|
-
cacheRef.current = (0,
|
|
482
|
+
cacheRef.current = (0, import_core12.computeElementRects)(viewport.store, stableMatch);
|
|
678
483
|
}
|
|
679
484
|
return cacheRef.current;
|
|
680
485
|
}, [viewport, stableMatch]);
|
|
@@ -687,7 +492,7 @@ function useElementRects(match) {
|
|
|
687
492
|
|
|
688
493
|
// src/minimap.tsx
|
|
689
494
|
var import_react16 = require("react");
|
|
690
|
-
var
|
|
495
|
+
var import_core13 = require("@fieldnotes/core");
|
|
691
496
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
692
497
|
var toggleStyle = {
|
|
693
498
|
position: "absolute",
|
|
@@ -719,7 +524,7 @@ function Minimap({
|
|
|
719
524
|
if (collapsed) return;
|
|
720
525
|
const canvas = canvasRef.current;
|
|
721
526
|
if (!canvas) return;
|
|
722
|
-
const controller = new
|
|
527
|
+
const controller = new import_core13.MinimapController(viewport, canvas, {
|
|
723
528
|
width,
|
|
724
529
|
height,
|
|
725
530
|
background,
|