@pixerate/editor 0.21.0 → 0.22.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 (70) hide show
  1. package/README.md +20 -11
  2. package/dist/agent/index.cjs +8 -8
  3. package/dist/agent/index.d.cts +2 -2
  4. package/dist/agent/index.d.ts +2 -2
  5. package/dist/agent/index.js +2 -2
  6. package/dist/canvas/index.cjs +1269 -13
  7. package/dist/canvas/index.cjs.map +1 -1
  8. package/dist/canvas/index.d.cts +432 -6
  9. package/dist/canvas/index.d.ts +432 -6
  10. package/dist/canvas/index.js +1264 -8
  11. package/dist/canvas/index.js.map +1 -1
  12. package/dist/{chunk-U6NDQFOK.cjs → chunk-6M3BCTBD.cjs} +427 -138
  13. package/dist/chunk-6M3BCTBD.cjs.map +1 -0
  14. package/dist/{chunk-TVRC4KVT.cjs → chunk-AA4ZEVCC.cjs} +845 -90
  15. package/dist/chunk-AA4ZEVCC.cjs.map +1 -0
  16. package/dist/{chunk-LA7PEGU3.cjs → chunk-CL37JGFW.cjs} +4 -4
  17. package/dist/{chunk-LA7PEGU3.cjs.map → chunk-CL37JGFW.cjs.map} +1 -1
  18. package/dist/{chunk-A7DKIA72.js → chunk-DENSCKFC.js} +642 -69
  19. package/dist/chunk-DENSCKFC.js.map +1 -0
  20. package/dist/{chunk-4QPLEUL2.cjs → chunk-GVSMRPHB.cjs} +1046 -54
  21. package/dist/chunk-GVSMRPHB.cjs.map +1 -0
  22. package/dist/{chunk-KYRZDWM4.js → chunk-JJDLPEWL.js} +2 -2
  23. package/dist/{chunk-3TYMNULT.js → chunk-MJZBNWG7.js} +807 -52
  24. package/dist/chunk-MJZBNWG7.js.map +1 -0
  25. package/dist/{chunk-CYFJCKC4.js → chunk-QGHGJ56O.js} +997 -5
  26. package/dist/chunk-QGHGJ56O.js.map +1 -0
  27. package/dist/{chunk-GVW4P7BG.js → chunk-RU52I7QO.js} +305 -16
  28. package/dist/chunk-RU52I7QO.js.map +1 -0
  29. package/dist/{chunk-JYRIOFEN.cjs → chunk-SAZRENEZ.cjs} +647 -74
  30. package/dist/chunk-SAZRENEZ.cjs.map +1 -0
  31. package/dist/{controller-OUdxPY-X.d.ts → controller-B7GIybc4.d.cts} +139 -7
  32. package/dist/{controller-OUdxPY-X.d.cts → controller-B7GIybc4.d.ts} +139 -7
  33. package/dist/extensions/index.cjs +14 -4
  34. package/dist/extensions/index.cjs.map +1 -1
  35. package/dist/extensions/index.d.cts +3 -3
  36. package/dist/extensions/index.d.ts +3 -3
  37. package/dist/extensions/index.js +13 -3
  38. package/dist/{index-k3mFbPx_.d.cts → index-CCr_z9kF.d.cts} +3 -3
  39. package/dist/{index-Ng1pG7JE.d.ts → index-Ck6ajwXh.d.ts} +3 -3
  40. package/dist/index.cjs +250 -16
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +294 -8
  43. package/dist/index.d.ts +294 -8
  44. package/dist/index.js +241 -7
  45. package/dist/index.js.map +1 -1
  46. package/dist/{registry-iAHbqkYt.d.cts → registry-GJI4gToU.d.cts} +15 -4
  47. package/dist/{registry-iAHbqkYt.d.ts → registry-GJI4gToU.d.ts} +15 -4
  48. package/dist/serializers/index.cjs +3 -3
  49. package/dist/serializers/index.d.cts +1 -1
  50. package/dist/serializers/index.d.ts +1 -1
  51. package/dist/serializers/index.js +2 -2
  52. package/dist/spreadsheet/index.cjs +7 -3
  53. package/dist/spreadsheet/index.cjs.map +1 -1
  54. package/dist/spreadsheet/index.d.cts +33 -4
  55. package/dist/spreadsheet/index.d.ts +33 -4
  56. package/dist/spreadsheet/index.js +6 -2
  57. package/dist/{track-changes-G8JcWB8b.d.cts → track-changes-BSF58RK0.d.cts} +92 -9
  58. package/dist/{track-changes-G8JcWB8b.d.ts → track-changes-BSF58RK0.d.ts} +92 -9
  59. package/dist/{types-DMe0vFB1.d.cts → types-CJ4U-HHI.d.cts} +1 -1
  60. package/dist/{types-DMe0vFB1.d.ts → types-CJ4U-HHI.d.ts} +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-3TYMNULT.js.map +0 -1
  63. package/dist/chunk-4QPLEUL2.cjs.map +0 -1
  64. package/dist/chunk-A7DKIA72.js.map +0 -1
  65. package/dist/chunk-CYFJCKC4.js.map +0 -1
  66. package/dist/chunk-GVW4P7BG.js.map +0 -1
  67. package/dist/chunk-JYRIOFEN.cjs.map +0 -1
  68. package/dist/chunk-TVRC4KVT.cjs.map +0 -1
  69. package/dist/chunk-U6NDQFOK.cjs.map +0 -1
  70. /package/dist/{chunk-KYRZDWM4.js.map → chunk-JJDLPEWL.js.map} +0 -0
@@ -1,5 +1,5 @@
1
- import { R as Rect, C as CanvasNode, X as XYPosition, a as CanvasEdge, I as IncrementalLayoutOptions, S as Side, b as CanvasLayoutOptions, P as PlaceBesideOptions, T as TrajectoryFunction, F as FanOutTrajectoryOptions, N as NodeTransition, c as CanvasNodeStyle, d as ReflowDisplacementOptions, D as DirectionalDisplacementOptions, e as CanvasClipboardPayload, f as Position } from '../types-DMe0vFB1.js';
2
- export { g as CanvasDockingCallbacks, h as CollapseNodeOptions, i as DisplacementDirection, j as DockStrategy, E as ExplodeNodeOptions, k as ExplosionSnapshot, G as GraphDifferences, l as Point, m as TrajectoryPoint } from '../types-DMe0vFB1.js';
1
+ import { R as Rect, C as CanvasNode, X as XYPosition, a as CanvasEdge, I as IncrementalLayoutOptions, S as Side, b as CanvasLayoutOptions, P as PlaceBesideOptions, T as TrajectoryFunction, F as FanOutTrajectoryOptions, N as NodeTransition, c as CanvasNodeStyle, d as ReflowDisplacementOptions, D as DirectionalDisplacementOptions, e as CanvasClipboardPayload, f as Position, g as Point } from '../types-CJ4U-HHI.js';
2
+ export { h as CanvasDockingCallbacks, i as CollapseNodeOptions, j as DisplacementDirection, k as DockStrategy, E as ExplodeNodeOptions, l as ExplosionSnapshot, G as GraphDifferences, m as TrajectoryPoint } from '../types-CJ4U-HHI.js';
3
3
  import { C as Command } from '../types-BZgcDsC5.js';
4
4
 
5
5
  declare const DEFAULT_NODE_WIDTH = 200;
@@ -765,6 +765,410 @@ declare const DEFAULT_ARRANGE_SHORTCUTS: readonly ArrangeShortcutBinding[];
765
765
  */
766
766
  declare function matchArrangeShortcut(event: KeyboardEvent, bindings?: readonly ArrangeShortcutBinding[]): CanvasArrangeAction | null;
767
767
 
768
+ /**
769
+ * Polygon boolean operations (union, intersection, difference, xor and divide) on
770
+ * multi-polygons with holes.
771
+ *
772
+ * Algorithm (overlay + winding classification):
773
+ * 1. Every input edge is collected into one segment set. Vertices are merged through a
774
+ * tolerance-aware point pool, so points closer than `epsilon` become one vertex.
775
+ * 2. Segments are split at every crossing, T-junction and collinear overlap until no two
776
+ * segments cross (a planar arrangement). Splitting is repeated because snapping a new
777
+ * vertex can move a segment by up to `epsilon`.
778
+ * 3. Coincident segments (shared edges) are merged, keeping for every operand the signed
779
+ * number of its edges that run along the segment.
780
+ * 4. For every segment the winding number of each operand on its right side is computed
781
+ * with a ray cast from the segment midpoint (the segment itself excluded), and the left
782
+ * side follows from the signed multiplicities. The fill rule turns windings into
783
+ * inside / outside flags and the operation decides whether each side is in the result.
784
+ * 5. Segments with the result on exactly one side are kept, oriented with the result on
785
+ * their left, and traced into rings (taking the sharpest left turn at shared vertices,
786
+ * so rings that touch at a vertex stay separate simple rings). Rings with a positive
787
+ * signed area are outer rings; negative ones are holes, assigned to the smallest outer
788
+ * ring that contains them.
789
+ *
790
+ * Handles shared edges, touching vertices, collinear overlaps, holes, nested and disjoint
791
+ * inputs and self-intersecting input rings (resolved by the operand's fill rule).
792
+ *
793
+ * Limits: the overlay is O(n²) in the number of edges (pruned by a sweep on x), which is
794
+ * comfortable for canvas shapes (thousands of edges) but not for GIS-scale data. Features
795
+ * narrower than `epsilon` collapse. Coordinates must be finite.
796
+ */
797
+
798
+ /** A closed ring of points. The closing point may be repeated or omitted. */
799
+ type PolygonRing = Point[];
800
+ /** A polygon: the outer ring followed by its holes. */
801
+ type PolygonWithHoles = PolygonRing[];
802
+ /** A set of polygons. */
803
+ type MultiPolygon = PolygonWithHoles[];
804
+ /** SVG fill rule used to decide which areas of a ring set are inside. */
805
+ type PolygonFillRule = 'nonzero' | 'evenodd';
806
+ /** Boolean operations. `xor` is Freeform's Exclude. */
807
+ type PolygonBooleanOperation = 'union' | 'intersection' | 'difference' | 'xor';
808
+ /**
809
+ * A raw ring set with a fill rule (e.g. flattened SVG path data). Ring orientation is
810
+ * significant for `nonzero`.
811
+ */
812
+ interface PolygonOperand {
813
+ rings: PolygonRing[];
814
+ fillRule?: PolygonFillRule;
815
+ }
816
+ type PolygonInput = MultiPolygon | PolygonOperand;
817
+ interface PolygonBooleanOptions {
818
+ /**
819
+ * Distance below which points are treated as equal. Defaults to `1e-9` times the
820
+ * largest coordinate magnitude of the inputs (at least `1e-9`).
821
+ */
822
+ epsilon?: number;
823
+ }
824
+ /** One region of `dividePolygons`, with the indices of the operands that cover it. */
825
+ interface PolygonPiece {
826
+ polygon: PolygonWithHoles;
827
+ operands: number[];
828
+ }
829
+ /** Signed shoelace area of a ring (positive when counter-clockwise in a y-up frame). */
830
+ declare function ringSignedArea(ring: readonly Point[]): number;
831
+ /** Area of a polygon (outer ring minus holes). */
832
+ declare function polygonArea(polygon: PolygonWithHoles): number;
833
+ /** Total area of a multi-polygon (holes subtracted). */
834
+ declare function multiPolygonArea(multi: MultiPolygon): number;
835
+ /** Axis-aligned bounds of a multi-polygon (or ring list), or `null` when empty. */
836
+ declare function multiPolygonBounds(input: MultiPolygon | PolygonRing[]): {
837
+ minX: number;
838
+ minY: number;
839
+ maxX: number;
840
+ maxY: number;
841
+ } | null;
842
+ /**
843
+ * Whether a point is inside a ring set under a fill rule. Points exactly on an edge may
844
+ * report either side.
845
+ */
846
+ declare function pointInRings(point: Point, rings: readonly (readonly Point[])[], fillRule?: PolygonFillRule): boolean;
847
+ /** Whether a point is inside a multi-polygon (holes excluded). */
848
+ declare function pointInMultiPolygon(point: Point, multi: MultiPolygon): boolean;
849
+ /**
850
+ * Applies a boolean operation to any number of operands.
851
+ * - `union`: covered by any operand.
852
+ * - `intersection`: covered by every operand.
853
+ * - `difference`: the first operand minus all others.
854
+ * - `xor`: covered by an odd number of operands (Exclude).
855
+ *
856
+ * Returns simple rings: outer rings have a positive signed area, holes a negative one.
857
+ * Rings may touch at vertices but never cross.
858
+ */
859
+ declare function polygonBoolean(operation: PolygonBooleanOperation, operands: PolygonInput[], options?: PolygonBooleanOptions): MultiPolygon;
860
+ declare const unionPolygons: (a: PolygonInput, b: PolygonInput, options?: PolygonBooleanOptions) => MultiPolygon;
861
+ declare const intersectPolygons: (a: PolygonInput, b: PolygonInput, options?: PolygonBooleanOptions) => MultiPolygon;
862
+ declare const subtractPolygons: (a: PolygonInput, b: PolygonInput, options?: PolygonBooleanOptions) => MultiPolygon;
863
+ declare const xorPolygons: (a: PolygonInput, b: PolygonInput, options?: PolygonBooleanOptions) => MultiPolygon;
864
+ /**
865
+ * Splits the overlay of the operands into its distinct regions (Freeform's Divide): every
866
+ * connected area covered by the same set of operands becomes one piece. Pieces are ordered
867
+ * by their operand set, then by size (largest first).
868
+ */
869
+ declare function dividePolygons(operands: PolygonInput[], options?: PolygonBooleanOptions): PolygonPiece[];
870
+
871
+ /**
872
+ * Shape geometry: shape descriptions (rect, rounded rect, ellipse, regular polygon, star and
873
+ * SVG path data) to polygons, SVG path parsing / flattening, and polygons back to path data.
874
+ */
875
+
876
+ /** Paint shared by every shape kind. Colours are any CSS colour. */
877
+ interface ShapePaint {
878
+ fill?: string;
879
+ stroke?: string;
880
+ strokeWidth?: number;
881
+ opacity?: number;
882
+ }
883
+ interface ShapeBase extends ShapePaint {
884
+ /** Clockwise rotation in degrees (on a y-down canvas) about the centre of the node box. */
885
+ rotation?: number;
886
+ }
887
+ /** Rectangle filling the node box, optionally with rounded corners. */
888
+ interface RectShape extends ShapeBase {
889
+ kind: 'rect';
890
+ /** One radius, or `[topLeft, topRight, bottomRight, bottomLeft]`. Clamped to fit. */
891
+ cornerRadius?: number | readonly [number, number, number, number];
892
+ }
893
+ /** Ellipse (circle when the node is square) inscribed in the node box. */
894
+ interface EllipseShape extends ShapeBase {
895
+ kind: 'ellipse';
896
+ }
897
+ /** Regular polygon, stretched so its bounding box fills the node box. */
898
+ interface RegularPolygonShape extends ShapeBase {
899
+ kind: 'polygon';
900
+ /** Number of sides (at least 3, default 6). The first vertex points up. */
901
+ sides?: number;
902
+ }
903
+ /** Star, stretched so its bounding box fills the node box. */
904
+ interface StarShape extends ShapeBase {
905
+ kind: 'star';
906
+ /** Number of points (at least 3, default 5). The first point points up. */
907
+ points?: number;
908
+ /** Inner radius as a fraction of the outer radius (default 0.5). */
909
+ innerRadius?: number;
910
+ }
911
+ /** Arbitrary SVG path data. */
912
+ interface PathShape extends ShapeBase {
913
+ kind: 'path';
914
+ d: string;
915
+ /**
916
+ * `[minX, minY, width, height]` of the path's coordinate space, scaled to the node box.
917
+ * Without it the path coordinates are node-local pixels.
918
+ */
919
+ viewBox?: readonly [number, number, number, number];
920
+ /** Fill rule (default `nonzero`, as in SVG). */
921
+ fillRule?: PolygonFillRule;
922
+ }
923
+ /**
924
+ * Shape description stored on a node as `data.shape`. Geometry is relative to the node
925
+ * box (`0,0` to `width,height`), so resizing the node resizes the shape.
926
+ */
927
+ type ShapeDescription = RectShape | EllipseShape | RegularPolygonShape | StarShape | PathShape;
928
+ type ShapeKind = ShapeDescription['kind'];
929
+ declare const SHAPE_KINDS: readonly ShapeKind[];
930
+ /** Whether a value is a supported shape description. */
931
+ declare function isShapeDescription(value: unknown): value is ShapeDescription;
932
+ interface ShapeSize {
933
+ width: number;
934
+ height: number;
935
+ }
936
+ interface FlattenOptions {
937
+ /** Maximum distance between a curve and its polyline, in output units (default 0.25). */
938
+ tolerance?: number;
939
+ /** Upper bound on the segments one curve is split into (default 512). */
940
+ maxSegments?: number;
941
+ }
942
+ /** Normalised absolute path command produced by `parseSvgPath`. */
943
+ type PathCommand = {
944
+ type: 'M';
945
+ x: number;
946
+ y: number;
947
+ } | {
948
+ type: 'L';
949
+ x: number;
950
+ y: number;
951
+ } | {
952
+ type: 'C';
953
+ x1: number;
954
+ y1: number;
955
+ x2: number;
956
+ y2: number;
957
+ x: number;
958
+ y: number;
959
+ } | {
960
+ type: 'Q';
961
+ x1: number;
962
+ y1: number;
963
+ x: number;
964
+ y: number;
965
+ } | {
966
+ type: 'A';
967
+ rx: number;
968
+ ry: number;
969
+ rotation: number;
970
+ largeArc: boolean;
971
+ sweep: boolean;
972
+ x: number;
973
+ y: number;
974
+ } | {
975
+ type: 'Z';
976
+ };
977
+ /**
978
+ * Parses SVG path data into absolute `M`, `L`, `C`, `Q`, `A` and `Z` commands. Relative
979
+ * commands, `H` / `V`, smooth curves (`S` / `T`) and implicit repeated commands are
980
+ * normalised. Parsing stops at the first malformed command (as browsers do).
981
+ */
982
+ declare function parseSvgPath(d: string): PathCommand[];
983
+ /**
984
+ * Flattens SVG path data into closed rings (one per subpath; open subpaths are closed the
985
+ * way SVG fills them). Curves are approximated within `tolerance`.
986
+ */
987
+ declare function flattenSvgPath(d: string | PathCommand[], options?: FlattenOptions): PolygonRing[];
988
+ /**
989
+ * SVG path data for a shape in node-local pixels (exact curves: arcs for rounded corners
990
+ * and ellipses), plus the fill rule and a `transform` for rotation / path view boxes.
991
+ * Use it to render a shape; use `shapeToPolygon` for geometry.
992
+ */
993
+ declare function getShapeSvg(shape: ShapeDescription, size: ShapeSize): {
994
+ d: string;
995
+ transform?: string;
996
+ fillRule: PolygonFillRule;
997
+ };
998
+ /** Everything a renderer needs to draw a shape as one SVG `<path>`. */
999
+ interface ShapeRenderData {
1000
+ /** SVG `viewBox` (`0 0 width height`): node-local pixels. */
1001
+ viewBox: string;
1002
+ width: number;
1003
+ height: number;
1004
+ d: string;
1005
+ transform?: string;
1006
+ fillRule: PolygonFillRule;
1007
+ fill: string;
1008
+ stroke: string;
1009
+ strokeWidth: number;
1010
+ opacity?: number;
1011
+ }
1012
+ /**
1013
+ * Resolves the SVG drawing of a shape for a node size. Without a size, a path's view box
1014
+ * size (or 100x100) is used. Paint defaults: `fill: currentColor`, `stroke: none`,
1015
+ * `strokeWidth: 1`.
1016
+ */
1017
+ declare function getShapeRenderData(shape: ShapeDescription, size?: Partial<ShapeSize>): ShapeRenderData;
1018
+ /**
1019
+ * Converts a shape to rings in node-local pixels (rotation applied), flattening curves at
1020
+ * `tolerance`. Returns the rings with the fill rule they must be read with.
1021
+ */
1022
+ declare function shapeToPolygon(shape: ShapeDescription, size: ShapeSize, options?: FlattenOptions): {
1023
+ rings: PolygonRing[];
1024
+ fillRule: PolygonFillRule;
1025
+ };
1026
+ /** Formats a number with at most `precision` decimals, without trailing zeros. */
1027
+ declare function formatNumber(value: number, precision?: number): string;
1028
+ /**
1029
+ * Simplifies a closed ring with Ramer–Douglas–Peucker at `tolerance`. Returns an empty
1030
+ * ring when fewer than three points survive.
1031
+ */
1032
+ declare function simplifyRing(ring: readonly Point[], tolerance: number): Point[];
1033
+ interface PolygonToPathOptions {
1034
+ /** Decimal places in the output (default 3). */
1035
+ precision?: number;
1036
+ /** Ramer–Douglas–Peucker tolerance; `0` (default) keeps every vertex. */
1037
+ simplify?: number;
1038
+ /** Added to every point before formatting (e.g. to make coordinates node-local). */
1039
+ offset?: {
1040
+ x: number;
1041
+ y: number;
1042
+ };
1043
+ }
1044
+ /**
1045
+ * Converts a multi-polygon (or a list of rings) to SVG path data using `M`/`L`/`Z`. Holes
1046
+ * keep their opposite orientation, so the path fills correctly with either fill rule.
1047
+ */
1048
+ declare function polygonToSvgPath(input: MultiPolygon | PolygonRing[], options?: PolygonToPathOptions): string;
1049
+
1050
+ /**
1051
+ * Shape nodes and Freeform-style shape boolean operations (Unite / Intersect / Subtract /
1052
+ * Exclude / Divide) on canvas nodes.
1053
+ *
1054
+ * A shape node is any node whose `data.shape` is a `ShapeDescription`. Its geometry is
1055
+ * relative to the node box, so moving or resizing the node moves / resizes the shape.
1056
+ */
1057
+
1058
+ /** Data key holding a node's shape description. */
1059
+ declare const SHAPE_DATA_KEY = "shape";
1060
+ /** Node type suggested for shape nodes (register `ShapeNode` under it). */
1061
+ declare const SHAPE_NODE_TYPE = "shape";
1062
+ /** Freeform's shape operations. `exclude` is xor; `divide` splits into every region. */
1063
+ type ShapeOperation = 'unite' | 'intersect' | 'subtract' | 'exclude' | 'divide';
1064
+ declare const SHAPE_OPERATIONS: readonly ShapeOperation[];
1065
+ /** Whether a node carries a supported `data.shape`. */
1066
+ declare function isShapeNode(node: CanvasNode | undefined | null): boolean;
1067
+ /** The node's shape description, or `null`. */
1068
+ declare function getNodeShape(node: CanvasNode | undefined | null): ShapeDescription | null;
1069
+ interface ShapeNodePolygonOptions extends NodeRectOptions {
1070
+ /** Curve flattening tolerance in flow units (default 0.25). */
1071
+ tolerance?: number;
1072
+ }
1073
+ /**
1074
+ * A shape node's outline in absolute flow coordinates (parent offsets, size and rotation
1075
+ * applied), or `null` for non-shape nodes.
1076
+ */
1077
+ declare function shapeNodeToPolygon(node: CanvasNode, lookup?: ReadonlyMap<string, CanvasNode>, options?: ShapeNodePolygonOptions): {
1078
+ rings: PolygonRing[];
1079
+ fillRule: PolygonFillRule;
1080
+ } | null;
1081
+ /** Why `combineShapeNodes` refused. */
1082
+ type CombineShapeNodesRefusal =
1083
+ /** A selected shape is locked; locked shapes are never consumed. */
1084
+ 'locked'
1085
+ /** Fewer than two shape nodes were selected. */
1086
+ | 'too-few'
1087
+ /** The operation leaves nothing (e.g. intersecting shapes that do not overlap). */
1088
+ | 'empty';
1089
+ interface CombineShapeNodesOptions extends ShapeNodePolygonOptions {
1090
+ /**
1091
+ * Which shape's node style and data the result inherits: `bottom` (default, like
1092
+ * Freeform: the back-most shape), `top`, `first` (first id passed), or a node id.
1093
+ * Divide pieces always take the style of the top-most shape covering them.
1094
+ */
1095
+ styleFrom?: 'bottom' | 'top' | 'first' | {
1096
+ id: string;
1097
+ };
1098
+ /** Id factory for new nodes (default `crypto.randomUUID`, with a counter fallback). */
1099
+ createId?: (index: number) => string;
1100
+ /** Node `type` for the new nodes (default: the style source's type). */
1101
+ nodeType?: string;
1102
+ /** Decimal places in the path data (default 3). */
1103
+ precision?: number;
1104
+ /** Ramer–Douglas–Peucker simplification tolerance for the result (default 0, off). */
1105
+ simplify?: number;
1106
+ /** Point-merge tolerance passed to the boolean engine. */
1107
+ epsilon?: number;
1108
+ /** Select the new nodes (default `true`). */
1109
+ select?: boolean;
1110
+ }
1111
+ type CombineShapeNodesResult<TNode extends CanvasNode = CanvasNode> = {
1112
+ ok: true;
1113
+ operation: ShapeOperation;
1114
+ /** Ids of the shape nodes consumed by the operation. */
1115
+ removeIds: string[];
1116
+ /** New path shape node(s): one, or one per region for `divide`. */
1117
+ nodes: TNode[];
1118
+ } | {
1119
+ ok: false;
1120
+ operation: ShapeOperation;
1121
+ reason: CombineShapeNodesRefusal;
1122
+ };
1123
+ /**
1124
+ * Checks whether `combineShapeNodes` can run, without computing geometry (it cannot
1125
+ * predict an `empty` result). Use it to enable menu items.
1126
+ */
1127
+ declare function canCombineShapeNodes(nodes: CanvasNode[], ids: Iterable<string>): {
1128
+ ok: true;
1129
+ shapeIds: string[];
1130
+ } | {
1131
+ ok: false;
1132
+ reason: Exclude<CombineShapeNodesRefusal, 'empty'>;
1133
+ };
1134
+ /**
1135
+ * Freeform-style shape operations on canvas nodes.
1136
+ *
1137
+ * - Only shape nodes (`data.shape`) among `ids` take part; other selected nodes are ignored.
1138
+ * - Refuses (`ok: false`) when a selected shape is locked, when fewer than two shapes are
1139
+ * selected, or when the result is empty. Nothing should be changed on refusal.
1140
+ * - `subtract` removes every other shape from the back-most one; the other operations are
1141
+ * symmetric. `divide` returns one node per distinct region of the overlay.
1142
+ * - Each new node is a `path` shape: its position / size is the result's bounding box and
1143
+ * its path data is node-local with `viewBox = [0, 0, width, height]`, so it scales with
1144
+ * the node. Rotation is baked into the path. Node fields and `data` (other than the
1145
+ * shape geometry, lock state and size) come from the style source.
1146
+ * - When all shapes share a parent, the new nodes keep it; otherwise they are top-level.
1147
+ *
1148
+ * Pure: returns the change; apply it with `applyShapeCombination` (or the arrange
1149
+ * controller's `combineShapes`, which also records one undo step).
1150
+ */
1151
+ declare function combineShapeNodes<TNode extends CanvasNode>(nodes: TNode[], ids: Iterable<string>, operation: ShapeOperation, options?: CombineShapeNodesOptions): CombineShapeNodesResult<TNode>;
1152
+ /**
1153
+ * Applies a successful `combineShapeNodes` result: removes the consumed nodes and inserts
1154
+ * the new ones at the array index of the first consumed node.
1155
+ * With `deselect` (default `true`) other nodes are deselected when the result is selected.
1156
+ */
1157
+ declare function applyShapeCombination<TNode extends CanvasNode>(nodes: TNode[], change: {
1158
+ removeIds: Iterable<string>;
1159
+ nodes: TNode[];
1160
+ }, options?: {
1161
+ deselect?: boolean;
1162
+ }): TNode[];
1163
+ /**
1164
+ * Reverses `applyShapeCombination`: removes the created nodes and puts the consumed nodes
1165
+ * back at their original array indices (`previous` is the node array before the change).
1166
+ */
1167
+ declare function revertShapeCombination<TNode extends CanvasNode>(nodes: TNode[], change: {
1168
+ removeIds: Iterable<string>;
1169
+ nodes: TNode[];
1170
+ }, previous: TNode[]): TNode[];
1171
+
768
1172
  /** Minimal history surface (`HistoryManager` satisfies it). */
769
1173
  interface ArrangeHistoryTarget {
770
1174
  execute(command: Command): void;
@@ -787,10 +1191,14 @@ interface CanvasArrangeControllerOptions<TNode extends CanvasNode = CanvasNode>
787
1191
  /** Called whenever the guide segments change (set while dragging, cleared on drop). */
788
1192
  onGuidesChange?: (guides: GuideLine[]) => void;
789
1193
  }
790
- /** A React Flow / SvelteFlow style node change; only `position` changes are inspected. */
1194
+ /**
1195
+ * A React Flow / SvelteFlow style node change; only `position` changes are inspected.
1196
+ * `id` is optional because a batch can contain changes without one (React Flow's
1197
+ * `add` change carries an `item` instead), so `NodeChange[]` must be accepted as is.
1198
+ */
791
1199
  interface PositionChangeLike {
792
1200
  type: string;
793
- id: string;
1201
+ id?: string;
794
1202
  position?: XYPosition;
795
1203
  dragging?: boolean;
796
1204
  [key: string]: any;
@@ -815,6 +1223,20 @@ declare function createCanvasArrangeController<TNode extends CanvasNode = Canvas
815
1223
  unlock: (ids?: Iterable<string>) => string[];
816
1224
  toggleLock(ids?: Iterable<string>): string[];
817
1225
  isLocked: (id: string) => boolean;
1226
+ /**
1227
+ * Freeform shape operation (Unite / Intersect / Subtract / Exclude / Divide) on the
1228
+ * shape nodes among `ids` (default: the selection). Replaces them with the result as
1229
+ * one undoable step. Refuses without changing anything when a selected shape is
1230
+ * locked, fewer than two shapes are selected, or the result is empty.
1231
+ */
1232
+ combineShapes(operation: ShapeOperation, ids?: Iterable<string>, combineOptions?: CombineShapeNodesOptions): CombineShapeNodesResult<TNode>;
1233
+ unite: (ids?: Iterable<string>, o?: CombineShapeNodesOptions) => CombineShapeNodesResult<TNode>;
1234
+ intersect: (ids?: Iterable<string>, o?: CombineShapeNodesOptions) => CombineShapeNodesResult<TNode>;
1235
+ subtract: (ids?: Iterable<string>, o?: CombineShapeNodesOptions) => CombineShapeNodesResult<TNode>;
1236
+ exclude: (ids?: Iterable<string>, o?: CombineShapeNodesOptions) => CombineShapeNodesResult<TNode>;
1237
+ divide: (ids?: Iterable<string>, o?: CombineShapeNodesOptions) => CombineShapeNodesResult<TNode>;
1238
+ /** Whether the shape operations can run on `ids` (default: the selection). */
1239
+ canCombineShapes: (ids?: Iterable<string>) => boolean;
818
1240
  /**
819
1241
  * Runs a shortcut action. Scene actions are not handled here (see the scenes store);
820
1242
  * returns `false` for them and for unknown actions.
@@ -834,9 +1256,13 @@ declare function createCanvasArrangeController<TNode extends CanvasNode = Canvas
834
1256
  * A batch without a dragging position change ends the drag and clears the guides.
835
1257
  */
836
1258
  snapPositionChanges<TChange extends PositionChangeLike>(changes: TChange[]): TChange[];
837
- /** Clears guides and the cached snap targets. */
1259
+ /**
1260
+ * Clears guides and the cached snap targets. Call it from the flow's drag-stop
1261
+ * handler: flow libraries write the raw pointer position when a drag ends, so the
1262
+ * last snapped positions from `drag` are written back here.
1263
+ */
838
1264
  endDrag(): void;
839
1265
  };
840
1266
  type CanvasArrangeController<TNode extends CanvasNode = CanvasNode> = ReturnType<typeof createCanvasArrangeController<TNode>>;
841
1267
 
842
- export { type AlignEdge, type AlignNodesOptions, type ArrangeHistoryTarget, type ArrangeShortcutBinding, CONNECTION_LINE_TYPES, type CanvasArrangeAction, type CanvasArrangeController, type CanvasArrangeControllerOptions, CanvasClipboardPayload, type CanvasConnectionLineType, CanvasEdge, type CanvasHeightOptions, CanvasLayoutOptions, CanvasNode, CanvasNodeStyle, type CanvasNodeUpdate, type CanvasScene, type CanvasScenesOptions, type CanvasScenesState, CanvasScenesStore, type CanvasViewport, type Clock, type ConnectorSnap, type ConnectorSnapOptions, type ConnectorSnapTarget, DEFAULT_ARRANGE_SHORTCUTS, DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH, DEFAULT_PLACEMENT_GAP, DirectionalDisplacementOptions, type DistributeAxis, type DistributeMode, type DistributeNodesOptions, FanOutTrajectoryOptions, type FitViewportOptions, type GuideIndex, type GuideLine, IncrementalLayoutOptions, LOCKED_DATA_KEY, LOCKED_PREVIOUS_FLAGS_KEY, ManualClock, type MatchSizeOptions, type MultiNodeTransitionOptions, type NodeRectOptions, NodeTransition, PlaceBesideOptions, Position, type PositionChangeLike, Rect, ReflowDisplacementOptions, type SerializedCanvasScenes, Side, type SizeDimension, type SnapGuidesOptions, type SnapNodeDragOptions, type SnapNodeDragResult, type SnapResult, StreamingLayoutManager, type StreamingLayoutManagerOptions, TrajectoryFunction, XYPosition, type ZOrderOperation, alignNodes, applyNodeUpdates, blendLayout, boundsOf, calculateDagreReflowDisplacement, calculateDirectionalDisplacement, canvasHeight, centerNodes, centre, collectDescendantIds, computeNodesBoundingBox, computeSnapGuides, connectedOnly, createBezierTrajectory, createCanvasArrangeController, createCanvasScenesStore, createFanOutTrajectory, createGuideIndex, createNodeGuideIndex, createNodeLookup, defaultEasing, distributeNodes, ensureLayout, estimateCanvasHeight, estimateNodeSize, findConnectorSnap, fitViewportToNodes, fitViewportToRect, flowSide, getAbsolutePosition, getCenteredNodePosition, getLayoutedNodes, getNodeRect, getNodeSize, handlePoint, invertNodeUpdates, isEventFromTextInput, isLocked, isValidCanvasEdge, isValidCanvasNode, isValidCanvasScene, isValidUrl, layoutBounds, linearPositionTrajectory, linearTrajectory, lockNodes, matchArrangeShortcut, matchSize, nearestHandlePositions, oppositePosition, overlaps, pageHidden, parseCanvasClipboardData, parseCanvasScenes, placeBeside, positionToSide, readStyleSize, realClock, remapPastedNodes, reorderNodes, repositionNodesTo, runMultiNodeTransition, serializeCanvasNodes, sideToPosition, snapNodeDrag, toggleLockNodes, unlockNodes, withStyleOpacity, withStyleSize };
1268
+ export { type AlignEdge, type AlignNodesOptions, type ArrangeHistoryTarget, type ArrangeShortcutBinding, CONNECTION_LINE_TYPES, type CanvasArrangeAction, type CanvasArrangeController, type CanvasArrangeControllerOptions, CanvasClipboardPayload, type CanvasConnectionLineType, CanvasEdge, type CanvasHeightOptions, CanvasLayoutOptions, CanvasNode, CanvasNodeStyle, type CanvasNodeUpdate, type CanvasScene, type CanvasScenesOptions, type CanvasScenesState, CanvasScenesStore, type CanvasViewport, type Clock, type CombineShapeNodesOptions, type CombineShapeNodesRefusal, type CombineShapeNodesResult, type ConnectorSnap, type ConnectorSnapOptions, type ConnectorSnapTarget, DEFAULT_ARRANGE_SHORTCUTS, DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH, DEFAULT_PLACEMENT_GAP, DirectionalDisplacementOptions, type DistributeAxis, type DistributeMode, type DistributeNodesOptions, type EllipseShape, FanOutTrajectoryOptions, type FitViewportOptions, type FlattenOptions, type GuideIndex, type GuideLine, IncrementalLayoutOptions, LOCKED_DATA_KEY, LOCKED_PREVIOUS_FLAGS_KEY, ManualClock, type MatchSizeOptions, type MultiNodeTransitionOptions, type MultiPolygon, type NodeRectOptions, NodeTransition, type PathCommand, type PathShape, PlaceBesideOptions, Point, type PolygonBooleanOperation, type PolygonBooleanOptions, type PolygonFillRule, type PolygonInput, type PolygonOperand, type PolygonPiece, type PolygonRing, type PolygonToPathOptions, type PolygonWithHoles, Position, type PositionChangeLike, Rect, type RectShape, ReflowDisplacementOptions, type RegularPolygonShape, SHAPE_DATA_KEY, SHAPE_KINDS, SHAPE_NODE_TYPE, SHAPE_OPERATIONS, type SerializedCanvasScenes, type ShapeDescription, type ShapeKind, type ShapeNodePolygonOptions, type ShapeOperation, type ShapePaint, type ShapeRenderData, type ShapeSize, Side, type SizeDimension, type SnapGuidesOptions, type SnapNodeDragOptions, type SnapNodeDragResult, type SnapResult, type StarShape, StreamingLayoutManager, type StreamingLayoutManagerOptions, TrajectoryFunction, XYPosition, type ZOrderOperation, alignNodes, applyNodeUpdates, applyShapeCombination, blendLayout, boundsOf, calculateDagreReflowDisplacement, calculateDirectionalDisplacement, canCombineShapeNodes, canvasHeight, centerNodes, centre, collectDescendantIds, combineShapeNodes, computeNodesBoundingBox, computeSnapGuides, connectedOnly, createBezierTrajectory, createCanvasArrangeController, createCanvasScenesStore, createFanOutTrajectory, createGuideIndex, createNodeGuideIndex, createNodeLookup, defaultEasing, distributeNodes, dividePolygons, ensureLayout, estimateCanvasHeight, estimateNodeSize, findConnectorSnap, fitViewportToNodes, fitViewportToRect, flattenSvgPath, flowSide, formatNumber, getAbsolutePosition, getCenteredNodePosition, getLayoutedNodes, getNodeRect, getNodeShape, getNodeSize, getShapeRenderData, getShapeSvg, handlePoint, intersectPolygons, invertNodeUpdates, isEventFromTextInput, isLocked, isShapeDescription, isShapeNode, isValidCanvasEdge, isValidCanvasNode, isValidCanvasScene, isValidUrl, layoutBounds, linearPositionTrajectory, linearTrajectory, lockNodes, matchArrangeShortcut, matchSize, multiPolygonArea, multiPolygonBounds, nearestHandlePositions, oppositePosition, overlaps, pageHidden, 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, withStyleOpacity, withStyleSize, xorPolygons };