@pixerate/editor-react 0.13.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 +5 -4
  2. package/dist/canvas/index.cjs +329 -84
  3. package/dist/canvas/index.cjs.map +1 -1
  4. package/dist/canvas/index.d.cts +82 -4
  5. package/dist/canvas/index.d.ts +82 -4
  6. package/dist/canvas/index.js +266 -18
  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-MHTAR3RS.js → chunk-QVQYYHJ5.js} +87 -29
  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 +2 -0
  23. package/dist/image-editor/index.d.ts +2 -0
  24. package/dist/image-editor/index.js +1 -1
  25. package/dist/index.cjs +624 -268
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +57 -9
  28. package/dist/index.d.ts +57 -9
  29. package/dist/index.js +147 -71
  30. package/dist/index.js.map +1 -1
  31. package/dist/spreadsheet/index.cjs +79 -22
  32. package/dist/spreadsheet/index.cjs.map +1 -1
  33. package/dist/spreadsheet/index.d.cts +2 -3
  34. package/dist/spreadsheet/index.d.ts +2 -3
  35. package/dist/spreadsheet/index.js +1 -1
  36. package/package.json +10 -2
  37. package/dist/chunk-MHTAR3RS.js.map +0 -1
  38. package/dist/chunk-TL27COKM.js.map +0 -1
@@ -1,8 +1,9 @@
1
+ import * as React$1 from 'react';
1
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
- 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 } 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, ConnectorSnap, ConnectorSnapTarget, DEFAULT_ARRANGE_SHORTCUTS, DirectionalDisplacementOptions, DisplacementDirection, DistributeAxis, DistributeMode, DockStrategy, ExplodeNodeOptions, ExplosionSnapshot, FanOutTrajectoryOptions, GraphDifferences, GuideIndex, GuideLine, IncrementalLayoutOptions, ManualClock, NodeTransition, PlaceBesideOptions, Point, Position, Rect, ReflowDisplacementOptions, Side, SizeDimension, SnapGuidesOptions, SnapResult, TrajectoryFunction, TrajectoryPoint, XYPosition, ZOrderOperation, alignNodes, applyNodeUpdates, blendLayout, boundsOf, calculateDagreReflowDisplacement, calculateDirectionalDisplacement, canvasHeight, centerNodes, centre, computeNodesBoundingBox, computeSnapGuides, connectedOnly, createBezierTrajectory, createCanvasScenesStore, createFanOutTrajectory, createGuideIndex, createNodeGuideIndex, defaultEasing, distributeNodes, ensureLayout, estimateCanvasHeight, estimateNodeSize, findConnectorSnap, fitViewportToNodes, fitViewportToRect, flowSide, getAbsolutePosition, getCenteredNodePosition, getLayoutedNodes, getNodeRect, getNodeSize, handlePoint, invertNodeUpdates, isEventFromTextInput, isLocked, isValidCanvasNode, isValidUrl, layoutBounds, linearPositionTrajectory, linearTrajectory, lockNodes, matchArrangeShortcut, matchSize, nearestHandlePositions, oppositePosition, overlaps, parseCanvasClipboardData, parseCanvasScenes, placeBeside, positionToSide, readStyleSize, realClock, remapPastedNodes, reorderNodes, repositionNodesTo, runMultiNodeTransition, serializeCanvasNodes, sideToPosition, snapNodeDrag, toggleLockNodes, unlockNodes, withStyleSize } from '@pixerate/editor/canvas';
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';
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[];
@@ -187,10 +188,21 @@ declare function useCanvasArrange<TNode extends CanvasNode = CanvasNode>(options
187
188
  unlock: (ids?: Iterable<string>) => string[];
188
189
  toggleLock(ids?: Iterable<string>): string[];
189
190
  isLocked: (id: string) => boolean;
191
+ combineShapes(operation: _pixerate_editor_canvas.ShapeOperation, ids?: Iterable<string>, combineOptions?: _pixerate_editor_canvas.CombineShapeNodesOptions): _pixerate_editor_canvas.CombineShapeNodesResult<TNode>;
192
+ unite: (ids?: Iterable<string>, o?: _pixerate_editor_canvas.CombineShapeNodesOptions) => _pixerate_editor_canvas.CombineShapeNodesResult<TNode>;
193
+ intersect: (ids?: Iterable<string>, o?: _pixerate_editor_canvas.CombineShapeNodesOptions) => _pixerate_editor_canvas.CombineShapeNodesResult<TNode>;
194
+ subtract: (ids?: Iterable<string>, o?: _pixerate_editor_canvas.CombineShapeNodesOptions) => _pixerate_editor_canvas.CombineShapeNodesResult<TNode>;
195
+ exclude: (ids?: Iterable<string>, o?: _pixerate_editor_canvas.CombineShapeNodesOptions) => _pixerate_editor_canvas.CombineShapeNodesResult<TNode>;
196
+ divide: (ids?: Iterable<string>, o?: _pixerate_editor_canvas.CombineShapeNodesOptions) => _pixerate_editor_canvas.CombineShapeNodesResult<TNode>;
197
+ canCombineShapes: (ids?: Iterable<string>) => boolean;
190
198
  runAction(action: CanvasArrangeAction): boolean;
191
199
  beginDrag(ids?: Iterable<string>): void;
192
200
  drag(ids?: Iterable<string>): _pixerate_editor_canvas.SnapNodeDragResult | null;
193
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[];
194
206
  endDrag(): void;
195
207
  };
196
208
  type CanvasArrange = ReturnType<typeof useCanvasArrange>;
@@ -273,12 +285,78 @@ interface CanvasGuidesLayerProps {
273
285
  color?: string;
274
286
  /** Colour of equal-spacing guides. */
275
287
  spacingColor?: string;
288
+ /** Colour of measuring lines, their labels and extension lines. */
289
+ measureColor?: string;
276
290
  className?: string;
277
291
  }
278
292
  /**
279
293
  * Smart-guide overlay for React Flow. Place it inside the flow container (it is absolutely
280
294
  * positioned over the whole pane) and pass the live viewport.
281
295
  */
282
- declare function CanvasGuidesLayer({ guides, viewport, color, spacingColor, className }: CanvasGuidesLayerProps): React__default.JSX.Element | null;
296
+ declare function CanvasGuidesLayer({ guides, viewport, color, spacingColor, measureColor, className }: CanvasGuidesLayerProps): React__default.JSX.Element | null;
283
297
 
284
- export { AgentPresenceLayer, type AgentPresenceLayerProps, type CanvasArrange, type CanvasGraphTarget, CanvasGuidesLayer, type CanvasGuidesLayerProps, type CanvasScenes, 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 };
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>;
338
+
339
+ interface ShapeNodeProps {
340
+ /** Node data; `data.shape` holds the shape description. */
341
+ data: {
342
+ shape?: ShapeDescription;
343
+ [key: string]: any;
344
+ };
345
+ /** Node width / height (React Flow passes them to custom nodes). */
346
+ width?: number;
347
+ height?: number;
348
+ selected?: boolean;
349
+ className?: string;
350
+ /** Rendered over the shape, e.g. React Flow `<Handle>`s or a label. */
351
+ children?: React__default.ReactNode;
352
+ [key: string]: any;
353
+ }
354
+ /**
355
+ * Headless shape node: draws `data.shape` as one SVG path that fills the node box.
356
+ * Register it as a React Flow node type (`nodeTypes={{ shape: ShapeNode }}`), or wrap it
357
+ * to add handles. Strokes keep their width when the node is resized
358
+ * (`vector-effect: non-scaling-stroke`). Renders nothing when `data.shape` is missing.
359
+ */
360
+ declare function ShapeNode({ data, width, height, selected, className, children }: ShapeNodeProps): React__default.JSX.Element | null;
361
+
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,
@@ -972,6 +1088,86 @@ import {
972
1088
  matchArrangeShortcut as matchArrangeShortcut2,
973
1089
  DEFAULT_ARRANGE_SHORTCUTS
974
1090
  } from "@pixerate/editor/canvas";
1091
+
1092
+ // src/canvas/ShapeNode.tsx
1093
+ import { getShapeRenderData, isShapeDescription } from "@pixerate/editor/canvas";
1094
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1095
+ function ShapeNode({ data, width, height, selected, className = "", children }) {
1096
+ const shape = data?.shape;
1097
+ if (!isShapeDescription(shape)) return null;
1098
+ const render = getShapeRenderData(shape, { width, height });
1099
+ return /* @__PURE__ */ jsxs3(
1100
+ "div",
1101
+ {
1102
+ className: `pixerate-shape-node ${className}`.trim(),
1103
+ "data-shape-kind": shape.kind,
1104
+ "data-selected": selected ? "true" : void 0,
1105
+ style: { position: "relative", width: "100%", height: "100%" },
1106
+ children: [
1107
+ /* @__PURE__ */ jsx3(
1108
+ "svg",
1109
+ {
1110
+ viewBox: render.viewBox,
1111
+ preserveAspectRatio: "none",
1112
+ width: "100%",
1113
+ height: "100%",
1114
+ style: { display: "block", overflow: "visible" },
1115
+ "aria-hidden": "true",
1116
+ children: /* @__PURE__ */ jsx3(
1117
+ "path",
1118
+ {
1119
+ d: render.d,
1120
+ transform: render.transform,
1121
+ fill: render.fill,
1122
+ fillRule: render.fillRule,
1123
+ stroke: render.stroke,
1124
+ strokeWidth: render.strokeWidth,
1125
+ opacity: render.opacity,
1126
+ vectorEffect: "non-scaling-stroke"
1127
+ }
1128
+ )
1129
+ }
1130
+ ),
1131
+ children
1132
+ ]
1133
+ }
1134
+ );
1135
+ }
1136
+
1137
+ // src/canvas/index.ts
1138
+ import {
1139
+ combineShapeNodes,
1140
+ canCombineShapeNodes,
1141
+ applyShapeCombination,
1142
+ revertShapeCombination,
1143
+ shapeNodeToPolygon,
1144
+ isShapeNode,
1145
+ getNodeShape,
1146
+ SHAPE_DATA_KEY,
1147
+ SHAPE_NODE_TYPE,
1148
+ SHAPE_OPERATIONS,
1149
+ SHAPE_KINDS,
1150
+ isShapeDescription as isShapeDescription2,
1151
+ shapeToPolygon,
1152
+ getShapeSvg,
1153
+ getShapeRenderData as getShapeRenderData2,
1154
+ parseSvgPath,
1155
+ flattenSvgPath,
1156
+ polygonToSvgPath,
1157
+ simplifyRing,
1158
+ polygonBoolean,
1159
+ unionPolygons,
1160
+ intersectPolygons,
1161
+ subtractPolygons,
1162
+ xorPolygons,
1163
+ dividePolygons,
1164
+ polygonArea,
1165
+ multiPolygonArea,
1166
+ multiPolygonBounds,
1167
+ ringSignedArea,
1168
+ pointInRings,
1169
+ pointInMultiPolygon
1170
+ } from "@pixerate/editor/canvas";
975
1171
  import {
976
1172
  getLayoutedNodes as getLayoutedNodes2,
977
1173
  ensureLayout as ensureLayout2,
@@ -1014,15 +1210,24 @@ export {
1014
1210
  CanvasScenesStore2 as CanvasScenesStore,
1015
1211
  DEFAULT_ARRANGE_SHORTCUTS,
1016
1212
  ManualClock,
1213
+ RESIZE_HANDLES,
1214
+ SHAPE_DATA_KEY,
1215
+ SHAPE_KINDS,
1216
+ SHAPE_NODE_TYPE,
1217
+ SHAPE_OPERATIONS,
1218
+ ShapeNode,
1017
1219
  alignNodes,
1018
1220
  applyNodeUpdates,
1221
+ applyShapeCombination,
1019
1222
  blendLayout,
1020
1223
  boundsOf,
1021
1224
  calculateDagreReflowDisplacement,
1022
1225
  calculateDirectionalDisplacement2 as calculateDirectionalDisplacement,
1226
+ canCombineShapeNodes,
1023
1227
  canvasHeight,
1024
1228
  centerNodes2 as centerNodes,
1025
1229
  centre,
1230
+ combineShapeNodes,
1026
1231
  computeNodesBoundingBox,
1027
1232
  computeSnapGuides,
1028
1233
  connectedOnly,
@@ -1031,24 +1236,42 @@ export {
1031
1236
  createFanOutTrajectory2 as createFanOutTrajectory,
1032
1237
  createGuideIndex,
1033
1238
  createNodeGuideIndex,
1239
+ cubicPointAt,
1240
+ cubicsToPathData,
1034
1241
  defaultEasing,
1035
1242
  distributeNodes,
1243
+ dividePolygons,
1036
1244
  ensureLayout2 as ensureLayout,
1037
1245
  estimateCanvasHeight,
1038
1246
  estimateNodeSize,
1039
1247
  findConnectorSnap,
1248
+ fitCubicRun,
1249
+ fitCubics,
1250
+ fitFreehandPath,
1251
+ fitPathData,
1040
1252
  fitViewportToNodes2 as fitViewportToNodes,
1041
1253
  fitViewportToRect,
1254
+ flattenSvgPath,
1042
1255
  flowSide,
1043
1256
  getAbsolutePosition,
1044
1257
  getCenteredNodePosition2 as getCenteredNodePosition,
1045
1258
  getLayoutedNodes2 as getLayoutedNodes,
1046
1259
  getNodeRect,
1260
+ getNodeShape,
1047
1261
  getNodeSize,
1262
+ getResizingNodeRect,
1263
+ getShapeRenderData2 as getShapeRenderData,
1264
+ getShapeSvg,
1048
1265
  handlePoint,
1266
+ inferResizeHandle,
1267
+ intersectPolygons,
1049
1268
  invertNodeUpdates,
1050
1269
  isEventFromTextInput3 as isEventFromTextInput,
1051
1270
  isLocked,
1271
+ isMeasureModifierHeld2 as isMeasureModifierHeld,
1272
+ isShapeDescription2 as isShapeDescription,
1273
+ isShapeNode,
1274
+ isStraightCubic,
1052
1275
  isValidCanvasNode,
1053
1276
  isValidUrl2 as isValidUrl,
1054
1277
  layoutBounds,
@@ -1057,23 +1280,46 @@ export {
1057
1280
  lockNodes,
1058
1281
  matchArrangeShortcut2 as matchArrangeShortcut,
1059
1282
  matchSize,
1283
+ measureBetween,
1284
+ measureLabel,
1285
+ measureSelection2 as measureSelection,
1286
+ measureToLine,
1287
+ multiPolygonArea,
1288
+ multiPolygonBounds,
1060
1289
  nearestHandlePositions,
1061
1290
  oppositePosition,
1062
1291
  overlaps,
1063
1292
  parseCanvasClipboardData2 as parseCanvasClipboardData,
1064
1293
  parseCanvasScenes,
1294
+ parseSvgPath,
1065
1295
  placeBeside2 as placeBeside,
1296
+ pointInMultiPolygon,
1297
+ pointInRings,
1298
+ polygonArea,
1299
+ polygonBoolean,
1300
+ polygonToSvgPath,
1066
1301
  positionToSide,
1067
1302
  readStyleSize,
1068
1303
  realClock,
1069
1304
  remapPastedNodes2 as remapPastedNodes,
1070
1305
  reorderNodes,
1071
1306
  repositionNodesTo,
1307
+ resizeHandleAxes,
1308
+ revertShapeCombination,
1309
+ ringSignedArea,
1072
1310
  runMultiNodeTransition2 as runMultiNodeTransition,
1073
1311
  serializeCanvasNodes2 as serializeCanvasNodes,
1312
+ shapeNodeToPolygon,
1313
+ shapeToPolygon,
1074
1314
  sideToPosition,
1315
+ simplifyRing,
1075
1316
  snapNodeDrag,
1317
+ snapNodeResize,
1318
+ snapResize,
1319
+ snapToGrid,
1320
+ subtractPolygons,
1076
1321
  toggleLockNodes,
1322
+ unionPolygons,
1077
1323
  unlockNodes,
1078
1324
  useCanvasArrange,
1079
1325
  useCanvasArrangeShortcuts,
@@ -1082,9 +1328,11 @@ export {
1082
1328
  useCanvasExplosion,
1083
1329
  useCanvasGraph,
1084
1330
  useCanvasLayout,
1331
+ useCanvasMeasure,
1085
1332
  useCanvasScenes,
1086
1333
  useCanvasShortcuts,
1087
1334
  useStreamingCanvas,
1088
- withStyleSize
1335
+ withStyleSize,
1336
+ xorPolygons
1089
1337
  };
1090
1338
  //# sourceMappingURL=index.js.map