@pixerate/editor-react 0.14.0 → 0.15.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.
Files changed (38) hide show
  1. package/README.md +2 -1
  2. package/dist/canvas/index.cjs +252 -119
  3. package/dist/canvas/index.cjs.map +1 -1
  4. package/dist/canvas/index.d.cts +55 -7
  5. package/dist/canvas/index.d.ts +55 -7
  6. package/dist/canvas/index.js +155 -19
  7. package/dist/canvas/index.js.map +1 -1
  8. package/dist/chunk-4ZC2WCUO.js +196 -0
  9. package/dist/chunk-4ZC2WCUO.js.map +1 -0
  10. package/dist/{chunk-TL27COKM.js → chunk-LPFZMZ3L.js} +45 -2
  11. package/dist/chunk-LPFZMZ3L.js.map +1 -0
  12. package/dist/{chunk-25S5EHH4.js → chunk-QVQYYHJ5.js} +4 -3
  13. package/dist/chunk-QVQYYHJ5.js.map +1 -0
  14. package/dist/commands/index.cjs +232 -0
  15. package/dist/commands/index.cjs.map +1 -0
  16. package/dist/commands/index.d.cts +69 -0
  17. package/dist/commands/index.d.ts +69 -0
  18. package/dist/commands/index.js +13 -0
  19. package/dist/commands/index.js.map +1 -0
  20. package/dist/image-editor/index.cjs +41 -0
  21. package/dist/image-editor/index.cjs.map +1 -1
  22. package/dist/image-editor/index.d.cts +5 -3
  23. package/dist/image-editor/index.d.ts +5 -3
  24. package/dist/image-editor/index.js +1 -1
  25. package/dist/index.cjs +535 -251
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +61 -22
  28. package/dist/index.d.ts +61 -22
  29. package/dist/index.js +131 -70
  30. package/dist/index.js.map +1 -1
  31. package/dist/spreadsheet/index.cjs +1 -1
  32. package/dist/spreadsheet/index.cjs.map +1 -1
  33. package/dist/spreadsheet/index.d.cts +7 -7
  34. package/dist/spreadsheet/index.d.ts +7 -7
  35. package/dist/spreadsheet/index.js +1 -1
  36. package/package.json +10 -2
  37. package/dist/chunk-25S5EHH4.js.map +0 -1
  38. package/dist/chunk-TL27COKM.js.map +0 -1
@@ -1,8 +1,9 @@
1
- import React$1 from 'react';
1
+ import * as React$1 from 'react';
2
+ import React__default from 'react';
2
3
  import { AgentPresence } from '@pixerate/editor/agent';
3
4
  import * as _pixerate_editor_canvas from '@pixerate/editor/canvas';
4
5
  import { CanvasNode, CanvasEdge, IncrementalLayoutOptions, XYPosition, GraphDifferences, Rect, CanvasLayoutOptions, Side, PlaceBesideOptions, getCenteredNodePosition, CanvasDockingCallbacks, DockStrategy, ExplodeNodeOptions, CollapseNodeOptions, ExplosionSnapshot, ArrangeHistoryTarget, SnapGuidesOptions, NodeRectOptions, GuideLine, CanvasArrangeAction, ArrangeShortcutBinding, CanvasScenesOptions, CanvasViewport, CanvasScenesStore, CanvasScene, FitViewportOptions, ShapeDescription } from '@pixerate/editor/canvas';
5
- export { AlignEdge, ArrangeShortcutBinding, CONNECTION_LINE_TYPES, CanvasArrangeAction, CanvasClipboardPayload, CanvasConnectionLineType, CanvasDockingCallbacks, CanvasEdge, CanvasHeightOptions, CanvasLayoutOptions, CanvasNode, CanvasNodeUpdate, CanvasScene, CanvasScenesState, CanvasScenesStore, CanvasViewport, Clock, CollapseNodeOptions, CombineShapeNodesOptions, CombineShapeNodesRefusal, CombineShapeNodesResult, ConnectorSnap, ConnectorSnapTarget, DEFAULT_ARRANGE_SHORTCUTS, DirectionalDisplacementOptions, DisplacementDirection, DistributeAxis, DistributeMode, DockStrategy, EllipseShape, ExplodeNodeOptions, ExplosionSnapshot, FanOutTrajectoryOptions, FlattenOptions, GraphDifferences, GuideIndex, GuideLine, IncrementalLayoutOptions, ManualClock, MultiPolygon, NodeTransition, PathCommand, PathShape, PlaceBesideOptions, Point, PolygonBooleanOperation, PolygonBooleanOptions, PolygonFillRule, PolygonInput, PolygonOperand, PolygonPiece, PolygonRing, PolygonToPathOptions, PolygonWithHoles, Position, Rect, RectShape, ReflowDisplacementOptions, RegularPolygonShape, SHAPE_DATA_KEY, SHAPE_KINDS, SHAPE_NODE_TYPE, SHAPE_OPERATIONS, ShapeDescription, ShapeKind, ShapeNodePolygonOptions, ShapeOperation, ShapePaint, ShapeRenderData, ShapeSize, Side, SizeDimension, SnapGuidesOptions, SnapResult, StarShape, TrajectoryFunction, TrajectoryPoint, XYPosition, ZOrderOperation, alignNodes, applyNodeUpdates, applyShapeCombination, blendLayout, boundsOf, calculateDagreReflowDisplacement, calculateDirectionalDisplacement, canCombineShapeNodes, canvasHeight, centerNodes, centre, combineShapeNodes, computeNodesBoundingBox, computeSnapGuides, connectedOnly, createBezierTrajectory, createCanvasScenesStore, createFanOutTrajectory, createGuideIndex, createNodeGuideIndex, defaultEasing, distributeNodes, dividePolygons, ensureLayout, estimateCanvasHeight, estimateNodeSize, findConnectorSnap, fitViewportToNodes, fitViewportToRect, flattenSvgPath, flowSide, getAbsolutePosition, getCenteredNodePosition, getLayoutedNodes, getNodeRect, getNodeShape, getNodeSize, getShapeRenderData, getShapeSvg, handlePoint, intersectPolygons, invertNodeUpdates, isEventFromTextInput, isLocked, isShapeDescription, isShapeNode, isValidCanvasNode, isValidUrl, layoutBounds, linearPositionTrajectory, linearTrajectory, lockNodes, matchArrangeShortcut, matchSize, multiPolygonArea, multiPolygonBounds, nearestHandlePositions, oppositePosition, overlaps, parseCanvasClipboardData, parseCanvasScenes, parseSvgPath, placeBeside, pointInMultiPolygon, pointInRings, polygonArea, polygonBoolean, polygonToSvgPath, positionToSide, readStyleSize, realClock, remapPastedNodes, reorderNodes, repositionNodesTo, revertShapeCombination, ringSignedArea, runMultiNodeTransition, serializeCanvasNodes, shapeNodeToPolygon, shapeToPolygon, sideToPosition, simplifyRing, snapNodeDrag, subtractPolygons, toggleLockNodes, unionPolygons, unlockNodes, withStyleSize, xorPolygons } from '@pixerate/editor/canvas';
6
+ export { AlignEdge, ArrangeShortcutBinding, CONNECTION_LINE_TYPES, CanvasArrangeAction, CanvasClipboardPayload, CanvasConnectionLineType, CanvasDockingCallbacks, CanvasEdge, CanvasHeightOptions, CanvasLayoutOptions, CanvasNode, CanvasNodeUpdate, CanvasScene, CanvasScenesState, CanvasScenesStore, CanvasViewport, Clock, CollapseNodeOptions, CombineShapeNodesOptions, CombineShapeNodesRefusal, CombineShapeNodesResult, ConnectorSnap, ConnectorSnapTarget, CubicSegment, DEFAULT_ARRANGE_SHORTCUTS, DirectionalDisplacementOptions, DisplacementDirection, DistributeAxis, DistributeMode, DockStrategy, EllipseShape, ExplodeNodeOptions, ExplosionSnapshot, FanOutTrajectoryOptions, FitCubicsOptions, FitPathDataOptions, FlattenOptions, GraphDifferences, GuideIndex, GuideLine, IncrementalLayoutOptions, ManualClock, MeasureGuide, MeasureSelectionOptions, MeasureSelectionResult, MultiPolygon, NodeTransition, PathCommand, PathShape, PlaceBesideOptions, Point, PolygonBooleanOperation, PolygonBooleanOptions, PolygonFillRule, PolygonInput, PolygonOperand, PolygonPiece, PolygonRing, PolygonToPathOptions, PolygonWithHoles, Position, RESIZE_HANDLES, Rect, RectShape, ReflowDisplacementOptions, RegularPolygonShape, ResizeHandle, SHAPE_DATA_KEY, SHAPE_KINDS, SHAPE_NODE_TYPE, SHAPE_OPERATIONS, ShapeDescription, ShapeKind, ShapeNodePolygonOptions, ShapeOperation, ShapePaint, ShapeRenderData, ShapeSize, Side, SizeDimension, SnapGuidesOptions, SnapNodeResizeOptions, SnapNodeResizeResult, SnapResizeOptions, SnapResizeResult, SnapResult, StarShape, TrajectoryFunction, TrajectoryPoint, XYPosition, ZOrderOperation, alignNodes, applyNodeUpdates, applyShapeCombination, blendLayout, boundsOf, calculateDagreReflowDisplacement, calculateDirectionalDisplacement, canCombineShapeNodes, canvasHeight, centerNodes, centre, combineShapeNodes, computeNodesBoundingBox, computeSnapGuides, connectedOnly, createBezierTrajectory, createCanvasScenesStore, createFanOutTrajectory, createGuideIndex, createNodeGuideIndex, cubicPointAt, cubicsToPathData, defaultEasing, distributeNodes, dividePolygons, ensureLayout, estimateCanvasHeight, estimateNodeSize, findConnectorSnap, fitCubicRun, fitCubics, fitFreehandPath, fitPathData, fitViewportToNodes, fitViewportToRect, flattenSvgPath, flowSide, getAbsolutePosition, getCenteredNodePosition, getLayoutedNodes, getNodeRect, getNodeShape, getNodeSize, getResizingNodeRect, getShapeRenderData, getShapeSvg, handlePoint, inferResizeHandle, intersectPolygons, invertNodeUpdates, isEventFromTextInput, isLocked, isMeasureModifierHeld, isShapeDescription, isShapeNode, isStraightCubic, isValidCanvasNode, isValidUrl, layoutBounds, linearPositionTrajectory, linearTrajectory, lockNodes, matchArrangeShortcut, matchSize, measureBetween, measureLabel, measureSelection, measureToLine, multiPolygonArea, multiPolygonBounds, nearestHandlePositions, oppositePosition, overlaps, parseCanvasClipboardData, parseCanvasScenes, parseSvgPath, placeBeside, pointInMultiPolygon, pointInRings, polygonArea, polygonBoolean, polygonToSvgPath, positionToSide, readStyleSize, realClock, remapPastedNodes, reorderNodes, repositionNodesTo, resizeHandleAxes, revertShapeCombination, ringSignedArea, runMultiNodeTransition, serializeCanvasNodes, shapeNodeToPolygon, shapeToPolygon, sideToPosition, simplifyRing, snapNodeDrag, snapNodeResize, snapResize, snapToGrid, subtractPolygons, toggleLockNodes, unionPolygons, unlockNodes, withStyleSize, xorPolygons } from '@pixerate/editor/canvas';
6
7
 
7
8
  interface AgentPresenceLayerProps {
8
9
  presences: AgentPresence[];
@@ -12,7 +13,7 @@ interface AgentPresenceLayerProps {
12
13
  * Visual multiplayer and agent choreography presence layer for React Canvas.
13
14
  * Renders floating cursor indicators, agent name tags, and active status tooltips.
14
15
  */
15
- declare function AgentPresenceLayer({ presences, className }: AgentPresenceLayerProps): React$1.JSX.Element | null;
16
+ declare function AgentPresenceLayer({ presences, className }: AgentPresenceLayerProps): React__default.JSX.Element | null;
16
17
 
17
18
  interface UseStreamingCanvasOptions<TNode extends CanvasNode = CanvasNode, TEdge extends CanvasEdge = CanvasEdge> {
18
19
  throttleMs?: number;
@@ -198,6 +199,10 @@ declare function useCanvasArrange<TNode extends CanvasNode = CanvasNode>(options
198
199
  beginDrag(ids?: Iterable<string>): void;
199
200
  drag(ids?: Iterable<string>): _pixerate_editor_canvas.SnapNodeDragResult | null;
200
201
  snapPositionChanges<TChange extends _pixerate_editor_canvas.PositionChangeLike>(changes: TChange[]): TChange[];
202
+ beginResize(id: string): void;
203
+ resize(id: string, handle?: _pixerate_editor_canvas.ResizeHandle): _pixerate_editor_canvas.SnapNodeResizeResult | null;
204
+ endResize(): void;
205
+ snapResizeChanges<TChange extends _pixerate_editor_canvas.PositionChangeLike>(changes: TChange[]): TChange[];
201
206
  endDrag(): void;
202
207
  };
203
208
  type CanvasArrange = ReturnType<typeof useCanvasArrange>;
@@ -280,13 +285,56 @@ interface CanvasGuidesLayerProps {
280
285
  color?: string;
281
286
  /** Colour of equal-spacing guides. */
282
287
  spacingColor?: string;
288
+ /** Colour of measuring lines, their labels and extension lines. */
289
+ measureColor?: string;
283
290
  className?: string;
284
291
  }
285
292
  /**
286
293
  * Smart-guide overlay for React Flow. Place it inside the flow container (it is absolutely
287
294
  * positioned over the whole pane) and pass the live viewport.
288
295
  */
289
- declare function CanvasGuidesLayer({ guides, viewport, color, spacingColor, className }: CanvasGuidesLayerProps): React$1.JSX.Element | null;
296
+ declare function CanvasGuidesLayer({ guides, viewport, color, spacingColor, measureColor, className }: CanvasGuidesLayerProps): React__default.JSX.Element | null;
297
+
298
+ interface UseCanvasMeasureOptions<TNode extends CanvasNode = CanvasNode> {
299
+ nodes: TNode[];
300
+ /** Ids measured from (default: nodes with `selected: true`). */
301
+ getSelectedIds?: () => string[];
302
+ /** Turns measuring off (default `true`). */
303
+ enabled?: boolean;
304
+ /** Measure only while Alt / Option is held (default `true`); `false` always measures. */
305
+ requireModifier?: boolean;
306
+ /** Element receiving the Alt key events (default `window`). */
307
+ targetElement?: HTMLElement | Window | null;
308
+ rectOptions?: NodeRectOptions;
309
+ }
310
+ /**
311
+ * Alt-hover distance measuring for React Flow: hold Alt / Option and hover a node to see
312
+ * red distance lines with labels from the selection to it (or to the selection's parent
313
+ * when hovering the selection or empty space). Wire `onNodeMouseEnter` / `onNodeMouseLeave`
314
+ * to `<ReactFlow>` and render `guides` with `<CanvasGuidesLayer>` (concatenate them with
315
+ * `arrange.guides` to share one layer).
316
+ */
317
+ declare function useCanvasMeasure<TNode extends CanvasNode = CanvasNode>(options: UseCanvasMeasureOptions<TNode>): {
318
+ /** Measuring lines (flow coordinates) to pass to `<CanvasGuidesLayer>`. */
319
+ guides: _pixerate_editor_canvas.MeasureGuide[];
320
+ /** The box measured to (outline it), or `null`. */
321
+ target: _pixerate_editor_canvas.Rect | null;
322
+ /** Whether measuring is showing (enabled and Alt held, unless `requireModifier: false`). */
323
+ active: boolean;
324
+ hoveredId: string | null;
325
+ setHoveredId: React$1.Dispatch<React$1.SetStateAction<string | null>>;
326
+ /** Sets the modifier state by hand (e.g. from a toolbar toggle). */
327
+ setModifier: React$1.Dispatch<React$1.SetStateAction<boolean>>;
328
+ onNodeMouseEnter: (event: {
329
+ altKey?: boolean;
330
+ } | null, node: {
331
+ id: string;
332
+ }) => void;
333
+ onNodeMouseLeave: (_event: unknown, node: {
334
+ id: string;
335
+ }) => void;
336
+ };
337
+ type CanvasMeasure = ReturnType<typeof useCanvasMeasure>;
290
338
 
291
339
  interface ShapeNodeProps {
292
340
  /** Node data; `data.shape` holds the shape description. */
@@ -300,7 +348,7 @@ interface ShapeNodeProps {
300
348
  selected?: boolean;
301
349
  className?: string;
302
350
  /** Rendered over the shape, e.g. React Flow `<Handle>`s or a label. */
303
- children?: React$1.ReactNode;
351
+ children?: React__default.ReactNode;
304
352
  [key: string]: any;
305
353
  }
306
354
  /**
@@ -309,6 +357,6 @@ interface ShapeNodeProps {
309
357
  * to add handles. Strokes keep their width when the node is resized
310
358
  * (`vector-effect: non-scaling-stroke`). Renders nothing when `data.shape` is missing.
311
359
  */
312
- declare function ShapeNode({ data, width, height, selected, className, children }: ShapeNodeProps): React$1.JSX.Element | null;
360
+ declare function ShapeNode({ data, width, height, selected, className, children }: ShapeNodeProps): React__default.JSX.Element | null;
313
361
 
314
- export { AgentPresenceLayer, type AgentPresenceLayerProps, type CanvasArrange, type CanvasGraphTarget, CanvasGuidesLayer, type CanvasGuidesLayerProps, type CanvasScenes, ShapeNode, type ShapeNodeProps, type UseCanvasArrangeOptions, type UseCanvasArrangeShortcutsOptions, type UseCanvasClipboardOptions, type UseCanvasDockingOptions, type UseCanvasGraphOptions, type UseCanvasLayoutOptions, type UseCanvasScenesOptions, type UseCanvasShortcutsOptions, type UseStreamingCanvasOptions, useCanvasArrange, useCanvasArrangeShortcuts, useCanvasClipboard, useCanvasDocking, useCanvasExplosion, useCanvasGraph, useCanvasLayout, useCanvasScenes, useCanvasShortcuts, useStreamingCanvas };
362
+ export { AgentPresenceLayer, type AgentPresenceLayerProps, type CanvasArrange, type CanvasGraphTarget, CanvasGuidesLayer, type CanvasGuidesLayerProps, type CanvasMeasure, type CanvasScenes, ShapeNode, type ShapeNodeProps, type UseCanvasArrangeOptions, type UseCanvasArrangeShortcutsOptions, type UseCanvasClipboardOptions, type UseCanvasDockingOptions, type UseCanvasGraphOptions, type UseCanvasLayoutOptions, type UseCanvasMeasureOptions, type UseCanvasScenesOptions, type UseCanvasShortcutsOptions, type UseStreamingCanvasOptions, useCanvasArrange, useCanvasArrangeShortcuts, useCanvasClipboard, useCanvasDocking, useCanvasExplosion, useCanvasGraph, useCanvasLayout, useCanvasMeasure, useCanvasScenes, useCanvasShortcuts, useStreamingCanvas };
@@ -891,19 +891,20 @@ function useCanvasScenes(options = {}) {
891
891
  }
892
892
 
893
893
  // src/canvas/CanvasGuidesLayer.tsx
894
- import { jsx as jsx2 } from "react/jsx-runtime";
894
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
895
895
  var DEFAULT_VIEWPORT = { x: 0, y: 0, zoom: 1 };
896
896
  function CanvasGuidesLayer({
897
897
  guides,
898
898
  viewport = DEFAULT_VIEWPORT,
899
899
  color = "#f59e0b",
900
900
  spacingColor = "#ec4899",
901
+ measureColor = "#ef4444",
901
902
  className = ""
902
903
  }) {
903
904
  if (!guides || guides.length === 0) return null;
904
905
  const sx = (x) => x * viewport.zoom + viewport.x;
905
906
  const sy = (y) => y * viewport.zoom + viewport.y;
906
- return /* @__PURE__ */ jsx2(
907
+ return /* @__PURE__ */ jsxs2(
907
908
  "svg",
908
909
  {
909
910
  className: `pixerate-canvas-guides ${className}`,
@@ -917,26 +918,141 @@ function CanvasGuidesLayer({
917
918
  zIndex: 10
918
919
  },
919
920
  "aria-hidden": "true",
920
- children: guides.map((guide, i) => /* @__PURE__ */ jsx2(
921
- "line",
922
- {
923
- "data-kind": guide.kind,
924
- x1: sx(guide.x1),
925
- y1: sy(guide.y1),
926
- x2: sx(guide.x2),
927
- y2: sy(guide.y2),
928
- stroke: guide.kind === "spacing" ? spacingColor : color,
929
- strokeWidth: 1,
930
- strokeDasharray: guide.kind === "centre" ? "4 3" : void 0,
931
- shapeRendering: "crispEdges"
932
- },
933
- i
934
- ))
921
+ children: [
922
+ guides.map((guide, i) => {
923
+ const measuring = guide.kind === "measure" || guide.kind === "extension";
924
+ return /* @__PURE__ */ jsx2(
925
+ "line",
926
+ {
927
+ "data-kind": guide.kind,
928
+ x1: sx(guide.x1),
929
+ y1: sy(guide.y1),
930
+ x2: sx(guide.x2),
931
+ y2: sy(guide.y2),
932
+ stroke: measuring ? measureColor : guide.kind === "spacing" ? spacingColor : color,
933
+ strokeWidth: 1,
934
+ strokeDasharray: guide.kind === "centre" ? "4 3" : guide.kind === "extension" ? "3 3" : void 0,
935
+ shapeRendering: "crispEdges"
936
+ },
937
+ i
938
+ );
939
+ }),
940
+ guides.map((guide, i) => {
941
+ if (!guide.label) return null;
942
+ const x = sx((guide.x1 + guide.x2) / 2);
943
+ const y = sy((guide.y1 + guide.y2) / 2);
944
+ const vertical = guide.orientation === "vertical";
945
+ const width = guide.label.length * 6.5 + 8;
946
+ return /* @__PURE__ */ jsxs2(
947
+ "g",
948
+ {
949
+ className: "pixerate-canvas-guides__label",
950
+ "data-label": guide.label,
951
+ transform: `translate(${vertical ? x + 4 : x - width / 2} ${vertical ? y - 8 : y + 4})`,
952
+ children: [
953
+ /* @__PURE__ */ jsx2("rect", { width, height: 16, rx: 3, fill: measureColor }),
954
+ /* @__PURE__ */ jsx2(
955
+ "text",
956
+ {
957
+ x: width / 2,
958
+ y: 11.5,
959
+ textAnchor: "middle",
960
+ fontSize: 11,
961
+ fontFamily: "system-ui, sans-serif",
962
+ fill: "#fff",
963
+ children: guide.label
964
+ }
965
+ )
966
+ ]
967
+ },
968
+ `label-${i}`
969
+ );
970
+ })
971
+ ]
935
972
  }
936
973
  );
937
974
  }
938
975
 
976
+ // src/canvas/useCanvasMeasure.ts
977
+ import { useCallback as useCallback7, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef7, useState as useState3 } from "react";
978
+ import {
979
+ isMeasureModifierHeld,
980
+ measureSelection
981
+ } from "@pixerate/editor/canvas";
982
+ var EMPTY = { guides: [], target: null, selection: null };
983
+ function useCanvasMeasure(options) {
984
+ const { nodes, enabled = true, requireModifier = true, targetElement, rectOptions } = options;
985
+ const [hoveredId, setHoveredId] = useState3(null);
986
+ const [modifier, setModifier] = useState3(false);
987
+ const optionsRef = useRef7(options);
988
+ optionsRef.current = options;
989
+ useEffect4(() => {
990
+ if (!enabled) return;
991
+ const target = targetElement ?? (typeof window !== "undefined" ? window : null);
992
+ if (!target) return;
993
+ const onKey = (event) => setModifier(isMeasureModifierHeld(event));
994
+ const onBlur = () => setModifier(false);
995
+ target.addEventListener("keydown", onKey);
996
+ target.addEventListener("keyup", onKey);
997
+ const win = typeof window !== "undefined" ? window : null;
998
+ win?.addEventListener("blur", onBlur);
999
+ return () => {
1000
+ target.removeEventListener("keydown", onKey);
1001
+ target.removeEventListener("keyup", onKey);
1002
+ win?.removeEventListener("blur", onBlur);
1003
+ };
1004
+ }, [enabled, targetElement]);
1005
+ const active = enabled && (!requireModifier || modifier);
1006
+ const result = useMemo3(() => {
1007
+ if (!active) return EMPTY;
1008
+ const ids = optionsRef.current.getSelectedIds?.() ?? nodes.filter((n) => n.selected).map((n) => n.id);
1009
+ return measureSelection(nodes, ids, hoveredId, rectOptions);
1010
+ }, [active, nodes, hoveredId, rectOptions]);
1011
+ const onNodeMouseEnter = useCallback7((event, node) => {
1012
+ setHoveredId(node.id);
1013
+ if (event && typeof event.altKey === "boolean") setModifier(event.altKey);
1014
+ }, []);
1015
+ const onNodeMouseLeave = useCallback7((_event, node) => {
1016
+ setHoveredId((current) => current === node.id ? null : current);
1017
+ }, []);
1018
+ return {
1019
+ /** Measuring lines (flow coordinates) to pass to `<CanvasGuidesLayer>`. */
1020
+ guides: result.guides,
1021
+ /** The box measured to (outline it), or `null`. */
1022
+ target: result.target,
1023
+ /** Whether measuring is showing (enabled and Alt held, unless `requireModifier: false`). */
1024
+ active,
1025
+ hoveredId,
1026
+ setHoveredId,
1027
+ /** Sets the modifier state by hand (e.g. from a toolbar toggle). */
1028
+ setModifier,
1029
+ onNodeMouseEnter,
1030
+ onNodeMouseLeave
1031
+ };
1032
+ }
1033
+
939
1034
  // src/canvas/index.ts
1035
+ import {
1036
+ measureBetween,
1037
+ measureToLine,
1038
+ measureSelection as measureSelection2,
1039
+ measureLabel,
1040
+ isMeasureModifierHeld as isMeasureModifierHeld2,
1041
+ snapToGrid,
1042
+ snapResize,
1043
+ snapNodeResize,
1044
+ inferResizeHandle,
1045
+ resizeHandleAxes,
1046
+ getResizingNodeRect,
1047
+ RESIZE_HANDLES,
1048
+ fitCubics,
1049
+ fitCubicRun,
1050
+ fitPathData,
1051
+ fitFreehandPath,
1052
+ cubicsToPathData,
1053
+ cubicPointAt,
1054
+ isStraightCubic
1055
+ } from "@pixerate/editor/canvas";
940
1056
  import {
941
1057
  alignNodes,
942
1058
  distributeNodes,
@@ -975,12 +1091,12 @@ import {
975
1091
 
976
1092
  // src/canvas/ShapeNode.tsx
977
1093
  import { getShapeRenderData, isShapeDescription } from "@pixerate/editor/canvas";
978
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1094
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
979
1095
  function ShapeNode({ data, width, height, selected, className = "", children }) {
980
1096
  const shape = data?.shape;
981
1097
  if (!isShapeDescription(shape)) return null;
982
1098
  const render = getShapeRenderData(shape, { width, height });
983
- return /* @__PURE__ */ jsxs2(
1099
+ return /* @__PURE__ */ jsxs3(
984
1100
  "div",
985
1101
  {
986
1102
  className: `pixerate-shape-node ${className}`.trim(),
@@ -1094,6 +1210,7 @@ export {
1094
1210
  CanvasScenesStore2 as CanvasScenesStore,
1095
1211
  DEFAULT_ARRANGE_SHORTCUTS,
1096
1212
  ManualClock,
1213
+ RESIZE_HANDLES,
1097
1214
  SHAPE_DATA_KEY,
1098
1215
  SHAPE_KINDS,
1099
1216
  SHAPE_NODE_TYPE,
@@ -1119,6 +1236,8 @@ export {
1119
1236
  createFanOutTrajectory2 as createFanOutTrajectory,
1120
1237
  createGuideIndex,
1121
1238
  createNodeGuideIndex,
1239
+ cubicPointAt,
1240
+ cubicsToPathData,
1122
1241
  defaultEasing,
1123
1242
  distributeNodes,
1124
1243
  dividePolygons,
@@ -1126,6 +1245,10 @@ export {
1126
1245
  estimateCanvasHeight,
1127
1246
  estimateNodeSize,
1128
1247
  findConnectorSnap,
1248
+ fitCubicRun,
1249
+ fitCubics,
1250
+ fitFreehandPath,
1251
+ fitPathData,
1129
1252
  fitViewportToNodes2 as fitViewportToNodes,
1130
1253
  fitViewportToRect,
1131
1254
  flattenSvgPath,
@@ -1136,15 +1259,19 @@ export {
1136
1259
  getNodeRect,
1137
1260
  getNodeShape,
1138
1261
  getNodeSize,
1262
+ getResizingNodeRect,
1139
1263
  getShapeRenderData2 as getShapeRenderData,
1140
1264
  getShapeSvg,
1141
1265
  handlePoint,
1266
+ inferResizeHandle,
1142
1267
  intersectPolygons,
1143
1268
  invertNodeUpdates,
1144
1269
  isEventFromTextInput3 as isEventFromTextInput,
1145
1270
  isLocked,
1271
+ isMeasureModifierHeld2 as isMeasureModifierHeld,
1146
1272
  isShapeDescription2 as isShapeDescription,
1147
1273
  isShapeNode,
1274
+ isStraightCubic,
1148
1275
  isValidCanvasNode,
1149
1276
  isValidUrl2 as isValidUrl,
1150
1277
  layoutBounds,
@@ -1153,6 +1280,10 @@ export {
1153
1280
  lockNodes,
1154
1281
  matchArrangeShortcut2 as matchArrangeShortcut,
1155
1282
  matchSize,
1283
+ measureBetween,
1284
+ measureLabel,
1285
+ measureSelection2 as measureSelection,
1286
+ measureToLine,
1156
1287
  multiPolygonArea,
1157
1288
  multiPolygonBounds,
1158
1289
  nearestHandlePositions,
@@ -1173,6 +1304,7 @@ export {
1173
1304
  remapPastedNodes2 as remapPastedNodes,
1174
1305
  reorderNodes,
1175
1306
  repositionNodesTo,
1307
+ resizeHandleAxes,
1176
1308
  revertShapeCombination,
1177
1309
  ringSignedArea,
1178
1310
  runMultiNodeTransition2 as runMultiNodeTransition,
@@ -1182,6 +1314,9 @@ export {
1182
1314
  sideToPosition,
1183
1315
  simplifyRing,
1184
1316
  snapNodeDrag,
1317
+ snapNodeResize,
1318
+ snapResize,
1319
+ snapToGrid,
1185
1320
  subtractPolygons,
1186
1321
  toggleLockNodes,
1187
1322
  unionPolygons,
@@ -1193,6 +1328,7 @@ export {
1193
1328
  useCanvasExplosion,
1194
1329
  useCanvasGraph,
1195
1330
  useCanvasLayout,
1331
+ useCanvasMeasure,
1196
1332
  useCanvasScenes,
1197
1333
  useCanvasShortcuts,
1198
1334
  useStreamingCanvas,