@fieldnotes/react 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -26,12 +26,14 @@ __export(index_exports, {
26
26
  ViewportContext: () => ViewportContext,
27
27
  useActiveTool: () => useActiveTool,
28
28
  useCamera: () => useCamera,
29
+ useElementRects: () => useElementRects,
29
30
  useElements: () => useElements,
30
31
  useHistory: () => useHistory,
31
32
  useLayers: () => useLayers,
32
33
  useSelection: () => useSelection,
33
34
  useSelectionOps: () => useSelectionOps,
34
35
  useSelectionStyle: () => useSelectionStyle,
36
+ useSelectionStyleDetails: () => useSelectionStyleDetails,
35
37
  useToolOptions: () => useToolOptions,
36
38
  useViewport: () => useViewport
37
39
  });
@@ -417,11 +419,22 @@ function useSelection() {
417
419
 
418
420
  // src/hooks/use-selection-style.ts
419
421
  var import_react12 = require("react");
422
+
423
+ // src/hooks/style-keys.ts
424
+ var STYLE_KEYS = [
425
+ "color",
426
+ "fillColor",
427
+ "strokeWidth",
428
+ "opacity",
429
+ "fontSize",
430
+ "strokeStyle"
431
+ ];
432
+
433
+ // src/hooks/use-selection-style.ts
420
434
  function styleEqual(a, b) {
421
435
  if (a === b) return true;
422
436
  if (a === null || b === null) return false;
423
- const keys = ["color", "fillColor", "strokeWidth", "opacity", "fontSize"];
424
- return keys.every((k) => a[k] === b[k]);
437
+ return STYLE_KEYS.every((k) => a[k] === b[k]);
425
438
  }
426
439
  function useSelectionStyle() {
427
440
  const viewport = useViewport();
@@ -448,12 +461,17 @@ function useSelectionStyle() {
448
461
  return [style, apply];
449
462
  }
450
463
 
451
- // src/hooks/use-selection-ops.ts
464
+ // src/hooks/use-selection-style-details.ts
452
465
  var import_react13 = require("react");
453
- function snapshotEqual(a, b) {
454
- 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;
466
+ function keysEqual(a, b) {
467
+ return a.length === b.length && a.every((k, i) => k === b[i]);
455
468
  }
456
- function useSelectionOps() {
469
+ function detailsEqual(a, b) {
470
+ if (a === b) return true;
471
+ if (a === null || b === null) return false;
472
+ return keysEqual(a.applicable, b.applicable) && keysEqual(a.mixed, b.mixed) && STYLE_KEYS.every((k) => a.common[k] === b.common[k]);
473
+ }
474
+ function useSelectionStyleDetails() {
457
475
  const viewport = useViewport();
458
476
  const cacheRef = (0, import_react13.useRef)(null);
459
477
  const subscribe = (0, import_react13.useCallback)(
@@ -468,6 +486,36 @@ function useSelectionOps() {
468
486
  [viewport]
469
487
  );
470
488
  const getSnapshot = (0, import_react13.useCallback)(() => {
489
+ const next = viewport.getSelectionStyleDetails();
490
+ if (detailsEqual(cacheRef.current, next)) return cacheRef.current;
491
+ cacheRef.current = next;
492
+ return next;
493
+ }, [viewport]);
494
+ const details = (0, import_react13.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
495
+ const apply = (0, import_react13.useCallback)((s) => viewport.applyStyleToSelection(s), [viewport]);
496
+ return [details, apply];
497
+ }
498
+
499
+ // src/hooks/use-selection-ops.ts
500
+ var import_react14 = require("react");
501
+ function snapshotEqual(a, b) {
502
+ 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;
503
+ }
504
+ function useSelectionOps() {
505
+ const viewport = useViewport();
506
+ const cacheRef = (0, import_react14.useRef)(null);
507
+ const subscribe = (0, import_react14.useCallback)(
508
+ (onChange) => {
509
+ const offSel = viewport.onSelectionChange(onChange);
510
+ const offStore = viewport.store.onChange(onChange);
511
+ return () => {
512
+ offSel();
513
+ offStore();
514
+ };
515
+ },
516
+ [viewport]
517
+ );
518
+ const getSnapshot = (0, import_react14.useCallback)(() => {
471
519
  const ids = viewport.getSelectedIds();
472
520
  const n = ids.length;
473
521
  let canUngroup = false;
@@ -492,17 +540,17 @@ function useSelectionOps() {
492
540
  cacheRef.current = next;
493
541
  return next;
494
542
  }, [viewport]);
495
- const snap = (0, import_react13.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
496
- const group = (0, import_react13.useCallback)(() => viewport.groupSelection(), [viewport]);
497
- const ungroup = (0, import_react13.useCallback)(() => viewport.ungroupSelection(), [viewport]);
498
- const toggleLock = (0, import_react13.useCallback)(() => viewport.toggleLockSelection(), [viewport]);
499
- const align = (0, import_react13.useCallback)((edge) => viewport.alignSelection(edge), [viewport]);
500
- const distribute = (0, import_react13.useCallback)(
543
+ const snap = (0, import_react14.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
544
+ const group = (0, import_react14.useCallback)(() => viewport.groupSelection(), [viewport]);
545
+ const ungroup = (0, import_react14.useCallback)(() => viewport.ungroupSelection(), [viewport]);
546
+ const toggleLock = (0, import_react14.useCallback)(() => viewport.toggleLockSelection(), [viewport]);
547
+ const align = (0, import_react14.useCallback)((edge) => viewport.alignSelection(edge), [viewport]);
548
+ const distribute = (0, import_react14.useCallback)(
501
549
  (axis) => viewport.distributeSelection(axis),
502
550
  [viewport]
503
551
  );
504
- const rotateCW = (0, import_react13.useCallback)(() => viewport.rotateSelection("cw"), [viewport]);
505
- const rotateCCW = (0, import_react13.useCallback)(() => viewport.rotateSelection("ccw"), [viewport]);
552
+ const rotateCW = (0, import_react14.useCallback)(() => viewport.rotateSelection("cw"), [viewport]);
553
+ const rotateCCW = (0, import_react14.useCallback)(() => viewport.rotateSelection("ccw"), [viewport]);
506
554
  return {
507
555
  selectedIds: snap.selectedIds,
508
556
  selectedCount: snap.selectedIds.length,
@@ -521,9 +569,54 @@ function useSelectionOps() {
521
569
  };
522
570
  }
523
571
 
524
- // src/minimap.tsx
525
- var import_react14 = require("react");
572
+ // src/hooks/use-element-rects.ts
573
+ var import_react15 = require("react");
526
574
  var import_core2 = require("@fieldnotes/core");
575
+ function useElementRects(match) {
576
+ const viewport = useViewport();
577
+ const matchRef = (0, import_react15.useRef)(match);
578
+ matchRef.current = match;
579
+ const stableMatch = (0, import_react15.useCallback)((el) => matchRef.current(el), []);
580
+ const cacheRef = (0, import_react15.useRef)(null);
581
+ const trackerRef = (0, import_react15.useRef)(null);
582
+ const subscribe = (0, import_react15.useCallback)(
583
+ (onStoreChange) => {
584
+ const tracker = new import_core2.ElementRectTracker(viewport, { match: stableMatch });
585
+ trackerRef.current = tracker;
586
+ const next = tracker.getRects();
587
+ const previous = cacheRef.current;
588
+ if (previous === null || !(0, import_core2.elementRectsEqual)(previous, next)) {
589
+ cacheRef.current = next;
590
+ onStoreChange();
591
+ }
592
+ const off = tracker.onChange((rects2) => {
593
+ cacheRef.current = rects2;
594
+ onStoreChange();
595
+ });
596
+ return () => {
597
+ off();
598
+ tracker.dispose();
599
+ if (trackerRef.current === tracker) trackerRef.current = null;
600
+ };
601
+ },
602
+ [viewport, stableMatch]
603
+ );
604
+ const getSnapshot = (0, import_react15.useCallback)(() => {
605
+ if (cacheRef.current === null) {
606
+ cacheRef.current = (0, import_core2.computeElementRects)(viewport.store, stableMatch);
607
+ }
608
+ return cacheRef.current;
609
+ }, [viewport, stableMatch]);
610
+ const rects = (0, import_react15.useSyncExternalStore)(subscribe, getSnapshot);
611
+ (0, import_react15.useEffect)(() => {
612
+ trackerRef.current?.setMatch(stableMatch);
613
+ }, [match, stableMatch]);
614
+ return rects;
615
+ }
616
+
617
+ // src/minimap.tsx
618
+ var import_react16 = require("react");
619
+ var import_core3 = require("@fieldnotes/core");
527
620
  var import_jsx_runtime2 = require("react/jsx-runtime");
528
621
  var toggleStyle = {
529
622
  position: "absolute",
@@ -549,13 +642,13 @@ function Minimap({
549
642
  style
550
643
  }) {
551
644
  const viewport = useViewport();
552
- const [collapsed, setCollapsed] = (0, import_react14.useState)(defaultCollapsed);
553
- const canvasRef = (0, import_react14.useRef)(null);
554
- (0, import_react14.useEffect)(() => {
645
+ const [collapsed, setCollapsed] = (0, import_react16.useState)(defaultCollapsed);
646
+ const canvasRef = (0, import_react16.useRef)(null);
647
+ (0, import_react16.useEffect)(() => {
555
648
  if (collapsed) return;
556
649
  const canvas = canvasRef.current;
557
650
  if (!canvas) return;
558
- const controller = new import_core2.MinimapController(viewport, canvas, {
651
+ const controller = new import_core3.MinimapController(viewport, canvas, {
559
652
  width,
560
653
  height,
561
654
  background,
@@ -613,12 +706,14 @@ function Minimap({
613
706
  ViewportContext,
614
707
  useActiveTool,
615
708
  useCamera,
709
+ useElementRects,
616
710
  useElements,
617
711
  useHistory,
618
712
  useLayers,
619
713
  useSelection,
620
714
  useSelectionOps,
621
715
  useSelectionStyle,
716
+ useSelectionStyleDetails,
622
717
  useToolOptions,
623
718
  useViewport
624
719
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/field-notes-canvas.tsx","../src/context.ts","../src/canvas-element.tsx","../src/hooks/use-viewport.ts","../src/hooks/use-active-tool.ts","../src/hooks/use-camera.ts","../src/hooks/use-tool-options.ts","../src/hooks/use-layers.ts","../src/hooks/use-history.ts","../src/hooks/use-elements.ts","../src/hooks/use-selection.ts","../src/hooks/use-selection-style.ts","../src/hooks/use-selection-ops.ts","../src/minimap.tsx"],"sourcesContent":["export { FieldNotesCanvas } from './field-notes-canvas';\nexport type { FieldNotesCanvasProps, FieldNotesCanvasRef } from './field-notes-canvas';\nexport { CanvasElement } from './canvas-element';\nexport type { CanvasElementProps } from './canvas-element';\nexport {\n useViewport,\n useActiveTool,\n useCamera,\n useToolOptions,\n useLayers,\n useHistory,\n useElements,\n useSelection,\n useSelectionStyle,\n useSelectionOps,\n} from './hooks';\nexport type {\n CameraState,\n UseLayersResult,\n UseHistoryResult,\n UseSelectionOpsResult,\n} from './hooks';\nexport type { ElementStyle } from '@fieldnotes/core';\nexport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\nexport { ViewportContext } from './context';\nexport { Minimap } from './minimap';\nexport type { MinimapProps } from './minimap';\n","import {\r\n useRef,\r\n useEffect,\r\n useState,\r\n forwardRef,\r\n useImperativeHandle,\r\n type ReactNode,\r\n type CSSProperties,\r\n} from 'react';\r\nimport { Viewport } from '@fieldnotes/core';\r\nimport type { ViewportOptions, Tool } from '@fieldnotes/core';\r\nimport { ViewportContext } from './context';\r\n\r\nexport interface FieldNotesCanvasProps {\r\n /** Constructor-only: changes after mount are ignored (the canvas is stateful). */\r\n options?: ViewportOptions;\r\n /**\r\n * Reactive (append-only): tools present here are registered; removal is not supported.\r\n * Hoist the array out of render — inline arrays reconstruct Tool instances and re-run\r\n * registration on every render.\r\n */\r\n tools?: Tool[];\r\n /** Uncontrolled initial tool. Ignored when `tool` is set. */\r\n defaultTool?: string;\r\n /** Controlled active tool. Pair with `onToolChange`. */\r\n tool?: string;\r\n /**\r\n * Fires whenever the active tool changes (keyboard, API, or `tool` prop).\r\n * Memoize with useCallback to avoid re-subscribing each render.\r\n */\r\n onToolChange?: (name: string) => void;\r\n /** Reactive: toggles grid snapping. */\r\n snapToGrid?: boolean;\r\n className?: string;\r\n style?: CSSProperties;\r\n children?: ReactNode;\r\n onReady?: (viewport: Viewport) => void;\r\n}\r\n\r\nexport interface FieldNotesCanvasRef {\r\n viewport: Viewport | null;\r\n}\r\n\r\nexport const FieldNotesCanvas = forwardRef<FieldNotesCanvasRef, FieldNotesCanvasProps>(\r\n function FieldNotesCanvas(\r\n {\r\n options,\r\n tools,\r\n defaultTool,\r\n tool,\r\n onToolChange,\r\n snapToGrid,\r\n className,\r\n style,\r\n children,\r\n onReady,\r\n },\r\n ref,\r\n ) {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const [viewport, setViewport] = useState<Viewport | null>(null);\r\n\r\n useImperativeHandle(ref, () => ({ viewport }), [viewport]);\r\n\r\n useEffect(() => {\r\n const el = containerRef.current;\r\n if (!el) return;\r\n\r\n const vp = new Viewport(el, options);\r\n\r\n if (tools) {\r\n for (const t of tools) {\r\n vp.toolManager.register(t);\r\n }\r\n }\r\n\r\n const initialTool = tool ?? defaultTool;\r\n if (initialTool) {\r\n vp.setTool(initialTool);\r\n }\r\n\r\n setViewport(vp);\r\n onReady?.(vp);\r\n\r\n return () => {\r\n vp.destroy();\r\n setViewport(null);\r\n };\r\n // Constructor effect: options/tools/defaultTool are mount-only by design.\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!viewport || tool === undefined) return;\r\n if (viewport.toolManager.activeTool?.name !== tool) {\r\n viewport.setTool(tool);\r\n }\r\n }, [viewport, tool]);\r\n\r\n useEffect(() => {\r\n if (!viewport || !onToolChange) return;\r\n return viewport.toolManager.onChange(onToolChange);\r\n }, [viewport, onToolChange]);\r\n\r\n useEffect(() => {\r\n if (!viewport || snapToGrid === undefined) return;\r\n viewport.setSnapToGrid(snapToGrid);\r\n }, [viewport, snapToGrid]);\r\n\r\n useEffect(() => {\r\n if (!viewport || !tools) return;\r\n for (const t of tools) {\r\n if (!viewport.toolManager.getTool(t.name)) {\r\n viewport.toolManager.register(t);\r\n }\r\n }\r\n }, [viewport, tools]);\r\n\r\n return (\r\n <div ref={containerRef} className={className} style={style}>\r\n {viewport && (\r\n <ViewportContext.Provider value={viewport}>{children}</ViewportContext.Provider>\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n","import { createContext } from 'react';\r\nimport type { Viewport } from '@fieldnotes/core';\r\n\r\nexport const ViewportContext = createContext<Viewport | null>(null);\r\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { useViewport } from './hooks/use-viewport';\r\n\r\n/** Props for {@link CanvasElement}. */\r\nexport interface CanvasElementProps {\r\n /** Canvas-space position of the element's top-left corner. */\r\n position: { x: number; y: number };\r\n /** Optional fixed size; omit to let the element size to its content. */\r\n size?: { w: number; h: number };\r\n children: ReactNode;\r\n}\r\n\r\n/**\r\n * Renders a React subtree as an HTML element embedded in the canvas coordinate space.\r\n * Must be used inside a `<FieldNotesCanvas>`.\r\n */\r\nexport function CanvasElement({ position, size, children }: CanvasElementProps) {\r\n const viewport = useViewport();\r\n const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\r\n const elementIdRef = useRef<string | null>(null);\r\n\r\n useEffect(() => {\r\n const container = document.createElement('div');\r\n Object.assign(container.style, {\r\n width: '100%',\r\n height: '100%',\r\n });\r\n\r\n // Append to domLayer immediately so portal children are queryable in the document\r\n // before the viewport render loop fires via requestAnimationFrame.\r\n viewport.domLayer.appendChild(container);\r\n\r\n const id = viewport.addHtmlElement(container, position, size);\r\n elementIdRef.current = id;\r\n setPortalTarget(container);\r\n\r\n return () => {\r\n if (elementIdRef.current) {\r\n viewport.store.remove(elementIdRef.current);\r\n viewport.requestRender();\r\n elementIdRef.current = null;\r\n }\r\n setPortalTarget(null);\r\n };\r\n }, [viewport]);\r\n\r\n useEffect(() => {\r\n const id = elementIdRef.current;\r\n if (!id) return;\r\n viewport.store.update(id, { position });\r\n if (size) {\r\n viewport.store.update(id, { size });\r\n }\r\n viewport.requestRender();\r\n // Primitive deps (position.x/y, size?.w/h) are intentional: the effect re-runs on VALUE change,\r\n // not object identity — so inline { x, y } literals and memoized-but-unchanged objects both behave\r\n // correctly (no over-firing on every parent re-render).\r\n }, [viewport, position.x, position.y, size?.w, size?.h]);\r\n\r\n if (!portalTarget) return null;\r\n return createPortal(children, portalTarget);\r\n}\r\n","import { useContext } from 'react';\r\nimport type { Viewport } from '@fieldnotes/core';\r\nimport { ViewportContext } from '../context';\r\n\r\n/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */\r\nexport function useViewport(): Viewport {\r\n const viewport = useContext(ViewportContext);\r\n if (!viewport) {\r\n throw new Error('useViewport must be used inside <FieldNotesCanvas>');\r\n }\r\n return viewport;\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\n/** `[activeToolName, setTool]` — re-renders on tool switches. */\r\nexport function useActiveTool(): [toolName: string, setTool: (name: string) => void] {\r\n const viewport = useViewport();\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.toolManager.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => viewport.toolManager.activeTool?.name ?? '', [viewport]);\r\n\r\n const toolName = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const setTool = useCallback((name: string) => viewport.setTool(name), [viewport]);\r\n\r\n return [toolName, setTool];\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\nexport interface CameraState {\r\n x: number;\r\n y: number;\r\n zoom: number;\r\n}\r\n\r\n/** Current camera position and zoom level — re-renders whenever the camera moves or zoom changes. */\r\nexport function useCamera(): CameraState {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<CameraState>({ x: 0, y: 0, zoom: 1 });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.camera.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): CameraState => {\r\n const { position, zoom } = viewport.camera;\r\n const cached = cachedRef.current;\r\n if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {\r\n return cached;\r\n }\r\n const next = { x: position.x, y: position.y, zoom };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction noop() {\r\n /* unsubscribe placeholder */\r\n}\r\n\r\n/**\r\n * `[options, setOptions]` for the named tool — re-renders when the tool's options change.\r\n * Returns `null` for options if the tool is not registered or does not expose options.\r\n */\r\nexport function useToolOptions<T extends Record<string, unknown>>(\r\n toolName: string,\r\n): [options: T | null, setOptions: (partial: Partial<T>) => void] {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<T | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n if (!tool?.onOptionsChange) return noop;\r\n return tool.onOptionsChange(onStoreChange);\r\n },\r\n [viewport, toolName],\r\n );\r\n\r\n const getSnapshot = useCallback((): T | null => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n if (!tool?.getOptions) return null;\r\n const next = tool.getOptions() as T;\r\n const cached = cachedRef.current;\r\n if (cached && shallowEqual(cached, next)) return cached;\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport, toolName]);\r\n\r\n const options = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const setOptions = useCallback(\r\n (partial: Partial<T>) => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n tool?.setOptions?.(partial as Record<string, unknown>);\r\n },\r\n [viewport, toolName],\r\n );\r\n\r\n return [options, setOptions];\r\n}\r\n\r\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\r\n const keysA = Object.keys(a);\r\n const keysB = Object.keys(b);\r\n if (keysA.length !== keysB.length) return false;\r\n for (const key of keysA) {\r\n const valA = a[key];\r\n const valB = b[key];\r\n if (valA === valB) continue;\r\n if (\r\n typeof valA === 'object' &&\r\n valA !== null &&\r\n typeof valB === 'object' &&\r\n valB !== null &&\r\n !Array.isArray(valA) &&\r\n !Array.isArray(valB)\r\n ) {\r\n const objA = valA as Record<string, unknown>;\r\n const objB = valB as Record<string, unknown>;\r\n const innerKeys = Object.keys(objA);\r\n if (\r\n innerKeys.length === Object.keys(objB).length &&\r\n innerKeys.every((k) => objA[k] === objB[k])\r\n ) {\r\n continue;\r\n }\r\n }\r\n return false;\r\n }\r\n return true;\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { Layer } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\ninterface LayersSnapshot {\r\n layers: Layer[];\r\n activeLayerId: string;\r\n}\r\n\r\nexport interface UseLayersResult {\r\n layers: Layer[];\r\n activeLayerId: string;\r\n createLayer: (name?: string) => Layer;\r\n removeLayer: (id: string) => void;\r\n renameLayer: (id: string, name: string) => void;\r\n reorderLayer: (id: string, newOrder: number) => void;\r\n setVisible: (id: string, visible: boolean) => void;\r\n setLocked: (id: string, locked: boolean) => void;\r\n setOpacity: (id: string, opacity: number) => void;\r\n setActiveLayer: (id: string) => void;\r\n moveElement: (elementId: string, layerId: string) => void;\r\n}\r\n\r\n/**\r\n * Current layer list and mutation helpers — re-renders whenever a layer is added, removed,\r\n * reordered, renamed, or its visibility/lock/opacity/active state changes.\r\n */\r\nexport function useLayers(): UseLayersResult {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<LayersSnapshot>({ layers: [], activeLayerId: '' });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.layerManager.on('change', onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): LayersSnapshot => {\r\n const layers = viewport.layerManager.getLayers();\r\n const activeLayerId = viewport.layerManager.activeLayerId;\r\n const cached = cachedRef.current;\r\n if (\r\n cached.activeLayerId === activeLayerId &&\r\n cached.layers.length === layers.length &&\r\n cached.layers.every((l, i) => {\r\n const next = layers[i];\r\n return (\r\n next !== undefined &&\r\n l.id === next.id &&\r\n l.name === next.name &&\r\n l.visible === next.visible &&\r\n l.locked === next.locked &&\r\n l.order === next.order &&\r\n l.opacity === next.opacity\r\n );\r\n })\r\n ) {\r\n return cached;\r\n }\r\n const next = { layers, activeLayerId };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const createLayer = useCallback(\r\n (name?: string) => viewport.layerManager.createLayer(name),\r\n [viewport],\r\n );\r\n\r\n const removeLayer = useCallback(\r\n (id: string) => viewport.layerManager.removeLayer(id),\r\n [viewport],\r\n );\r\n\r\n const renameLayer = useCallback(\r\n (id: string, name: string) => viewport.layerManager.renameLayer(id, name),\r\n [viewport],\r\n );\r\n\r\n const reorderLayer = useCallback(\r\n (id: string, newOrder: number) => viewport.layerManager.reorderLayer(id, newOrder),\r\n [viewport],\r\n );\r\n\r\n const setVisible = useCallback(\r\n (id: string, visible: boolean) => viewport.layerManager.setLayerVisible(id, visible),\r\n [viewport],\r\n );\r\n\r\n const setLocked = useCallback(\r\n (id: string, locked: boolean) => viewport.layerManager.setLayerLocked(id, locked),\r\n [viewport],\r\n );\r\n\r\n const setOpacity = useCallback(\r\n (id: string, opacity: number) => viewport.layerManager.setLayerOpacity(id, opacity),\r\n [viewport],\r\n );\r\n\r\n const setActiveLayer = useCallback(\r\n (id: string) => viewport.layerManager.setActiveLayer(id),\r\n [viewport],\r\n );\r\n\r\n const moveElement = useCallback(\r\n (elementId: string, layerId: string) =>\r\n viewport.layerManager.moveElementToLayer(elementId, layerId),\r\n [viewport],\r\n );\r\n\r\n return {\r\n layers: snapshot.layers,\r\n activeLayerId: snapshot.activeLayerId,\r\n createLayer,\r\n removeLayer,\r\n renameLayer,\r\n reorderLayer,\r\n setVisible,\r\n setLocked,\r\n setOpacity,\r\n setActiveLayer,\r\n moveElement,\r\n };\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\ninterface HistorySnapshot {\r\n canUndo: boolean;\r\n canRedo: boolean;\r\n}\r\n\r\nexport interface UseHistoryResult {\r\n canUndo: boolean;\r\n canRedo: boolean;\r\n undo: () => void;\r\n redo: () => void;\r\n}\r\n\r\n/** `{ canUndo, canRedo, undo, redo }` — re-renders when undo/redo availability changes. */\r\nexport function useHistory(): UseHistoryResult {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<HistorySnapshot>({ canUndo: false, canRedo: false });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.history.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): HistorySnapshot => {\r\n const canUndo = viewport.history.canUndo;\r\n const canRedo = viewport.history.canRedo;\r\n const cached = cachedRef.current;\r\n if (cached.canUndo === canUndo && cached.canRedo === canRedo) {\r\n return cached;\r\n }\r\n const next = { canUndo, canRedo };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const undo = useCallback(() => viewport.undo(), [viewport]);\r\n const redo = useCallback(() => viewport.redo(), [viewport]);\r\n\r\n return {\r\n canUndo: snapshot.canUndo,\r\n canRedo: snapshot.canRedo,\r\n undo,\r\n redo,\r\n };\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { CanvasElement, ElementType } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction shallowEqual(a: unknown, b: unknown): boolean {\r\n if (Object.is(a, b)) return true;\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));\r\n }\r\n if (\r\n typeof a === 'object' &&\r\n a !== null &&\r\n typeof b === 'object' &&\r\n b !== null &&\r\n !Array.isArray(a) &&\r\n !Array.isArray(b)\r\n ) {\r\n const ka = Object.keys(a);\r\n const kb = Object.keys(b);\r\n return (\r\n ka.length === kb.length &&\r\n ka.every(\r\n (k) =>\r\n k in (b as Record<string, unknown>) &&\r\n Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\r\n )\r\n );\r\n }\r\n return false;\r\n}\r\n\r\n/** All elements; re-renders on every store mutation (use a selector for hot paths). */\r\nexport function useElements(): CanvasElement[];\r\n/** Elements of one type; re-renders on every store mutation. */\r\nexport function useElements<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[];\r\n/**\r\n * Derived value; re-renders only when the selected value changes (per `isEqual`,\r\n * default: one-level shallow compare — arrays by index, plain objects by key, primitives by\r\n * Object.is). Keep the selector referentially stable (useCallback or module scope).\r\n *\r\n * Supply `isEqual` for deeper structures. Note: selectors returning nested fresh objects\r\n * (e.g. `els => els.map(e => ({ ...e.position }))`) still need a custom comparator because\r\n * the default only compares one level deep.\r\n */\r\nexport function useElements<R>(\r\n selector: (elements: CanvasElement[]) => R,\r\n isEqual?: (a: R, b: R) => boolean,\r\n): R;\r\nexport function useElements<R>(\r\n arg?: ElementType | ((elements: CanvasElement[]) => R),\r\n isEqual?: (a: R, b: R) => boolean,\r\n): CanvasElement[] | R {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<CanvasElement[]>([]);\r\n const selectedRef = useRef<{ value: R } | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.store.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): CanvasElement[] | R => {\r\n if (typeof arg === 'function') {\r\n const next = arg(viewport.store.getAll());\r\n const prev = selectedRef.current;\r\n const equal: (a: R, b: R) => boolean = isEqual ?? (shallowEqual as (a: R, b: R) => boolean);\r\n if (prev !== null && equal(prev.value, next)) {\r\n return prev.value;\r\n }\r\n selectedRef.current = { value: next };\r\n return next;\r\n }\r\n\r\n const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();\r\n const cached = cachedRef.current;\r\n if (cached.length === next.length && cached.every((el, i) => el === next[i])) {\r\n return cached;\r\n }\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport, arg, isEqual]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\n/** Reactive selected element ids. Stable array reference — only changes when the selection changes. */\r\nexport function useSelection(): string[] {\r\n const viewport = useViewport();\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => viewport.onSelectionChange(onChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => viewport.getSelectedIds(), [viewport]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { ElementStyle } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction styleEqual(a: ElementStyle | null, b: ElementStyle | null): boolean {\r\n if (a === b) return true;\r\n if (a === null || b === null) return false;\r\n const keys: (keyof ElementStyle)[] = ['color', 'fillColor', 'strokeWidth', 'opacity', 'fontSize'];\r\n return keys.every((k) => a[k] === b[k]);\r\n}\r\n\r\n/**\r\n * Reactive normalized style of the current selection.\r\n * Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.\r\n * `applyPatch` applies an `ElementStyle` patch to every selected element.\r\n */\r\nexport function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void] {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<ElementStyle | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n const next = viewport.getSelectionStyle();\r\n if (styleEqual(cacheRef.current, next)) return cacheRef.current;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const style = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\r\n\r\n return [style, apply];\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nexport interface UseSelectionOpsResult {\r\n selectedIds: string[];\r\n selectedCount: number;\r\n canGroup: boolean;\r\n canUngroup: boolean;\r\n canAlign: boolean;\r\n canDistribute: boolean;\r\n isLocked: boolean | null;\r\n group: () => void;\r\n ungroup: () => void;\r\n toggleLock: () => void;\r\n align: (edge: AlignEdge) => void;\r\n distribute: (axis: DistributeAxis) => void;\r\n rotateCW: () => void;\r\n rotateCCW: () => void;\r\n}\r\n\r\ninterface Snapshot {\r\n selectedIds: string[];\r\n canGroup: boolean;\r\n canUngroup: boolean;\r\n canAlign: boolean;\r\n canDistribute: boolean;\r\n isLocked: boolean | null;\r\n}\r\n\r\nfunction snapshotEqual(a: Snapshot, b: Snapshot): boolean {\r\n return (\r\n a.selectedIds === b.selectedIds &&\r\n a.canGroup === b.canGroup &&\r\n a.canUngroup === b.canUngroup &&\r\n a.canAlign === b.canAlign &&\r\n a.canDistribute === b.canDistribute &&\r\n a.isLocked === b.isLocked\r\n );\r\n}\r\n\r\n/**\r\n * Reactive selection operations + derived predicates for the current selection.\r\n * Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;\r\n * `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,\r\n * and `null` when empty or mixed. Actions delegate to the core Viewport.\r\n */\r\nexport function useSelectionOps(): UseSelectionOpsResult {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<Snapshot | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): Snapshot => {\r\n const ids = viewport.getSelectedIds();\r\n const n = ids.length;\r\n let canUngroup = false;\r\n let lockedCount = 0;\r\n for (const id of ids) {\r\n const el = viewport.store.getById(id);\r\n if (!el) continue;\r\n if (el.groupId !== undefined) canUngroup = true;\r\n if (el.locked) lockedCount++;\r\n }\r\n const isLocked: boolean | null =\r\n n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;\r\n const next: Snapshot = {\r\n selectedIds: ids,\r\n canGroup: n >= 2,\r\n canUngroup,\r\n canAlign: n >= 2,\r\n canDistribute: n >= 3,\r\n isLocked,\r\n };\r\n const prev = cacheRef.current;\r\n if (prev && snapshotEqual(prev, next)) return prev;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n const group = useCallback(() => viewport.groupSelection(), [viewport]);\r\n const ungroup = useCallback(() => viewport.ungroupSelection(), [viewport]);\r\n const toggleLock = useCallback(() => viewport.toggleLockSelection(), [viewport]);\r\n const align = useCallback((edge: AlignEdge) => viewport.alignSelection(edge), [viewport]);\r\n const distribute = useCallback(\r\n (axis: DistributeAxis) => viewport.distributeSelection(axis),\r\n [viewport],\r\n );\r\n const rotateCW = useCallback(() => viewport.rotateSelection('cw'), [viewport]);\r\n const rotateCCW = useCallback(() => viewport.rotateSelection('ccw'), [viewport]);\r\n\r\n return {\r\n selectedIds: snap.selectedIds,\r\n selectedCount: snap.selectedIds.length,\r\n canGroup: snap.canGroup,\r\n canUngroup: snap.canUngroup,\r\n canAlign: snap.canAlign,\r\n canDistribute: snap.canDistribute,\r\n isLocked: snap.isLocked,\r\n group,\r\n ungroup,\r\n toggleLock,\r\n align,\r\n distribute,\r\n rotateCW,\r\n rotateCCW,\r\n };\r\n}\r\n","import { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { MinimapController } from '@fieldnotes/core';\nimport { useViewport } from './hooks/use-viewport';\n\nexport interface MinimapProps {\n /** Thumbnail width in CSS pixels. Default `200`. */\n width?: number;\n /** Thumbnail height in CSS pixels. Default `140`. */\n height?: number;\n /** Start collapsed (icon button only). Uncontrolled. Default `false`. */\n defaultCollapsed?: boolean;\n /** Backdrop fill behind the thumbnail. */\n background?: string;\n /** Viewport rectangle stroke color. */\n viewportStroke?: string;\n className?: string;\n style?: CSSProperties;\n}\n\nconst toggleStyle: CSSProperties = {\n position: 'absolute',\n top: 2,\n right: 2,\n width: 24,\n height: 24,\n padding: 0,\n border: 'none',\n borderRadius: 4,\n background: 'rgba(0,0,0,0.35)',\n color: '#fff',\n font: '14px/1 system-ui, sans-serif',\n cursor: 'pointer',\n};\n\n/**\n * Collapsible thumbnail overview navigator. Renders inside `<FieldNotesCanvas>`\n * (or any `ViewportContext.Provider`). Positioning is host-owned — place and\n * style the component via `className`/`style`. While collapsed, no controller\n * exists: zero listeners, zero rendering.\n */\nexport function Minimap({\n width = 200,\n height = 140,\n defaultCollapsed = false,\n background,\n viewportStroke,\n className,\n style,\n}: MinimapProps) {\n const viewport = useViewport();\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n\n useEffect(() => {\n if (collapsed) return;\n const canvas = canvasRef.current;\n if (!canvas) return;\n const controller = new MinimapController(viewport, canvas, {\n width,\n height,\n background,\n viewportStroke,\n });\n return () => controller.dispose();\n }, [viewport, collapsed, width, height, background, viewportStroke]);\n\n if (collapsed) {\n return (\n <button\n type=\"button\"\n aria-label=\"Expand minimap\"\n onClick={() => setCollapsed(false)}\n className={className}\n style={{\n minWidth: 44,\n minHeight: 44,\n border: '1px solid rgba(0,0,0,0.15)',\n borderRadius: 8,\n background: 'rgba(255,255,255,0.85)',\n cursor: 'pointer',\n font: '18px/1 system-ui, sans-serif',\n ...style,\n }}\n >\n {'▣'}\n </button>\n );\n }\n\n return (\n <div className={className} style={{ position: 'relative', ...style }}>\n <canvas\n ref={canvasRef}\n style={{ width: `${width}px`, height: `${height}px`, display: 'block' }}\n />\n <button\n type=\"button\"\n aria-label=\"Collapse minimap\"\n onClick={() => setCollapsed(true)}\n style={toggleStyle}\n >\n {'–'}\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","FieldNotesCanvas","import_react","import_react","import_react","import_react","import_react","import_react","next","import_react","import_react","shallowEqual","next","import_react","import_react","import_react","import_react","import_core","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/field-notes-canvas.tsx","../src/context.ts","../src/canvas-element.tsx","../src/hooks/use-viewport.ts","../src/hooks/use-active-tool.ts","../src/hooks/use-camera.ts","../src/hooks/use-tool-options.ts","../src/hooks/use-layers.ts","../src/hooks/use-history.ts","../src/hooks/use-elements.ts","../src/hooks/use-selection.ts","../src/hooks/use-selection-style.ts","../src/hooks/style-keys.ts","../src/hooks/use-selection-style-details.ts","../src/hooks/use-selection-ops.ts","../src/hooks/use-element-rects.ts","../src/minimap.tsx"],"sourcesContent":["export { FieldNotesCanvas } from './field-notes-canvas';\nexport type { FieldNotesCanvasProps, FieldNotesCanvasRef } from './field-notes-canvas';\nexport { CanvasElement } from './canvas-element';\nexport type { CanvasElementProps } from './canvas-element';\nexport {\n useViewport,\n useActiveTool,\n useCamera,\n useToolOptions,\n useLayers,\n useHistory,\n useElements,\n useSelection,\n useSelectionStyle,\n useSelectionStyleDetails,\n useSelectionOps,\n useElementRects,\n} from './hooks';\nexport type {\n CameraState,\n UseLayersResult,\n UseHistoryResult,\n UseSelectionOpsResult,\n} from './hooks';\nexport type { ElementStyle, SelectionStyleDetails, ElementRect } from '@fieldnotes/core';\nexport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\nexport { ViewportContext } from './context';\nexport { Minimap } from './minimap';\nexport type { MinimapProps } from './minimap';\n","import {\r\n useRef,\r\n useEffect,\r\n useState,\r\n forwardRef,\r\n useImperativeHandle,\r\n type ReactNode,\r\n type CSSProperties,\r\n} from 'react';\r\nimport { Viewport } from '@fieldnotes/core';\r\nimport type { ViewportOptions, Tool } from '@fieldnotes/core';\r\nimport { ViewportContext } from './context';\r\n\r\nexport interface FieldNotesCanvasProps {\r\n /** Constructor-only: changes after mount are ignored (the canvas is stateful). */\r\n options?: ViewportOptions;\r\n /**\r\n * Reactive (append-only): tools present here are registered; removal is not supported.\r\n * Hoist the array out of render — inline arrays reconstruct Tool instances and re-run\r\n * registration on every render.\r\n */\r\n tools?: Tool[];\r\n /** Uncontrolled initial tool. Ignored when `tool` is set. */\r\n defaultTool?: string;\r\n /** Controlled active tool. Pair with `onToolChange`. */\r\n tool?: string;\r\n /**\r\n * Fires whenever the active tool changes (keyboard, API, or `tool` prop).\r\n * Memoize with useCallback to avoid re-subscribing each render.\r\n */\r\n onToolChange?: (name: string) => void;\r\n /** Reactive: toggles grid snapping. */\r\n snapToGrid?: boolean;\r\n className?: string;\r\n style?: CSSProperties;\r\n children?: ReactNode;\r\n onReady?: (viewport: Viewport) => void;\r\n}\r\n\r\nexport interface FieldNotesCanvasRef {\r\n viewport: Viewport | null;\r\n}\r\n\r\nexport const FieldNotesCanvas = forwardRef<FieldNotesCanvasRef, FieldNotesCanvasProps>(\r\n function FieldNotesCanvas(\r\n {\r\n options,\r\n tools,\r\n defaultTool,\r\n tool,\r\n onToolChange,\r\n snapToGrid,\r\n className,\r\n style,\r\n children,\r\n onReady,\r\n },\r\n ref,\r\n ) {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const [viewport, setViewport] = useState<Viewport | null>(null);\r\n\r\n useImperativeHandle(ref, () => ({ viewport }), [viewport]);\r\n\r\n useEffect(() => {\r\n const el = containerRef.current;\r\n if (!el) return;\r\n\r\n const vp = new Viewport(el, options);\r\n\r\n if (tools) {\r\n for (const t of tools) {\r\n vp.toolManager.register(t);\r\n }\r\n }\r\n\r\n const initialTool = tool ?? defaultTool;\r\n if (initialTool) {\r\n vp.setTool(initialTool);\r\n }\r\n\r\n setViewport(vp);\r\n onReady?.(vp);\r\n\r\n return () => {\r\n vp.destroy();\r\n setViewport(null);\r\n };\r\n // Constructor effect: options/tools/defaultTool are mount-only by design.\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!viewport || tool === undefined) return;\r\n if (viewport.toolManager.activeTool?.name !== tool) {\r\n viewport.setTool(tool);\r\n }\r\n }, [viewport, tool]);\r\n\r\n useEffect(() => {\r\n if (!viewport || !onToolChange) return;\r\n return viewport.toolManager.onChange(onToolChange);\r\n }, [viewport, onToolChange]);\r\n\r\n useEffect(() => {\r\n if (!viewport || snapToGrid === undefined) return;\r\n viewport.setSnapToGrid(snapToGrid);\r\n }, [viewport, snapToGrid]);\r\n\r\n useEffect(() => {\r\n if (!viewport || !tools) return;\r\n for (const t of tools) {\r\n if (!viewport.toolManager.getTool(t.name)) {\r\n viewport.toolManager.register(t);\r\n }\r\n }\r\n }, [viewport, tools]);\r\n\r\n return (\r\n <div ref={containerRef} className={className} style={style}>\r\n {viewport && (\r\n <ViewportContext.Provider value={viewport}>{children}</ViewportContext.Provider>\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n","import { createContext } from 'react';\r\nimport type { Viewport } from '@fieldnotes/core';\r\n\r\nexport const ViewportContext = createContext<Viewport | null>(null);\r\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { useViewport } from './hooks/use-viewport';\r\n\r\n/** Props for {@link CanvasElement}. */\r\nexport interface CanvasElementProps {\r\n /** Canvas-space position of the element's top-left corner. */\r\n position: { x: number; y: number };\r\n /** Optional fixed size; omit to let the element size to its content. */\r\n size?: { w: number; h: number };\r\n children: ReactNode;\r\n}\r\n\r\n/**\r\n * Renders a React subtree as an HTML element embedded in the canvas coordinate space.\r\n * Must be used inside a `<FieldNotesCanvas>`.\r\n */\r\nexport function CanvasElement({ position, size, children }: CanvasElementProps) {\r\n const viewport = useViewport();\r\n const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\r\n const elementIdRef = useRef<string | null>(null);\r\n\r\n useEffect(() => {\r\n const container = document.createElement('div');\r\n Object.assign(container.style, {\r\n width: '100%',\r\n height: '100%',\r\n });\r\n\r\n // Append to domLayer immediately so portal children are queryable in the document\r\n // before the viewport render loop fires via requestAnimationFrame.\r\n viewport.domLayer.appendChild(container);\r\n\r\n const id = viewport.addHtmlElement(container, position, size);\r\n elementIdRef.current = id;\r\n setPortalTarget(container);\r\n\r\n return () => {\r\n if (elementIdRef.current) {\r\n viewport.store.remove(elementIdRef.current);\r\n viewport.requestRender();\r\n elementIdRef.current = null;\r\n }\r\n setPortalTarget(null);\r\n };\r\n }, [viewport]);\r\n\r\n useEffect(() => {\r\n const id = elementIdRef.current;\r\n if (!id) return;\r\n viewport.store.update(id, { position });\r\n if (size) {\r\n viewport.store.update(id, { size });\r\n }\r\n viewport.requestRender();\r\n // Primitive deps (position.x/y, size?.w/h) are intentional: the effect re-runs on VALUE change,\r\n // not object identity — so inline { x, y } literals and memoized-but-unchanged objects both behave\r\n // correctly (no over-firing on every parent re-render).\r\n }, [viewport, position.x, position.y, size?.w, size?.h]);\r\n\r\n if (!portalTarget) return null;\r\n return createPortal(children, portalTarget);\r\n}\r\n","import { useContext } from 'react';\r\nimport type { Viewport } from '@fieldnotes/core';\r\nimport { ViewportContext } from '../context';\r\n\r\n/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */\r\nexport function useViewport(): Viewport {\r\n const viewport = useContext(ViewportContext);\r\n if (!viewport) {\r\n throw new Error('useViewport must be used inside <FieldNotesCanvas>');\r\n }\r\n return viewport;\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\n/** `[activeToolName, setTool]` — re-renders on tool switches. */\r\nexport function useActiveTool(): [toolName: string, setTool: (name: string) => void] {\r\n const viewport = useViewport();\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.toolManager.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => viewport.toolManager.activeTool?.name ?? '', [viewport]);\r\n\r\n const toolName = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const setTool = useCallback((name: string) => viewport.setTool(name), [viewport]);\r\n\r\n return [toolName, setTool];\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\nexport interface CameraState {\r\n x: number;\r\n y: number;\r\n zoom: number;\r\n}\r\n\r\n/** Current camera position and zoom level — re-renders whenever the camera moves or zoom changes. */\r\nexport function useCamera(): CameraState {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<CameraState>({ x: 0, y: 0, zoom: 1 });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.camera.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): CameraState => {\r\n const { position, zoom } = viewport.camera;\r\n const cached = cachedRef.current;\r\n if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {\r\n return cached;\r\n }\r\n const next = { x: position.x, y: position.y, zoom };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction noop() {\r\n /* unsubscribe placeholder */\r\n}\r\n\r\n/**\r\n * `[options, setOptions]` for the named tool — re-renders when the tool's options change.\r\n * Returns `null` for options if the tool is not registered or does not expose options.\r\n */\r\nexport function useToolOptions<T extends Record<string, unknown>>(\r\n toolName: string,\r\n): [options: T | null, setOptions: (partial: Partial<T>) => void] {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<T | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n if (!tool?.onOptionsChange) return noop;\r\n return tool.onOptionsChange(onStoreChange);\r\n },\r\n [viewport, toolName],\r\n );\r\n\r\n const getSnapshot = useCallback((): T | null => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n if (!tool?.getOptions) return null;\r\n const next = tool.getOptions() as T;\r\n const cached = cachedRef.current;\r\n if (cached && shallowEqual(cached, next)) return cached;\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport, toolName]);\r\n\r\n const options = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const setOptions = useCallback(\r\n (partial: Partial<T>) => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n tool?.setOptions?.(partial as Record<string, unknown>);\r\n },\r\n [viewport, toolName],\r\n );\r\n\r\n return [options, setOptions];\r\n}\r\n\r\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\r\n const keysA = Object.keys(a);\r\n const keysB = Object.keys(b);\r\n if (keysA.length !== keysB.length) return false;\r\n for (const key of keysA) {\r\n const valA = a[key];\r\n const valB = b[key];\r\n if (valA === valB) continue;\r\n if (\r\n typeof valA === 'object' &&\r\n valA !== null &&\r\n typeof valB === 'object' &&\r\n valB !== null &&\r\n !Array.isArray(valA) &&\r\n !Array.isArray(valB)\r\n ) {\r\n const objA = valA as Record<string, unknown>;\r\n const objB = valB as Record<string, unknown>;\r\n const innerKeys = Object.keys(objA);\r\n if (\r\n innerKeys.length === Object.keys(objB).length &&\r\n innerKeys.every((k) => objA[k] === objB[k])\r\n ) {\r\n continue;\r\n }\r\n }\r\n return false;\r\n }\r\n return true;\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { Layer } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\ninterface LayersSnapshot {\r\n layers: Layer[];\r\n activeLayerId: string;\r\n}\r\n\r\nexport interface UseLayersResult {\r\n layers: Layer[];\r\n activeLayerId: string;\r\n createLayer: (name?: string) => Layer;\r\n removeLayer: (id: string) => void;\r\n renameLayer: (id: string, name: string) => void;\r\n reorderLayer: (id: string, newOrder: number) => void;\r\n setVisible: (id: string, visible: boolean) => void;\r\n setLocked: (id: string, locked: boolean) => void;\r\n setOpacity: (id: string, opacity: number) => void;\r\n setActiveLayer: (id: string) => void;\r\n moveElement: (elementId: string, layerId: string) => void;\r\n}\r\n\r\n/**\r\n * Current layer list and mutation helpers — re-renders whenever a layer is added, removed,\r\n * reordered, renamed, or its visibility/lock/opacity/active state changes.\r\n */\r\nexport function useLayers(): UseLayersResult {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<LayersSnapshot>({ layers: [], activeLayerId: '' });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.layerManager.on('change', onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): LayersSnapshot => {\r\n const layers = viewport.layerManager.getLayers();\r\n const activeLayerId = viewport.layerManager.activeLayerId;\r\n const cached = cachedRef.current;\r\n if (\r\n cached.activeLayerId === activeLayerId &&\r\n cached.layers.length === layers.length &&\r\n cached.layers.every((l, i) => {\r\n const next = layers[i];\r\n return (\r\n next !== undefined &&\r\n l.id === next.id &&\r\n l.name === next.name &&\r\n l.visible === next.visible &&\r\n l.locked === next.locked &&\r\n l.order === next.order &&\r\n l.opacity === next.opacity\r\n );\r\n })\r\n ) {\r\n return cached;\r\n }\r\n const next = { layers, activeLayerId };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const createLayer = useCallback(\r\n (name?: string) => viewport.layerManager.createLayer(name),\r\n [viewport],\r\n );\r\n\r\n const removeLayer = useCallback(\r\n (id: string) => viewport.layerManager.removeLayer(id),\r\n [viewport],\r\n );\r\n\r\n const renameLayer = useCallback(\r\n (id: string, name: string) => viewport.layerManager.renameLayer(id, name),\r\n [viewport],\r\n );\r\n\r\n const reorderLayer = useCallback(\r\n (id: string, newOrder: number) => viewport.layerManager.reorderLayer(id, newOrder),\r\n [viewport],\r\n );\r\n\r\n const setVisible = useCallback(\r\n (id: string, visible: boolean) => viewport.layerManager.setLayerVisible(id, visible),\r\n [viewport],\r\n );\r\n\r\n const setLocked = useCallback(\r\n (id: string, locked: boolean) => viewport.layerManager.setLayerLocked(id, locked),\r\n [viewport],\r\n );\r\n\r\n const setOpacity = useCallback(\r\n (id: string, opacity: number) => viewport.layerManager.setLayerOpacity(id, opacity),\r\n [viewport],\r\n );\r\n\r\n const setActiveLayer = useCallback(\r\n (id: string) => viewport.layerManager.setActiveLayer(id),\r\n [viewport],\r\n );\r\n\r\n const moveElement = useCallback(\r\n (elementId: string, layerId: string) =>\r\n viewport.layerManager.moveElementToLayer(elementId, layerId),\r\n [viewport],\r\n );\r\n\r\n return {\r\n layers: snapshot.layers,\r\n activeLayerId: snapshot.activeLayerId,\r\n createLayer,\r\n removeLayer,\r\n renameLayer,\r\n reorderLayer,\r\n setVisible,\r\n setLocked,\r\n setOpacity,\r\n setActiveLayer,\r\n moveElement,\r\n };\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\ninterface HistorySnapshot {\r\n canUndo: boolean;\r\n canRedo: boolean;\r\n}\r\n\r\nexport interface UseHistoryResult {\r\n canUndo: boolean;\r\n canRedo: boolean;\r\n undo: () => void;\r\n redo: () => void;\r\n}\r\n\r\n/** `{ canUndo, canRedo, undo, redo }` — re-renders when undo/redo availability changes. */\r\nexport function useHistory(): UseHistoryResult {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<HistorySnapshot>({ canUndo: false, canRedo: false });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.history.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): HistorySnapshot => {\r\n const canUndo = viewport.history.canUndo;\r\n const canRedo = viewport.history.canRedo;\r\n const cached = cachedRef.current;\r\n if (cached.canUndo === canUndo && cached.canRedo === canRedo) {\r\n return cached;\r\n }\r\n const next = { canUndo, canRedo };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const undo = useCallback(() => viewport.undo(), [viewport]);\r\n const redo = useCallback(() => viewport.redo(), [viewport]);\r\n\r\n return {\r\n canUndo: snapshot.canUndo,\r\n canRedo: snapshot.canRedo,\r\n undo,\r\n redo,\r\n };\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { CanvasElement, ElementType } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction shallowEqual(a: unknown, b: unknown): boolean {\r\n if (Object.is(a, b)) return true;\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));\r\n }\r\n if (\r\n typeof a === 'object' &&\r\n a !== null &&\r\n typeof b === 'object' &&\r\n b !== null &&\r\n !Array.isArray(a) &&\r\n !Array.isArray(b)\r\n ) {\r\n const ka = Object.keys(a);\r\n const kb = Object.keys(b);\r\n return (\r\n ka.length === kb.length &&\r\n ka.every(\r\n (k) =>\r\n k in (b as Record<string, unknown>) &&\r\n Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\r\n )\r\n );\r\n }\r\n return false;\r\n}\r\n\r\n/** All elements; re-renders on every store mutation (use a selector for hot paths). */\r\nexport function useElements(): CanvasElement[];\r\n/** Elements of one type; re-renders on every store mutation. */\r\nexport function useElements<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[];\r\n/**\r\n * Derived value; re-renders only when the selected value changes (per `isEqual`,\r\n * default: one-level shallow compare — arrays by index, plain objects by key, primitives by\r\n * Object.is). Keep the selector referentially stable (useCallback or module scope).\r\n *\r\n * Supply `isEqual` for deeper structures. Note: selectors returning nested fresh objects\r\n * (e.g. `els => els.map(e => ({ ...e.position }))`) still need a custom comparator because\r\n * the default only compares one level deep.\r\n */\r\nexport function useElements<R>(\r\n selector: (elements: CanvasElement[]) => R,\r\n isEqual?: (a: R, b: R) => boolean,\r\n): R;\r\nexport function useElements<R>(\r\n arg?: ElementType | ((elements: CanvasElement[]) => R),\r\n isEqual?: (a: R, b: R) => boolean,\r\n): CanvasElement[] | R {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<CanvasElement[]>([]);\r\n const selectedRef = useRef<{ value: R } | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.store.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): CanvasElement[] | R => {\r\n if (typeof arg === 'function') {\r\n const next = arg(viewport.store.getAll());\r\n const prev = selectedRef.current;\r\n const equal: (a: R, b: R) => boolean = isEqual ?? (shallowEqual as (a: R, b: R) => boolean);\r\n if (prev !== null && equal(prev.value, next)) {\r\n return prev.value;\r\n }\r\n selectedRef.current = { value: next };\r\n return next;\r\n }\r\n\r\n const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();\r\n const cached = cachedRef.current;\r\n if (cached.length === next.length && cached.every((el, i) => el === next[i])) {\r\n return cached;\r\n }\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport, arg, isEqual]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\n/** Reactive selected element ids. Stable array reference — only changes when the selection changes. */\r\nexport function useSelection(): string[] {\r\n const viewport = useViewport();\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => viewport.onSelectionChange(onChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => viewport.getSelectedIds(), [viewport]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { ElementStyle } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\nimport { STYLE_KEYS } from './style-keys';\r\n\r\nfunction styleEqual(a: ElementStyle | null, b: ElementStyle | null): boolean {\r\n if (a === b) return true;\r\n if (a === null || b === null) return false;\r\n return STYLE_KEYS.every((k) => a[k] === b[k]);\r\n}\r\n\r\n/**\r\n * Reactive normalized style of the current selection.\r\n * Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.\r\n * `applyPatch` applies an `ElementStyle` patch to every selected element.\r\n */\r\nexport function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void] {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<ElementStyle | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n const next = viewport.getSelectionStyle();\r\n if (styleEqual(cacheRef.current, next)) return cacheRef.current;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const style = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\r\n\r\n return [style, apply];\r\n}\r\n","import type { ElementStyle } from '@fieldnotes/core';\r\n\r\n/**\r\n * The `ElementStyle` fields the selection-style hooks compare and cache.\r\n * Internal to `@fieldnotes/react` — not exported from the package index.\r\n * Shared between `useSelectionStyle` and `useSelectionStyleDetails` so the\r\n * two hooks cannot drift out of sync (a prior desync here dropped\r\n * `strokeStyle` from one hook's equality check and caused stale style data).\r\n */\r\nexport const STYLE_KEYS: readonly (keyof ElementStyle)[] = [\r\n 'color',\r\n 'fillColor',\r\n 'strokeWidth',\r\n 'opacity',\r\n 'fontSize',\r\n 'strokeStyle',\r\n];\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\nimport { STYLE_KEYS } from './style-keys';\r\n\r\nfunction keysEqual(\r\n a: readonly (keyof ElementStyle)[],\r\n b: readonly (keyof ElementStyle)[],\r\n): boolean {\r\n return a.length === b.length && a.every((k, i) => k === b[i]);\r\n}\r\n\r\nfunction detailsEqual(a: SelectionStyleDetails | null, b: SelectionStyleDetails | null): boolean {\r\n if (a === b) return true;\r\n if (a === null || b === null) return false;\r\n return (\r\n keysEqual(a.applicable, b.applicable) &&\r\n keysEqual(a.mixed, b.mixed) &&\r\n STYLE_KEYS.every((k) => a.common[k] === b.common[k])\r\n );\r\n}\r\n\r\n/**\r\n * Reactive style details of the current selection: per-field applicability and\r\n * mixed-state, plus the common style. `null` when nothing valid is selected.\r\n * The apply function delegates to `applyStyleToSelection` (one undo step).\r\n */\r\nexport function useSelectionStyleDetails(): [\r\n SelectionStyleDetails | null,\r\n (style: ElementStyle) => void,\r\n] {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<SelectionStyleDetails | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n const next = viewport.getSelectionStyleDetails();\r\n if (detailsEqual(cacheRef.current, next)) return cacheRef.current;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const details = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\r\n\r\n return [details, apply];\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nexport interface UseSelectionOpsResult {\r\n selectedIds: string[];\r\n selectedCount: number;\r\n canGroup: boolean;\r\n canUngroup: boolean;\r\n canAlign: boolean;\r\n canDistribute: boolean;\r\n isLocked: boolean | null;\r\n group: () => void;\r\n ungroup: () => void;\r\n toggleLock: () => void;\r\n align: (edge: AlignEdge) => void;\r\n distribute: (axis: DistributeAxis) => void;\r\n rotateCW: () => void;\r\n rotateCCW: () => void;\r\n}\r\n\r\ninterface Snapshot {\r\n selectedIds: string[];\r\n canGroup: boolean;\r\n canUngroup: boolean;\r\n canAlign: boolean;\r\n canDistribute: boolean;\r\n isLocked: boolean | null;\r\n}\r\n\r\nfunction snapshotEqual(a: Snapshot, b: Snapshot): boolean {\r\n return (\r\n a.selectedIds === b.selectedIds &&\r\n a.canGroup === b.canGroup &&\r\n a.canUngroup === b.canUngroup &&\r\n a.canAlign === b.canAlign &&\r\n a.canDistribute === b.canDistribute &&\r\n a.isLocked === b.isLocked\r\n );\r\n}\r\n\r\n/**\r\n * Reactive selection operations + derived predicates for the current selection.\r\n * Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;\r\n * `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,\r\n * and `null` when empty or mixed. Actions delegate to the core Viewport.\r\n */\r\nexport function useSelectionOps(): UseSelectionOpsResult {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<Snapshot | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): Snapshot => {\r\n const ids = viewport.getSelectedIds();\r\n const n = ids.length;\r\n let canUngroup = false;\r\n let lockedCount = 0;\r\n for (const id of ids) {\r\n const el = viewport.store.getById(id);\r\n if (!el) continue;\r\n if (el.groupId !== undefined) canUngroup = true;\r\n if (el.locked) lockedCount++;\r\n }\r\n const isLocked: boolean | null =\r\n n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;\r\n const next: Snapshot = {\r\n selectedIds: ids,\r\n canGroup: n >= 2,\r\n canUngroup,\r\n canAlign: n >= 2,\r\n canDistribute: n >= 3,\r\n isLocked,\r\n };\r\n const prev = cacheRef.current;\r\n if (prev && snapshotEqual(prev, next)) return prev;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n const group = useCallback(() => viewport.groupSelection(), [viewport]);\r\n const ungroup = useCallback(() => viewport.ungroupSelection(), [viewport]);\r\n const toggleLock = useCallback(() => viewport.toggleLockSelection(), [viewport]);\r\n const align = useCallback((edge: AlignEdge) => viewport.alignSelection(edge), [viewport]);\r\n const distribute = useCallback(\r\n (axis: DistributeAxis) => viewport.distributeSelection(axis),\r\n [viewport],\r\n );\r\n const rotateCW = useCallback(() => viewport.rotateSelection('cw'), [viewport]);\r\n const rotateCCW = useCallback(() => viewport.rotateSelection('ccw'), [viewport]);\r\n\r\n return {\r\n selectedIds: snap.selectedIds,\r\n selectedCount: snap.selectedIds.length,\r\n canGroup: snap.canGroup,\r\n canUngroup: snap.canUngroup,\r\n canAlign: snap.canAlign,\r\n canDistribute: snap.canDistribute,\r\n isLocked: snap.isLocked,\r\n group,\r\n ungroup,\r\n toggleLock,\r\n align,\r\n distribute,\r\n rotateCW,\r\n rotateCCW,\r\n };\r\n}\r\n","import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react';\nimport { ElementRectTracker, computeElementRects, elementRectsEqual } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nimport type { CanvasElement, ElementRect, ElementRectMatch } from '@fieldnotes/core';\n\n/**\n * World rects of the elements a host matcher selects, re-rendering only when a\n * tracked field changes. Camera motion never re-renders: position content under\n * one camera transform and let the browser composite it.\n *\n * `match` may be an inline arrow — it is read through a ref, so it never\n * re-subscribes; a semantic change is picked up via `setMatch`.\n */\nexport function useElementRects(match: ElementRectMatch): readonly ElementRect[] {\n const viewport = useViewport();\n\n const matchRef = useRef<ElementRectMatch>(match);\n matchRef.current = match;\n const stableMatch = useCallback((el: CanvasElement) => matchRef.current(el), []);\n\n const cacheRef = useRef<readonly ElementRect[] | null>(null);\n const trackerRef = useRef<ElementRectTracker | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n // Constructed HERE, not in a memo: Strict Mode rehearses\n // setup -> cleanup -> setup without re-creating memoized state, so a\n // memo-created tracker disposed by the first cleanup would be reused\n // already disposed and would never emit again.\n const tracker = new ElementRectTracker(viewport, { match: stableMatch });\n trackerRef.current = tracker;\n\n const next = tracker.getRects();\n const previous = cacheRef.current;\n if (previous === null || !elementRectsEqual(previous, next)) {\n cacheRef.current = next;\n onStoreChange();\n }\n\n const off = tracker.onChange((rects) => {\n cacheRef.current = rects;\n onStoreChange();\n });\n\n return () => {\n off();\n tracker.dispose();\n if (trackerRef.current === tracker) trackerRef.current = null;\n };\n },\n [viewport, stableMatch],\n );\n\n const getSnapshot = useCallback((): readonly ElementRect[] => {\n if (cacheRef.current === null) {\n cacheRef.current = computeElementRects(viewport.store, stableMatch);\n }\n return cacheRef.current;\n }, [viewport, stableMatch]);\n\n const rects = useSyncExternalStore(subscribe, getSnapshot);\n\n // `stableMatch` never changes identity while its behavior does, so the\n // tracker needs an explicit nudge whenever the caller's matcher changes.\n useEffect(() => {\n trackerRef.current?.setMatch(stableMatch);\n }, [match, stableMatch]);\n\n return rects;\n}\n","import { useEffect, useRef, useState, type CSSProperties } from 'react';\r\nimport { MinimapController } from '@fieldnotes/core';\r\nimport { useViewport } from './hooks/use-viewport';\r\n\r\nexport interface MinimapProps {\r\n /** Thumbnail width in CSS pixels. Default `200`. */\r\n width?: number;\r\n /** Thumbnail height in CSS pixels. Default `140`. */\r\n height?: number;\r\n /** Start collapsed (icon button only). Uncontrolled. Default `false`. */\r\n defaultCollapsed?: boolean;\r\n /** Backdrop fill behind the thumbnail. */\r\n background?: string;\r\n /** Viewport rectangle stroke color. */\r\n viewportStroke?: string;\r\n className?: string;\r\n style?: CSSProperties;\r\n}\r\n\r\nconst toggleStyle: CSSProperties = {\r\n position: 'absolute',\r\n top: 2,\r\n right: 2,\r\n width: 24,\r\n height: 24,\r\n padding: 0,\r\n border: 'none',\r\n borderRadius: 4,\r\n background: 'rgba(0,0,0,0.35)',\r\n color: '#fff',\r\n font: '14px/1 system-ui, sans-serif',\r\n cursor: 'pointer',\r\n};\r\n\r\n/**\r\n * Collapsible thumbnail overview navigator. Renders inside `<FieldNotesCanvas>`\r\n * (or any `ViewportContext.Provider`). Positioning is host-owned — place and\r\n * style the component via `className`/`style`. While collapsed, no controller\r\n * exists: zero listeners, zero rendering.\r\n */\r\nexport function Minimap({\r\n width = 200,\r\n height = 140,\r\n defaultCollapsed = false,\r\n background,\r\n viewportStroke,\r\n className,\r\n style,\r\n}: MinimapProps) {\r\n const viewport = useViewport();\r\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n\r\n useEffect(() => {\r\n if (collapsed) return;\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const controller = new MinimapController(viewport, canvas, {\r\n width,\r\n height,\r\n background,\r\n viewportStroke,\r\n });\r\n return () => controller.dispose();\r\n }, [viewport, collapsed, width, height, background, viewportStroke]);\r\n\r\n if (collapsed) {\r\n return (\r\n <button\r\n type=\"button\"\r\n aria-label=\"Expand minimap\"\r\n onClick={() => setCollapsed(false)}\r\n className={className}\r\n style={{\r\n minWidth: 44,\r\n minHeight: 44,\r\n border: '1px solid rgba(0,0,0,0.15)',\r\n borderRadius: 8,\r\n background: 'rgba(255,255,255,0.85)',\r\n cursor: 'pointer',\r\n font: '18px/1 system-ui, sans-serif',\r\n ...style,\r\n }}\r\n >\r\n {'▣'}\r\n </button>\r\n );\r\n }\r\n\r\n return (\r\n <div className={className} style={{ position: 'relative', ...style }}>\r\n <canvas\r\n ref={canvasRef}\r\n style={{ width: `${width}px`, height: `${height}px`, display: 'block' }}\r\n />\r\n <button\r\n type=\"button\"\r\n aria-label=\"Collapse minimap\"\r\n onClick={() => setCollapsed(true)}\r\n style={toggleStyle}\r\n >\r\n {'–'}\r\n </button>\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["import_react","FieldNotesCanvas","import_react","import_react","import_react","import_react","import_react","import_react","next","import_react","import_react","shallowEqual","next","import_react","import_react","import_react","import_react","import_react","import_core","rects","import_react","import_core","import_jsx_runtime"]}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { CSSProperties, ReactNode } from 'react';
3
- import { ViewportOptions, Tool, Viewport, Layer, CanvasElement as CanvasElement$1, ElementType, ElementStyle, AlignEdge, DistributeAxis } from '@fieldnotes/core';
4
- export { AlignEdge, DistributeAxis, ElementStyle } from '@fieldnotes/core';
3
+ import { ViewportOptions, Tool, Viewport, Layer, CanvasElement as CanvasElement$1, ElementType, ElementStyle, SelectionStyleDetails, AlignEdge, DistributeAxis, ElementRectMatch, ElementRect } from '@fieldnotes/core';
4
+ export { AlignEdge, DistributeAxis, ElementRect, ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
 
7
7
  interface FieldNotesCanvasProps {
@@ -129,6 +129,16 @@ declare function useSelection(): string[];
129
129
  */
130
130
  declare function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void];
131
131
 
132
+ /**
133
+ * Reactive style details of the current selection: per-field applicability and
134
+ * mixed-state, plus the common style. `null` when nothing valid is selected.
135
+ * The apply function delegates to `applyStyleToSelection` (one undo step).
136
+ */
137
+ declare function useSelectionStyleDetails(): [
138
+ SelectionStyleDetails | null,
139
+ (style: ElementStyle) => void
140
+ ];
141
+
132
142
  interface UseSelectionOpsResult {
133
143
  selectedIds: string[];
134
144
  selectedCount: number;
@@ -153,6 +163,16 @@ interface UseSelectionOpsResult {
153
163
  */
154
164
  declare function useSelectionOps(): UseSelectionOpsResult;
155
165
 
166
+ /**
167
+ * World rects of the elements a host matcher selects, re-rendering only when a
168
+ * tracked field changes. Camera motion never re-renders: position content under
169
+ * one camera transform and let the browser composite it.
170
+ *
171
+ * `match` may be an inline arrow — it is read through a ref, so it never
172
+ * re-subscribes; a semantic change is picked up via `setMatch`.
173
+ */
174
+ declare function useElementRects(match: ElementRectMatch): readonly ElementRect[];
175
+
156
176
  declare const ViewportContext: react.Context<Viewport | null>;
157
177
 
158
178
  interface MinimapProps {
@@ -177,4 +197,4 @@ interface MinimapProps {
177
197
  */
178
198
  declare function Minimap({ width, height, defaultCollapsed, background, viewportStroke, className, style, }: MinimapProps): react_jsx_runtime.JSX.Element;
179
199
 
180
- export { type CameraState, CanvasElement, type CanvasElementProps, FieldNotesCanvas, type FieldNotesCanvasProps, type FieldNotesCanvasRef, Minimap, type MinimapProps, type UseHistoryResult, type UseLayersResult, type UseSelectionOpsResult, ViewportContext, useActiveTool, useCamera, useElements, useHistory, useLayers, useSelection, useSelectionOps, useSelectionStyle, useToolOptions, useViewport };
200
+ export { type CameraState, CanvasElement, type CanvasElementProps, FieldNotesCanvas, type FieldNotesCanvasProps, type FieldNotesCanvasRef, Minimap, type MinimapProps, type UseHistoryResult, type UseLayersResult, type UseSelectionOpsResult, ViewportContext, useActiveTool, useCamera, useElementRects, useElements, useHistory, useLayers, useSelection, useSelectionOps, useSelectionStyle, useSelectionStyleDetails, useToolOptions, useViewport };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { CSSProperties, ReactNode } from 'react';
3
- import { ViewportOptions, Tool, Viewport, Layer, CanvasElement as CanvasElement$1, ElementType, ElementStyle, AlignEdge, DistributeAxis } from '@fieldnotes/core';
4
- export { AlignEdge, DistributeAxis, ElementStyle } from '@fieldnotes/core';
3
+ import { ViewportOptions, Tool, Viewport, Layer, CanvasElement as CanvasElement$1, ElementType, ElementStyle, SelectionStyleDetails, AlignEdge, DistributeAxis, ElementRectMatch, ElementRect } from '@fieldnotes/core';
4
+ export { AlignEdge, DistributeAxis, ElementRect, ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
 
7
7
  interface FieldNotesCanvasProps {
@@ -129,6 +129,16 @@ declare function useSelection(): string[];
129
129
  */
130
130
  declare function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void];
131
131
 
132
+ /**
133
+ * Reactive style details of the current selection: per-field applicability and
134
+ * mixed-state, plus the common style. `null` when nothing valid is selected.
135
+ * The apply function delegates to `applyStyleToSelection` (one undo step).
136
+ */
137
+ declare function useSelectionStyleDetails(): [
138
+ SelectionStyleDetails | null,
139
+ (style: ElementStyle) => void
140
+ ];
141
+
132
142
  interface UseSelectionOpsResult {
133
143
  selectedIds: string[];
134
144
  selectedCount: number;
@@ -153,6 +163,16 @@ interface UseSelectionOpsResult {
153
163
  */
154
164
  declare function useSelectionOps(): UseSelectionOpsResult;
155
165
 
166
+ /**
167
+ * World rects of the elements a host matcher selects, re-rendering only when a
168
+ * tracked field changes. Camera motion never re-renders: position content under
169
+ * one camera transform and let the browser composite it.
170
+ *
171
+ * `match` may be an inline arrow — it is read through a ref, so it never
172
+ * re-subscribes; a semantic change is picked up via `setMatch`.
173
+ */
174
+ declare function useElementRects(match: ElementRectMatch): readonly ElementRect[];
175
+
156
176
  declare const ViewportContext: react.Context<Viewport | null>;
157
177
 
158
178
  interface MinimapProps {
@@ -177,4 +197,4 @@ interface MinimapProps {
177
197
  */
178
198
  declare function Minimap({ width, height, defaultCollapsed, background, viewportStroke, className, style, }: MinimapProps): react_jsx_runtime.JSX.Element;
179
199
 
180
- export { type CameraState, CanvasElement, type CanvasElementProps, FieldNotesCanvas, type FieldNotesCanvasProps, type FieldNotesCanvasRef, Minimap, type MinimapProps, type UseHistoryResult, type UseLayersResult, type UseSelectionOpsResult, ViewportContext, useActiveTool, useCamera, useElements, useHistory, useLayers, useSelection, useSelectionOps, useSelectionStyle, useToolOptions, useViewport };
200
+ export { type CameraState, CanvasElement, type CanvasElementProps, FieldNotesCanvas, type FieldNotesCanvasProps, type FieldNotesCanvasRef, Minimap, type MinimapProps, type UseHistoryResult, type UseLayersResult, type UseSelectionOpsResult, ViewportContext, useActiveTool, useCamera, useElementRects, useElements, useHistory, useLayers, useSelection, useSelectionOps, useSelectionStyle, useSelectionStyleDetails, useToolOptions, useViewport };
package/dist/index.js CHANGED
@@ -384,11 +384,22 @@ function useSelection() {
384
384
 
385
385
  // src/hooks/use-selection-style.ts
386
386
  import { useCallback as useCallback8, useRef as useRef8, useSyncExternalStore as useSyncExternalStore8 } from "react";
387
+
388
+ // src/hooks/style-keys.ts
389
+ var STYLE_KEYS = [
390
+ "color",
391
+ "fillColor",
392
+ "strokeWidth",
393
+ "opacity",
394
+ "fontSize",
395
+ "strokeStyle"
396
+ ];
397
+
398
+ // src/hooks/use-selection-style.ts
387
399
  function styleEqual(a, b) {
388
400
  if (a === b) return true;
389
401
  if (a === null || b === null) return false;
390
- const keys = ["color", "fillColor", "strokeWidth", "opacity", "fontSize"];
391
- return keys.every((k) => a[k] === b[k]);
402
+ return STYLE_KEYS.every((k) => a[k] === b[k]);
392
403
  }
393
404
  function useSelectionStyle() {
394
405
  const viewport = useViewport();
@@ -415,12 +426,17 @@ function useSelectionStyle() {
415
426
  return [style, apply];
416
427
  }
417
428
 
418
- // src/hooks/use-selection-ops.ts
429
+ // src/hooks/use-selection-style-details.ts
419
430
  import { useCallback as useCallback9, useRef as useRef9, useSyncExternalStore as useSyncExternalStore9 } from "react";
420
- function snapshotEqual(a, b) {
421
- 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;
431
+ function keysEqual(a, b) {
432
+ return a.length === b.length && a.every((k, i) => k === b[i]);
422
433
  }
423
- function useSelectionOps() {
434
+ function detailsEqual(a, b) {
435
+ if (a === b) return true;
436
+ if (a === null || b === null) return false;
437
+ return keysEqual(a.applicable, b.applicable) && keysEqual(a.mixed, b.mixed) && STYLE_KEYS.every((k) => a.common[k] === b.common[k]);
438
+ }
439
+ function useSelectionStyleDetails() {
424
440
  const viewport = useViewport();
425
441
  const cacheRef = useRef9(null);
426
442
  const subscribe = useCallback9(
@@ -435,6 +451,36 @@ function useSelectionOps() {
435
451
  [viewport]
436
452
  );
437
453
  const getSnapshot = useCallback9(() => {
454
+ const next = viewport.getSelectionStyleDetails();
455
+ if (detailsEqual(cacheRef.current, next)) return cacheRef.current;
456
+ cacheRef.current = next;
457
+ return next;
458
+ }, [viewport]);
459
+ const details = useSyncExternalStore9(subscribe, getSnapshot, getSnapshot);
460
+ const apply = useCallback9((s) => viewport.applyStyleToSelection(s), [viewport]);
461
+ return [details, apply];
462
+ }
463
+
464
+ // src/hooks/use-selection-ops.ts
465
+ import { useCallback as useCallback10, useRef as useRef10, useSyncExternalStore as useSyncExternalStore10 } from "react";
466
+ function snapshotEqual(a, b) {
467
+ 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;
468
+ }
469
+ function useSelectionOps() {
470
+ const viewport = useViewport();
471
+ const cacheRef = useRef10(null);
472
+ const subscribe = useCallback10(
473
+ (onChange) => {
474
+ const offSel = viewport.onSelectionChange(onChange);
475
+ const offStore = viewport.store.onChange(onChange);
476
+ return () => {
477
+ offSel();
478
+ offStore();
479
+ };
480
+ },
481
+ [viewport]
482
+ );
483
+ const getSnapshot = useCallback10(() => {
438
484
  const ids = viewport.getSelectedIds();
439
485
  const n = ids.length;
440
486
  let canUngroup = false;
@@ -459,17 +505,17 @@ function useSelectionOps() {
459
505
  cacheRef.current = next;
460
506
  return next;
461
507
  }, [viewport]);
462
- const snap = useSyncExternalStore9(subscribe, getSnapshot, getSnapshot);
463
- const group = useCallback9(() => viewport.groupSelection(), [viewport]);
464
- const ungroup = useCallback9(() => viewport.ungroupSelection(), [viewport]);
465
- const toggleLock = useCallback9(() => viewport.toggleLockSelection(), [viewport]);
466
- const align = useCallback9((edge) => viewport.alignSelection(edge), [viewport]);
467
- const distribute = useCallback9(
508
+ const snap = useSyncExternalStore10(subscribe, getSnapshot, getSnapshot);
509
+ const group = useCallback10(() => viewport.groupSelection(), [viewport]);
510
+ const ungroup = useCallback10(() => viewport.ungroupSelection(), [viewport]);
511
+ const toggleLock = useCallback10(() => viewport.toggleLockSelection(), [viewport]);
512
+ const align = useCallback10((edge) => viewport.alignSelection(edge), [viewport]);
513
+ const distribute = useCallback10(
468
514
  (axis) => viewport.distributeSelection(axis),
469
515
  [viewport]
470
516
  );
471
- const rotateCW = useCallback9(() => viewport.rotateSelection("cw"), [viewport]);
472
- const rotateCCW = useCallback9(() => viewport.rotateSelection("ccw"), [viewport]);
517
+ const rotateCW = useCallback10(() => viewport.rotateSelection("cw"), [viewport]);
518
+ const rotateCCW = useCallback10(() => viewport.rotateSelection("ccw"), [viewport]);
473
519
  return {
474
520
  selectedIds: snap.selectedIds,
475
521
  selectedCount: snap.selectedIds.length,
@@ -488,8 +534,53 @@ function useSelectionOps() {
488
534
  };
489
535
  }
490
536
 
537
+ // src/hooks/use-element-rects.ts
538
+ import { useCallback as useCallback11, useEffect as useEffect3, useRef as useRef11, useSyncExternalStore as useSyncExternalStore11 } from "react";
539
+ import { ElementRectTracker, computeElementRects, elementRectsEqual } from "@fieldnotes/core";
540
+ function useElementRects(match) {
541
+ const viewport = useViewport();
542
+ const matchRef = useRef11(match);
543
+ matchRef.current = match;
544
+ const stableMatch = useCallback11((el) => matchRef.current(el), []);
545
+ const cacheRef = useRef11(null);
546
+ const trackerRef = useRef11(null);
547
+ const subscribe = useCallback11(
548
+ (onStoreChange) => {
549
+ const tracker = new ElementRectTracker(viewport, { match: stableMatch });
550
+ trackerRef.current = tracker;
551
+ const next = tracker.getRects();
552
+ const previous = cacheRef.current;
553
+ if (previous === null || !elementRectsEqual(previous, next)) {
554
+ cacheRef.current = next;
555
+ onStoreChange();
556
+ }
557
+ const off = tracker.onChange((rects2) => {
558
+ cacheRef.current = rects2;
559
+ onStoreChange();
560
+ });
561
+ return () => {
562
+ off();
563
+ tracker.dispose();
564
+ if (trackerRef.current === tracker) trackerRef.current = null;
565
+ };
566
+ },
567
+ [viewport, stableMatch]
568
+ );
569
+ const getSnapshot = useCallback11(() => {
570
+ if (cacheRef.current === null) {
571
+ cacheRef.current = computeElementRects(viewport.store, stableMatch);
572
+ }
573
+ return cacheRef.current;
574
+ }, [viewport, stableMatch]);
575
+ const rects = useSyncExternalStore11(subscribe, getSnapshot);
576
+ useEffect3(() => {
577
+ trackerRef.current?.setMatch(stableMatch);
578
+ }, [match, stableMatch]);
579
+ return rects;
580
+ }
581
+
491
582
  // src/minimap.tsx
492
- import { useEffect as useEffect3, useRef as useRef10, useState as useState3 } from "react";
583
+ import { useEffect as useEffect4, useRef as useRef12, useState as useState3 } from "react";
493
584
  import { MinimapController } from "@fieldnotes/core";
494
585
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
495
586
  var toggleStyle = {
@@ -517,8 +608,8 @@ function Minimap({
517
608
  }) {
518
609
  const viewport = useViewport();
519
610
  const [collapsed, setCollapsed] = useState3(defaultCollapsed);
520
- const canvasRef = useRef10(null);
521
- useEffect3(() => {
611
+ const canvasRef = useRef12(null);
612
+ useEffect4(() => {
522
613
  if (collapsed) return;
523
614
  const canvas = canvasRef.current;
524
615
  if (!canvas) return;
@@ -579,12 +670,14 @@ export {
579
670
  ViewportContext,
580
671
  useActiveTool,
581
672
  useCamera,
673
+ useElementRects,
582
674
  useElements,
583
675
  useHistory,
584
676
  useLayers,
585
677
  useSelection,
586
678
  useSelectionOps,
587
679
  useSelectionStyle,
680
+ useSelectionStyleDetails,
588
681
  useToolOptions,
589
682
  useViewport
590
683
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/field-notes-canvas.tsx","../src/context.ts","../src/canvas-element.tsx","../src/hooks/use-viewport.ts","../src/hooks/use-active-tool.ts","../src/hooks/use-camera.ts","../src/hooks/use-tool-options.ts","../src/hooks/use-layers.ts","../src/hooks/use-history.ts","../src/hooks/use-elements.ts","../src/hooks/use-selection.ts","../src/hooks/use-selection-style.ts","../src/hooks/use-selection-ops.ts","../src/minimap.tsx"],"sourcesContent":["import {\r\n useRef,\r\n useEffect,\r\n useState,\r\n forwardRef,\r\n useImperativeHandle,\r\n type ReactNode,\r\n type CSSProperties,\r\n} from 'react';\r\nimport { Viewport } from '@fieldnotes/core';\r\nimport type { ViewportOptions, Tool } from '@fieldnotes/core';\r\nimport { ViewportContext } from './context';\r\n\r\nexport interface FieldNotesCanvasProps {\r\n /** Constructor-only: changes after mount are ignored (the canvas is stateful). */\r\n options?: ViewportOptions;\r\n /**\r\n * Reactive (append-only): tools present here are registered; removal is not supported.\r\n * Hoist the array out of render — inline arrays reconstruct Tool instances and re-run\r\n * registration on every render.\r\n */\r\n tools?: Tool[];\r\n /** Uncontrolled initial tool. Ignored when `tool` is set. */\r\n defaultTool?: string;\r\n /** Controlled active tool. Pair with `onToolChange`. */\r\n tool?: string;\r\n /**\r\n * Fires whenever the active tool changes (keyboard, API, or `tool` prop).\r\n * Memoize with useCallback to avoid re-subscribing each render.\r\n */\r\n onToolChange?: (name: string) => void;\r\n /** Reactive: toggles grid snapping. */\r\n snapToGrid?: boolean;\r\n className?: string;\r\n style?: CSSProperties;\r\n children?: ReactNode;\r\n onReady?: (viewport: Viewport) => void;\r\n}\r\n\r\nexport interface FieldNotesCanvasRef {\r\n viewport: Viewport | null;\r\n}\r\n\r\nexport const FieldNotesCanvas = forwardRef<FieldNotesCanvasRef, FieldNotesCanvasProps>(\r\n function FieldNotesCanvas(\r\n {\r\n options,\r\n tools,\r\n defaultTool,\r\n tool,\r\n onToolChange,\r\n snapToGrid,\r\n className,\r\n style,\r\n children,\r\n onReady,\r\n },\r\n ref,\r\n ) {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const [viewport, setViewport] = useState<Viewport | null>(null);\r\n\r\n useImperativeHandle(ref, () => ({ viewport }), [viewport]);\r\n\r\n useEffect(() => {\r\n const el = containerRef.current;\r\n if (!el) return;\r\n\r\n const vp = new Viewport(el, options);\r\n\r\n if (tools) {\r\n for (const t of tools) {\r\n vp.toolManager.register(t);\r\n }\r\n }\r\n\r\n const initialTool = tool ?? defaultTool;\r\n if (initialTool) {\r\n vp.setTool(initialTool);\r\n }\r\n\r\n setViewport(vp);\r\n onReady?.(vp);\r\n\r\n return () => {\r\n vp.destroy();\r\n setViewport(null);\r\n };\r\n // Constructor effect: options/tools/defaultTool are mount-only by design.\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!viewport || tool === undefined) return;\r\n if (viewport.toolManager.activeTool?.name !== tool) {\r\n viewport.setTool(tool);\r\n }\r\n }, [viewport, tool]);\r\n\r\n useEffect(() => {\r\n if (!viewport || !onToolChange) return;\r\n return viewport.toolManager.onChange(onToolChange);\r\n }, [viewport, onToolChange]);\r\n\r\n useEffect(() => {\r\n if (!viewport || snapToGrid === undefined) return;\r\n viewport.setSnapToGrid(snapToGrid);\r\n }, [viewport, snapToGrid]);\r\n\r\n useEffect(() => {\r\n if (!viewport || !tools) return;\r\n for (const t of tools) {\r\n if (!viewport.toolManager.getTool(t.name)) {\r\n viewport.toolManager.register(t);\r\n }\r\n }\r\n }, [viewport, tools]);\r\n\r\n return (\r\n <div ref={containerRef} className={className} style={style}>\r\n {viewport && (\r\n <ViewportContext.Provider value={viewport}>{children}</ViewportContext.Provider>\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n","import { createContext } from 'react';\r\nimport type { Viewport } from '@fieldnotes/core';\r\n\r\nexport const ViewportContext = createContext<Viewport | null>(null);\r\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { useViewport } from './hooks/use-viewport';\r\n\r\n/** Props for {@link CanvasElement}. */\r\nexport interface CanvasElementProps {\r\n /** Canvas-space position of the element's top-left corner. */\r\n position: { x: number; y: number };\r\n /** Optional fixed size; omit to let the element size to its content. */\r\n size?: { w: number; h: number };\r\n children: ReactNode;\r\n}\r\n\r\n/**\r\n * Renders a React subtree as an HTML element embedded in the canvas coordinate space.\r\n * Must be used inside a `<FieldNotesCanvas>`.\r\n */\r\nexport function CanvasElement({ position, size, children }: CanvasElementProps) {\r\n const viewport = useViewport();\r\n const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\r\n const elementIdRef = useRef<string | null>(null);\r\n\r\n useEffect(() => {\r\n const container = document.createElement('div');\r\n Object.assign(container.style, {\r\n width: '100%',\r\n height: '100%',\r\n });\r\n\r\n // Append to domLayer immediately so portal children are queryable in the document\r\n // before the viewport render loop fires via requestAnimationFrame.\r\n viewport.domLayer.appendChild(container);\r\n\r\n const id = viewport.addHtmlElement(container, position, size);\r\n elementIdRef.current = id;\r\n setPortalTarget(container);\r\n\r\n return () => {\r\n if (elementIdRef.current) {\r\n viewport.store.remove(elementIdRef.current);\r\n viewport.requestRender();\r\n elementIdRef.current = null;\r\n }\r\n setPortalTarget(null);\r\n };\r\n }, [viewport]);\r\n\r\n useEffect(() => {\r\n const id = elementIdRef.current;\r\n if (!id) return;\r\n viewport.store.update(id, { position });\r\n if (size) {\r\n viewport.store.update(id, { size });\r\n }\r\n viewport.requestRender();\r\n // Primitive deps (position.x/y, size?.w/h) are intentional: the effect re-runs on VALUE change,\r\n // not object identity — so inline { x, y } literals and memoized-but-unchanged objects both behave\r\n // correctly (no over-firing on every parent re-render).\r\n }, [viewport, position.x, position.y, size?.w, size?.h]);\r\n\r\n if (!portalTarget) return null;\r\n return createPortal(children, portalTarget);\r\n}\r\n","import { useContext } from 'react';\r\nimport type { Viewport } from '@fieldnotes/core';\r\nimport { ViewportContext } from '../context';\r\n\r\n/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */\r\nexport function useViewport(): Viewport {\r\n const viewport = useContext(ViewportContext);\r\n if (!viewport) {\r\n throw new Error('useViewport must be used inside <FieldNotesCanvas>');\r\n }\r\n return viewport;\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\n/** `[activeToolName, setTool]` — re-renders on tool switches. */\r\nexport function useActiveTool(): [toolName: string, setTool: (name: string) => void] {\r\n const viewport = useViewport();\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.toolManager.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => viewport.toolManager.activeTool?.name ?? '', [viewport]);\r\n\r\n const toolName = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const setTool = useCallback((name: string) => viewport.setTool(name), [viewport]);\r\n\r\n return [toolName, setTool];\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\nexport interface CameraState {\r\n x: number;\r\n y: number;\r\n zoom: number;\r\n}\r\n\r\n/** Current camera position and zoom level — re-renders whenever the camera moves or zoom changes. */\r\nexport function useCamera(): CameraState {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<CameraState>({ x: 0, y: 0, zoom: 1 });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.camera.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): CameraState => {\r\n const { position, zoom } = viewport.camera;\r\n const cached = cachedRef.current;\r\n if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {\r\n return cached;\r\n }\r\n const next = { x: position.x, y: position.y, zoom };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction noop() {\r\n /* unsubscribe placeholder */\r\n}\r\n\r\n/**\r\n * `[options, setOptions]` for the named tool — re-renders when the tool's options change.\r\n * Returns `null` for options if the tool is not registered or does not expose options.\r\n */\r\nexport function useToolOptions<T extends Record<string, unknown>>(\r\n toolName: string,\r\n): [options: T | null, setOptions: (partial: Partial<T>) => void] {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<T | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n if (!tool?.onOptionsChange) return noop;\r\n return tool.onOptionsChange(onStoreChange);\r\n },\r\n [viewport, toolName],\r\n );\r\n\r\n const getSnapshot = useCallback((): T | null => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n if (!tool?.getOptions) return null;\r\n const next = tool.getOptions() as T;\r\n const cached = cachedRef.current;\r\n if (cached && shallowEqual(cached, next)) return cached;\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport, toolName]);\r\n\r\n const options = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const setOptions = useCallback(\r\n (partial: Partial<T>) => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n tool?.setOptions?.(partial as Record<string, unknown>);\r\n },\r\n [viewport, toolName],\r\n );\r\n\r\n return [options, setOptions];\r\n}\r\n\r\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\r\n const keysA = Object.keys(a);\r\n const keysB = Object.keys(b);\r\n if (keysA.length !== keysB.length) return false;\r\n for (const key of keysA) {\r\n const valA = a[key];\r\n const valB = b[key];\r\n if (valA === valB) continue;\r\n if (\r\n typeof valA === 'object' &&\r\n valA !== null &&\r\n typeof valB === 'object' &&\r\n valB !== null &&\r\n !Array.isArray(valA) &&\r\n !Array.isArray(valB)\r\n ) {\r\n const objA = valA as Record<string, unknown>;\r\n const objB = valB as Record<string, unknown>;\r\n const innerKeys = Object.keys(objA);\r\n if (\r\n innerKeys.length === Object.keys(objB).length &&\r\n innerKeys.every((k) => objA[k] === objB[k])\r\n ) {\r\n continue;\r\n }\r\n }\r\n return false;\r\n }\r\n return true;\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { Layer } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\ninterface LayersSnapshot {\r\n layers: Layer[];\r\n activeLayerId: string;\r\n}\r\n\r\nexport interface UseLayersResult {\r\n layers: Layer[];\r\n activeLayerId: string;\r\n createLayer: (name?: string) => Layer;\r\n removeLayer: (id: string) => void;\r\n renameLayer: (id: string, name: string) => void;\r\n reorderLayer: (id: string, newOrder: number) => void;\r\n setVisible: (id: string, visible: boolean) => void;\r\n setLocked: (id: string, locked: boolean) => void;\r\n setOpacity: (id: string, opacity: number) => void;\r\n setActiveLayer: (id: string) => void;\r\n moveElement: (elementId: string, layerId: string) => void;\r\n}\r\n\r\n/**\r\n * Current layer list and mutation helpers — re-renders whenever a layer is added, removed,\r\n * reordered, renamed, or its visibility/lock/opacity/active state changes.\r\n */\r\nexport function useLayers(): UseLayersResult {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<LayersSnapshot>({ layers: [], activeLayerId: '' });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.layerManager.on('change', onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): LayersSnapshot => {\r\n const layers = viewport.layerManager.getLayers();\r\n const activeLayerId = viewport.layerManager.activeLayerId;\r\n const cached = cachedRef.current;\r\n if (\r\n cached.activeLayerId === activeLayerId &&\r\n cached.layers.length === layers.length &&\r\n cached.layers.every((l, i) => {\r\n const next = layers[i];\r\n return (\r\n next !== undefined &&\r\n l.id === next.id &&\r\n l.name === next.name &&\r\n l.visible === next.visible &&\r\n l.locked === next.locked &&\r\n l.order === next.order &&\r\n l.opacity === next.opacity\r\n );\r\n })\r\n ) {\r\n return cached;\r\n }\r\n const next = { layers, activeLayerId };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const createLayer = useCallback(\r\n (name?: string) => viewport.layerManager.createLayer(name),\r\n [viewport],\r\n );\r\n\r\n const removeLayer = useCallback(\r\n (id: string) => viewport.layerManager.removeLayer(id),\r\n [viewport],\r\n );\r\n\r\n const renameLayer = useCallback(\r\n (id: string, name: string) => viewport.layerManager.renameLayer(id, name),\r\n [viewport],\r\n );\r\n\r\n const reorderLayer = useCallback(\r\n (id: string, newOrder: number) => viewport.layerManager.reorderLayer(id, newOrder),\r\n [viewport],\r\n );\r\n\r\n const setVisible = useCallback(\r\n (id: string, visible: boolean) => viewport.layerManager.setLayerVisible(id, visible),\r\n [viewport],\r\n );\r\n\r\n const setLocked = useCallback(\r\n (id: string, locked: boolean) => viewport.layerManager.setLayerLocked(id, locked),\r\n [viewport],\r\n );\r\n\r\n const setOpacity = useCallback(\r\n (id: string, opacity: number) => viewport.layerManager.setLayerOpacity(id, opacity),\r\n [viewport],\r\n );\r\n\r\n const setActiveLayer = useCallback(\r\n (id: string) => viewport.layerManager.setActiveLayer(id),\r\n [viewport],\r\n );\r\n\r\n const moveElement = useCallback(\r\n (elementId: string, layerId: string) =>\r\n viewport.layerManager.moveElementToLayer(elementId, layerId),\r\n [viewport],\r\n );\r\n\r\n return {\r\n layers: snapshot.layers,\r\n activeLayerId: snapshot.activeLayerId,\r\n createLayer,\r\n removeLayer,\r\n renameLayer,\r\n reorderLayer,\r\n setVisible,\r\n setLocked,\r\n setOpacity,\r\n setActiveLayer,\r\n moveElement,\r\n };\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\ninterface HistorySnapshot {\r\n canUndo: boolean;\r\n canRedo: boolean;\r\n}\r\n\r\nexport interface UseHistoryResult {\r\n canUndo: boolean;\r\n canRedo: boolean;\r\n undo: () => void;\r\n redo: () => void;\r\n}\r\n\r\n/** `{ canUndo, canRedo, undo, redo }` — re-renders when undo/redo availability changes. */\r\nexport function useHistory(): UseHistoryResult {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<HistorySnapshot>({ canUndo: false, canRedo: false });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.history.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): HistorySnapshot => {\r\n const canUndo = viewport.history.canUndo;\r\n const canRedo = viewport.history.canRedo;\r\n const cached = cachedRef.current;\r\n if (cached.canUndo === canUndo && cached.canRedo === canRedo) {\r\n return cached;\r\n }\r\n const next = { canUndo, canRedo };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const undo = useCallback(() => viewport.undo(), [viewport]);\r\n const redo = useCallback(() => viewport.redo(), [viewport]);\r\n\r\n return {\r\n canUndo: snapshot.canUndo,\r\n canRedo: snapshot.canRedo,\r\n undo,\r\n redo,\r\n };\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { CanvasElement, ElementType } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction shallowEqual(a: unknown, b: unknown): boolean {\r\n if (Object.is(a, b)) return true;\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));\r\n }\r\n if (\r\n typeof a === 'object' &&\r\n a !== null &&\r\n typeof b === 'object' &&\r\n b !== null &&\r\n !Array.isArray(a) &&\r\n !Array.isArray(b)\r\n ) {\r\n const ka = Object.keys(a);\r\n const kb = Object.keys(b);\r\n return (\r\n ka.length === kb.length &&\r\n ka.every(\r\n (k) =>\r\n k in (b as Record<string, unknown>) &&\r\n Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\r\n )\r\n );\r\n }\r\n return false;\r\n}\r\n\r\n/** All elements; re-renders on every store mutation (use a selector for hot paths). */\r\nexport function useElements(): CanvasElement[];\r\n/** Elements of one type; re-renders on every store mutation. */\r\nexport function useElements<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[];\r\n/**\r\n * Derived value; re-renders only when the selected value changes (per `isEqual`,\r\n * default: one-level shallow compare — arrays by index, plain objects by key, primitives by\r\n * Object.is). Keep the selector referentially stable (useCallback or module scope).\r\n *\r\n * Supply `isEqual` for deeper structures. Note: selectors returning nested fresh objects\r\n * (e.g. `els => els.map(e => ({ ...e.position }))`) still need a custom comparator because\r\n * the default only compares one level deep.\r\n */\r\nexport function useElements<R>(\r\n selector: (elements: CanvasElement[]) => R,\r\n isEqual?: (a: R, b: R) => boolean,\r\n): R;\r\nexport function useElements<R>(\r\n arg?: ElementType | ((elements: CanvasElement[]) => R),\r\n isEqual?: (a: R, b: R) => boolean,\r\n): CanvasElement[] | R {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<CanvasElement[]>([]);\r\n const selectedRef = useRef<{ value: R } | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.store.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): CanvasElement[] | R => {\r\n if (typeof arg === 'function') {\r\n const next = arg(viewport.store.getAll());\r\n const prev = selectedRef.current;\r\n const equal: (a: R, b: R) => boolean = isEqual ?? (shallowEqual as (a: R, b: R) => boolean);\r\n if (prev !== null && equal(prev.value, next)) {\r\n return prev.value;\r\n }\r\n selectedRef.current = { value: next };\r\n return next;\r\n }\r\n\r\n const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();\r\n const cached = cachedRef.current;\r\n if (cached.length === next.length && cached.every((el, i) => el === next[i])) {\r\n return cached;\r\n }\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport, arg, isEqual]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\n/** Reactive selected element ids. Stable array reference — only changes when the selection changes. */\r\nexport function useSelection(): string[] {\r\n const viewport = useViewport();\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => viewport.onSelectionChange(onChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => viewport.getSelectedIds(), [viewport]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { ElementStyle } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction styleEqual(a: ElementStyle | null, b: ElementStyle | null): boolean {\r\n if (a === b) return true;\r\n if (a === null || b === null) return false;\r\n const keys: (keyof ElementStyle)[] = ['color', 'fillColor', 'strokeWidth', 'opacity', 'fontSize'];\r\n return keys.every((k) => a[k] === b[k]);\r\n}\r\n\r\n/**\r\n * Reactive normalized style of the current selection.\r\n * Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.\r\n * `applyPatch` applies an `ElementStyle` patch to every selected element.\r\n */\r\nexport function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void] {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<ElementStyle | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n const next = viewport.getSelectionStyle();\r\n if (styleEqual(cacheRef.current, next)) return cacheRef.current;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const style = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\r\n\r\n return [style, apply];\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nexport interface UseSelectionOpsResult {\r\n selectedIds: string[];\r\n selectedCount: number;\r\n canGroup: boolean;\r\n canUngroup: boolean;\r\n canAlign: boolean;\r\n canDistribute: boolean;\r\n isLocked: boolean | null;\r\n group: () => void;\r\n ungroup: () => void;\r\n toggleLock: () => void;\r\n align: (edge: AlignEdge) => void;\r\n distribute: (axis: DistributeAxis) => void;\r\n rotateCW: () => void;\r\n rotateCCW: () => void;\r\n}\r\n\r\ninterface Snapshot {\r\n selectedIds: string[];\r\n canGroup: boolean;\r\n canUngroup: boolean;\r\n canAlign: boolean;\r\n canDistribute: boolean;\r\n isLocked: boolean | null;\r\n}\r\n\r\nfunction snapshotEqual(a: Snapshot, b: Snapshot): boolean {\r\n return (\r\n a.selectedIds === b.selectedIds &&\r\n a.canGroup === b.canGroup &&\r\n a.canUngroup === b.canUngroup &&\r\n a.canAlign === b.canAlign &&\r\n a.canDistribute === b.canDistribute &&\r\n a.isLocked === b.isLocked\r\n );\r\n}\r\n\r\n/**\r\n * Reactive selection operations + derived predicates for the current selection.\r\n * Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;\r\n * `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,\r\n * and `null` when empty or mixed. Actions delegate to the core Viewport.\r\n */\r\nexport function useSelectionOps(): UseSelectionOpsResult {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<Snapshot | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): Snapshot => {\r\n const ids = viewport.getSelectedIds();\r\n const n = ids.length;\r\n let canUngroup = false;\r\n let lockedCount = 0;\r\n for (const id of ids) {\r\n const el = viewport.store.getById(id);\r\n if (!el) continue;\r\n if (el.groupId !== undefined) canUngroup = true;\r\n if (el.locked) lockedCount++;\r\n }\r\n const isLocked: boolean | null =\r\n n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;\r\n const next: Snapshot = {\r\n selectedIds: ids,\r\n canGroup: n >= 2,\r\n canUngroup,\r\n canAlign: n >= 2,\r\n canDistribute: n >= 3,\r\n isLocked,\r\n };\r\n const prev = cacheRef.current;\r\n if (prev && snapshotEqual(prev, next)) return prev;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n const group = useCallback(() => viewport.groupSelection(), [viewport]);\r\n const ungroup = useCallback(() => viewport.ungroupSelection(), [viewport]);\r\n const toggleLock = useCallback(() => viewport.toggleLockSelection(), [viewport]);\r\n const align = useCallback((edge: AlignEdge) => viewport.alignSelection(edge), [viewport]);\r\n const distribute = useCallback(\r\n (axis: DistributeAxis) => viewport.distributeSelection(axis),\r\n [viewport],\r\n );\r\n const rotateCW = useCallback(() => viewport.rotateSelection('cw'), [viewport]);\r\n const rotateCCW = useCallback(() => viewport.rotateSelection('ccw'), [viewport]);\r\n\r\n return {\r\n selectedIds: snap.selectedIds,\r\n selectedCount: snap.selectedIds.length,\r\n canGroup: snap.canGroup,\r\n canUngroup: snap.canUngroup,\r\n canAlign: snap.canAlign,\r\n canDistribute: snap.canDistribute,\r\n isLocked: snap.isLocked,\r\n group,\r\n ungroup,\r\n toggleLock,\r\n align,\r\n distribute,\r\n rotateCW,\r\n rotateCCW,\r\n };\r\n}\r\n","import { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { MinimapController } from '@fieldnotes/core';\nimport { useViewport } from './hooks/use-viewport';\n\nexport interface MinimapProps {\n /** Thumbnail width in CSS pixels. Default `200`. */\n width?: number;\n /** Thumbnail height in CSS pixels. Default `140`. */\n height?: number;\n /** Start collapsed (icon button only). Uncontrolled. Default `false`. */\n defaultCollapsed?: boolean;\n /** Backdrop fill behind the thumbnail. */\n background?: string;\n /** Viewport rectangle stroke color. */\n viewportStroke?: string;\n className?: string;\n style?: CSSProperties;\n}\n\nconst toggleStyle: CSSProperties = {\n position: 'absolute',\n top: 2,\n right: 2,\n width: 24,\n height: 24,\n padding: 0,\n border: 'none',\n borderRadius: 4,\n background: 'rgba(0,0,0,0.35)',\n color: '#fff',\n font: '14px/1 system-ui, sans-serif',\n cursor: 'pointer',\n};\n\n/**\n * Collapsible thumbnail overview navigator. Renders inside `<FieldNotesCanvas>`\n * (or any `ViewportContext.Provider`). Positioning is host-owned — place and\n * style the component via `className`/`style`. While collapsed, no controller\n * exists: zero listeners, zero rendering.\n */\nexport function Minimap({\n width = 200,\n height = 140,\n defaultCollapsed = false,\n background,\n viewportStroke,\n className,\n style,\n}: MinimapProps) {\n const viewport = useViewport();\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n\n useEffect(() => {\n if (collapsed) return;\n const canvas = canvasRef.current;\n if (!canvas) return;\n const controller = new MinimapController(viewport, canvas, {\n width,\n height,\n background,\n viewportStroke,\n });\n return () => controller.dispose();\n }, [viewport, collapsed, width, height, background, viewportStroke]);\n\n if (collapsed) {\n return (\n <button\n type=\"button\"\n aria-label=\"Expand minimap\"\n onClick={() => setCollapsed(false)}\n className={className}\n style={{\n minWidth: 44,\n minHeight: 44,\n border: '1px solid rgba(0,0,0,0.15)',\n borderRadius: 8,\n background: 'rgba(255,255,255,0.85)',\n cursor: 'pointer',\n font: '18px/1 system-ui, sans-serif',\n ...style,\n }}\n >\n {'▣'}\n </button>\n );\n }\n\n return (\n <div className={className} style={{ position: 'relative', ...style }}>\n <canvas\n ref={canvasRef}\n style={{ width: `${width}px`, height: `${height}px`, display: 'block' }}\n />\n <button\n type=\"button\"\n aria-label=\"Collapse minimap\"\n onClick={() => setCollapsed(true)}\n style={toggleStyle}\n >\n {'–'}\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":["FieldNotesCanvas","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","next","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","shallowEqual","useRef","useCallback","next","useSyncExternalStore","useCallback","useSyncExternalStore","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useEffect","useRef","useState","jsx","useState","useRef","useEffect"]}
1
+ {"version":3,"sources":["../src/field-notes-canvas.tsx","../src/context.ts","../src/canvas-element.tsx","../src/hooks/use-viewport.ts","../src/hooks/use-active-tool.ts","../src/hooks/use-camera.ts","../src/hooks/use-tool-options.ts","../src/hooks/use-layers.ts","../src/hooks/use-history.ts","../src/hooks/use-elements.ts","../src/hooks/use-selection.ts","../src/hooks/use-selection-style.ts","../src/hooks/style-keys.ts","../src/hooks/use-selection-style-details.ts","../src/hooks/use-selection-ops.ts","../src/hooks/use-element-rects.ts","../src/minimap.tsx"],"sourcesContent":["import {\r\n useRef,\r\n useEffect,\r\n useState,\r\n forwardRef,\r\n useImperativeHandle,\r\n type ReactNode,\r\n type CSSProperties,\r\n} from 'react';\r\nimport { Viewport } from '@fieldnotes/core';\r\nimport type { ViewportOptions, Tool } from '@fieldnotes/core';\r\nimport { ViewportContext } from './context';\r\n\r\nexport interface FieldNotesCanvasProps {\r\n /** Constructor-only: changes after mount are ignored (the canvas is stateful). */\r\n options?: ViewportOptions;\r\n /**\r\n * Reactive (append-only): tools present here are registered; removal is not supported.\r\n * Hoist the array out of render — inline arrays reconstruct Tool instances and re-run\r\n * registration on every render.\r\n */\r\n tools?: Tool[];\r\n /** Uncontrolled initial tool. Ignored when `tool` is set. */\r\n defaultTool?: string;\r\n /** Controlled active tool. Pair with `onToolChange`. */\r\n tool?: string;\r\n /**\r\n * Fires whenever the active tool changes (keyboard, API, or `tool` prop).\r\n * Memoize with useCallback to avoid re-subscribing each render.\r\n */\r\n onToolChange?: (name: string) => void;\r\n /** Reactive: toggles grid snapping. */\r\n snapToGrid?: boolean;\r\n className?: string;\r\n style?: CSSProperties;\r\n children?: ReactNode;\r\n onReady?: (viewport: Viewport) => void;\r\n}\r\n\r\nexport interface FieldNotesCanvasRef {\r\n viewport: Viewport | null;\r\n}\r\n\r\nexport const FieldNotesCanvas = forwardRef<FieldNotesCanvasRef, FieldNotesCanvasProps>(\r\n function FieldNotesCanvas(\r\n {\r\n options,\r\n tools,\r\n defaultTool,\r\n tool,\r\n onToolChange,\r\n snapToGrid,\r\n className,\r\n style,\r\n children,\r\n onReady,\r\n },\r\n ref,\r\n ) {\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const [viewport, setViewport] = useState<Viewport | null>(null);\r\n\r\n useImperativeHandle(ref, () => ({ viewport }), [viewport]);\r\n\r\n useEffect(() => {\r\n const el = containerRef.current;\r\n if (!el) return;\r\n\r\n const vp = new Viewport(el, options);\r\n\r\n if (tools) {\r\n for (const t of tools) {\r\n vp.toolManager.register(t);\r\n }\r\n }\r\n\r\n const initialTool = tool ?? defaultTool;\r\n if (initialTool) {\r\n vp.setTool(initialTool);\r\n }\r\n\r\n setViewport(vp);\r\n onReady?.(vp);\r\n\r\n return () => {\r\n vp.destroy();\r\n setViewport(null);\r\n };\r\n // Constructor effect: options/tools/defaultTool are mount-only by design.\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!viewport || tool === undefined) return;\r\n if (viewport.toolManager.activeTool?.name !== tool) {\r\n viewport.setTool(tool);\r\n }\r\n }, [viewport, tool]);\r\n\r\n useEffect(() => {\r\n if (!viewport || !onToolChange) return;\r\n return viewport.toolManager.onChange(onToolChange);\r\n }, [viewport, onToolChange]);\r\n\r\n useEffect(() => {\r\n if (!viewport || snapToGrid === undefined) return;\r\n viewport.setSnapToGrid(snapToGrid);\r\n }, [viewport, snapToGrid]);\r\n\r\n useEffect(() => {\r\n if (!viewport || !tools) return;\r\n for (const t of tools) {\r\n if (!viewport.toolManager.getTool(t.name)) {\r\n viewport.toolManager.register(t);\r\n }\r\n }\r\n }, [viewport, tools]);\r\n\r\n return (\r\n <div ref={containerRef} className={className} style={style}>\r\n {viewport && (\r\n <ViewportContext.Provider value={viewport}>{children}</ViewportContext.Provider>\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n","import { createContext } from 'react';\r\nimport type { Viewport } from '@fieldnotes/core';\r\n\r\nexport const ViewportContext = createContext<Viewport | null>(null);\r\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { useViewport } from './hooks/use-viewport';\r\n\r\n/** Props for {@link CanvasElement}. */\r\nexport interface CanvasElementProps {\r\n /** Canvas-space position of the element's top-left corner. */\r\n position: { x: number; y: number };\r\n /** Optional fixed size; omit to let the element size to its content. */\r\n size?: { w: number; h: number };\r\n children: ReactNode;\r\n}\r\n\r\n/**\r\n * Renders a React subtree as an HTML element embedded in the canvas coordinate space.\r\n * Must be used inside a `<FieldNotesCanvas>`.\r\n */\r\nexport function CanvasElement({ position, size, children }: CanvasElementProps) {\r\n const viewport = useViewport();\r\n const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\r\n const elementIdRef = useRef<string | null>(null);\r\n\r\n useEffect(() => {\r\n const container = document.createElement('div');\r\n Object.assign(container.style, {\r\n width: '100%',\r\n height: '100%',\r\n });\r\n\r\n // Append to domLayer immediately so portal children are queryable in the document\r\n // before the viewport render loop fires via requestAnimationFrame.\r\n viewport.domLayer.appendChild(container);\r\n\r\n const id = viewport.addHtmlElement(container, position, size);\r\n elementIdRef.current = id;\r\n setPortalTarget(container);\r\n\r\n return () => {\r\n if (elementIdRef.current) {\r\n viewport.store.remove(elementIdRef.current);\r\n viewport.requestRender();\r\n elementIdRef.current = null;\r\n }\r\n setPortalTarget(null);\r\n };\r\n }, [viewport]);\r\n\r\n useEffect(() => {\r\n const id = elementIdRef.current;\r\n if (!id) return;\r\n viewport.store.update(id, { position });\r\n if (size) {\r\n viewport.store.update(id, { size });\r\n }\r\n viewport.requestRender();\r\n // Primitive deps (position.x/y, size?.w/h) are intentional: the effect re-runs on VALUE change,\r\n // not object identity — so inline { x, y } literals and memoized-but-unchanged objects both behave\r\n // correctly (no over-firing on every parent re-render).\r\n }, [viewport, position.x, position.y, size?.w, size?.h]);\r\n\r\n if (!portalTarget) return null;\r\n return createPortal(children, portalTarget);\r\n}\r\n","import { useContext } from 'react';\r\nimport type { Viewport } from '@fieldnotes/core';\r\nimport { ViewportContext } from '../context';\r\n\r\n/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */\r\nexport function useViewport(): Viewport {\r\n const viewport = useContext(ViewportContext);\r\n if (!viewport) {\r\n throw new Error('useViewport must be used inside <FieldNotesCanvas>');\r\n }\r\n return viewport;\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\n/** `[activeToolName, setTool]` — re-renders on tool switches. */\r\nexport function useActiveTool(): [toolName: string, setTool: (name: string) => void] {\r\n const viewport = useViewport();\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.toolManager.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => viewport.toolManager.activeTool?.name ?? '', [viewport]);\r\n\r\n const toolName = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const setTool = useCallback((name: string) => viewport.setTool(name), [viewport]);\r\n\r\n return [toolName, setTool];\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\nexport interface CameraState {\r\n x: number;\r\n y: number;\r\n zoom: number;\r\n}\r\n\r\n/** Current camera position and zoom level — re-renders whenever the camera moves or zoom changes. */\r\nexport function useCamera(): CameraState {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<CameraState>({ x: 0, y: 0, zoom: 1 });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.camera.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): CameraState => {\r\n const { position, zoom } = viewport.camera;\r\n const cached = cachedRef.current;\r\n if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {\r\n return cached;\r\n }\r\n const next = { x: position.x, y: position.y, zoom };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction noop() {\r\n /* unsubscribe placeholder */\r\n}\r\n\r\n/**\r\n * `[options, setOptions]` for the named tool — re-renders when the tool's options change.\r\n * Returns `null` for options if the tool is not registered or does not expose options.\r\n */\r\nexport function useToolOptions<T extends Record<string, unknown>>(\r\n toolName: string,\r\n): [options: T | null, setOptions: (partial: Partial<T>) => void] {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<T | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n if (!tool?.onOptionsChange) return noop;\r\n return tool.onOptionsChange(onStoreChange);\r\n },\r\n [viewport, toolName],\r\n );\r\n\r\n const getSnapshot = useCallback((): T | null => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n if (!tool?.getOptions) return null;\r\n const next = tool.getOptions() as T;\r\n const cached = cachedRef.current;\r\n if (cached && shallowEqual(cached, next)) return cached;\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport, toolName]);\r\n\r\n const options = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const setOptions = useCallback(\r\n (partial: Partial<T>) => {\r\n const tool = viewport.toolManager.getTool(toolName);\r\n tool?.setOptions?.(partial as Record<string, unknown>);\r\n },\r\n [viewport, toolName],\r\n );\r\n\r\n return [options, setOptions];\r\n}\r\n\r\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\r\n const keysA = Object.keys(a);\r\n const keysB = Object.keys(b);\r\n if (keysA.length !== keysB.length) return false;\r\n for (const key of keysA) {\r\n const valA = a[key];\r\n const valB = b[key];\r\n if (valA === valB) continue;\r\n if (\r\n typeof valA === 'object' &&\r\n valA !== null &&\r\n typeof valB === 'object' &&\r\n valB !== null &&\r\n !Array.isArray(valA) &&\r\n !Array.isArray(valB)\r\n ) {\r\n const objA = valA as Record<string, unknown>;\r\n const objB = valB as Record<string, unknown>;\r\n const innerKeys = Object.keys(objA);\r\n if (\r\n innerKeys.length === Object.keys(objB).length &&\r\n innerKeys.every((k) => objA[k] === objB[k])\r\n ) {\r\n continue;\r\n }\r\n }\r\n return false;\r\n }\r\n return true;\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { Layer } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\ninterface LayersSnapshot {\r\n layers: Layer[];\r\n activeLayerId: string;\r\n}\r\n\r\nexport interface UseLayersResult {\r\n layers: Layer[];\r\n activeLayerId: string;\r\n createLayer: (name?: string) => Layer;\r\n removeLayer: (id: string) => void;\r\n renameLayer: (id: string, name: string) => void;\r\n reorderLayer: (id: string, newOrder: number) => void;\r\n setVisible: (id: string, visible: boolean) => void;\r\n setLocked: (id: string, locked: boolean) => void;\r\n setOpacity: (id: string, opacity: number) => void;\r\n setActiveLayer: (id: string) => void;\r\n moveElement: (elementId: string, layerId: string) => void;\r\n}\r\n\r\n/**\r\n * Current layer list and mutation helpers — re-renders whenever a layer is added, removed,\r\n * reordered, renamed, or its visibility/lock/opacity/active state changes.\r\n */\r\nexport function useLayers(): UseLayersResult {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<LayersSnapshot>({ layers: [], activeLayerId: '' });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.layerManager.on('change', onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): LayersSnapshot => {\r\n const layers = viewport.layerManager.getLayers();\r\n const activeLayerId = viewport.layerManager.activeLayerId;\r\n const cached = cachedRef.current;\r\n if (\r\n cached.activeLayerId === activeLayerId &&\r\n cached.layers.length === layers.length &&\r\n cached.layers.every((l, i) => {\r\n const next = layers[i];\r\n return (\r\n next !== undefined &&\r\n l.id === next.id &&\r\n l.name === next.name &&\r\n l.visible === next.visible &&\r\n l.locked === next.locked &&\r\n l.order === next.order &&\r\n l.opacity === next.opacity\r\n );\r\n })\r\n ) {\r\n return cached;\r\n }\r\n const next = { layers, activeLayerId };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const createLayer = useCallback(\r\n (name?: string) => viewport.layerManager.createLayer(name),\r\n [viewport],\r\n );\r\n\r\n const removeLayer = useCallback(\r\n (id: string) => viewport.layerManager.removeLayer(id),\r\n [viewport],\r\n );\r\n\r\n const renameLayer = useCallback(\r\n (id: string, name: string) => viewport.layerManager.renameLayer(id, name),\r\n [viewport],\r\n );\r\n\r\n const reorderLayer = useCallback(\r\n (id: string, newOrder: number) => viewport.layerManager.reorderLayer(id, newOrder),\r\n [viewport],\r\n );\r\n\r\n const setVisible = useCallback(\r\n (id: string, visible: boolean) => viewport.layerManager.setLayerVisible(id, visible),\r\n [viewport],\r\n );\r\n\r\n const setLocked = useCallback(\r\n (id: string, locked: boolean) => viewport.layerManager.setLayerLocked(id, locked),\r\n [viewport],\r\n );\r\n\r\n const setOpacity = useCallback(\r\n (id: string, opacity: number) => viewport.layerManager.setLayerOpacity(id, opacity),\r\n [viewport],\r\n );\r\n\r\n const setActiveLayer = useCallback(\r\n (id: string) => viewport.layerManager.setActiveLayer(id),\r\n [viewport],\r\n );\r\n\r\n const moveElement = useCallback(\r\n (elementId: string, layerId: string) =>\r\n viewport.layerManager.moveElementToLayer(elementId, layerId),\r\n [viewport],\r\n );\r\n\r\n return {\r\n layers: snapshot.layers,\r\n activeLayerId: snapshot.activeLayerId,\r\n createLayer,\r\n removeLayer,\r\n renameLayer,\r\n reorderLayer,\r\n setVisible,\r\n setLocked,\r\n setOpacity,\r\n setActiveLayer,\r\n moveElement,\r\n };\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\ninterface HistorySnapshot {\r\n canUndo: boolean;\r\n canRedo: boolean;\r\n}\r\n\r\nexport interface UseHistoryResult {\r\n canUndo: boolean;\r\n canRedo: boolean;\r\n undo: () => void;\r\n redo: () => void;\r\n}\r\n\r\n/** `{ canUndo, canRedo, undo, redo }` — re-renders when undo/redo availability changes. */\r\nexport function useHistory(): UseHistoryResult {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<HistorySnapshot>({ canUndo: false, canRedo: false });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.history.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): HistorySnapshot => {\r\n const canUndo = viewport.history.canUndo;\r\n const canRedo = viewport.history.canRedo;\r\n const cached = cachedRef.current;\r\n if (cached.canUndo === canUndo && cached.canRedo === canRedo) {\r\n return cached;\r\n }\r\n const next = { canUndo, canRedo };\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\r\n\r\n const undo = useCallback(() => viewport.undo(), [viewport]);\r\n const redo = useCallback(() => viewport.redo(), [viewport]);\r\n\r\n return {\r\n canUndo: snapshot.canUndo,\r\n canRedo: snapshot.canRedo,\r\n undo,\r\n redo,\r\n };\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { CanvasElement, ElementType } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nfunction shallowEqual(a: unknown, b: unknown): boolean {\r\n if (Object.is(a, b)) return true;\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));\r\n }\r\n if (\r\n typeof a === 'object' &&\r\n a !== null &&\r\n typeof b === 'object' &&\r\n b !== null &&\r\n !Array.isArray(a) &&\r\n !Array.isArray(b)\r\n ) {\r\n const ka = Object.keys(a);\r\n const kb = Object.keys(b);\r\n return (\r\n ka.length === kb.length &&\r\n ka.every(\r\n (k) =>\r\n k in (b as Record<string, unknown>) &&\r\n Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\r\n )\r\n );\r\n }\r\n return false;\r\n}\r\n\r\n/** All elements; re-renders on every store mutation (use a selector for hot paths). */\r\nexport function useElements(): CanvasElement[];\r\n/** Elements of one type; re-renders on every store mutation. */\r\nexport function useElements<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[];\r\n/**\r\n * Derived value; re-renders only when the selected value changes (per `isEqual`,\r\n * default: one-level shallow compare — arrays by index, plain objects by key, primitives by\r\n * Object.is). Keep the selector referentially stable (useCallback or module scope).\r\n *\r\n * Supply `isEqual` for deeper structures. Note: selectors returning nested fresh objects\r\n * (e.g. `els => els.map(e => ({ ...e.position }))`) still need a custom comparator because\r\n * the default only compares one level deep.\r\n */\r\nexport function useElements<R>(\r\n selector: (elements: CanvasElement[]) => R,\r\n isEqual?: (a: R, b: R) => boolean,\r\n): R;\r\nexport function useElements<R>(\r\n arg?: ElementType | ((elements: CanvasElement[]) => R),\r\n isEqual?: (a: R, b: R) => boolean,\r\n): CanvasElement[] | R {\r\n const viewport = useViewport();\r\n const cachedRef = useRef<CanvasElement[]>([]);\r\n const selectedRef = useRef<{ value: R } | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => viewport.store.onChange(onStoreChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): CanvasElement[] | R => {\r\n if (typeof arg === 'function') {\r\n const next = arg(viewport.store.getAll());\r\n const prev = selectedRef.current;\r\n const equal: (a: R, b: R) => boolean = isEqual ?? (shallowEqual as (a: R, b: R) => boolean);\r\n if (prev !== null && equal(prev.value, next)) {\r\n return prev.value;\r\n }\r\n selectedRef.current = { value: next };\r\n return next;\r\n }\r\n\r\n const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();\r\n const cached = cachedRef.current;\r\n if (cached.length === next.length && cached.every((el, i) => el === next[i])) {\r\n return cached;\r\n }\r\n cachedRef.current = next;\r\n return next;\r\n }, [viewport, arg, isEqual]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useViewport } from './use-viewport';\r\n\r\n/** Reactive selected element ids. Stable array reference — only changes when the selection changes. */\r\nexport function useSelection(): string[] {\r\n const viewport = useViewport();\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => viewport.onSelectionChange(onChange),\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => viewport.getSelectedIds(), [viewport]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { ElementStyle } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\nimport { STYLE_KEYS } from './style-keys';\r\n\r\nfunction styleEqual(a: ElementStyle | null, b: ElementStyle | null): boolean {\r\n if (a === b) return true;\r\n if (a === null || b === null) return false;\r\n return STYLE_KEYS.every((k) => a[k] === b[k]);\r\n}\r\n\r\n/**\r\n * Reactive normalized style of the current selection.\r\n * Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.\r\n * `applyPatch` applies an `ElementStyle` patch to every selected element.\r\n */\r\nexport function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void] {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<ElementStyle | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n const next = viewport.getSelectionStyle();\r\n if (styleEqual(cacheRef.current, next)) return cacheRef.current;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const style = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\r\n\r\n return [style, apply];\r\n}\r\n","import type { ElementStyle } from '@fieldnotes/core';\r\n\r\n/**\r\n * The `ElementStyle` fields the selection-style hooks compare and cache.\r\n * Internal to `@fieldnotes/react` — not exported from the package index.\r\n * Shared between `useSelectionStyle` and `useSelectionStyleDetails` so the\r\n * two hooks cannot drift out of sync (a prior desync here dropped\r\n * `strokeStyle` from one hook's equality check and caused stale style data).\r\n */\r\nexport const STYLE_KEYS: readonly (keyof ElementStyle)[] = [\r\n 'color',\r\n 'fillColor',\r\n 'strokeWidth',\r\n 'opacity',\r\n 'fontSize',\r\n 'strokeStyle',\r\n];\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\nimport { STYLE_KEYS } from './style-keys';\r\n\r\nfunction keysEqual(\r\n a: readonly (keyof ElementStyle)[],\r\n b: readonly (keyof ElementStyle)[],\r\n): boolean {\r\n return a.length === b.length && a.every((k, i) => k === b[i]);\r\n}\r\n\r\nfunction detailsEqual(a: SelectionStyleDetails | null, b: SelectionStyleDetails | null): boolean {\r\n if (a === b) return true;\r\n if (a === null || b === null) return false;\r\n return (\r\n keysEqual(a.applicable, b.applicable) &&\r\n keysEqual(a.mixed, b.mixed) &&\r\n STYLE_KEYS.every((k) => a.common[k] === b.common[k])\r\n );\r\n}\r\n\r\n/**\r\n * Reactive style details of the current selection: per-field applicability and\r\n * mixed-state, plus the common style. `null` when nothing valid is selected.\r\n * The apply function delegates to `applyStyleToSelection` (one undo step).\r\n */\r\nexport function useSelectionStyleDetails(): [\r\n SelectionStyleDetails | null,\r\n (style: ElementStyle) => void,\r\n] {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<SelectionStyleDetails | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n const next = viewport.getSelectionStyleDetails();\r\n if (detailsEqual(cacheRef.current, next)) return cacheRef.current;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const details = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\r\n\r\n return [details, apply];\r\n}\r\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\r\nimport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\r\nimport { useViewport } from './use-viewport';\r\n\r\nexport interface UseSelectionOpsResult {\r\n selectedIds: string[];\r\n selectedCount: number;\r\n canGroup: boolean;\r\n canUngroup: boolean;\r\n canAlign: boolean;\r\n canDistribute: boolean;\r\n isLocked: boolean | null;\r\n group: () => void;\r\n ungroup: () => void;\r\n toggleLock: () => void;\r\n align: (edge: AlignEdge) => void;\r\n distribute: (axis: DistributeAxis) => void;\r\n rotateCW: () => void;\r\n rotateCCW: () => void;\r\n}\r\n\r\ninterface Snapshot {\r\n selectedIds: string[];\r\n canGroup: boolean;\r\n canUngroup: boolean;\r\n canAlign: boolean;\r\n canDistribute: boolean;\r\n isLocked: boolean | null;\r\n}\r\n\r\nfunction snapshotEqual(a: Snapshot, b: Snapshot): boolean {\r\n return (\r\n a.selectedIds === b.selectedIds &&\r\n a.canGroup === b.canGroup &&\r\n a.canUngroup === b.canUngroup &&\r\n a.canAlign === b.canAlign &&\r\n a.canDistribute === b.canDistribute &&\r\n a.isLocked === b.isLocked\r\n );\r\n}\r\n\r\n/**\r\n * Reactive selection operations + derived predicates for the current selection.\r\n * Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;\r\n * `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,\r\n * and `null` when empty or mixed. Actions delegate to the core Viewport.\r\n */\r\nexport function useSelectionOps(): UseSelectionOpsResult {\r\n const viewport = useViewport();\r\n const cacheRef = useRef<Snapshot | null>(null);\r\n\r\n const subscribe = useCallback(\r\n (onChange: () => void) => {\r\n const offSel = viewport.onSelectionChange(onChange);\r\n const offStore = viewport.store.onChange(onChange);\r\n return () => {\r\n offSel();\r\n offStore();\r\n };\r\n },\r\n [viewport],\r\n );\r\n\r\n const getSnapshot = useCallback((): Snapshot => {\r\n const ids = viewport.getSelectedIds();\r\n const n = ids.length;\r\n let canUngroup = false;\r\n let lockedCount = 0;\r\n for (const id of ids) {\r\n const el = viewport.store.getById(id);\r\n if (!el) continue;\r\n if (el.groupId !== undefined) canUngroup = true;\r\n if (el.locked) lockedCount++;\r\n }\r\n const isLocked: boolean | null =\r\n n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;\r\n const next: Snapshot = {\r\n selectedIds: ids,\r\n canGroup: n >= 2,\r\n canUngroup,\r\n canAlign: n >= 2,\r\n canDistribute: n >= 3,\r\n isLocked,\r\n };\r\n const prev = cacheRef.current;\r\n if (prev && snapshotEqual(prev, next)) return prev;\r\n cacheRef.current = next;\r\n return next;\r\n }, [viewport]);\r\n\r\n const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n const group = useCallback(() => viewport.groupSelection(), [viewport]);\r\n const ungroup = useCallback(() => viewport.ungroupSelection(), [viewport]);\r\n const toggleLock = useCallback(() => viewport.toggleLockSelection(), [viewport]);\r\n const align = useCallback((edge: AlignEdge) => viewport.alignSelection(edge), [viewport]);\r\n const distribute = useCallback(\r\n (axis: DistributeAxis) => viewport.distributeSelection(axis),\r\n [viewport],\r\n );\r\n const rotateCW = useCallback(() => viewport.rotateSelection('cw'), [viewport]);\r\n const rotateCCW = useCallback(() => viewport.rotateSelection('ccw'), [viewport]);\r\n\r\n return {\r\n selectedIds: snap.selectedIds,\r\n selectedCount: snap.selectedIds.length,\r\n canGroup: snap.canGroup,\r\n canUngroup: snap.canUngroup,\r\n canAlign: snap.canAlign,\r\n canDistribute: snap.canDistribute,\r\n isLocked: snap.isLocked,\r\n group,\r\n ungroup,\r\n toggleLock,\r\n align,\r\n distribute,\r\n rotateCW,\r\n rotateCCW,\r\n };\r\n}\r\n","import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react';\nimport { ElementRectTracker, computeElementRects, elementRectsEqual } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nimport type { CanvasElement, ElementRect, ElementRectMatch } from '@fieldnotes/core';\n\n/**\n * World rects of the elements a host matcher selects, re-rendering only when a\n * tracked field changes. Camera motion never re-renders: position content under\n * one camera transform and let the browser composite it.\n *\n * `match` may be an inline arrow — it is read through a ref, so it never\n * re-subscribes; a semantic change is picked up via `setMatch`.\n */\nexport function useElementRects(match: ElementRectMatch): readonly ElementRect[] {\n const viewport = useViewport();\n\n const matchRef = useRef<ElementRectMatch>(match);\n matchRef.current = match;\n const stableMatch = useCallback((el: CanvasElement) => matchRef.current(el), []);\n\n const cacheRef = useRef<readonly ElementRect[] | null>(null);\n const trackerRef = useRef<ElementRectTracker | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n // Constructed HERE, not in a memo: Strict Mode rehearses\n // setup -> cleanup -> setup without re-creating memoized state, so a\n // memo-created tracker disposed by the first cleanup would be reused\n // already disposed and would never emit again.\n const tracker = new ElementRectTracker(viewport, { match: stableMatch });\n trackerRef.current = tracker;\n\n const next = tracker.getRects();\n const previous = cacheRef.current;\n if (previous === null || !elementRectsEqual(previous, next)) {\n cacheRef.current = next;\n onStoreChange();\n }\n\n const off = tracker.onChange((rects) => {\n cacheRef.current = rects;\n onStoreChange();\n });\n\n return () => {\n off();\n tracker.dispose();\n if (trackerRef.current === tracker) trackerRef.current = null;\n };\n },\n [viewport, stableMatch],\n );\n\n const getSnapshot = useCallback((): readonly ElementRect[] => {\n if (cacheRef.current === null) {\n cacheRef.current = computeElementRects(viewport.store, stableMatch);\n }\n return cacheRef.current;\n }, [viewport, stableMatch]);\n\n const rects = useSyncExternalStore(subscribe, getSnapshot);\n\n // `stableMatch` never changes identity while its behavior does, so the\n // tracker needs an explicit nudge whenever the caller's matcher changes.\n useEffect(() => {\n trackerRef.current?.setMatch(stableMatch);\n }, [match, stableMatch]);\n\n return rects;\n}\n","import { useEffect, useRef, useState, type CSSProperties } from 'react';\r\nimport { MinimapController } from '@fieldnotes/core';\r\nimport { useViewport } from './hooks/use-viewport';\r\n\r\nexport interface MinimapProps {\r\n /** Thumbnail width in CSS pixels. Default `200`. */\r\n width?: number;\r\n /** Thumbnail height in CSS pixels. Default `140`. */\r\n height?: number;\r\n /** Start collapsed (icon button only). Uncontrolled. Default `false`. */\r\n defaultCollapsed?: boolean;\r\n /** Backdrop fill behind the thumbnail. */\r\n background?: string;\r\n /** Viewport rectangle stroke color. */\r\n viewportStroke?: string;\r\n className?: string;\r\n style?: CSSProperties;\r\n}\r\n\r\nconst toggleStyle: CSSProperties = {\r\n position: 'absolute',\r\n top: 2,\r\n right: 2,\r\n width: 24,\r\n height: 24,\r\n padding: 0,\r\n border: 'none',\r\n borderRadius: 4,\r\n background: 'rgba(0,0,0,0.35)',\r\n color: '#fff',\r\n font: '14px/1 system-ui, sans-serif',\r\n cursor: 'pointer',\r\n};\r\n\r\n/**\r\n * Collapsible thumbnail overview navigator. Renders inside `<FieldNotesCanvas>`\r\n * (or any `ViewportContext.Provider`). Positioning is host-owned — place and\r\n * style the component via `className`/`style`. While collapsed, no controller\r\n * exists: zero listeners, zero rendering.\r\n */\r\nexport function Minimap({\r\n width = 200,\r\n height = 140,\r\n defaultCollapsed = false,\r\n background,\r\n viewportStroke,\r\n className,\r\n style,\r\n}: MinimapProps) {\r\n const viewport = useViewport();\r\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n\r\n useEffect(() => {\r\n if (collapsed) return;\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const controller = new MinimapController(viewport, canvas, {\r\n width,\r\n height,\r\n background,\r\n viewportStroke,\r\n });\r\n return () => controller.dispose();\r\n }, [viewport, collapsed, width, height, background, viewportStroke]);\r\n\r\n if (collapsed) {\r\n return (\r\n <button\r\n type=\"button\"\r\n aria-label=\"Expand minimap\"\r\n onClick={() => setCollapsed(false)}\r\n className={className}\r\n style={{\r\n minWidth: 44,\r\n minHeight: 44,\r\n border: '1px solid rgba(0,0,0,0.15)',\r\n borderRadius: 8,\r\n background: 'rgba(255,255,255,0.85)',\r\n cursor: 'pointer',\r\n font: '18px/1 system-ui, sans-serif',\r\n ...style,\r\n }}\r\n >\r\n {'▣'}\r\n </button>\r\n );\r\n }\r\n\r\n return (\r\n <div className={className} style={{ position: 'relative', ...style }}>\r\n <canvas\r\n ref={canvasRef}\r\n style={{ width: `${width}px`, height: `${height}px`, display: 'block' }}\r\n />\r\n <button\r\n type=\"button\"\r\n aria-label=\"Collapse minimap\"\r\n onClick={() => setCollapsed(true)}\r\n style={toggleStyle}\r\n >\r\n {'–'}\r\n </button>\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["FieldNotesCanvas","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","next","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","shallowEqual","useRef","useCallback","next","useSyncExternalStore","useCallback","useSyncExternalStore","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useEffect","useRef","useSyncExternalStore","useRef","useCallback","rects","useSyncExternalStore","useEffect","useEffect","useRef","useState","jsx","useState","useRef","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fieldnotes/react",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "React wrapper for Field Notes canvas SDK",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -36,7 +36,7 @@
36
36
  "fieldnotes"
37
37
  ],
38
38
  "peerDependencies": {
39
- "@fieldnotes/core": ">=0.58.0 <1.0.0",
39
+ "@fieldnotes/core": ">=0.63.0 <1.0.0",
40
40
  "react": ">=18 <20",
41
41
  "react-dom": ">=18 <20"
42
42
  },
@@ -50,7 +50,7 @@
50
50
  "react-dom": "^19.2.4",
51
51
  "tsup": "^8.5.1",
52
52
  "vitest": "^4.1.0",
53
- "@fieldnotes/core": "0.58.0"
53
+ "@fieldnotes/core": "0.63.0"
54
54
  },
55
55
  "scripts": {
56
56
  "build": "tsup",