@fieldnotes/react 0.12.0 → 0.13.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/README.md +2 -0
- package/dist/index.cjs +34 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +34 -8
- package/dist/index.js.map +1 -1
- package/package.json +13 -6
package/README.md
CHANGED
|
@@ -122,6 +122,8 @@ Embedded components use a **two-mode interaction model**: by default they can be
|
|
|
122
122
|
|
|
123
123
|
`position` is required; `size` is optional — omit it to let the element size to its content. Both props are reactive: updating them moves or resizes the element on the canvas.
|
|
124
124
|
|
|
125
|
+
`<CanvasElement>` is **host-owned**: React is the source of truth for its element. Its store mutations carry `origin: 'host'`, so mounting, moving, resizing and unmounting never create undo steps and are never sent to a sync relay (the DOM subtree exists only in this document). The element is **transient**: `exportState()` / `exportJSON()` omit it, so a saved canvas never contains a ghost of a React embed. After a store `clear` (a user's clear-canvas gesture or a remote one) or a `loadState()` the component re-registers itself, so the embed survives. To persist an embed across reloads, use the viewport's `registerHtmlRenderer` with an `htmlType` and serializable `data` instead.
|
|
126
|
+
|
|
125
127
|
## Undo / Redo
|
|
126
128
|
|
|
127
129
|
`useHistory` returns reactive undo/redo state and action callbacks:
|
package/dist/index.cjs
CHANGED
|
@@ -126,36 +126,62 @@ function useViewport() {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// src/canvas-element.tsx
|
|
129
|
+
var HOST_ORIGIN = "host";
|
|
129
130
|
function CanvasElement({ position, size, children }) {
|
|
130
131
|
const viewport = useViewport();
|
|
131
132
|
const [portalTarget, setPortalTarget] = (0, import_react4.useState)(null);
|
|
132
133
|
const elementIdRef = (0, import_react4.useRef)(null);
|
|
134
|
+
const geometryRef = (0, import_react4.useRef)({ position, size });
|
|
133
135
|
(0, import_react4.useEffect)(() => {
|
|
134
136
|
const container = document.createElement("div");
|
|
135
137
|
Object.assign(container.style, {
|
|
136
138
|
width: "100%",
|
|
137
139
|
height: "100%"
|
|
138
140
|
});
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
const register = () => {
|
|
142
|
+
viewport.domLayer.appendChild(container);
|
|
143
|
+
const { position: current, size: currentSize } = geometryRef.current;
|
|
144
|
+
return viewport.addHtmlElement(container, current, currentSize, {
|
|
145
|
+
transient: true,
|
|
146
|
+
origin: HOST_ORIGIN
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
elementIdRef.current = register();
|
|
142
150
|
setPortalTarget(container);
|
|
151
|
+
let disposed = false;
|
|
152
|
+
const handleStoreReplacement = () => {
|
|
153
|
+
const clearedId = elementIdRef.current;
|
|
154
|
+
if (clearedId === null) return;
|
|
155
|
+
queueMicrotask(() => {
|
|
156
|
+
if (disposed || elementIdRef.current !== clearedId) return;
|
|
157
|
+
if (viewport.store.getById(clearedId)?.type === "html") {
|
|
158
|
+
viewport.updateHtmlElement(clearedId, container);
|
|
159
|
+
} else {
|
|
160
|
+
elementIdRef.current = register();
|
|
161
|
+
}
|
|
162
|
+
viewport.requestRender();
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
const unsubscribeClear = viewport.store.on("clear", handleStoreReplacement);
|
|
166
|
+
const unsubscribeBatch = viewport.store.on("batch", handleStoreReplacement);
|
|
143
167
|
return () => {
|
|
168
|
+
disposed = true;
|
|
169
|
+
unsubscribeClear();
|
|
170
|
+
unsubscribeBatch();
|
|
144
171
|
if (elementIdRef.current) {
|
|
145
|
-
viewport.store.remove(elementIdRef.current);
|
|
172
|
+
viewport.store.remove(elementIdRef.current, { origin: HOST_ORIGIN });
|
|
146
173
|
viewport.requestRender();
|
|
147
174
|
elementIdRef.current = null;
|
|
148
175
|
}
|
|
176
|
+
if (container.parentNode === viewport.domLayer) container.remove();
|
|
149
177
|
setPortalTarget(null);
|
|
150
178
|
};
|
|
151
179
|
}, [viewport]);
|
|
152
180
|
(0, import_react4.useEffect)(() => {
|
|
181
|
+
geometryRef.current = { position, size };
|
|
153
182
|
const id = elementIdRef.current;
|
|
154
183
|
if (!id) return;
|
|
155
|
-
viewport.store.update(id, { position });
|
|
156
|
-
if (size) {
|
|
157
|
-
viewport.store.update(id, { size });
|
|
158
|
-
}
|
|
184
|
+
viewport.store.update(id, { position, ...size ? { size } : {} }, { origin: HOST_ORIGIN });
|
|
159
185
|
viewport.requestRender();
|
|
160
186
|
}, [viewport, position.x, position.y, size?.w, size?.h]);
|
|
161
187
|
if (!portalTarget) return null;
|
package/dist/index.cjs.map
CHANGED
|
@@ -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/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 {\n useRef,\n useEffect,\n useState,\n forwardRef,\n useImperativeHandle,\n type ReactNode,\n type CSSProperties,\n} from 'react';\nimport { Viewport } from '@fieldnotes/core';\nimport type { ViewportOptions, Tool } from '@fieldnotes/core';\nimport { ViewportContext } from './context';\n\nexport interface FieldNotesCanvasProps {\n /** Constructor-only: changes after mount are ignored (the canvas is stateful). */\n options?: ViewportOptions;\n /**\n * Reactive (append-only): tools present here are registered; removal is not supported.\n * Hoist the array out of render — inline arrays reconstruct Tool instances and re-run\n * registration on every render.\n */\n tools?: Tool[];\n /** Uncontrolled initial tool. Ignored when `tool` is set. */\n defaultTool?: string;\n /** Controlled active tool. Pair with `onToolChange`. */\n tool?: string;\n /**\n * Fires whenever the active tool changes (keyboard, API, or `tool` prop).\n * Memoize with useCallback to avoid re-subscribing each render.\n */\n onToolChange?: (name: string) => void;\n /**\n * Reactive compatibility toggle for the core snap flag.\n * @deprecated Grid snapping is domain behavior. Configure it through the\n * VTT grid/constraint service instead.\n */\n snapToGrid?: boolean;\n className?: string;\n style?: CSSProperties;\n children?: ReactNode;\n onReady?: (viewport: Viewport) => void;\n}\n\nexport interface FieldNotesCanvasRef {\n viewport: Viewport | null;\n}\n\nexport const FieldNotesCanvas = forwardRef<FieldNotesCanvasRef, FieldNotesCanvasProps>(\n function FieldNotesCanvas(\n {\n options,\n tools,\n defaultTool,\n tool,\n onToolChange,\n snapToGrid,\n className,\n style,\n children,\n onReady,\n },\n ref,\n ) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [viewport, setViewport] = useState<Viewport | null>(null);\n\n useImperativeHandle(ref, () => ({ viewport }), [viewport]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const vp = new Viewport(el, options);\n\n if (tools) {\n for (const t of tools) {\n vp.toolManager.register(t);\n }\n }\n\n const initialTool = tool ?? defaultTool;\n if (initialTool) {\n vp.setTool(initialTool);\n }\n\n setViewport(vp);\n onReady?.(vp);\n\n return () => {\n vp.destroy();\n setViewport(null);\n };\n // Constructor effect: options/tools/defaultTool are mount-only by design.\n }, []);\n\n useEffect(() => {\n if (!viewport || tool === undefined) return;\n if (viewport.toolManager.activeTool?.name !== tool) {\n viewport.setTool(tool);\n }\n }, [viewport, tool]);\n\n useEffect(() => {\n if (!viewport || !onToolChange) return;\n return viewport.toolManager.onChange(onToolChange);\n }, [viewport, onToolChange]);\n\n useEffect(() => {\n if (!viewport || snapToGrid === undefined) return;\n viewport.setSnapToGrid(snapToGrid);\n }, [viewport, snapToGrid]);\n\n useEffect(() => {\n if (!viewport || !tools) return;\n for (const t of tools) {\n if (!viewport.toolManager.getTool(t.name)) {\n viewport.toolManager.register(t);\n }\n }\n }, [viewport, tools]);\n\n return (\n <div ref={containerRef} className={className} style={style}>\n {viewport && (\n <ViewportContext.Provider value={viewport}>{children}</ViewportContext.Provider>\n )}\n </div>\n );\n },\n);\n","import { createContext } from 'react';\nimport type { Viewport } from '@fieldnotes/core';\n\nexport const ViewportContext = createContext<Viewport | null>(null);\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useViewport } from './hooks/use-viewport';\n\n/** Props for {@link CanvasElement}. */\nexport interface CanvasElementProps {\n /** Canvas-space position of the element's top-left corner. */\n position: { x: number; y: number };\n /** Optional fixed size; omit to let the element size to its content. */\n size?: { w: number; h: number };\n children: ReactNode;\n}\n\n/**\n * Renders a React subtree as an HTML element embedded in the canvas coordinate space.\n * Must be used inside a `<FieldNotesCanvas>`.\n */\nexport function CanvasElement({ position, size, children }: CanvasElementProps) {\n const viewport = useViewport();\n const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\n const elementIdRef = useRef<string | null>(null);\n\n useEffect(() => {\n const container = document.createElement('div');\n Object.assign(container.style, {\n width: '100%',\n height: '100%',\n });\n\n // Append to domLayer immediately so portal children are queryable in the document\n // before the viewport render loop fires via requestAnimationFrame.\n viewport.domLayer.appendChild(container);\n\n const id = viewport.addHtmlElement(container, position, size);\n elementIdRef.current = id;\n setPortalTarget(container);\n\n return () => {\n if (elementIdRef.current) {\n viewport.store.remove(elementIdRef.current);\n viewport.requestRender();\n elementIdRef.current = null;\n }\n setPortalTarget(null);\n };\n }, [viewport]);\n\n useEffect(() => {\n const id = elementIdRef.current;\n if (!id) return;\n viewport.store.update(id, { position });\n if (size) {\n viewport.store.update(id, { size });\n }\n viewport.requestRender();\n // Primitive deps (position.x/y, size?.w/h) are intentional: the effect re-runs on VALUE change,\n // not object identity — so inline { x, y } literals and memoized-but-unchanged objects both behave\n // correctly (no over-firing on every parent re-render).\n }, [viewport, position.x, position.y, size?.w, size?.h]);\n\n if (!portalTarget) return null;\n return createPortal(children, portalTarget);\n}\n","import { useContext } from 'react';\nimport type { Viewport } from '@fieldnotes/core';\nimport { ViewportContext } from '../context';\n\n/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */\nexport function useViewport(): Viewport {\n const viewport = useContext(ViewportContext);\n if (!viewport) {\n throw new Error('useViewport must be used inside <FieldNotesCanvas>');\n }\n return viewport;\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\n/** `[activeToolName, setTool]` — re-renders on tool switches. */\nexport function useActiveTool(): [toolName: string, setTool: (name: string) => void] {\n const viewport = useViewport();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.toolManager.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback(() => viewport.toolManager.activeTool?.name ?? '', [viewport]);\n\n const toolName = useSyncExternalStore(subscribe, getSnapshot);\n\n const setTool = useCallback((name: string) => viewport.setTool(name), [viewport]);\n\n return [toolName, setTool];\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\nexport interface CameraState {\n x: number;\n y: number;\n zoom: number;\n}\n\n/** Current camera position and zoom level — re-renders whenever the camera moves or zoom changes. */\nexport function useCamera(): CameraState {\n const viewport = useViewport();\n const cachedRef = useRef<CameraState>({ x: 0, y: 0, zoom: 1 });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.camera.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): CameraState => {\n const { position, zoom } = viewport.camera;\n const cached = cachedRef.current;\n if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {\n return cached;\n }\n const next = { x: position.x, y: position.y, zoom };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\nfunction noop() {\n /* unsubscribe placeholder */\n}\n\n/**\n * `[options, setOptions]` for the named tool — re-renders when the tool's options change.\n * Returns `null` for options if the tool is not registered or does not expose options.\n */\nexport function useToolOptions<T extends Record<string, unknown>>(\n toolName: string,\n): [options: T | null, setOptions: (partial: Partial<T>) => void] {\n const viewport = useViewport();\n const cachedRef = useRef<T | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n const tool = viewport.toolManager.getTool(toolName);\n if (!tool?.onOptionsChange) return noop;\n return tool.onOptionsChange(onStoreChange);\n },\n [viewport, toolName],\n );\n\n const getSnapshot = useCallback((): T | null => {\n const tool = viewport.toolManager.getTool(toolName);\n if (!tool?.getOptions) return null;\n const next = tool.getOptions() as T;\n const cached = cachedRef.current;\n if (cached && shallowEqual(cached, next)) return cached;\n cachedRef.current = next;\n return next;\n }, [viewport, toolName]);\n\n const options = useSyncExternalStore(subscribe, getSnapshot);\n\n const setOptions = useCallback(\n (partial: Partial<T>) => {\n const tool = viewport.toolManager.getTool(toolName);\n tool?.setOptions?.(partial as Record<string, unknown>);\n },\n [viewport, toolName],\n );\n\n return [options, setOptions];\n}\n\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n const valA = a[key];\n const valB = b[key];\n if (valA === valB) continue;\n if (\n typeof valA === 'object' &&\n valA !== null &&\n typeof valB === 'object' &&\n valB !== null &&\n !Array.isArray(valA) &&\n !Array.isArray(valB)\n ) {\n const objA = valA as Record<string, unknown>;\n const objB = valB as Record<string, unknown>;\n const innerKeys = Object.keys(objA);\n if (\n innerKeys.length === Object.keys(objB).length &&\n innerKeys.every((k) => objA[k] === objB[k])\n ) {\n continue;\n }\n }\n return false;\n }\n return true;\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { Layer } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\ninterface LayersSnapshot {\n layers: Layer[];\n activeLayerId: string;\n}\n\nexport interface UseLayersResult {\n layers: Layer[];\n activeLayerId: string;\n createLayer: (name?: string) => Layer;\n removeLayer: (id: string) => void;\n renameLayer: (id: string, name: string) => void;\n reorderLayer: (id: string, newOrder: number) => void;\n setVisible: (id: string, visible: boolean) => void;\n setLocked: (id: string, locked: boolean) => void;\n setOpacity: (id: string, opacity: number) => void;\n setActiveLayer: (id: string) => void;\n moveElement: (elementId: string, layerId: string) => void;\n}\n\n/**\n * Current layer list and mutation helpers — re-renders whenever a layer is added, removed,\n * reordered, renamed, or its visibility/lock/opacity/active state changes.\n */\nexport function useLayers(): UseLayersResult {\n const viewport = useViewport();\n const cachedRef = useRef<LayersSnapshot>({ layers: [], activeLayerId: '' });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.layerManager.on('change', onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): LayersSnapshot => {\n const layers = viewport.layerManager.getLayers();\n const activeLayerId = viewport.layerManager.activeLayerId;\n const cached = cachedRef.current;\n if (\n cached.activeLayerId === activeLayerId &&\n cached.layers.length === layers.length &&\n cached.layers.every((l, i) => {\n const next = layers[i];\n return (\n next !== undefined &&\n l.id === next.id &&\n l.name === next.name &&\n l.visible === next.visible &&\n l.locked === next.locked &&\n l.order === next.order &&\n l.opacity === next.opacity\n );\n })\n ) {\n return cached;\n }\n const next = { layers, activeLayerId };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\n\n const createLayer = useCallback(\n (name?: string) => viewport.layerManager.createLayer(name),\n [viewport],\n );\n\n const removeLayer = useCallback(\n (id: string) => viewport.layerManager.removeLayer(id),\n [viewport],\n );\n\n const renameLayer = useCallback(\n (id: string, name: string) => viewport.layerManager.renameLayer(id, name),\n [viewport],\n );\n\n const reorderLayer = useCallback(\n (id: string, newOrder: number) => viewport.layerManager.reorderLayer(id, newOrder),\n [viewport],\n );\n\n const setVisible = useCallback(\n (id: string, visible: boolean) => viewport.layerManager.setLayerVisible(id, visible),\n [viewport],\n );\n\n const setLocked = useCallback(\n (id: string, locked: boolean) => viewport.layerManager.setLayerLocked(id, locked),\n [viewport],\n );\n\n const setOpacity = useCallback(\n (id: string, opacity: number) => viewport.layerManager.setLayerOpacity(id, opacity),\n [viewport],\n );\n\n const setActiveLayer = useCallback(\n (id: string) => viewport.layerManager.setActiveLayer(id),\n [viewport],\n );\n\n const moveElement = useCallback(\n (elementId: string, layerId: string) =>\n viewport.layerManager.moveElementToLayer(elementId, layerId),\n [viewport],\n );\n\n return {\n layers: snapshot.layers,\n activeLayerId: snapshot.activeLayerId,\n createLayer,\n removeLayer,\n renameLayer,\n reorderLayer,\n setVisible,\n setLocked,\n setOpacity,\n setActiveLayer,\n moveElement,\n };\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\ninterface HistorySnapshot {\n canUndo: boolean;\n canRedo: boolean;\n}\n\nexport interface UseHistoryResult {\n canUndo: boolean;\n canRedo: boolean;\n undo: () => void;\n redo: () => void;\n}\n\n/** `{ canUndo, canRedo, undo, redo }` — re-renders when undo/redo availability changes. */\nexport function useHistory(): UseHistoryResult {\n const viewport = useViewport();\n const cachedRef = useRef<HistorySnapshot>({ canUndo: false, canRedo: false });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.history.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): HistorySnapshot => {\n const canUndo = viewport.history.canUndo;\n const canRedo = viewport.history.canRedo;\n const cached = cachedRef.current;\n if (cached.canUndo === canUndo && cached.canRedo === canRedo) {\n return cached;\n }\n const next = { canUndo, canRedo };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\n\n const undo = useCallback(() => viewport.undo(), [viewport]);\n const redo = useCallback(() => viewport.redo(), [viewport]);\n\n return {\n canUndo: snapshot.canUndo,\n canRedo: snapshot.canRedo,\n undo,\n redo,\n };\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { CanvasElement, ElementType } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));\n }\n if (\n typeof a === 'object' &&\n a !== null &&\n typeof b === 'object' &&\n b !== null &&\n !Array.isArray(a) &&\n !Array.isArray(b)\n ) {\n const ka = Object.keys(a);\n const kb = Object.keys(b);\n return (\n ka.length === kb.length &&\n ka.every(\n (k) =>\n k in (b as Record<string, unknown>) &&\n Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\n )\n );\n }\n return false;\n}\n\n/** All elements; re-renders on every store mutation (use a selector for hot paths). */\nexport function useElements(): CanvasElement[];\n/** Elements of one type; re-renders on every store mutation. */\nexport function useElements<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[];\n/**\n * Derived value; re-renders only when the selected value changes (per `isEqual`,\n * default: one-level shallow compare — arrays by index, plain objects by key, primitives by\n * Object.is). Keep the selector referentially stable (useCallback or module scope).\n *\n * Supply `isEqual` for deeper structures. Note: selectors returning nested fresh objects\n * (e.g. `els => els.map(e => ({ ...e.position }))`) still need a custom comparator because\n * the default only compares one level deep.\n */\nexport function useElements<R>(\n selector: (elements: CanvasElement[]) => R,\n isEqual?: (a: R, b: R) => boolean,\n): R;\nexport function useElements<R>(\n arg?: ElementType | ((elements: CanvasElement[]) => R),\n isEqual?: (a: R, b: R) => boolean,\n): CanvasElement[] | R {\n const viewport = useViewport();\n const cachedRef = useRef<CanvasElement[]>([]);\n const selectedRef = useRef<{ value: R } | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.store.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): CanvasElement[] | R => {\n if (typeof arg === 'function') {\n const next = arg(viewport.store.getAll());\n const prev = selectedRef.current;\n const equal: (a: R, b: R) => boolean = isEqual ?? (shallowEqual as (a: R, b: R) => boolean);\n if (prev !== null && equal(prev.value, next)) {\n return prev.value;\n }\n selectedRef.current = { value: next };\n return next;\n }\n\n const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();\n const cached = cachedRef.current;\n if (cached.length === next.length && cached.every((el, i) => el === next[i])) {\n return cached;\n }\n cachedRef.current = next;\n return next;\n }, [viewport, arg, isEqual]);\n\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\n/** Reactive selected element ids. Stable array reference — only changes when the selection changes. */\nexport function useSelection(): string[] {\n const viewport = useViewport();\n\n const subscribe = useCallback(\n (onChange: () => void) => viewport.onSelectionChange(onChange),\n [viewport],\n );\n\n const getSnapshot = useCallback(() => viewport.getSelectedIds(), [viewport]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { ElementStyle } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\nimport { STYLE_KEYS } from './style-keys';\n\nfunction styleEqual(a: ElementStyle | null, b: ElementStyle | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return STYLE_KEYS.every((k) => a[k] === b[k]);\n}\n\n/**\n * Reactive normalized style of the current selection.\n * Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.\n * `applyPatch` applies an `ElementStyle` patch to every selected element.\n */\nexport function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void] {\n const viewport = useViewport();\n const cacheRef = useRef<ElementStyle | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback(() => {\n const next = viewport.getSelectionStyle();\n if (styleEqual(cacheRef.current, next)) return cacheRef.current;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const style = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\n\n return [style, apply];\n}\n","import type { ElementStyle } from '@fieldnotes/core';\n\n/**\n * The `ElementStyle` fields the selection-style hooks compare and cache.\n * Internal to `@fieldnotes/react` — not exported from the package index.\n * Shared between `useSelectionStyle` and `useSelectionStyleDetails` so the\n * two hooks cannot drift out of sync (a prior desync here dropped\n * `strokeStyle` from one hook's equality check and caused stale style data).\n */\nexport const STYLE_KEYS: readonly (keyof ElementStyle)[] = [\n 'color',\n 'fillColor',\n 'strokeWidth',\n 'opacity',\n 'fontSize',\n 'strokeStyle',\n];\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\nimport { STYLE_KEYS } from './style-keys';\n\nfunction keysEqual(\n a: readonly (keyof ElementStyle)[],\n b: readonly (keyof ElementStyle)[],\n): boolean {\n return a.length === b.length && a.every((k, i) => k === b[i]);\n}\n\nfunction detailsEqual(a: SelectionStyleDetails | null, b: SelectionStyleDetails | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return (\n keysEqual(a.applicable, b.applicable) &&\n keysEqual(a.mixed, b.mixed) &&\n STYLE_KEYS.every((k) => a.common[k] === b.common[k])\n );\n}\n\n/**\n * Reactive style details of the current selection: per-field applicability and\n * mixed-state, plus the common style. `null` when nothing valid is selected.\n * The apply function delegates to `applyStyleToSelection` (one undo step).\n */\nexport function useSelectionStyleDetails(): [\n SelectionStyleDetails | null,\n (style: ElementStyle) => void,\n] {\n const viewport = useViewport();\n const cacheRef = useRef<SelectionStyleDetails | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback(() => {\n const next = viewport.getSelectionStyleDetails();\n if (detailsEqual(cacheRef.current, next)) return cacheRef.current;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const details = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\n\n return [details, apply];\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nexport interface UseSelectionOpsResult {\n selectedIds: string[];\n selectedCount: number;\n canGroup: boolean;\n canUngroup: boolean;\n canAlign: boolean;\n canDistribute: boolean;\n isLocked: boolean | null;\n group: () => void;\n ungroup: () => void;\n toggleLock: () => void;\n align: (edge: AlignEdge) => void;\n distribute: (axis: DistributeAxis) => void;\n rotateCW: () => void;\n rotateCCW: () => void;\n}\n\ninterface Snapshot {\n selectedIds: string[];\n canGroup: boolean;\n canUngroup: boolean;\n canAlign: boolean;\n canDistribute: boolean;\n isLocked: boolean | null;\n}\n\nfunction snapshotEqual(a: Snapshot, b: Snapshot): boolean {\n return (\n a.selectedIds === b.selectedIds &&\n a.canGroup === b.canGroup &&\n a.canUngroup === b.canUngroup &&\n a.canAlign === b.canAlign &&\n a.canDistribute === b.canDistribute &&\n a.isLocked === b.isLocked\n );\n}\n\n/**\n * Reactive selection operations + derived predicates for the current selection.\n * Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;\n * `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,\n * and `null` when empty or mixed. Actions delegate to the core Viewport.\n */\nexport function useSelectionOps(): UseSelectionOpsResult {\n const viewport = useViewport();\n const cacheRef = useRef<Snapshot | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback((): Snapshot => {\n const ids = viewport.getSelectedIds();\n const n = ids.length;\n let canUngroup = false;\n let lockedCount = 0;\n for (const id of ids) {\n const el = viewport.store.getById(id);\n if (!el) continue;\n if (el.groupId !== undefined) canUngroup = true;\n if (el.locked) lockedCount++;\n }\n const isLocked: boolean | null =\n n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;\n const next: Snapshot = {\n selectedIds: ids,\n canGroup: n >= 2,\n canUngroup,\n canAlign: n >= 2,\n canDistribute: n >= 3,\n isLocked,\n };\n const prev = cacheRef.current;\n if (prev && snapshotEqual(prev, next)) return prev;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const group = useCallback(() => viewport.groupSelection(), [viewport]);\n const ungroup = useCallback(() => viewport.ungroupSelection(), [viewport]);\n const toggleLock = useCallback(() => viewport.toggleLockSelection(), [viewport]);\n const align = useCallback((edge: AlignEdge) => viewport.alignSelection(edge), [viewport]);\n const distribute = useCallback(\n (axis: DistributeAxis) => viewport.distributeSelection(axis),\n [viewport],\n );\n const rotateCW = useCallback(() => viewport.rotateSelection('cw'), [viewport]);\n const rotateCCW = useCallback(() => viewport.rotateSelection('ccw'), [viewport]);\n\n return {\n selectedIds: snap.selectedIds,\n selectedCount: snap.selectedIds.length,\n canGroup: snap.canGroup,\n canUngroup: snap.canUngroup,\n canAlign: snap.canAlign,\n canDistribute: snap.canDistribute,\n isLocked: snap.isLocked,\n group,\n ungroup,\n toggleLock,\n align,\n distribute,\n rotateCW,\n rotateCCW,\n };\n}\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';\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_react","import_core","rects","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 {\n useRef,\n useEffect,\n useState,\n forwardRef,\n useImperativeHandle,\n type ReactNode,\n type CSSProperties,\n} from 'react';\nimport { Viewport } from '@fieldnotes/core';\nimport type { ViewportOptions, Tool } from '@fieldnotes/core';\nimport { ViewportContext } from './context';\n\nexport interface FieldNotesCanvasProps {\n /** Constructor-only: changes after mount are ignored (the canvas is stateful). */\n options?: ViewportOptions;\n /**\n * Reactive (append-only): tools present here are registered; removal is not supported.\n * Hoist the array out of render — inline arrays reconstruct Tool instances and re-run\n * registration on every render.\n */\n tools?: Tool[];\n /** Uncontrolled initial tool. Ignored when `tool` is set. */\n defaultTool?: string;\n /** Controlled active tool. Pair with `onToolChange`. */\n tool?: string;\n /**\n * Fires whenever the active tool changes (keyboard, API, or `tool` prop).\n * Memoize with useCallback to avoid re-subscribing each render.\n */\n onToolChange?: (name: string) => void;\n /**\n * Reactive compatibility toggle for the core snap flag.\n * @deprecated Grid snapping is domain behavior. Configure it through the\n * VTT grid/constraint service instead.\n */\n snapToGrid?: boolean;\n className?: string;\n style?: CSSProperties;\n children?: ReactNode;\n onReady?: (viewport: Viewport) => void;\n}\n\nexport interface FieldNotesCanvasRef {\n viewport: Viewport | null;\n}\n\nexport const FieldNotesCanvas = forwardRef<FieldNotesCanvasRef, FieldNotesCanvasProps>(\n function FieldNotesCanvas(\n {\n options,\n tools,\n defaultTool,\n tool,\n onToolChange,\n snapToGrid,\n className,\n style,\n children,\n onReady,\n },\n ref,\n ) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [viewport, setViewport] = useState<Viewport | null>(null);\n\n useImperativeHandle(ref, () => ({ viewport }), [viewport]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const vp = new Viewport(el, options);\n\n if (tools) {\n for (const t of tools) {\n vp.toolManager.register(t);\n }\n }\n\n const initialTool = tool ?? defaultTool;\n if (initialTool) {\n vp.setTool(initialTool);\n }\n\n setViewport(vp);\n onReady?.(vp);\n\n return () => {\n vp.destroy();\n setViewport(null);\n };\n // Constructor effect: options/tools/defaultTool are mount-only by design.\n }, []);\n\n useEffect(() => {\n if (!viewport || tool === undefined) return;\n if (viewport.toolManager.activeTool?.name !== tool) {\n viewport.setTool(tool);\n }\n }, [viewport, tool]);\n\n useEffect(() => {\n if (!viewport || !onToolChange) return;\n return viewport.toolManager.onChange(onToolChange);\n }, [viewport, onToolChange]);\n\n useEffect(() => {\n if (!viewport || snapToGrid === undefined) return;\n viewport.setSnapToGrid(snapToGrid);\n }, [viewport, snapToGrid]);\n\n useEffect(() => {\n if (!viewport || !tools) return;\n for (const t of tools) {\n if (!viewport.toolManager.getTool(t.name)) {\n viewport.toolManager.register(t);\n }\n }\n }, [viewport, tools]);\n\n return (\n <div ref={containerRef} className={className} style={style}>\n {viewport && (\n <ViewportContext.Provider value={viewport}>{children}</ViewportContext.Provider>\n )}\n </div>\n );\n },\n);\n","import { createContext } from 'react';\nimport type { Viewport } from '@fieldnotes/core';\n\nexport const ViewportContext = createContext<Viewport | null>(null);\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useViewport } from './hooks/use-viewport';\n\n/** Props for {@link CanvasElement}. */\nexport interface CanvasElementProps {\n /** Canvas-space position of the element's top-left corner. */\n position: { x: number; y: number };\n /** Optional fixed size; omit to let the element size to its content. */\n size?: { w: number; h: number };\n children: ReactNode;\n}\n\n/**\n * Marks every store mutation this component makes as host-owned: external origin, so it\n * neither creates an undo step nor is re-broadcast to the sync hub.\n */\nconst HOST_ORIGIN = 'host';\n\n/**\n * Renders a React subtree as an HTML element embedded in the canvas coordinate space.\n * The element is host-owned and transient: it is driven entirely by props, never appears\n * in exported state, and never records an undo step.\n * Must be used inside a `<FieldNotesCanvas>`.\n */\nexport function CanvasElement({ position, size, children }: CanvasElementProps) {\n const viewport = useViewport();\n const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\n const elementIdRef = useRef<string | null>(null);\n // Latest geometry, so a re-registration after a store clear uses current props rather than\n // the values captured when the mount effect ran.\n const geometryRef = useRef<{\n position: { x: number; y: number };\n size?: { w: number; h: number };\n }>({ position, size });\n\n useEffect(() => {\n const container = document.createElement('div');\n Object.assign(container.style, {\n width: '100%',\n height: '100%',\n });\n\n const register = () => {\n // Append to domLayer immediately so portal children are queryable in the document\n // before the viewport render loop fires via requestAnimationFrame.\n viewport.domLayer.appendChild(container);\n const { position: current, size: currentSize } = geometryRef.current;\n return viewport.addHtmlElement(container, current, currentSize, {\n transient: true,\n origin: HOST_ORIGIN,\n });\n };\n\n elementIdRef.current = register();\n setPortalTarget(container);\n\n let disposed = false;\n // A store clear detaches every canvas-owned DOM node and forgets the content registered\n // for it, so this component has to hand its container back afterwards. The decision is\n // deferred to a microtask because a remote clear is followed — synchronously, by the sync\n // client — by re-adding the transient elements: reading the store inside the event would\n // always report this element gone and add a duplicate.\n const handleStoreReplacement = () => {\n const clearedId = elementIdRef.current;\n if (clearedId === null) return;\n queueMicrotask(() => {\n if (disposed || elementIdRef.current !== clearedId) return;\n if (viewport.store.getById(clearedId)?.type === 'html') {\n // Survived the clear (the sync client re-adds transient elements after a remote\n // clear): restore the container as that element's content instead of adding a second.\n viewport.updateHtmlElement(clearedId, container);\n } else {\n elementIdRef.current = register();\n }\n viewport.requestRender();\n });\n };\n // `clear` covers a clear-canvas gesture and a remote clear. A wholesale state replacement\n // (`loadState`/`loadJSON`) runs inside `suspendNotifications`, so the store coalesces its\n // events into a single `batch` instead: the same recovery applies.\n const unsubscribeClear = viewport.store.on('clear', handleStoreReplacement);\n const unsubscribeBatch = viewport.store.on('batch', handleStoreReplacement);\n\n return () => {\n disposed = true;\n unsubscribeClear();\n unsubscribeBatch();\n if (elementIdRef.current) {\n viewport.store.remove(elementIdRef.current, { origin: HOST_ORIGIN });\n viewport.requestRender();\n elementIdRef.current = null;\n }\n // Removing the element usually detaches the container, but when no render pass ran between\n // this effect and its cleanup (StrictMode's double invocation) the node is still parented\n // in the DOM layer as an empty div.\n if (container.parentNode === viewport.domLayer) container.remove();\n setPortalTarget(null);\n };\n }, [viewport]);\n\n useEffect(() => {\n geometryRef.current = { position, size };\n const id = elementIdRef.current;\n if (!id) return;\n viewport.store.update(id, { position, ...(size ? { size } : {}) }, { origin: HOST_ORIGIN });\n viewport.requestRender();\n // Primitive deps (position.x/y, size?.w/h) are intentional: the effect re-runs on VALUE change,\n // not object identity — so inline { x, y } literals and memoized-but-unchanged objects both behave\n // correctly (no over-firing on every parent re-render).\n }, [viewport, position.x, position.y, size?.w, size?.h]);\n\n if (!portalTarget) return null;\n return createPortal(children, portalTarget);\n}\n","import { useContext } from 'react';\nimport type { Viewport } from '@fieldnotes/core';\nimport { ViewportContext } from '../context';\n\n/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */\nexport function useViewport(): Viewport {\n const viewport = useContext(ViewportContext);\n if (!viewport) {\n throw new Error('useViewport must be used inside <FieldNotesCanvas>');\n }\n return viewport;\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\n/** `[activeToolName, setTool]` — re-renders on tool switches. */\nexport function useActiveTool(): [toolName: string, setTool: (name: string) => void] {\n const viewport = useViewport();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.toolManager.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback(() => viewport.toolManager.activeTool?.name ?? '', [viewport]);\n\n const toolName = useSyncExternalStore(subscribe, getSnapshot);\n\n const setTool = useCallback((name: string) => viewport.setTool(name), [viewport]);\n\n return [toolName, setTool];\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\nexport interface CameraState {\n x: number;\n y: number;\n zoom: number;\n}\n\n/** Current camera position and zoom level — re-renders whenever the camera moves or zoom changes. */\nexport function useCamera(): CameraState {\n const viewport = useViewport();\n const cachedRef = useRef<CameraState>({ x: 0, y: 0, zoom: 1 });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.camera.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): CameraState => {\n const { position, zoom } = viewport.camera;\n const cached = cachedRef.current;\n if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {\n return cached;\n }\n const next = { x: position.x, y: position.y, zoom };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\nfunction noop() {\n /* unsubscribe placeholder */\n}\n\n/**\n * `[options, setOptions]` for the named tool — re-renders when the tool's options change.\n * Returns `null` for options if the tool is not registered or does not expose options.\n */\nexport function useToolOptions<T extends Record<string, unknown>>(\n toolName: string,\n): [options: T | null, setOptions: (partial: Partial<T>) => void] {\n const viewport = useViewport();\n const cachedRef = useRef<T | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n const tool = viewport.toolManager.getTool(toolName);\n if (!tool?.onOptionsChange) return noop;\n return tool.onOptionsChange(onStoreChange);\n },\n [viewport, toolName],\n );\n\n const getSnapshot = useCallback((): T | null => {\n const tool = viewport.toolManager.getTool(toolName);\n if (!tool?.getOptions) return null;\n const next = tool.getOptions() as T;\n const cached = cachedRef.current;\n if (cached && shallowEqual(cached, next)) return cached;\n cachedRef.current = next;\n return next;\n }, [viewport, toolName]);\n\n const options = useSyncExternalStore(subscribe, getSnapshot);\n\n const setOptions = useCallback(\n (partial: Partial<T>) => {\n const tool = viewport.toolManager.getTool(toolName);\n tool?.setOptions?.(partial as Record<string, unknown>);\n },\n [viewport, toolName],\n );\n\n return [options, setOptions];\n}\n\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n const valA = a[key];\n const valB = b[key];\n if (valA === valB) continue;\n if (\n typeof valA === 'object' &&\n valA !== null &&\n typeof valB === 'object' &&\n valB !== null &&\n !Array.isArray(valA) &&\n !Array.isArray(valB)\n ) {\n const objA = valA as Record<string, unknown>;\n const objB = valB as Record<string, unknown>;\n const innerKeys = Object.keys(objA);\n if (\n innerKeys.length === Object.keys(objB).length &&\n innerKeys.every((k) => objA[k] === objB[k])\n ) {\n continue;\n }\n }\n return false;\n }\n return true;\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { Layer } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\ninterface LayersSnapshot {\n layers: Layer[];\n activeLayerId: string;\n}\n\nexport interface UseLayersResult {\n layers: Layer[];\n activeLayerId: string;\n createLayer: (name?: string) => Layer;\n removeLayer: (id: string) => void;\n renameLayer: (id: string, name: string) => void;\n reorderLayer: (id: string, newOrder: number) => void;\n setVisible: (id: string, visible: boolean) => void;\n setLocked: (id: string, locked: boolean) => void;\n setOpacity: (id: string, opacity: number) => void;\n setActiveLayer: (id: string) => void;\n moveElement: (elementId: string, layerId: string) => void;\n}\n\n/**\n * Current layer list and mutation helpers — re-renders whenever a layer is added, removed,\n * reordered, renamed, or its visibility/lock/opacity/active state changes.\n */\nexport function useLayers(): UseLayersResult {\n const viewport = useViewport();\n const cachedRef = useRef<LayersSnapshot>({ layers: [], activeLayerId: '' });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.layerManager.on('change', onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): LayersSnapshot => {\n const layers = viewport.layerManager.getLayers();\n const activeLayerId = viewport.layerManager.activeLayerId;\n const cached = cachedRef.current;\n if (\n cached.activeLayerId === activeLayerId &&\n cached.layers.length === layers.length &&\n cached.layers.every((l, i) => {\n const next = layers[i];\n return (\n next !== undefined &&\n l.id === next.id &&\n l.name === next.name &&\n l.visible === next.visible &&\n l.locked === next.locked &&\n l.order === next.order &&\n l.opacity === next.opacity\n );\n })\n ) {\n return cached;\n }\n const next = { layers, activeLayerId };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\n\n const createLayer = useCallback(\n (name?: string) => viewport.layerManager.createLayer(name),\n [viewport],\n );\n\n const removeLayer = useCallback(\n (id: string) => viewport.layerManager.removeLayer(id),\n [viewport],\n );\n\n const renameLayer = useCallback(\n (id: string, name: string) => viewport.layerManager.renameLayer(id, name),\n [viewport],\n );\n\n const reorderLayer = useCallback(\n (id: string, newOrder: number) => viewport.layerManager.reorderLayer(id, newOrder),\n [viewport],\n );\n\n const setVisible = useCallback(\n (id: string, visible: boolean) => viewport.layerManager.setLayerVisible(id, visible),\n [viewport],\n );\n\n const setLocked = useCallback(\n (id: string, locked: boolean) => viewport.layerManager.setLayerLocked(id, locked),\n [viewport],\n );\n\n const setOpacity = useCallback(\n (id: string, opacity: number) => viewport.layerManager.setLayerOpacity(id, opacity),\n [viewport],\n );\n\n const setActiveLayer = useCallback(\n (id: string) => viewport.layerManager.setActiveLayer(id),\n [viewport],\n );\n\n const moveElement = useCallback(\n (elementId: string, layerId: string) =>\n viewport.layerManager.moveElementToLayer(elementId, layerId),\n [viewport],\n );\n\n return {\n layers: snapshot.layers,\n activeLayerId: snapshot.activeLayerId,\n createLayer,\n removeLayer,\n renameLayer,\n reorderLayer,\n setVisible,\n setLocked,\n setOpacity,\n setActiveLayer,\n moveElement,\n };\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\ninterface HistorySnapshot {\n canUndo: boolean;\n canRedo: boolean;\n}\n\nexport interface UseHistoryResult {\n canUndo: boolean;\n canRedo: boolean;\n undo: () => void;\n redo: () => void;\n}\n\n/** `{ canUndo, canRedo, undo, redo }` — re-renders when undo/redo availability changes. */\nexport function useHistory(): UseHistoryResult {\n const viewport = useViewport();\n const cachedRef = useRef<HistorySnapshot>({ canUndo: false, canRedo: false });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.history.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): HistorySnapshot => {\n const canUndo = viewport.history.canUndo;\n const canRedo = viewport.history.canRedo;\n const cached = cachedRef.current;\n if (cached.canUndo === canUndo && cached.canRedo === canRedo) {\n return cached;\n }\n const next = { canUndo, canRedo };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\n\n const undo = useCallback(() => viewport.undo(), [viewport]);\n const redo = useCallback(() => viewport.redo(), [viewport]);\n\n return {\n canUndo: snapshot.canUndo,\n canRedo: snapshot.canRedo,\n undo,\n redo,\n };\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { CanvasElement, ElementType } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));\n }\n if (\n typeof a === 'object' &&\n a !== null &&\n typeof b === 'object' &&\n b !== null &&\n !Array.isArray(a) &&\n !Array.isArray(b)\n ) {\n const ka = Object.keys(a);\n const kb = Object.keys(b);\n return (\n ka.length === kb.length &&\n ka.every(\n (k) =>\n k in (b as Record<string, unknown>) &&\n Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\n )\n );\n }\n return false;\n}\n\n/** All elements; re-renders on every store mutation (use a selector for hot paths). */\nexport function useElements(): CanvasElement[];\n/** Elements of one type; re-renders on every store mutation. */\nexport function useElements<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[];\n/**\n * Derived value; re-renders only when the selected value changes (per `isEqual`,\n * default: one-level shallow compare — arrays by index, plain objects by key, primitives by\n * Object.is). Keep the selector referentially stable (useCallback or module scope).\n *\n * Supply `isEqual` for deeper structures. Note: selectors returning nested fresh objects\n * (e.g. `els => els.map(e => ({ ...e.position }))`) still need a custom comparator because\n * the default only compares one level deep.\n */\nexport function useElements<R>(\n selector: (elements: CanvasElement[]) => R,\n isEqual?: (a: R, b: R) => boolean,\n): R;\nexport function useElements<R>(\n arg?: ElementType | ((elements: CanvasElement[]) => R),\n isEqual?: (a: R, b: R) => boolean,\n): CanvasElement[] | R {\n const viewport = useViewport();\n const cachedRef = useRef<CanvasElement[]>([]);\n const selectedRef = useRef<{ value: R } | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.store.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): CanvasElement[] | R => {\n if (typeof arg === 'function') {\n const next = arg(viewport.store.getAll());\n const prev = selectedRef.current;\n const equal: (a: R, b: R) => boolean = isEqual ?? (shallowEqual as (a: R, b: R) => boolean);\n if (prev !== null && equal(prev.value, next)) {\n return prev.value;\n }\n selectedRef.current = { value: next };\n return next;\n }\n\n const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();\n const cached = cachedRef.current;\n if (cached.length === next.length && cached.every((el, i) => el === next[i])) {\n return cached;\n }\n cachedRef.current = next;\n return next;\n }, [viewport, arg, isEqual]);\n\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\n/** Reactive selected element ids. Stable array reference — only changes when the selection changes. */\nexport function useSelection(): string[] {\n const viewport = useViewport();\n\n const subscribe = useCallback(\n (onChange: () => void) => viewport.onSelectionChange(onChange),\n [viewport],\n );\n\n const getSnapshot = useCallback(() => viewport.getSelectedIds(), [viewport]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { ElementStyle } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\nimport { STYLE_KEYS } from './style-keys';\n\nfunction styleEqual(a: ElementStyle | null, b: ElementStyle | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return STYLE_KEYS.every((k) => a[k] === b[k]);\n}\n\n/**\n * Reactive normalized style of the current selection.\n * Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.\n * `applyPatch` applies an `ElementStyle` patch to every selected element.\n */\nexport function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void] {\n const viewport = useViewport();\n const cacheRef = useRef<ElementStyle | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback(() => {\n const next = viewport.getSelectionStyle();\n if (styleEqual(cacheRef.current, next)) return cacheRef.current;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const style = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\n\n return [style, apply];\n}\n","import type { ElementStyle } from '@fieldnotes/core';\n\n/**\n * The `ElementStyle` fields the selection-style hooks compare and cache.\n * Internal to `@fieldnotes/react` — not exported from the package index.\n * Shared between `useSelectionStyle` and `useSelectionStyleDetails` so the\n * two hooks cannot drift out of sync (a prior desync here dropped\n * `strokeStyle` from one hook's equality check and caused stale style data).\n */\nexport const STYLE_KEYS: readonly (keyof ElementStyle)[] = [\n 'color',\n 'fillColor',\n 'strokeWidth',\n 'opacity',\n 'fontSize',\n 'strokeStyle',\n];\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\nimport { STYLE_KEYS } from './style-keys';\n\nfunction keysEqual(\n a: readonly (keyof ElementStyle)[],\n b: readonly (keyof ElementStyle)[],\n): boolean {\n return a.length === b.length && a.every((k, i) => k === b[i]);\n}\n\nfunction detailsEqual(a: SelectionStyleDetails | null, b: SelectionStyleDetails | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return (\n keysEqual(a.applicable, b.applicable) &&\n keysEqual(a.mixed, b.mixed) &&\n STYLE_KEYS.every((k) => a.common[k] === b.common[k])\n );\n}\n\n/**\n * Reactive style details of the current selection: per-field applicability and\n * mixed-state, plus the common style. `null` when nothing valid is selected.\n * The apply function delegates to `applyStyleToSelection` (one undo step).\n */\nexport function useSelectionStyleDetails(): [\n SelectionStyleDetails | null,\n (style: ElementStyle) => void,\n] {\n const viewport = useViewport();\n const cacheRef = useRef<SelectionStyleDetails | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback(() => {\n const next = viewport.getSelectionStyleDetails();\n if (detailsEqual(cacheRef.current, next)) return cacheRef.current;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const details = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\n\n return [details, apply];\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nexport interface UseSelectionOpsResult {\n selectedIds: string[];\n selectedCount: number;\n canGroup: boolean;\n canUngroup: boolean;\n canAlign: boolean;\n canDistribute: boolean;\n isLocked: boolean | null;\n group: () => void;\n ungroup: () => void;\n toggleLock: () => void;\n align: (edge: AlignEdge) => void;\n distribute: (axis: DistributeAxis) => void;\n rotateCW: () => void;\n rotateCCW: () => void;\n}\n\ninterface Snapshot {\n selectedIds: string[];\n canGroup: boolean;\n canUngroup: boolean;\n canAlign: boolean;\n canDistribute: boolean;\n isLocked: boolean | null;\n}\n\nfunction snapshotEqual(a: Snapshot, b: Snapshot): boolean {\n return (\n a.selectedIds === b.selectedIds &&\n a.canGroup === b.canGroup &&\n a.canUngroup === b.canUngroup &&\n a.canAlign === b.canAlign &&\n a.canDistribute === b.canDistribute &&\n a.isLocked === b.isLocked\n );\n}\n\n/**\n * Reactive selection operations + derived predicates for the current selection.\n * Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;\n * `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,\n * and `null` when empty or mixed. Actions delegate to the core Viewport.\n */\nexport function useSelectionOps(): UseSelectionOpsResult {\n const viewport = useViewport();\n const cacheRef = useRef<Snapshot | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback((): Snapshot => {\n const ids = viewport.getSelectedIds();\n const n = ids.length;\n let canUngroup = false;\n let lockedCount = 0;\n for (const id of ids) {\n const el = viewport.store.getById(id);\n if (!el) continue;\n if (el.groupId !== undefined) canUngroup = true;\n if (el.locked) lockedCount++;\n }\n const isLocked: boolean | null =\n n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;\n const next: Snapshot = {\n selectedIds: ids,\n canGroup: n >= 2,\n canUngroup,\n canAlign: n >= 2,\n canDistribute: n >= 3,\n isLocked,\n };\n const prev = cacheRef.current;\n if (prev && snapshotEqual(prev, next)) return prev;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const group = useCallback(() => viewport.groupSelection(), [viewport]);\n const ungroup = useCallback(() => viewport.ungroupSelection(), [viewport]);\n const toggleLock = useCallback(() => viewport.toggleLockSelection(), [viewport]);\n const align = useCallback((edge: AlignEdge) => viewport.alignSelection(edge), [viewport]);\n const distribute = useCallback(\n (axis: DistributeAxis) => viewport.distributeSelection(axis),\n [viewport],\n );\n const rotateCW = useCallback(() => viewport.rotateSelection('cw'), [viewport]);\n const rotateCCW = useCallback(() => viewport.rotateSelection('ccw'), [viewport]);\n\n return {\n selectedIds: snap.selectedIds,\n selectedCount: snap.selectedIds.length,\n canGroup: snap.canGroup,\n canUngroup: snap.canUngroup,\n canAlign: snap.canAlign,\n canDistribute: snap.canDistribute,\n isLocked: snap.isLocked,\n group,\n ungroup,\n toggleLock,\n align,\n distribute,\n rotateCW,\n rotateCCW,\n };\n}\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';\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_react","import_core","rects","import_react","import_core","import_jsx_runtime"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -54,6 +54,8 @@ interface CanvasElementProps {
|
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Renders a React subtree as an HTML element embedded in the canvas coordinate space.
|
|
57
|
+
* The element is host-owned and transient: it is driven entirely by props, never appears
|
|
58
|
+
* in exported state, and never records an undo step.
|
|
57
59
|
* Must be used inside a `<FieldNotesCanvas>`.
|
|
58
60
|
*/
|
|
59
61
|
declare function CanvasElement({ position, size, children }: CanvasElementProps): react.ReactPortal | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ interface CanvasElementProps {
|
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Renders a React subtree as an HTML element embedded in the canvas coordinate space.
|
|
57
|
+
* The element is host-owned and transient: it is driven entirely by props, never appears
|
|
58
|
+
* in exported state, and never records an undo step.
|
|
57
59
|
* Must be used inside a `<FieldNotesCanvas>`.
|
|
58
60
|
*/
|
|
59
61
|
declare function CanvasElement({ position, size, children }: CanvasElementProps): react.ReactPortal | null;
|
package/dist/index.js
CHANGED
|
@@ -91,36 +91,62 @@ function useViewport() {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// src/canvas-element.tsx
|
|
94
|
+
var HOST_ORIGIN = "host";
|
|
94
95
|
function CanvasElement({ position, size, children }) {
|
|
95
96
|
const viewport = useViewport();
|
|
96
97
|
const [portalTarget, setPortalTarget] = useState2(null);
|
|
97
98
|
const elementIdRef = useRef2(null);
|
|
99
|
+
const geometryRef = useRef2({ position, size });
|
|
98
100
|
useEffect2(() => {
|
|
99
101
|
const container = document.createElement("div");
|
|
100
102
|
Object.assign(container.style, {
|
|
101
103
|
width: "100%",
|
|
102
104
|
height: "100%"
|
|
103
105
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
const register = () => {
|
|
107
|
+
viewport.domLayer.appendChild(container);
|
|
108
|
+
const { position: current, size: currentSize } = geometryRef.current;
|
|
109
|
+
return viewport.addHtmlElement(container, current, currentSize, {
|
|
110
|
+
transient: true,
|
|
111
|
+
origin: HOST_ORIGIN
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
elementIdRef.current = register();
|
|
107
115
|
setPortalTarget(container);
|
|
116
|
+
let disposed = false;
|
|
117
|
+
const handleStoreReplacement = () => {
|
|
118
|
+
const clearedId = elementIdRef.current;
|
|
119
|
+
if (clearedId === null) return;
|
|
120
|
+
queueMicrotask(() => {
|
|
121
|
+
if (disposed || elementIdRef.current !== clearedId) return;
|
|
122
|
+
if (viewport.store.getById(clearedId)?.type === "html") {
|
|
123
|
+
viewport.updateHtmlElement(clearedId, container);
|
|
124
|
+
} else {
|
|
125
|
+
elementIdRef.current = register();
|
|
126
|
+
}
|
|
127
|
+
viewport.requestRender();
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const unsubscribeClear = viewport.store.on("clear", handleStoreReplacement);
|
|
131
|
+
const unsubscribeBatch = viewport.store.on("batch", handleStoreReplacement);
|
|
108
132
|
return () => {
|
|
133
|
+
disposed = true;
|
|
134
|
+
unsubscribeClear();
|
|
135
|
+
unsubscribeBatch();
|
|
109
136
|
if (elementIdRef.current) {
|
|
110
|
-
viewport.store.remove(elementIdRef.current);
|
|
137
|
+
viewport.store.remove(elementIdRef.current, { origin: HOST_ORIGIN });
|
|
111
138
|
viewport.requestRender();
|
|
112
139
|
elementIdRef.current = null;
|
|
113
140
|
}
|
|
141
|
+
if (container.parentNode === viewport.domLayer) container.remove();
|
|
114
142
|
setPortalTarget(null);
|
|
115
143
|
};
|
|
116
144
|
}, [viewport]);
|
|
117
145
|
useEffect2(() => {
|
|
146
|
+
geometryRef.current = { position, size };
|
|
118
147
|
const id = elementIdRef.current;
|
|
119
148
|
if (!id) return;
|
|
120
|
-
viewport.store.update(id, { position });
|
|
121
|
-
if (size) {
|
|
122
|
-
viewport.store.update(id, { size });
|
|
123
|
-
}
|
|
149
|
+
viewport.store.update(id, { position, ...size ? { size } : {} }, { origin: HOST_ORIGIN });
|
|
124
150
|
viewport.requestRender();
|
|
125
151
|
}, [viewport, position.x, position.y, size?.w, size?.h]);
|
|
126
152
|
if (!portalTarget) return null;
|
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/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 {\n useRef,\n useEffect,\n useState,\n forwardRef,\n useImperativeHandle,\n type ReactNode,\n type CSSProperties,\n} from 'react';\nimport { Viewport } from '@fieldnotes/core';\nimport type { ViewportOptions, Tool } from '@fieldnotes/core';\nimport { ViewportContext } from './context';\n\nexport interface FieldNotesCanvasProps {\n /** Constructor-only: changes after mount are ignored (the canvas is stateful). */\n options?: ViewportOptions;\n /**\n * Reactive (append-only): tools present here are registered; removal is not supported.\n * Hoist the array out of render — inline arrays reconstruct Tool instances and re-run\n * registration on every render.\n */\n tools?: Tool[];\n /** Uncontrolled initial tool. Ignored when `tool` is set. */\n defaultTool?: string;\n /** Controlled active tool. Pair with `onToolChange`. */\n tool?: string;\n /**\n * Fires whenever the active tool changes (keyboard, API, or `tool` prop).\n * Memoize with useCallback to avoid re-subscribing each render.\n */\n onToolChange?: (name: string) => void;\n /**\n * Reactive compatibility toggle for the core snap flag.\n * @deprecated Grid snapping is domain behavior. Configure it through the\n * VTT grid/constraint service instead.\n */\n snapToGrid?: boolean;\n className?: string;\n style?: CSSProperties;\n children?: ReactNode;\n onReady?: (viewport: Viewport) => void;\n}\n\nexport interface FieldNotesCanvasRef {\n viewport: Viewport | null;\n}\n\nexport const FieldNotesCanvas = forwardRef<FieldNotesCanvasRef, FieldNotesCanvasProps>(\n function FieldNotesCanvas(\n {\n options,\n tools,\n defaultTool,\n tool,\n onToolChange,\n snapToGrid,\n className,\n style,\n children,\n onReady,\n },\n ref,\n ) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [viewport, setViewport] = useState<Viewport | null>(null);\n\n useImperativeHandle(ref, () => ({ viewport }), [viewport]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const vp = new Viewport(el, options);\n\n if (tools) {\n for (const t of tools) {\n vp.toolManager.register(t);\n }\n }\n\n const initialTool = tool ?? defaultTool;\n if (initialTool) {\n vp.setTool(initialTool);\n }\n\n setViewport(vp);\n onReady?.(vp);\n\n return () => {\n vp.destroy();\n setViewport(null);\n };\n // Constructor effect: options/tools/defaultTool are mount-only by design.\n }, []);\n\n useEffect(() => {\n if (!viewport || tool === undefined) return;\n if (viewport.toolManager.activeTool?.name !== tool) {\n viewport.setTool(tool);\n }\n }, [viewport, tool]);\n\n useEffect(() => {\n if (!viewport || !onToolChange) return;\n return viewport.toolManager.onChange(onToolChange);\n }, [viewport, onToolChange]);\n\n useEffect(() => {\n if (!viewport || snapToGrid === undefined) return;\n viewport.setSnapToGrid(snapToGrid);\n }, [viewport, snapToGrid]);\n\n useEffect(() => {\n if (!viewport || !tools) return;\n for (const t of tools) {\n if (!viewport.toolManager.getTool(t.name)) {\n viewport.toolManager.register(t);\n }\n }\n }, [viewport, tools]);\n\n return (\n <div ref={containerRef} className={className} style={style}>\n {viewport && (\n <ViewportContext.Provider value={viewport}>{children}</ViewportContext.Provider>\n )}\n </div>\n );\n },\n);\n","import { createContext } from 'react';\nimport type { Viewport } from '@fieldnotes/core';\n\nexport const ViewportContext = createContext<Viewport | null>(null);\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useViewport } from './hooks/use-viewport';\n\n/** Props for {@link CanvasElement}. */\nexport interface CanvasElementProps {\n /** Canvas-space position of the element's top-left corner. */\n position: { x: number; y: number };\n /** Optional fixed size; omit to let the element size to its content. */\n size?: { w: number; h: number };\n children: ReactNode;\n}\n\n/**\n * Renders a React subtree as an HTML element embedded in the canvas coordinate space.\n * Must be used inside a `<FieldNotesCanvas>`.\n */\nexport function CanvasElement({ position, size, children }: CanvasElementProps) {\n const viewport = useViewport();\n const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\n const elementIdRef = useRef<string | null>(null);\n\n useEffect(() => {\n const container = document.createElement('div');\n Object.assign(container.style, {\n width: '100%',\n height: '100%',\n });\n\n // Append to domLayer immediately so portal children are queryable in the document\n // before the viewport render loop fires via requestAnimationFrame.\n viewport.domLayer.appendChild(container);\n\n const id = viewport.addHtmlElement(container, position, size);\n elementIdRef.current = id;\n setPortalTarget(container);\n\n return () => {\n if (elementIdRef.current) {\n viewport.store.remove(elementIdRef.current);\n viewport.requestRender();\n elementIdRef.current = null;\n }\n setPortalTarget(null);\n };\n }, [viewport]);\n\n useEffect(() => {\n const id = elementIdRef.current;\n if (!id) return;\n viewport.store.update(id, { position });\n if (size) {\n viewport.store.update(id, { size });\n }\n viewport.requestRender();\n // Primitive deps (position.x/y, size?.w/h) are intentional: the effect re-runs on VALUE change,\n // not object identity — so inline { x, y } literals and memoized-but-unchanged objects both behave\n // correctly (no over-firing on every parent re-render).\n }, [viewport, position.x, position.y, size?.w, size?.h]);\n\n if (!portalTarget) return null;\n return createPortal(children, portalTarget);\n}\n","import { useContext } from 'react';\nimport type { Viewport } from '@fieldnotes/core';\nimport { ViewportContext } from '../context';\n\n/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */\nexport function useViewport(): Viewport {\n const viewport = useContext(ViewportContext);\n if (!viewport) {\n throw new Error('useViewport must be used inside <FieldNotesCanvas>');\n }\n return viewport;\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\n/** `[activeToolName, setTool]` — re-renders on tool switches. */\nexport function useActiveTool(): [toolName: string, setTool: (name: string) => void] {\n const viewport = useViewport();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.toolManager.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback(() => viewport.toolManager.activeTool?.name ?? '', [viewport]);\n\n const toolName = useSyncExternalStore(subscribe, getSnapshot);\n\n const setTool = useCallback((name: string) => viewport.setTool(name), [viewport]);\n\n return [toolName, setTool];\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\nexport interface CameraState {\n x: number;\n y: number;\n zoom: number;\n}\n\n/** Current camera position and zoom level — re-renders whenever the camera moves or zoom changes. */\nexport function useCamera(): CameraState {\n const viewport = useViewport();\n const cachedRef = useRef<CameraState>({ x: 0, y: 0, zoom: 1 });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.camera.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): CameraState => {\n const { position, zoom } = viewport.camera;\n const cached = cachedRef.current;\n if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {\n return cached;\n }\n const next = { x: position.x, y: position.y, zoom };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\nfunction noop() {\n /* unsubscribe placeholder */\n}\n\n/**\n * `[options, setOptions]` for the named tool — re-renders when the tool's options change.\n * Returns `null` for options if the tool is not registered or does not expose options.\n */\nexport function useToolOptions<T extends Record<string, unknown>>(\n toolName: string,\n): [options: T | null, setOptions: (partial: Partial<T>) => void] {\n const viewport = useViewport();\n const cachedRef = useRef<T | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n const tool = viewport.toolManager.getTool(toolName);\n if (!tool?.onOptionsChange) return noop;\n return tool.onOptionsChange(onStoreChange);\n },\n [viewport, toolName],\n );\n\n const getSnapshot = useCallback((): T | null => {\n const tool = viewport.toolManager.getTool(toolName);\n if (!tool?.getOptions) return null;\n const next = tool.getOptions() as T;\n const cached = cachedRef.current;\n if (cached && shallowEqual(cached, next)) return cached;\n cachedRef.current = next;\n return next;\n }, [viewport, toolName]);\n\n const options = useSyncExternalStore(subscribe, getSnapshot);\n\n const setOptions = useCallback(\n (partial: Partial<T>) => {\n const tool = viewport.toolManager.getTool(toolName);\n tool?.setOptions?.(partial as Record<string, unknown>);\n },\n [viewport, toolName],\n );\n\n return [options, setOptions];\n}\n\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n const valA = a[key];\n const valB = b[key];\n if (valA === valB) continue;\n if (\n typeof valA === 'object' &&\n valA !== null &&\n typeof valB === 'object' &&\n valB !== null &&\n !Array.isArray(valA) &&\n !Array.isArray(valB)\n ) {\n const objA = valA as Record<string, unknown>;\n const objB = valB as Record<string, unknown>;\n const innerKeys = Object.keys(objA);\n if (\n innerKeys.length === Object.keys(objB).length &&\n innerKeys.every((k) => objA[k] === objB[k])\n ) {\n continue;\n }\n }\n return false;\n }\n return true;\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { Layer } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\ninterface LayersSnapshot {\n layers: Layer[];\n activeLayerId: string;\n}\n\nexport interface UseLayersResult {\n layers: Layer[];\n activeLayerId: string;\n createLayer: (name?: string) => Layer;\n removeLayer: (id: string) => void;\n renameLayer: (id: string, name: string) => void;\n reorderLayer: (id: string, newOrder: number) => void;\n setVisible: (id: string, visible: boolean) => void;\n setLocked: (id: string, locked: boolean) => void;\n setOpacity: (id: string, opacity: number) => void;\n setActiveLayer: (id: string) => void;\n moveElement: (elementId: string, layerId: string) => void;\n}\n\n/**\n * Current layer list and mutation helpers — re-renders whenever a layer is added, removed,\n * reordered, renamed, or its visibility/lock/opacity/active state changes.\n */\nexport function useLayers(): UseLayersResult {\n const viewport = useViewport();\n const cachedRef = useRef<LayersSnapshot>({ layers: [], activeLayerId: '' });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.layerManager.on('change', onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): LayersSnapshot => {\n const layers = viewport.layerManager.getLayers();\n const activeLayerId = viewport.layerManager.activeLayerId;\n const cached = cachedRef.current;\n if (\n cached.activeLayerId === activeLayerId &&\n cached.layers.length === layers.length &&\n cached.layers.every((l, i) => {\n const next = layers[i];\n return (\n next !== undefined &&\n l.id === next.id &&\n l.name === next.name &&\n l.visible === next.visible &&\n l.locked === next.locked &&\n l.order === next.order &&\n l.opacity === next.opacity\n );\n })\n ) {\n return cached;\n }\n const next = { layers, activeLayerId };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\n\n const createLayer = useCallback(\n (name?: string) => viewport.layerManager.createLayer(name),\n [viewport],\n );\n\n const removeLayer = useCallback(\n (id: string) => viewport.layerManager.removeLayer(id),\n [viewport],\n );\n\n const renameLayer = useCallback(\n (id: string, name: string) => viewport.layerManager.renameLayer(id, name),\n [viewport],\n );\n\n const reorderLayer = useCallback(\n (id: string, newOrder: number) => viewport.layerManager.reorderLayer(id, newOrder),\n [viewport],\n );\n\n const setVisible = useCallback(\n (id: string, visible: boolean) => viewport.layerManager.setLayerVisible(id, visible),\n [viewport],\n );\n\n const setLocked = useCallback(\n (id: string, locked: boolean) => viewport.layerManager.setLayerLocked(id, locked),\n [viewport],\n );\n\n const setOpacity = useCallback(\n (id: string, opacity: number) => viewport.layerManager.setLayerOpacity(id, opacity),\n [viewport],\n );\n\n const setActiveLayer = useCallback(\n (id: string) => viewport.layerManager.setActiveLayer(id),\n [viewport],\n );\n\n const moveElement = useCallback(\n (elementId: string, layerId: string) =>\n viewport.layerManager.moveElementToLayer(elementId, layerId),\n [viewport],\n );\n\n return {\n layers: snapshot.layers,\n activeLayerId: snapshot.activeLayerId,\n createLayer,\n removeLayer,\n renameLayer,\n reorderLayer,\n setVisible,\n setLocked,\n setOpacity,\n setActiveLayer,\n moveElement,\n };\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\ninterface HistorySnapshot {\n canUndo: boolean;\n canRedo: boolean;\n}\n\nexport interface UseHistoryResult {\n canUndo: boolean;\n canRedo: boolean;\n undo: () => void;\n redo: () => void;\n}\n\n/** `{ canUndo, canRedo, undo, redo }` — re-renders when undo/redo availability changes. */\nexport function useHistory(): UseHistoryResult {\n const viewport = useViewport();\n const cachedRef = useRef<HistorySnapshot>({ canUndo: false, canRedo: false });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.history.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): HistorySnapshot => {\n const canUndo = viewport.history.canUndo;\n const canRedo = viewport.history.canRedo;\n const cached = cachedRef.current;\n if (cached.canUndo === canUndo && cached.canRedo === canRedo) {\n return cached;\n }\n const next = { canUndo, canRedo };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\n\n const undo = useCallback(() => viewport.undo(), [viewport]);\n const redo = useCallback(() => viewport.redo(), [viewport]);\n\n return {\n canUndo: snapshot.canUndo,\n canRedo: snapshot.canRedo,\n undo,\n redo,\n };\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { CanvasElement, ElementType } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));\n }\n if (\n typeof a === 'object' &&\n a !== null &&\n typeof b === 'object' &&\n b !== null &&\n !Array.isArray(a) &&\n !Array.isArray(b)\n ) {\n const ka = Object.keys(a);\n const kb = Object.keys(b);\n return (\n ka.length === kb.length &&\n ka.every(\n (k) =>\n k in (b as Record<string, unknown>) &&\n Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\n )\n );\n }\n return false;\n}\n\n/** All elements; re-renders on every store mutation (use a selector for hot paths). */\nexport function useElements(): CanvasElement[];\n/** Elements of one type; re-renders on every store mutation. */\nexport function useElements<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[];\n/**\n * Derived value; re-renders only when the selected value changes (per `isEqual`,\n * default: one-level shallow compare — arrays by index, plain objects by key, primitives by\n * Object.is). Keep the selector referentially stable (useCallback or module scope).\n *\n * Supply `isEqual` for deeper structures. Note: selectors returning nested fresh objects\n * (e.g. `els => els.map(e => ({ ...e.position }))`) still need a custom comparator because\n * the default only compares one level deep.\n */\nexport function useElements<R>(\n selector: (elements: CanvasElement[]) => R,\n isEqual?: (a: R, b: R) => boolean,\n): R;\nexport function useElements<R>(\n arg?: ElementType | ((elements: CanvasElement[]) => R),\n isEqual?: (a: R, b: R) => boolean,\n): CanvasElement[] | R {\n const viewport = useViewport();\n const cachedRef = useRef<CanvasElement[]>([]);\n const selectedRef = useRef<{ value: R } | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.store.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): CanvasElement[] | R => {\n if (typeof arg === 'function') {\n const next = arg(viewport.store.getAll());\n const prev = selectedRef.current;\n const equal: (a: R, b: R) => boolean = isEqual ?? (shallowEqual as (a: R, b: R) => boolean);\n if (prev !== null && equal(prev.value, next)) {\n return prev.value;\n }\n selectedRef.current = { value: next };\n return next;\n }\n\n const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();\n const cached = cachedRef.current;\n if (cached.length === next.length && cached.every((el, i) => el === next[i])) {\n return cached;\n }\n cachedRef.current = next;\n return next;\n }, [viewport, arg, isEqual]);\n\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\n/** Reactive selected element ids. Stable array reference — only changes when the selection changes. */\nexport function useSelection(): string[] {\n const viewport = useViewport();\n\n const subscribe = useCallback(\n (onChange: () => void) => viewport.onSelectionChange(onChange),\n [viewport],\n );\n\n const getSnapshot = useCallback(() => viewport.getSelectedIds(), [viewport]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { ElementStyle } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\nimport { STYLE_KEYS } from './style-keys';\n\nfunction styleEqual(a: ElementStyle | null, b: ElementStyle | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return STYLE_KEYS.every((k) => a[k] === b[k]);\n}\n\n/**\n * Reactive normalized style of the current selection.\n * Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.\n * `applyPatch` applies an `ElementStyle` patch to every selected element.\n */\nexport function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void] {\n const viewport = useViewport();\n const cacheRef = useRef<ElementStyle | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback(() => {\n const next = viewport.getSelectionStyle();\n if (styleEqual(cacheRef.current, next)) return cacheRef.current;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const style = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\n\n return [style, apply];\n}\n","import type { ElementStyle } from '@fieldnotes/core';\n\n/**\n * The `ElementStyle` fields the selection-style hooks compare and cache.\n * Internal to `@fieldnotes/react` — not exported from the package index.\n * Shared between `useSelectionStyle` and `useSelectionStyleDetails` so the\n * two hooks cannot drift out of sync (a prior desync here dropped\n * `strokeStyle` from one hook's equality check and caused stale style data).\n */\nexport const STYLE_KEYS: readonly (keyof ElementStyle)[] = [\n 'color',\n 'fillColor',\n 'strokeWidth',\n 'opacity',\n 'fontSize',\n 'strokeStyle',\n];\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\nimport { STYLE_KEYS } from './style-keys';\n\nfunction keysEqual(\n a: readonly (keyof ElementStyle)[],\n b: readonly (keyof ElementStyle)[],\n): boolean {\n return a.length === b.length && a.every((k, i) => k === b[i]);\n}\n\nfunction detailsEqual(a: SelectionStyleDetails | null, b: SelectionStyleDetails | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return (\n keysEqual(a.applicable, b.applicable) &&\n keysEqual(a.mixed, b.mixed) &&\n STYLE_KEYS.every((k) => a.common[k] === b.common[k])\n );\n}\n\n/**\n * Reactive style details of the current selection: per-field applicability and\n * mixed-state, plus the common style. `null` when nothing valid is selected.\n * The apply function delegates to `applyStyleToSelection` (one undo step).\n */\nexport function useSelectionStyleDetails(): [\n SelectionStyleDetails | null,\n (style: ElementStyle) => void,\n] {\n const viewport = useViewport();\n const cacheRef = useRef<SelectionStyleDetails | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback(() => {\n const next = viewport.getSelectionStyleDetails();\n if (detailsEqual(cacheRef.current, next)) return cacheRef.current;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const details = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\n\n return [details, apply];\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nexport interface UseSelectionOpsResult {\n selectedIds: string[];\n selectedCount: number;\n canGroup: boolean;\n canUngroup: boolean;\n canAlign: boolean;\n canDistribute: boolean;\n isLocked: boolean | null;\n group: () => void;\n ungroup: () => void;\n toggleLock: () => void;\n align: (edge: AlignEdge) => void;\n distribute: (axis: DistributeAxis) => void;\n rotateCW: () => void;\n rotateCCW: () => void;\n}\n\ninterface Snapshot {\n selectedIds: string[];\n canGroup: boolean;\n canUngroup: boolean;\n canAlign: boolean;\n canDistribute: boolean;\n isLocked: boolean | null;\n}\n\nfunction snapshotEqual(a: Snapshot, b: Snapshot): boolean {\n return (\n a.selectedIds === b.selectedIds &&\n a.canGroup === b.canGroup &&\n a.canUngroup === b.canUngroup &&\n a.canAlign === b.canAlign &&\n a.canDistribute === b.canDistribute &&\n a.isLocked === b.isLocked\n );\n}\n\n/**\n * Reactive selection operations + derived predicates for the current selection.\n * Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;\n * `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,\n * and `null` when empty or mixed. Actions delegate to the core Viewport.\n */\nexport function useSelectionOps(): UseSelectionOpsResult {\n const viewport = useViewport();\n const cacheRef = useRef<Snapshot | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback((): Snapshot => {\n const ids = viewport.getSelectedIds();\n const n = ids.length;\n let canUngroup = false;\n let lockedCount = 0;\n for (const id of ids) {\n const el = viewport.store.getById(id);\n if (!el) continue;\n if (el.groupId !== undefined) canUngroup = true;\n if (el.locked) lockedCount++;\n }\n const isLocked: boolean | null =\n n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;\n const next: Snapshot = {\n selectedIds: ids,\n canGroup: n >= 2,\n canUngroup,\n canAlign: n >= 2,\n canDistribute: n >= 3,\n isLocked,\n };\n const prev = cacheRef.current;\n if (prev && snapshotEqual(prev, next)) return prev;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const group = useCallback(() => viewport.groupSelection(), [viewport]);\n const ungroup = useCallback(() => viewport.ungroupSelection(), [viewport]);\n const toggleLock = useCallback(() => viewport.toggleLockSelection(), [viewport]);\n const align = useCallback((edge: AlignEdge) => viewport.alignSelection(edge), [viewport]);\n const distribute = useCallback(\n (axis: DistributeAxis) => viewport.distributeSelection(axis),\n [viewport],\n );\n const rotateCW = useCallback(() => viewport.rotateSelection('cw'), [viewport]);\n const rotateCCW = useCallback(() => viewport.rotateSelection('ccw'), [viewport]);\n\n return {\n selectedIds: snap.selectedIds,\n selectedCount: snap.selectedIds.length,\n canGroup: snap.canGroup,\n canUngroup: snap.canUngroup,\n canAlign: snap.canAlign,\n canDistribute: snap.canDistribute,\n isLocked: snap.isLocked,\n group,\n ungroup,\n toggleLock,\n align,\n distribute,\n rotateCW,\n rotateCCW,\n };\n}\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';\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","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useCallback","useEffect","useRef","useSyncExternalStore","useRef","useCallback","rects","useSyncExternalStore","useEffect","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 {\n useRef,\n useEffect,\n useState,\n forwardRef,\n useImperativeHandle,\n type ReactNode,\n type CSSProperties,\n} from 'react';\nimport { Viewport } from '@fieldnotes/core';\nimport type { ViewportOptions, Tool } from '@fieldnotes/core';\nimport { ViewportContext } from './context';\n\nexport interface FieldNotesCanvasProps {\n /** Constructor-only: changes after mount are ignored (the canvas is stateful). */\n options?: ViewportOptions;\n /**\n * Reactive (append-only): tools present here are registered; removal is not supported.\n * Hoist the array out of render — inline arrays reconstruct Tool instances and re-run\n * registration on every render.\n */\n tools?: Tool[];\n /** Uncontrolled initial tool. Ignored when `tool` is set. */\n defaultTool?: string;\n /** Controlled active tool. Pair with `onToolChange`. */\n tool?: string;\n /**\n * Fires whenever the active tool changes (keyboard, API, or `tool` prop).\n * Memoize with useCallback to avoid re-subscribing each render.\n */\n onToolChange?: (name: string) => void;\n /**\n * Reactive compatibility toggle for the core snap flag.\n * @deprecated Grid snapping is domain behavior. Configure it through the\n * VTT grid/constraint service instead.\n */\n snapToGrid?: boolean;\n className?: string;\n style?: CSSProperties;\n children?: ReactNode;\n onReady?: (viewport: Viewport) => void;\n}\n\nexport interface FieldNotesCanvasRef {\n viewport: Viewport | null;\n}\n\nexport const FieldNotesCanvas = forwardRef<FieldNotesCanvasRef, FieldNotesCanvasProps>(\n function FieldNotesCanvas(\n {\n options,\n tools,\n defaultTool,\n tool,\n onToolChange,\n snapToGrid,\n className,\n style,\n children,\n onReady,\n },\n ref,\n ) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [viewport, setViewport] = useState<Viewport | null>(null);\n\n useImperativeHandle(ref, () => ({ viewport }), [viewport]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const vp = new Viewport(el, options);\n\n if (tools) {\n for (const t of tools) {\n vp.toolManager.register(t);\n }\n }\n\n const initialTool = tool ?? defaultTool;\n if (initialTool) {\n vp.setTool(initialTool);\n }\n\n setViewport(vp);\n onReady?.(vp);\n\n return () => {\n vp.destroy();\n setViewport(null);\n };\n // Constructor effect: options/tools/defaultTool are mount-only by design.\n }, []);\n\n useEffect(() => {\n if (!viewport || tool === undefined) return;\n if (viewport.toolManager.activeTool?.name !== tool) {\n viewport.setTool(tool);\n }\n }, [viewport, tool]);\n\n useEffect(() => {\n if (!viewport || !onToolChange) return;\n return viewport.toolManager.onChange(onToolChange);\n }, [viewport, onToolChange]);\n\n useEffect(() => {\n if (!viewport || snapToGrid === undefined) return;\n viewport.setSnapToGrid(snapToGrid);\n }, [viewport, snapToGrid]);\n\n useEffect(() => {\n if (!viewport || !tools) return;\n for (const t of tools) {\n if (!viewport.toolManager.getTool(t.name)) {\n viewport.toolManager.register(t);\n }\n }\n }, [viewport, tools]);\n\n return (\n <div ref={containerRef} className={className} style={style}>\n {viewport && (\n <ViewportContext.Provider value={viewport}>{children}</ViewportContext.Provider>\n )}\n </div>\n );\n },\n);\n","import { createContext } from 'react';\nimport type { Viewport } from '@fieldnotes/core';\n\nexport const ViewportContext = createContext<Viewport | null>(null);\n","import { useEffect, useRef, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useViewport } from './hooks/use-viewport';\n\n/** Props for {@link CanvasElement}. */\nexport interface CanvasElementProps {\n /** Canvas-space position of the element's top-left corner. */\n position: { x: number; y: number };\n /** Optional fixed size; omit to let the element size to its content. */\n size?: { w: number; h: number };\n children: ReactNode;\n}\n\n/**\n * Marks every store mutation this component makes as host-owned: external origin, so it\n * neither creates an undo step nor is re-broadcast to the sync hub.\n */\nconst HOST_ORIGIN = 'host';\n\n/**\n * Renders a React subtree as an HTML element embedded in the canvas coordinate space.\n * The element is host-owned and transient: it is driven entirely by props, never appears\n * in exported state, and never records an undo step.\n * Must be used inside a `<FieldNotesCanvas>`.\n */\nexport function CanvasElement({ position, size, children }: CanvasElementProps) {\n const viewport = useViewport();\n const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\n const elementIdRef = useRef<string | null>(null);\n // Latest geometry, so a re-registration after a store clear uses current props rather than\n // the values captured when the mount effect ran.\n const geometryRef = useRef<{\n position: { x: number; y: number };\n size?: { w: number; h: number };\n }>({ position, size });\n\n useEffect(() => {\n const container = document.createElement('div');\n Object.assign(container.style, {\n width: '100%',\n height: '100%',\n });\n\n const register = () => {\n // Append to domLayer immediately so portal children are queryable in the document\n // before the viewport render loop fires via requestAnimationFrame.\n viewport.domLayer.appendChild(container);\n const { position: current, size: currentSize } = geometryRef.current;\n return viewport.addHtmlElement(container, current, currentSize, {\n transient: true,\n origin: HOST_ORIGIN,\n });\n };\n\n elementIdRef.current = register();\n setPortalTarget(container);\n\n let disposed = false;\n // A store clear detaches every canvas-owned DOM node and forgets the content registered\n // for it, so this component has to hand its container back afterwards. The decision is\n // deferred to a microtask because a remote clear is followed — synchronously, by the sync\n // client — by re-adding the transient elements: reading the store inside the event would\n // always report this element gone and add a duplicate.\n const handleStoreReplacement = () => {\n const clearedId = elementIdRef.current;\n if (clearedId === null) return;\n queueMicrotask(() => {\n if (disposed || elementIdRef.current !== clearedId) return;\n if (viewport.store.getById(clearedId)?.type === 'html') {\n // Survived the clear (the sync client re-adds transient elements after a remote\n // clear): restore the container as that element's content instead of adding a second.\n viewport.updateHtmlElement(clearedId, container);\n } else {\n elementIdRef.current = register();\n }\n viewport.requestRender();\n });\n };\n // `clear` covers a clear-canvas gesture and a remote clear. A wholesale state replacement\n // (`loadState`/`loadJSON`) runs inside `suspendNotifications`, so the store coalesces its\n // events into a single `batch` instead: the same recovery applies.\n const unsubscribeClear = viewport.store.on('clear', handleStoreReplacement);\n const unsubscribeBatch = viewport.store.on('batch', handleStoreReplacement);\n\n return () => {\n disposed = true;\n unsubscribeClear();\n unsubscribeBatch();\n if (elementIdRef.current) {\n viewport.store.remove(elementIdRef.current, { origin: HOST_ORIGIN });\n viewport.requestRender();\n elementIdRef.current = null;\n }\n // Removing the element usually detaches the container, but when no render pass ran between\n // this effect and its cleanup (StrictMode's double invocation) the node is still parented\n // in the DOM layer as an empty div.\n if (container.parentNode === viewport.domLayer) container.remove();\n setPortalTarget(null);\n };\n }, [viewport]);\n\n useEffect(() => {\n geometryRef.current = { position, size };\n const id = elementIdRef.current;\n if (!id) return;\n viewport.store.update(id, { position, ...(size ? { size } : {}) }, { origin: HOST_ORIGIN });\n viewport.requestRender();\n // Primitive deps (position.x/y, size?.w/h) are intentional: the effect re-runs on VALUE change,\n // not object identity — so inline { x, y } literals and memoized-but-unchanged objects both behave\n // correctly (no over-firing on every parent re-render).\n }, [viewport, position.x, position.y, size?.w, size?.h]);\n\n if (!portalTarget) return null;\n return createPortal(children, portalTarget);\n}\n","import { useContext } from 'react';\nimport type { Viewport } from '@fieldnotes/core';\nimport { ViewportContext } from '../context';\n\n/** The Viewport from the nearest `<FieldNotesCanvas>`. Throws outside one. */\nexport function useViewport(): Viewport {\n const viewport = useContext(ViewportContext);\n if (!viewport) {\n throw new Error('useViewport must be used inside <FieldNotesCanvas>');\n }\n return viewport;\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\n/** `[activeToolName, setTool]` — re-renders on tool switches. */\nexport function useActiveTool(): [toolName: string, setTool: (name: string) => void] {\n const viewport = useViewport();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.toolManager.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback(() => viewport.toolManager.activeTool?.name ?? '', [viewport]);\n\n const toolName = useSyncExternalStore(subscribe, getSnapshot);\n\n const setTool = useCallback((name: string) => viewport.setTool(name), [viewport]);\n\n return [toolName, setTool];\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\nexport interface CameraState {\n x: number;\n y: number;\n zoom: number;\n}\n\n/** Current camera position and zoom level — re-renders whenever the camera moves or zoom changes. */\nexport function useCamera(): CameraState {\n const viewport = useViewport();\n const cachedRef = useRef<CameraState>({ x: 0, y: 0, zoom: 1 });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.camera.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): CameraState => {\n const { position, zoom } = viewport.camera;\n const cached = cachedRef.current;\n if (cached.x === position.x && cached.y === position.y && cached.zoom === zoom) {\n return cached;\n }\n const next = { x: position.x, y: position.y, zoom };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\nfunction noop() {\n /* unsubscribe placeholder */\n}\n\n/**\n * `[options, setOptions]` for the named tool — re-renders when the tool's options change.\n * Returns `null` for options if the tool is not registered or does not expose options.\n */\nexport function useToolOptions<T extends Record<string, unknown>>(\n toolName: string,\n): [options: T | null, setOptions: (partial: Partial<T>) => void] {\n const viewport = useViewport();\n const cachedRef = useRef<T | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n const tool = viewport.toolManager.getTool(toolName);\n if (!tool?.onOptionsChange) return noop;\n return tool.onOptionsChange(onStoreChange);\n },\n [viewport, toolName],\n );\n\n const getSnapshot = useCallback((): T | null => {\n const tool = viewport.toolManager.getTool(toolName);\n if (!tool?.getOptions) return null;\n const next = tool.getOptions() as T;\n const cached = cachedRef.current;\n if (cached && shallowEqual(cached, next)) return cached;\n cachedRef.current = next;\n return next;\n }, [viewport, toolName]);\n\n const options = useSyncExternalStore(subscribe, getSnapshot);\n\n const setOptions = useCallback(\n (partial: Partial<T>) => {\n const tool = viewport.toolManager.getTool(toolName);\n tool?.setOptions?.(partial as Record<string, unknown>);\n },\n [viewport, toolName],\n );\n\n return [options, setOptions];\n}\n\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n const valA = a[key];\n const valB = b[key];\n if (valA === valB) continue;\n if (\n typeof valA === 'object' &&\n valA !== null &&\n typeof valB === 'object' &&\n valB !== null &&\n !Array.isArray(valA) &&\n !Array.isArray(valB)\n ) {\n const objA = valA as Record<string, unknown>;\n const objB = valB as Record<string, unknown>;\n const innerKeys = Object.keys(objA);\n if (\n innerKeys.length === Object.keys(objB).length &&\n innerKeys.every((k) => objA[k] === objB[k])\n ) {\n continue;\n }\n }\n return false;\n }\n return true;\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { Layer } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\ninterface LayersSnapshot {\n layers: Layer[];\n activeLayerId: string;\n}\n\nexport interface UseLayersResult {\n layers: Layer[];\n activeLayerId: string;\n createLayer: (name?: string) => Layer;\n removeLayer: (id: string) => void;\n renameLayer: (id: string, name: string) => void;\n reorderLayer: (id: string, newOrder: number) => void;\n setVisible: (id: string, visible: boolean) => void;\n setLocked: (id: string, locked: boolean) => void;\n setOpacity: (id: string, opacity: number) => void;\n setActiveLayer: (id: string) => void;\n moveElement: (elementId: string, layerId: string) => void;\n}\n\n/**\n * Current layer list and mutation helpers — re-renders whenever a layer is added, removed,\n * reordered, renamed, or its visibility/lock/opacity/active state changes.\n */\nexport function useLayers(): UseLayersResult {\n const viewport = useViewport();\n const cachedRef = useRef<LayersSnapshot>({ layers: [], activeLayerId: '' });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.layerManager.on('change', onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): LayersSnapshot => {\n const layers = viewport.layerManager.getLayers();\n const activeLayerId = viewport.layerManager.activeLayerId;\n const cached = cachedRef.current;\n if (\n cached.activeLayerId === activeLayerId &&\n cached.layers.length === layers.length &&\n cached.layers.every((l, i) => {\n const next = layers[i];\n return (\n next !== undefined &&\n l.id === next.id &&\n l.name === next.name &&\n l.visible === next.visible &&\n l.locked === next.locked &&\n l.order === next.order &&\n l.opacity === next.opacity\n );\n })\n ) {\n return cached;\n }\n const next = { layers, activeLayerId };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\n\n const createLayer = useCallback(\n (name?: string) => viewport.layerManager.createLayer(name),\n [viewport],\n );\n\n const removeLayer = useCallback(\n (id: string) => viewport.layerManager.removeLayer(id),\n [viewport],\n );\n\n const renameLayer = useCallback(\n (id: string, name: string) => viewport.layerManager.renameLayer(id, name),\n [viewport],\n );\n\n const reorderLayer = useCallback(\n (id: string, newOrder: number) => viewport.layerManager.reorderLayer(id, newOrder),\n [viewport],\n );\n\n const setVisible = useCallback(\n (id: string, visible: boolean) => viewport.layerManager.setLayerVisible(id, visible),\n [viewport],\n );\n\n const setLocked = useCallback(\n (id: string, locked: boolean) => viewport.layerManager.setLayerLocked(id, locked),\n [viewport],\n );\n\n const setOpacity = useCallback(\n (id: string, opacity: number) => viewport.layerManager.setLayerOpacity(id, opacity),\n [viewport],\n );\n\n const setActiveLayer = useCallback(\n (id: string) => viewport.layerManager.setActiveLayer(id),\n [viewport],\n );\n\n const moveElement = useCallback(\n (elementId: string, layerId: string) =>\n viewport.layerManager.moveElementToLayer(elementId, layerId),\n [viewport],\n );\n\n return {\n layers: snapshot.layers,\n activeLayerId: snapshot.activeLayerId,\n createLayer,\n removeLayer,\n renameLayer,\n reorderLayer,\n setVisible,\n setLocked,\n setOpacity,\n setActiveLayer,\n moveElement,\n };\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\ninterface HistorySnapshot {\n canUndo: boolean;\n canRedo: boolean;\n}\n\nexport interface UseHistoryResult {\n canUndo: boolean;\n canRedo: boolean;\n undo: () => void;\n redo: () => void;\n}\n\n/** `{ canUndo, canRedo, undo, redo }` — re-renders when undo/redo availability changes. */\nexport function useHistory(): UseHistoryResult {\n const viewport = useViewport();\n const cachedRef = useRef<HistorySnapshot>({ canUndo: false, canRedo: false });\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.history.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): HistorySnapshot => {\n const canUndo = viewport.history.canUndo;\n const canRedo = viewport.history.canRedo;\n const cached = cachedRef.current;\n if (cached.canUndo === canUndo && cached.canRedo === canRedo) {\n return cached;\n }\n const next = { canUndo, canRedo };\n cachedRef.current = next;\n return next;\n }, [viewport]);\n\n const snapshot = useSyncExternalStore(subscribe, getSnapshot);\n\n const undo = useCallback(() => viewport.undo(), [viewport]);\n const redo = useCallback(() => viewport.redo(), [viewport]);\n\n return {\n canUndo: snapshot.canUndo,\n canRedo: snapshot.canRedo,\n undo,\n redo,\n };\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { CanvasElement, ElementType } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));\n }\n if (\n typeof a === 'object' &&\n a !== null &&\n typeof b === 'object' &&\n b !== null &&\n !Array.isArray(a) &&\n !Array.isArray(b)\n ) {\n const ka = Object.keys(a);\n const kb = Object.keys(b);\n return (\n ka.length === kb.length &&\n ka.every(\n (k) =>\n k in (b as Record<string, unknown>) &&\n Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\n )\n );\n }\n return false;\n}\n\n/** All elements; re-renders on every store mutation (use a selector for hot paths). */\nexport function useElements(): CanvasElement[];\n/** Elements of one type; re-renders on every store mutation. */\nexport function useElements<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[];\n/**\n * Derived value; re-renders only when the selected value changes (per `isEqual`,\n * default: one-level shallow compare — arrays by index, plain objects by key, primitives by\n * Object.is). Keep the selector referentially stable (useCallback or module scope).\n *\n * Supply `isEqual` for deeper structures. Note: selectors returning nested fresh objects\n * (e.g. `els => els.map(e => ({ ...e.position }))`) still need a custom comparator because\n * the default only compares one level deep.\n */\nexport function useElements<R>(\n selector: (elements: CanvasElement[]) => R,\n isEqual?: (a: R, b: R) => boolean,\n): R;\nexport function useElements<R>(\n arg?: ElementType | ((elements: CanvasElement[]) => R),\n isEqual?: (a: R, b: R) => boolean,\n): CanvasElement[] | R {\n const viewport = useViewport();\n const cachedRef = useRef<CanvasElement[]>([]);\n const selectedRef = useRef<{ value: R } | null>(null);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => viewport.store.onChange(onStoreChange),\n [viewport],\n );\n\n const getSnapshot = useCallback((): CanvasElement[] | R => {\n if (typeof arg === 'function') {\n const next = arg(viewport.store.getAll());\n const prev = selectedRef.current;\n const equal: (a: R, b: R) => boolean = isEqual ?? (shallowEqual as (a: R, b: R) => boolean);\n if (prev !== null && equal(prev.value, next)) {\n return prev.value;\n }\n selectedRef.current = { value: next };\n return next;\n }\n\n const next = arg ? viewport.store.getElementsByType(arg) : viewport.store.getAll();\n const cached = cachedRef.current;\n if (cached.length === next.length && cached.every((el, i) => el === next[i])) {\n return cached;\n }\n cachedRef.current = next;\n return next;\n }, [viewport, arg, isEqual]);\n\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useViewport } from './use-viewport';\n\n/** Reactive selected element ids. Stable array reference — only changes when the selection changes. */\nexport function useSelection(): string[] {\n const viewport = useViewport();\n\n const subscribe = useCallback(\n (onChange: () => void) => viewport.onSelectionChange(onChange),\n [viewport],\n );\n\n const getSnapshot = useCallback(() => viewport.getSelectedIds(), [viewport]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { ElementStyle } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\nimport { STYLE_KEYS } from './style-keys';\n\nfunction styleEqual(a: ElementStyle | null, b: ElementStyle | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return STYLE_KEYS.every((k) => a[k] === b[k]);\n}\n\n/**\n * Reactive normalized style of the current selection.\n * Returns `[style, applyPatch]` — `style` is `null` when nothing is selected.\n * `applyPatch` applies an `ElementStyle` patch to every selected element.\n */\nexport function useSelectionStyle(): [ElementStyle | null, (style: ElementStyle) => void] {\n const viewport = useViewport();\n const cacheRef = useRef<ElementStyle | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback(() => {\n const next = viewport.getSelectionStyle();\n if (styleEqual(cacheRef.current, next)) return cacheRef.current;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const style = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\n\n return [style, apply];\n}\n","import type { ElementStyle } from '@fieldnotes/core';\n\n/**\n * The `ElementStyle` fields the selection-style hooks compare and cache.\n * Internal to `@fieldnotes/react` — not exported from the package index.\n * Shared between `useSelectionStyle` and `useSelectionStyleDetails` so the\n * two hooks cannot drift out of sync (a prior desync here dropped\n * `strokeStyle` from one hook's equality check and caused stale style data).\n */\nexport const STYLE_KEYS: readonly (keyof ElementStyle)[] = [\n 'color',\n 'fillColor',\n 'strokeWidth',\n 'opacity',\n 'fontSize',\n 'strokeStyle',\n];\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { ElementStyle, SelectionStyleDetails } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\nimport { STYLE_KEYS } from './style-keys';\n\nfunction keysEqual(\n a: readonly (keyof ElementStyle)[],\n b: readonly (keyof ElementStyle)[],\n): boolean {\n return a.length === b.length && a.every((k, i) => k === b[i]);\n}\n\nfunction detailsEqual(a: SelectionStyleDetails | null, b: SelectionStyleDetails | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return (\n keysEqual(a.applicable, b.applicable) &&\n keysEqual(a.mixed, b.mixed) &&\n STYLE_KEYS.every((k) => a.common[k] === b.common[k])\n );\n}\n\n/**\n * Reactive style details of the current selection: per-field applicability and\n * mixed-state, plus the common style. `null` when nothing valid is selected.\n * The apply function delegates to `applyStyleToSelection` (one undo step).\n */\nexport function useSelectionStyleDetails(): [\n SelectionStyleDetails | null,\n (style: ElementStyle) => void,\n] {\n const viewport = useViewport();\n const cacheRef = useRef<SelectionStyleDetails | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback(() => {\n const next = viewport.getSelectionStyleDetails();\n if (detailsEqual(cacheRef.current, next)) return cacheRef.current;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const details = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const apply = useCallback((s: ElementStyle) => viewport.applyStyleToSelection(s), [viewport]);\n\n return [details, apply];\n}\n","import { useCallback, useRef, useSyncExternalStore } from 'react';\nimport type { AlignEdge, DistributeAxis } from '@fieldnotes/core';\nimport { useViewport } from './use-viewport';\n\nexport interface UseSelectionOpsResult {\n selectedIds: string[];\n selectedCount: number;\n canGroup: boolean;\n canUngroup: boolean;\n canAlign: boolean;\n canDistribute: boolean;\n isLocked: boolean | null;\n group: () => void;\n ungroup: () => void;\n toggleLock: () => void;\n align: (edge: AlignEdge) => void;\n distribute: (axis: DistributeAxis) => void;\n rotateCW: () => void;\n rotateCCW: () => void;\n}\n\ninterface Snapshot {\n selectedIds: string[];\n canGroup: boolean;\n canUngroup: boolean;\n canAlign: boolean;\n canDistribute: boolean;\n isLocked: boolean | null;\n}\n\nfunction snapshotEqual(a: Snapshot, b: Snapshot): boolean {\n return (\n a.selectedIds === b.selectedIds &&\n a.canGroup === b.canGroup &&\n a.canUngroup === b.canUngroup &&\n a.canAlign === b.canAlign &&\n a.canDistribute === b.canDistribute &&\n a.isLocked === b.isLocked\n );\n}\n\n/**\n * Reactive selection operations + derived predicates for the current selection.\n * Predicates (`canGroup`/`canAlign`/…) reflect whether each action is meaningful;\n * `isLocked` is `true`/`false` when the selection is uniformly locked/unlocked,\n * and `null` when empty or mixed. Actions delegate to the core Viewport.\n */\nexport function useSelectionOps(): UseSelectionOpsResult {\n const viewport = useViewport();\n const cacheRef = useRef<Snapshot | null>(null);\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const offSel = viewport.onSelectionChange(onChange);\n const offStore = viewport.store.onChange(onChange);\n return () => {\n offSel();\n offStore();\n };\n },\n [viewport],\n );\n\n const getSnapshot = useCallback((): Snapshot => {\n const ids = viewport.getSelectedIds();\n const n = ids.length;\n let canUngroup = false;\n let lockedCount = 0;\n for (const id of ids) {\n const el = viewport.store.getById(id);\n if (!el) continue;\n if (el.groupId !== undefined) canUngroup = true;\n if (el.locked) lockedCount++;\n }\n const isLocked: boolean | null =\n n === 0 ? null : lockedCount === n ? true : lockedCount === 0 ? false : null;\n const next: Snapshot = {\n selectedIds: ids,\n canGroup: n >= 2,\n canUngroup,\n canAlign: n >= 2,\n canDistribute: n >= 3,\n isLocked,\n };\n const prev = cacheRef.current;\n if (prev && snapshotEqual(prev, next)) return prev;\n cacheRef.current = next;\n return next;\n }, [viewport]);\n\n const snap = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const group = useCallback(() => viewport.groupSelection(), [viewport]);\n const ungroup = useCallback(() => viewport.ungroupSelection(), [viewport]);\n const toggleLock = useCallback(() => viewport.toggleLockSelection(), [viewport]);\n const align = useCallback((edge: AlignEdge) => viewport.alignSelection(edge), [viewport]);\n const distribute = useCallback(\n (axis: DistributeAxis) => viewport.distributeSelection(axis),\n [viewport],\n );\n const rotateCW = useCallback(() => viewport.rotateSelection('cw'), [viewport]);\n const rotateCCW = useCallback(() => viewport.rotateSelection('ccw'), [viewport]);\n\n return {\n selectedIds: snap.selectedIds,\n selectedCount: snap.selectedIds.length,\n canGroup: snap.canGroup,\n canUngroup: snap.canUngroup,\n canAlign: snap.canAlign,\n canDistribute: snap.canDistribute,\n isLocked: snap.isLocked,\n group,\n ungroup,\n toggleLock,\n align,\n distribute,\n rotateCW,\n rotateCCW,\n };\n}\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';\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","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.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "React wrapper for Field Notes canvas SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -9,9 +9,14 @@
|
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.cts",
|
|
18
|
+
"default": "./dist/index.cjs"
|
|
19
|
+
}
|
|
15
20
|
}
|
|
16
21
|
},
|
|
17
22
|
"files": [
|
|
@@ -36,7 +41,7 @@
|
|
|
36
41
|
"fieldnotes"
|
|
37
42
|
],
|
|
38
43
|
"peerDependencies": {
|
|
39
|
-
"@fieldnotes/core": ">=0.
|
|
44
|
+
"@fieldnotes/core": ">=0.83.0 <1.0.0",
|
|
40
45
|
"react": ">=18 <20",
|
|
41
46
|
"react-dom": ">=18 <20"
|
|
42
47
|
},
|
|
@@ -50,11 +55,13 @@
|
|
|
50
55
|
"react-dom": "^19.2.4",
|
|
51
56
|
"tsup": "^8.5.1",
|
|
52
57
|
"vitest": "^4.1.0",
|
|
53
|
-
"@fieldnotes/core": "0.
|
|
58
|
+
"@fieldnotes/core": "0.83.0"
|
|
54
59
|
},
|
|
55
60
|
"scripts": {
|
|
56
61
|
"build": "tsup",
|
|
62
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
57
63
|
"test": "vitest run",
|
|
64
|
+
"test:coverage": "vitest run --coverage",
|
|
58
65
|
"test:watch": "vitest"
|
|
59
66
|
}
|
|
60
67
|
}
|