orcasvn-react-diagrams 0.1.51 → 0.1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -484,7 +484,7 @@ function generateUniqueId() {
484
484
  }
485
485
 
486
486
  var Element$2 = /** @class */ (function () {
487
- function Element(x, y, width, height, cssClass, renderShape, texts, ports, portMovealeAreas, portSlideRailSVGClassName, portDirection, parentElement, textsPlaceHolderClassName, textsPlaceHolderFlexStyle, textsPlaceHolderFlexboxPosition) {
487
+ function Element(id, x, y, width, height, cssClass, renderShape, texts, ports, portMovealeAreas, portSlideRailSVGClassName, portDirection, parentElement, textsPlaceHolderClassName, textsPlaceHolderFlexStyle, textsPlaceHolderFlexboxPosition) {
488
488
  if (portMovealeAreas === void 0) { portMovealeAreas = []; }
489
489
  this.positionAnchor = exports.PositioningAnchor.TopLeft;
490
490
  this._childrenElements = [];
@@ -494,7 +494,7 @@ var Element$2 = /** @class */ (function () {
494
494
  };
495
495
  //internal properties
496
496
  this._eventEmitter = new EventEmitter();
497
- this._id = generateUniqueId();
497
+ this._id = id || generateUniqueId();
498
498
  this._position = { x: x, y: y };
499
499
  this._size = { width: width, height: height };
500
500
  this.cssClass = cssClass;
@@ -696,11 +696,11 @@ var CustomShape = React.forwardRef(function (props, ref) {
696
696
  });
697
697
 
698
698
  var Port$1 = /** @class */ (function () {
699
- function Port(x, y, label, shapeRenderer, width, height) {
699
+ function Port(id, x, y, label, shapeRenderer, width, height) {
700
700
  var _this = this;
701
701
  //internal properties
702
702
  this._eventEmitter = new EventEmitter();
703
- this._id = generateUniqueId();
703
+ this._id = id || generateUniqueId();
704
704
  this.position = { x: x, y: y };
705
705
  if (!height) {
706
706
  height = width;
@@ -731,8 +731,9 @@ var Port$1 = /** @class */ (function () {
731
731
  }());
732
732
 
733
733
  var ElementLink$1 = /** @class */ (function () {
734
- function ElementLink(sourceElement, sourcePort, targetElement, targetPort, tempTargetPosition, points, path, markerStart, markerEnd, markerDistanceFromPort, markerSize, label, sourceLabel, targetLabel) {
735
- this.id = generateUniqueId();
734
+ // constructor(id: string | null, sourceElement: IElement, sourcePort: IPort, targetElement: IElement, targetPort: IPort, tempTargetPosition: IPosition, points?: IPosition[]);
735
+ function ElementLink(id, sourceElement, sourcePort, targetElement, targetPort, tempTargetPosition, points, path, markerStart, markerEnd, markerDistanceFromPort, markerSize, label, sourceLabel, targetLabel) {
736
+ this.id = id || generateUniqueId();
736
737
  this.sourceElement = sourceElement;
737
738
  this.sourcePort = sourcePort;
738
739
  if (tempTargetPosition) {
@@ -769,8 +770,8 @@ var ElementLink$1 = /** @class */ (function () {
769
770
  }());
770
771
 
771
772
  var Text$2 = /** @class */ (function () {
772
- function Text(content, width, height, editable, x, y, align, fontSize, border, style) {
773
- this._id = generateUniqueId();
773
+ function Text(id, content, width, height, editable, selectable, x, y, align, fontSize, border, style) {
774
+ this._id = id || generateUniqueId();
774
775
  this.content = content;
775
776
  this.align = align;
776
777
  this.fontSize = fontSize;
@@ -778,6 +779,10 @@ var Text$2 = /** @class */ (function () {
778
779
  this.size = { width: width, height: height };
779
780
  this.style = style;
780
781
  this.editable = editable;
782
+ this.selectable = selectable;
783
+ if (selectable === undefined) {
784
+ this.selectable = true; // Default to true if not specified
785
+ }
781
786
  if (x && y) {
782
787
  this.position = { x: x, y: y };
783
788
  }
@@ -1710,9 +1715,9 @@ var paperEventEmitterContext = React.createContext({
1710
1715
  });
1711
1716
 
1712
1717
  var Text = React.forwardRef(function (_a, ref) {
1713
- var id = _a.id, content = _a.content, x = _a.x, y = _a.y, width = _a.width, height = _a.height, editable = _a.editable, _b = _a.align, align = _b === void 0 ? exports.TextAlign.left : _b, fontSizeProp = _a.fontSize, border = _a.border, container = _a.container, parentAbsolutePosition = _a.parentAbsolutePosition, onSelected = _a.onSelected, onMoved = _a.onMoved, onResized = _a.onResized, onContentChanged = _a.onContentChanged;
1714
- var _c = React.useState(false), isSelected = _c[0], setIsSelected = _c[1];
1715
- var _d = React.useState(false), isEditing = _d[0], setIsEditing = _d[1];
1718
+ var id = _a.id, content = _a.content, x = _a.x, y = _a.y, width = _a.width, height = _a.height, editable = _a.editable, _b = _a.selectable, selectable = _b === void 0 ? true : _b, _c = _a.align, align = _c === void 0 ? exports.TextAlign.left : _c, fontSizeProp = _a.fontSize, border = _a.border, container = _a.container, parentAbsolutePosition = _a.parentAbsolutePosition, onSelected = _a.onSelected, onMoved = _a.onMoved, onResized = _a.onResized, onContentChanged = _a.onContentChanged;
1719
+ var _d = React.useState(false), isSelected = _d[0], setIsSelected = _d[1];
1720
+ var _e = React.useState(false), isEditing = _e[0], setIsEditing = _e[1];
1716
1721
  var absolutePosition = React.useMemo(function () {
1717
1722
  var _a, _b;
1718
1723
  return {
@@ -1721,7 +1726,7 @@ var Text = React.forwardRef(function (_a, ref) {
1721
1726
  };
1722
1727
  }, [x, y, parentAbsolutePosition === null || parentAbsolutePosition === void 0 ? void 0 : parentAbsolutePosition.x, parentAbsolutePosition === null || parentAbsolutePosition === void 0 ? void 0 : parentAbsolutePosition.y]);
1723
1728
  var svgRef = React.useRef();
1724
- var _e = React.useContext(paperEventEmitterContext), onPaperClicked = _e.onPaperClicked, emitTextSelected = _e.emitTextSelected, onPortSelected = _e.onPortSelected, onElementSelected = _e.onElementSelected, onTextSelected = _e.onTextSelected;
1729
+ var _f = React.useContext(paperEventEmitterContext), onPaperClicked = _f.onPaperClicked, emitTextSelected = _f.emitTextSelected, onPortSelected = _f.onPortSelected, onElementSelected = _f.onElementSelected, onTextSelected = _f.onTextSelected;
1725
1730
  React.useEffect(function () {
1726
1731
  var paperClickListener = onPaperClicked(function (ev) {
1727
1732
  var _a;
@@ -1754,6 +1759,8 @@ var Text = React.forwardRef(function (_a, ref) {
1754
1759
  }, []);
1755
1760
  //Handle click on svg element
1756
1761
  var handleClick = function (ev) {
1762
+ if (!selectable)
1763
+ return;
1757
1764
  ev.stopPropagation();
1758
1765
  var position = {
1759
1766
  x: x,
@@ -7914,7 +7921,7 @@ var Port1 = React.forwardRef(function (props, ref) {
7914
7921
  var renderLabel = function (label) {
7915
7922
  var content = label.content, size = label.size;
7916
7923
  var position = label.position || PORT_LABEL_POSITION;
7917
- return React.createElement(Text$1, { id: label.id, ref: textRef, x: x + position.x, y: y + position.y, parentAbsolutePosition: parentAbsolutePosition, width: size.width, height: size.height, editable: label.editable, content: content, fontSize: label.fontSize, border: label.border, container: container, onMoved: function (xOnPaper, yOnPaper) {
7924
+ return React.createElement(Text$1, { id: label.id, ref: textRef, x: x + position.x, y: y + position.y, parentAbsolutePosition: parentAbsolutePosition, width: size.width, height: size.height, editable: label.editable, selectable: label.selectable, content: content, fontSize: label.fontSize, border: label.border, container: container, onMoved: function (xOnPaper, yOnPaper) {
7918
7925
  if (onPortLabelMoved) {
7919
7926
  var relativePosInSideEle = transformAbsPositionToRelativePositionInsideElement({ x: xOnPaper, y: yOnPaper }, parentAbsolutePosition);
7920
7927
  var newXPort = relativePosInSideEle.x - x;
@@ -8055,6 +8062,55 @@ function addPointToList(point, listPoints, path) {
8055
8062
  var addedIndex = getAddIndex(0, listPoints.length - 1);
8056
8063
  listPoints.splice(addedIndex, 0, point);
8057
8064
  return __spreadArray([], listPoints, true);
8065
+ }
8066
+ // Parse the d attribute of a path element and extract points from path commands
8067
+ function getPointsFromPathData(dAttribute) {
8068
+ var points = [];
8069
+ // Remove extra whitespace and split by command letters
8070
+ var cleanD = dAttribute.replace(/\s+/g, ' ').trim();
8071
+ // Regular expression to match path commands (M, L, C, etc.) and their values
8072
+ var commandRegex = /([MLCZmlcz])\s*([^MLCZmlcz]*)/g;
8073
+ var match;
8074
+ while ((match = commandRegex.exec(cleanD)) !== null) {
8075
+ var command = match[1].toUpperCase();
8076
+ var values = match[2].trim();
8077
+ if (values) {
8078
+ var coords = values.split(/[\s,]+/).map(Number).filter(function (num) { return !isNaN(num); });
8079
+ switch (command) {
8080
+ case 'M': // Move to
8081
+ if (coords.length >= 2) {
8082
+ points.push({ x: coords[0], y: coords[1] });
8083
+ }
8084
+ break;
8085
+ case 'L': // Line to
8086
+ if (coords.length >= 2) {
8087
+ points.push({ x: coords[0], y: coords[1] });
8088
+ }
8089
+ break;
8090
+ case 'C': // Cubic bezier curve
8091
+ // For cubic curves, we take the end point (last 2 coordinates)
8092
+ if (coords.length >= 6) {
8093
+ points.push({ x: coords[4], y: coords[5] });
8094
+ }
8095
+ break;
8096
+ case 'Q': // Quadratic bezier curve
8097
+ // For quadratic curves, we take the end point (last 2 coordinates)
8098
+ if (coords.length >= 4) {
8099
+ points.push({ x: coords[2], y: coords[3] });
8100
+ }
8101
+ break;
8102
+ }
8103
+ }
8104
+ }
8105
+ return points;
8106
+ }
8107
+ // Get points from a path element's d attribute
8108
+ function getPointsFromPathElement(pathElement) {
8109
+ var dAttribute = pathElement.getAttribute('d');
8110
+ if (!dAttribute) {
8111
+ return [];
8112
+ }
8113
+ return getPointsFromPathData(dAttribute);
8058
8114
  }
8059
8115
 
8060
8116
  //Defined remove icon for element link, shown when element link is selected.
@@ -8070,24 +8126,26 @@ function CloseIcon(_a) {
8070
8126
  React.createElement("path", { d: "M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-11.414L9.172 7.757 7.757 9.172 10.586 12l-2.829 2.828 1.415 1.415L12 13.414l2.828 2.829 1.415-1.415L13.414 12l2.829-2.828-1.415-1.415L12 10.586z" })))));
8071
8127
  }
8072
8128
 
8073
- var makerStart = React.createElement("circle", { cx: 10, cy: 10, r: 10, fill: "blue" });
8074
- var makerEnd = React.createElement("path", { d: "M0 0 L 20 10 L0 20 Z", fill: "blue" }); //<path d="M0 0 L 10 5 L0 10 Z"></path>
8129
+ // const makerStart = <circle cx={10} cy={10} r={10} fill="blue"></circle>
8130
+ // const makerEnd = <path d="M0 0 L 20 10 L0 20 Z" fill="blue"></path>//<path d="M0 0 L 10 5 L0 10 Z"></path>
8075
8131
  var IElementLink = function (_a) {
8076
8132
  var _b, _c;
8077
- var id = _a.id, path = _a.path, stroke = _a.stroke, _d = _a.strokeWidth, strokeWidth = _d === void 0 ? 4 : _d, pointsProp = _a.points, sourcePosition = _a.sourcePosition, targetPosition = _a.targetPosition, onPathChanged = _a.onPathChanged, onClickDelete = _a.onClickDelete, onSelected = _a.onSelected, onDeselected = _a.onDeselected, container = _a.container, _e = _a.markerStart, markerStart = _e === void 0 ? makerStart : _e, _f = _a.markerEnd, markerEnd = _f === void 0 ? makerEnd : _f, _g = _a.markerDistanceFromPort, markerDistanceFromPort = _g === void 0 ? LINK_MARKER_DISTANCE_FROM_PORT : _g, _h = _a.markerSize, markerSize = _h === void 0 ? LINK_MARKER_SIZE : _h, label = _a.label, sourceLabel = _a.sourceLabel, targetLabel = _a.targetLabel, onLabelMoved = _a.onLabelMoved, onLabelResized = _a.onLabelResized, onLabelContentChanged = _a.onLabelContentChanged;
8078
- var _j = React.useState(path), pathStr = _j[0], setPathStr = _j[1];
8079
- var _k = React.useState(pointsProp !== null && pointsProp !== void 0 ? pointsProp : []), points = _k[0], setPoints = _k[1];
8080
- var _l = React.useState(false), isDragging = _l[0], setIsDragging = _l[1];
8081
- var _m = React.useState(), draggingPointIndex = _m[0], setDraggingPointIndex = _m[1];
8082
- var _o = React.useState({
8133
+ var id = _a.id, path = _a.path, stroke = _a.stroke, _d = _a.strokeWidth, strokeWidth = _d === void 0 ? 4 : _d, pointsProp = _a.points, sourcePosition = _a.sourcePosition, targetPosition = _a.targetPosition, onPathChanged = _a.onPathChanged, onClickDelete = _a.onClickDelete, onSelected = _a.onSelected, onDeselected = _a.onDeselected, onPointsChanged = _a.onPointsChanged, container = _a.container, markerStart = _a.markerStart, markerEnd = _a.markerEnd, _e = _a.markerDistanceFromPort, markerDistanceFromPort = _e === void 0 ? LINK_MARKER_DISTANCE_FROM_PORT : _e, _f = _a.markerSize, markerSize = _f === void 0 ? LINK_MARKER_SIZE : _f, label = _a.label, sourceLabel = _a.sourceLabel, targetLabel = _a.targetLabel, onLabelMoved = _a.onLabelMoved, onLabelResized = _a.onLabelResized, onLabelContentChanged = _a.onLabelContentChanged;
8134
+ var _g = React.useState(path), pathStr = _g[0], setPathStr = _g[1];
8135
+ var _h = React.useState(pointsProp !== null && pointsProp !== void 0 ? pointsProp : []), points = _h[0], setPoints = _h[1];
8136
+ var _j = React.useState(false), isDragging = _j[0], setIsDragging = _j[1];
8137
+ var _k = React.useState(), draggingPointIndex = _k[0], setDraggingPointIndex = _k[1];
8138
+ var _l = React.useState({
8083
8139
  current: null,
8084
- }), selectedLabelRef = _o[0], setSelectedLabelRef = _o[1];
8085
- var _p = React.useState(false), isSelectedLink = _p[0], setIsSelectedLink = _p[1];
8086
- var _q = React.useContext(paperEventEmitterContext), onPaperClicked = _q.onPaperClicked, onElementSelected = _q.onElementSelected;
8140
+ }), selectedLabelRef = _l[0], setSelectedLabelRef = _l[1];
8141
+ var _m = React.useState(false), isSelectedLink = _m[0], setIsSelectedLink = _m[1];
8142
+ var _o = React.useContext(paperEventEmitterContext), onPaperClicked = _o.onPaperClicked, onElementSelected = _o.onElementSelected;
8087
8143
  var pathRef = React.useRef(null);
8088
8144
  var labelRef = React.useRef(null);
8089
8145
  var sourceLabelRef = React.useRef(null);
8090
8146
  var targetLabelRef = React.useRef(null);
8147
+ var isFirstRender = React.useRef(true);
8148
+ var onPointsChangedRef = React.useRef();
8091
8149
  var angleMarkerStart = '0';
8092
8150
  var angleMarkerEnd = '0';
8093
8151
  var markerStartPosition;
@@ -8117,6 +8175,18 @@ var IElementLink = function (_a) {
8117
8175
  elementSelectedListener.off();
8118
8176
  };
8119
8177
  }, []);
8178
+ // Store onPointsChanged in a ref to avoid unnecessary re-renders
8179
+ React.useEffect(function () {
8180
+ onPointsChangedRef.current = onPointsChanged;
8181
+ }, [onPointsChanged]);
8182
+ React.useEffect(function () {
8183
+ var _a;
8184
+ if (isFirstRender.current) {
8185
+ isFirstRender.current = false;
8186
+ return;
8187
+ }
8188
+ (_a = onPointsChangedRef.current) === null || _a === void 0 ? void 0 : _a.call(onPointsChangedRef, points, id);
8189
+ }, [points]);
8120
8190
  React.useLayoutEffect(function () {
8121
8191
  var pointsList = __spreadArray(__spreadArray([sourcePosition], points, true), [targetPosition], false);
8122
8192
  var _pathStr = createSmoothPathString(pointsList, undefined, false);
@@ -8292,7 +8362,7 @@ var IElementLink = function (_a) {
8292
8362
  position.x += relativePositionTo.x;
8293
8363
  position.y += relativePositionTo.y;
8294
8364
  }
8295
- return (React.createElement(Text$1, { id: label.id, x: position.x, y: position.y, width: size.width, height: size.height, editable: label.editable, content: content, fontSize: label.fontSize, border: label.border, ref: curLabelRef, container: container, onSelected: function () { return setSelectedLabelRef(curLabelRef); }, onMoved: handleLabelMoved, onResized: handleLabelResized, onContentChanged: handleLabelContentChanged }));
8365
+ return (React.createElement(Text$1, { id: label.id, x: position.x, y: position.y, width: size.width, height: size.height, editable: label.editable, selectable: label.selectable, content: content, fontSize: label.fontSize, border: label.border, ref: curLabelRef, container: container, onSelected: function () { return setSelectedLabelRef(curLabelRef); }, onMoved: handleLabelMoved, onResized: handleLabelResized, onContentChanged: handleLabelContentChanged }));
8296
8366
  };
8297
8367
  if ((_b = pathRef.current) === null || _b === void 0 ? void 0 : _b.getAttribute('d')) {
8298
8368
  if (markerStart) {
@@ -8495,15 +8565,18 @@ var Element = React.forwardRef(function (props, forwardedRef) {
8495
8565
  //Listen trigger of Delete key, handle delete port is selected
8496
8566
  React.useEffect(function () {
8497
8567
  var listener = _paperEventEmitterContext.onCommandDeleteSelectedPort(function () {
8568
+ var _a;
8498
8569
  if (selectedPort) {
8499
- setPorts(function (prev) { return prev.filter(function (p) { return p.id !== selectedPort.id; }); });
8570
+ var newPorts = portsRef.current.filter(function (p) { return p.id !== selectedPort.id; });
8571
+ setPorts(newPorts);
8500
8572
  setSelectedPort(undefined);
8573
+ (_a = props.onPortsChanged) === null || _a === void 0 ? void 0 : _a.call(props, newPorts, id);
8501
8574
  }
8502
8575
  });
8503
8576
  return function () {
8504
8577
  listener.off();
8505
8578
  };
8506
- }, [selectedPort]);
8579
+ }, [selectedPort, props.onPortsChanged]);
8507
8580
  React.useEffect(function () {
8508
8581
  //Listener onMouseDown event on #paper-container
8509
8582
  var eventListener = _paperEventEmitterContext.onPaperClicked(function (ev) {
@@ -8842,7 +8915,7 @@ var Element = React.forwardRef(function (props, forwardedRef) {
8842
8915
  }), texts === null || texts === void 0 ? void 0 :
8843
8916
  texts.map(function (t, index) {
8844
8917
  var _a, _b;
8845
- return React.createElement(Text$1, { id: t.id, key: index, content: t.content, x: ((_a = t.position) === null || _a === void 0 ? void 0 : _a.x) || 0, y: ((_b = t.position) === null || _b === void 0 ? void 0 : _b.y) || 0, width: t.size.width, height: t.size.height, editable: t.editable, align: t.align, fontSize: t.fontSize, border: t.border, container: container, style: t.style, parentAbsolutePosition: elementAbsPosition, onContentChanged: function (ev, newContent) { return onTextUpdated === null || onTextUpdated === void 0 ? void 0 : onTextUpdated(id, t.id, newContent); } });
8918
+ return React.createElement(Text$1, { id: t.id, key: index, content: t.content, x: ((_a = t.position) === null || _a === void 0 ? void 0 : _a.x) || 0, y: ((_b = t.position) === null || _b === void 0 ? void 0 : _b.y) || 0, width: t.size.width, height: t.size.height, editable: t.editable, selectable: t.selectable, align: t.align, fontSize: t.fontSize, border: t.border, container: container, style: t.style, parentAbsolutePosition: elementAbsPosition, onContentChanged: function (ev, newContent) { return onTextUpdated === null || onTextUpdated === void 0 ? void 0 : onTextUpdated(id, t.id, newContent); } });
8846
8919
  }),
8847
8920
  children)));
8848
8921
  });
@@ -9440,6 +9513,17 @@ var Paper = function (props) {
9440
9513
  props.onLinksChanged(newLinks);
9441
9514
  }
9442
9515
  }, [props.onLinksChanged, links]);
9516
+ var handlePointsOfLinkChange = React.useCallback(function (points, id) {
9517
+ //Update path of element link, that changed
9518
+ // const prevLinks = linksRef.current;
9519
+ var updatedLinkIndex = links.findIndex(function (l) { return l.id === id; });
9520
+ links[updatedLinkIndex].points = points;
9521
+ var newLinks = __spreadArray([], links, true);
9522
+ setLinks(newLinks);
9523
+ if (props.onLinksChanged) {
9524
+ props.onLinksChanged(newLinks);
9525
+ }
9526
+ }, [props.onLinksChanged, links]);
9443
9527
  var handlePortMoved = React.useCallback(function (port, elementId, oldPosition, newPosition) {
9444
9528
  var _a;
9445
9529
  var element = elementsRef.current.find(function (e) { return e.id === elementId; });
@@ -9548,6 +9632,13 @@ var Paper = function (props) {
9548
9632
  setTempLink(null);
9549
9633
  }
9550
9634
  }, [paperEventEmitter, createElementLink, props.onPortMouseUp, props.onLinksChanged]);
9635
+ var handlePortsChanged = React.useCallback(function (ports, elementId) {
9636
+ var element = elementsRef.current.find(function (e) { return e.id === elementId; });
9637
+ if (element) {
9638
+ //broadcast ports changed to parent component
9639
+ props.onPortsChanged(ports, element);
9640
+ }
9641
+ }, [props.onPortsChanged]);
9551
9642
  var handleLinkLabelMoved = React.useCallback(function (newX, newY, index, labelType) {
9552
9643
  var prevLinks = linksRef.current;
9553
9644
  var newLinks = __spreadArray([], prevLinks, true);
@@ -9798,7 +9889,7 @@ var Paper = function (props) {
9798
9889
  //use the defined react element or the default Element component
9799
9890
  var ReactElement = element.reactElement || Element$1;
9800
9891
  return (React.createElement("g", { id: "group-of-element-".concat(element.id), key: element.id },
9801
- React.createElement(ReactElement, { key: "element-".concat(element.id), id: element.id, ref: function (refDOM) { return element.DOM = refDOM; }, height: element.size.height, width: element.size.width, x: element.positionAnchor === exports.PositioningAnchor.Center ? element.position.x - element.size.width / 2 : element.position.x, y: element.positionAnchor === exports.PositioningAnchor.Center ? element.position.y - element.size.height / 2 : element.position.y, onClick: handleElementClicked, onContextMenu: handleContextMenu, onMouseUp: handleMouseUp, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, container: paperContainerRef.current, renderShape: element.renderShape, cssClass: element.cssClass, texts: element.texts, ports: element.ports, portMoveableAreas: element.portMoveableAreas, portSlideRailSVGClassName: element.portSlideRailSVGClassName, portDirection: element.portDirection, defaultPortSize: element.defaultPortSize, onPortMoved: handlePortMoved, onPortMouseDown: handlePortMouseDown, onPortMouseUp: handlePortMouseUp,
9892
+ React.createElement(ReactElement, { key: "element-".concat(element.id), id: element.id, ref: function (refDOM) { return element.DOM = refDOM; }, height: element.size.height, width: element.size.width, x: element.positionAnchor === exports.PositioningAnchor.Center ? element.position.x - element.size.width / 2 : element.position.x, y: element.positionAnchor === exports.PositioningAnchor.Center ? element.position.y - element.size.height / 2 : element.position.y, onClick: handleElementClicked, onContextMenu: handleContextMenu, onMouseUp: handleMouseUp, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, container: paperContainerRef.current, renderShape: element.renderShape, cssClass: element.cssClass, texts: element.texts, ports: element.ports, portMoveableAreas: element.portMoveableAreas, portSlideRailSVGClassName: element.portSlideRailSVGClassName, portDirection: element.portDirection, defaultPortSize: element.defaultPortSize, onPortMoved: handlePortMoved, onPortMouseDown: handlePortMouseDown, onPortMouseUp: handlePortMouseUp, onPortsChanged: handlePortsChanged,
9802
9893
  // portPlaceholderShape={(<Circle x={0} y={0} width={10} height={10} fill='red' positioningAnchor={PositioningAnchor.Center} />)}
9803
9894
  onMouseUpAtLinkedPortPlaceholder: handleMouseUpAtLinkedPortPlaceholder, onTextUpdated: handleElementTextChange, onManuallyTriggerRenderPort: props.onManuallyTriggerRenderPort, textsPlaceHolderClassName: element.textsPlaceHolderClassName, textsPlaceHolderFlexStyle: element.textsPlaceHolderFlexStyle, textsPlaceHolderFlexboxPosition: element.textsPlaceHolderFlexboxPosition, parentAbsolutePosition: element.parentElement ? getAbsolutePosition(element.parentElement) : undefined },
9804
9895
  element.childrenElementsInTree && element.childrenElementsInTree.map(renderElementInTree),
@@ -9863,7 +9954,7 @@ var Paper = function (props) {
9863
9954
  paperEventEmitter.emitElementResized(selectedElement, oldSize, newSize);
9864
9955
  setMouseDownedOnPaper(false);
9865
9956
  } }))));
9866
- }, [handleElementClicked, handleContextMenu, handlePortMoved, handlePortMouseDown, handlePortMouseUp, handleMouseUpAtLinkedPortPlaceholder, handleElementTextChange, handleMouseUp, handleMouseMove, handleMouseLeave, selectedElement, selectedElementAbsPosition]);
9957
+ }, [handlePortsChanged, handleElementClicked, handleContextMenu, handlePortMoved, handlePortMouseDown, handlePortMouseUp, handleMouseUpAtLinkedPortPlaceholder, handleElementTextChange, handleMouseUp, handleMouseMove, handleMouseLeave, selectedElement, selectedElementAbsPosition]);
9867
9958
  var ElementsInTree = React.useMemo(function () {
9868
9959
  return elementsInTree.map(function (element, index) {
9869
9960
  return renderElementInTree(element);
@@ -9882,13 +9973,13 @@ var Paper = function (props) {
9882
9973
  }, targetPosition: {
9883
9974
  x: getAbsolutePosition(link.targetElement).x + link.targetPort.position.x,
9884
9975
  y: getAbsolutePosition(link.targetElement).y + link.targetPort.position.y
9885
- }, points: link.points, onPathChanged: handlePathChange, onClickDelete: handleClickLinkDelete(link, index), onSelected: function () { return handleSelectLink(link); }, onDeselected: function () { return handleDeselectLink(); }, container: paperContainerRef.current, markerStart: link.markerStart, markerEnd: link.markerEnd, markerDistanceFromPort: link.markerDistanceFromPort, markerSize: link.markerSize, label: link.label, sourceLabel: link.sourceLabel, targetLabel: link.targetLabel, onLabelMoved: onLabelMoved(index), onLabelResized: onLabelResized(index), onLabelContentChanged: onLabelContentChanged(index) }));
9976
+ }, points: link.points, onPathChanged: handlePathChange, onPointsChanged: handlePointsOfLinkChange, onClickDelete: handleClickLinkDelete(link, index), onSelected: function () { return handleSelectLink(link); }, onDeselected: function () { return handleDeselectLink(); }, container: paperContainerRef.current, markerStart: link.markerStart, markerEnd: link.markerEnd, markerDistanceFromPort: link.markerDistanceFromPort, markerSize: link.markerSize, label: link.label, sourceLabel: link.sourceLabel, targetLabel: link.targetLabel, onLabelMoved: onLabelMoved(index), onLabelResized: onLabelResized(index), onLabelContentChanged: onLabelContentChanged(index) }));
9886
9977
  }),
9887
9978
  (tempLink === null || tempLink === void 0 ? void 0 : tempLink.tempTargetPosition) && React.createElement(ElementLink, { id: tempLink.id, points: tempLink.points, sourcePosition: {
9888
9979
  x: getAbsolutePosition(tempLink.sourceElement).x + tempLink.sourcePort.position.x,
9889
9980
  y: getAbsolutePosition(tempLink.sourceElement).y + tempLink.sourcePort.position.y
9890
9981
  }, targetPosition: tempLink.tempTargetPosition, container: paperContainerRef.current, markerStart: tempLink.markerStart, markerEnd: tempLink.markerEnd, markerDistanceFromPort: tempLink.markerDistanceFromPort, markerSize: tempLink.markerSize }),
9891
- texts.map(function (text, index) { return (React.createElement(Text$1, { key: text.id, id: text.id, x: text.position.x, y: text.position.y, width: text.size.width, height: text.size.height, editable: text.editable, fontSize: text.fontSize, border: text.border, container: paperContainerRef.current, content: text.content, align: text.align, onSelected: function () {
9982
+ texts.map(function (text, index) { return (React.createElement(Text$1, { key: text.id, id: text.id, x: text.position.x, y: text.position.y, width: text.size.width, height: text.size.height, editable: text.editable, selectable: text.selectable, fontSize: text.fontSize, border: text.border, container: paperContainerRef.current, content: text.content, align: text.align, onSelected: function () {
9892
9983
  setSelectedText(text);
9893
9984
  } })); })),
9894
9985
  React.createElement(BBoxDebugger, { elementSVG: selectedElementSVG }),
@@ -9896,6 +9987,83 @@ var Paper = function (props) {
9896
9987
  };
9897
9988
  var Paper$1 = React.memo(Paper);
9898
9989
 
9990
+ /**
9991
+ * Zoom context to manage zoom level and related state.
9992
+ * This context can be used to provide zoom functionality across the application.
9993
+ */
9994
+ var zoomContext = React.createContext(null);
9995
+ var ZoomContextProvider = function (_a) {
9996
+ var children = _a.children;
9997
+ var _b = React.useState(1), zoom = _b[0], setZoom = _b[1];
9998
+ var _c = React.useState(0), scrollLeft = _c[0], setScrollLeft = _c[1];
9999
+ var _d = React.useState(0), scrollTop = _d[0], setScrollTop = _d[1];
10000
+ var wrapperRef = React.useRef(null);
10001
+ var contentRef = React.useRef(null);
10002
+ var handleWheel = function (e) {
10003
+ // Chỉ zoom khi giữ Ctrl
10004
+ if (!e.ctrlKey)
10005
+ return;
10006
+ e.preventDefault();
10007
+ var delta = -e.deltaY;
10008
+ var zoomFactor = 0.05;
10009
+ var newZoom = zoom + (delta > 0 ? zoomFactor : -zoomFactor);
10010
+ newZoom = Math.max(0.1, Math.min(newZoom, 4));
10011
+ if (!wrapperRef.current || !contentRef.current)
10012
+ return;
10013
+ var wrapper = wrapperRef.current;
10014
+ var content = contentRef.current;
10015
+ // Get bounding rectangle of the content
10016
+ var rect = content.getBoundingClientRect();
10017
+ var offsetX = e.clientX - rect.left;
10018
+ var offsetY = e.clientY - rect.top;
10019
+ var percentX = offsetX / (content.offsetWidth);
10020
+ var percentY = offsetY / (content.offsetHeight);
10021
+ console.log(offsetX, offsetY, content.offsetWidth, content.offsetHeight, percentX, percentY);
10022
+ // Old width and height of content
10023
+ var prevWidth = content.offsetWidth * zoom;
10024
+ var prevHeight = content.offsetHeight * zoom;
10025
+ var newWidth = content.offsetWidth * newZoom;
10026
+ var newHeight = content.offsetHeight * newZoom;
10027
+ var scrollLeft = wrapper.scrollLeft + (percentX * (newWidth - prevWidth));
10028
+ var scrollTop = wrapper.scrollTop + (percentY * (newHeight - prevHeight));
10029
+ setZoom(newZoom);
10030
+ setScrollLeft(scrollLeft);
10031
+ setScrollTop(scrollTop);
10032
+ };
10033
+ React.useLayoutEffect(function () {
10034
+ var _a;
10035
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.scrollTo({
10036
+ left: scrollLeft,
10037
+ top: scrollTop,
10038
+ });
10039
+ }, [zoom, scrollLeft, scrollTop]);
10040
+ var resetZoom = function () {
10041
+ setZoom(1);
10042
+ };
10043
+ React.useEffect(function () {
10044
+ var preventBrowserZoom = function (e) {
10045
+ if (e.ctrlKey || e.metaKey) {
10046
+ e.preventDefault();
10047
+ }
10048
+ };
10049
+ window.addEventListener("wheel", preventBrowserZoom, { passive: false });
10050
+ return function () {
10051
+ window.removeEventListener("wheel", preventBrowserZoom);
10052
+ };
10053
+ }, []);
10054
+ return (React.createElement(zoomContext.Provider, { value: { zoom: zoom, setZoom: setZoom, resetZoom: resetZoom } },
10055
+ React.createElement("div", { ref: wrapperRef, onWheel: handleWheel, style: {
10056
+ width: "100vw",
10057
+ height: "92vh",
10058
+ overflow: "auto",
10059
+ } },
10060
+ React.createElement("div", { ref: contentRef, style: {
10061
+ transform: "scale(".concat(zoom, ")"),
10062
+ transformOrigin: "top left",
10063
+ // transition: "transform 0.1s linear",
10064
+ } }, children))));
10065
+ };
10066
+
9899
10067
  var Editor = function (_a) {
9900
10068
  var editorContext = _a.editorContext, width = _a.width, height = _a.height;
9901
10069
  var _b = React.useState([]), elements = _b[0], setElements = _b[1];
@@ -9944,6 +10112,9 @@ var Editor = function (_a) {
9944
10112
  var handlePortSelected = React.useCallback(function (port, element) {
9945
10113
  editorContext.onPortSelectedHandler(port, element);
9946
10114
  }, [editorContext]);
10115
+ var handlePortsChanged = React.useCallback(function (ports, element) {
10116
+ element.ports = ports;
10117
+ }, [editorContext]);
9947
10118
  var handleElementContextMenu = React.useCallback(function (element, event) {
9948
10119
  editorContext.onElementContextMenuHandler(element, event);
9949
10120
  }, [editorContext]);
@@ -10004,7 +10175,8 @@ var Editor = function (_a) {
10004
10175
  var handlePaperMouseUp = React.useCallback(function (position) {
10005
10176
  editorContext.onPaperMouseUpHandler(position);
10006
10177
  }, [editorContext]);
10007
- return (React.createElement(Paper$1, { key: "paper", size: { width: width, height: height }, elements: elements, links: links, texts: texts, onPaperClicked: handlePaperClicked, onPortMouseDown: handlePortMouseDown, onPortMouseUp: handlePortMouseUp, onPortMoved: handlePortMoved, onPortSelected: handlePortSelected, onElementContextMenu: handleElementContextMenu, onElementMoved: handleElementMoved, onElementResized: handleElementResized, onElementSelected: handleElementSelected, onElementMouseLeave: handleElementMouseLeave, onElementMouseMove: handleElementMouseMove, onElementMouseDown: handleElementMouseDown, onElementMouseUp: handleElementMouseUp, onElementsChanged: handleElementsChanged, onCreatingLink: handleOnCreatingLink, onCreatingPortByLinking: handleOnCreatingPortByLinking, onLinkSelected: handleLinkSelected, onLinksChanged: handleLinksChanged, onTextSelected: handleTextSelected, onTextsChanged: handleTextsChanged, onPaperMouseMoved: handlePaperMouseMoved, onPaperMouseUp: handlePaperMouseUp, onPaperMouseDown: handlePaperMouseDown, onManuallyTriggerRenderElement: editorContext.onManuallyTriggerRenderElement.bind(editorContext), onManuallyTriggerRenderPort: editorContext.onManuallyTriggerRenderPort.bind(editorContext) }));
10178
+ return (React.createElement(ZoomContextProvider, null,
10179
+ React.createElement(Paper$1, { key: "paper", size: { width: width, height: height }, elements: elements, links: links, texts: texts, onPaperClicked: handlePaperClicked, onPortMouseDown: handlePortMouseDown, onPortMouseUp: handlePortMouseUp, onPortMoved: handlePortMoved, onPortSelected: handlePortSelected, onPortsChanged: handlePortsChanged, onElementContextMenu: handleElementContextMenu, onElementMoved: handleElementMoved, onElementResized: handleElementResized, onElementSelected: handleElementSelected, onElementMouseLeave: handleElementMouseLeave, onElementMouseMove: handleElementMouseMove, onElementMouseDown: handleElementMouseDown, onElementMouseUp: handleElementMouseUp, onElementsChanged: handleElementsChanged, onCreatingLink: handleOnCreatingLink, onCreatingPortByLinking: handleOnCreatingPortByLinking, onLinkSelected: handleLinkSelected, onLinksChanged: handleLinksChanged, onTextSelected: handleTextSelected, onTextsChanged: handleTextsChanged, onPaperMouseMoved: handlePaperMouseMoved, onPaperMouseUp: handlePaperMouseUp, onPaperMouseDown: handlePaperMouseDown, onManuallyTriggerRenderElement: editorContext.onManuallyTriggerRenderElement.bind(editorContext), onManuallyTriggerRenderPort: editorContext.onManuallyTriggerRenderPort.bind(editorContext) })));
10008
10180
  };
10009
10181
 
10010
10182
  exports.CircleRC = Circle;
@@ -10044,6 +10216,8 @@ exports.getElementRotationInfo = getElementRotationInfo;
10044
10216
  exports.getFirstIntersection = getFirstIntersection;
10045
10217
  exports.getFourVertexesOfBBoxFromElement = getFourVertexesOfBBoxFromElement;
10046
10218
  exports.getIntersectionPositions = getIntersectionPositions;
10219
+ exports.getPointsFromPathData = getPointsFromPathData;
10220
+ exports.getPointsFromPathElement = getPointsFromPathElement;
10047
10221
  exports.getPortAbsolutePosition = getPortAbsolutePosition;
10048
10222
  exports.getRectangleCorners = getRectangleCorners;
10049
10223
  exports.getRelativePosition = getRelativePosition;
@@ -21,6 +21,7 @@ interface PaperProps {
21
21
  onPortMouseUp?: (port: IPort, element: IElement) => void;
22
22
  onPortMoved?: (position: IPosition, port: IPort, element: IElement) => void;
23
23
  onPortSelected?: (port: IPort, element: IElement) => void;
24
+ onPortsChanged: (ports: IPort[], element: IElement) => void;
24
25
  onElementContextMenu?: (element: IElement, mouseEvent: React.MouseEvent<SVGElement>) => void;
25
26
  onElementMoved?: (position: IPosition, element: IElement, index: number) => void;
26
27
  onElementResized?: (size: ISize, element: IElement, index: number) => void;
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ interface IZoomContext {
3
+ zoom: number;
4
+ setZoom: (zoom: number) => void;
5
+ resetZoom: () => void;
6
+ }
7
+ /**
8
+ * Zoom context to manage zoom level and related state.
9
+ * This context can be used to provide zoom functionality across the application.
10
+ */
11
+ export declare const zoomContext: React.Context<IZoomContext | null>;
12
+ export declare const ZoomContextProvider: ({ children }: {
13
+ children: React.ReactNode;
14
+ }) => React.JSX.Element;
15
+ export {};
@@ -21,6 +21,7 @@ export default interface IElementLinkProps {
21
21
  markerDistanceFromPort?: number;
22
22
  markerSize?: number;
23
23
  onPathChanged?: (path: string, id: string) => void;
24
+ onPointsChanged?: (points: IPosition[], id: string) => void;
24
25
  onClickDelete?: (ev: React.MouseEvent) => void;
25
26
  onSelected?: () => void;
26
27
  onDeselected?: () => void;
@@ -29,6 +29,7 @@ interface IElementProps {
29
29
  onPortMoved?: onPortMovedHandler;
30
30
  onPortMouseDown?: onPortMouseDownHandler;
31
31
  onPortMouseUp?: onPortMouseUpHandler;
32
+ onPortsChanged?: (ports: IPort[], elementId: string) => void;
32
33
  portPlaceholderShape?: JSX.Element;
33
34
  onMouseMove?: (event: React.MouseEvent, elementId: string) => void;
34
35
  onMouseLeave?: (event: React.MouseEvent, elementId: string) => void;
@@ -7,6 +7,7 @@ export default interface IText {
7
7
  content: string;
8
8
  size: ISize;
9
9
  editable: boolean;
10
+ selectable?: boolean;
10
11
  position?: IPosition;
11
12
  align?: TextAlign;
12
13
  fontSize?: number;
@@ -12,6 +12,7 @@ export default interface ITextProps {
12
12
  parentAbsolutePosition?: IPosition;
13
13
  height: number;
14
14
  width: number;
15
+ selectable?: boolean;
15
16
  align?: TextAlign;
16
17
  fontSize?: number;
17
18
  border?: string;
@@ -37,7 +37,7 @@ export default class Element implements IElement {
37
37
  textsPlaceHolderFlexStyle?: IFlexboxType;
38
38
  textsPlaceHolderFlexboxPosition?: IPosition;
39
39
  _eventEmitter: EventEmitter;
40
- constructor(x: number, y: number, width: number, height: number, cssClass?: string, renderShape?: (props: IElementProps) => JSX.Element, texts?: IText[], ports?: IPort[], portMovealeAreas?: IPosition[][], portSlideRailSVGClassName?: string, portDirection?: SubObjectDirection, parentElement?: Element, textsPlaceHolderClassName?: string, textsPlaceHolderFlexStyle?: IFlexboxType, textsPlaceHolderFlexboxPosition?: IPosition);
40
+ constructor(id: string | null, x: number, y: number, width: number, height: number, cssClass?: string, renderShape?: (props: IElementProps) => JSX.Element, texts?: IText[], ports?: IPort[], portMovealeAreas?: IPosition[][], portSlideRailSVGClassName?: string, portDirection?: SubObjectDirection, parentElement?: Element, textsPlaceHolderClassName?: string, textsPlaceHolderFlexStyle?: IFlexboxType, textsPlaceHolderFlexboxPosition?: IPosition);
41
41
  get id(): string;
42
42
  get size(): ISize;
43
43
  set size(value: ISize);
@@ -20,5 +20,5 @@ export default class ElementLink implements IElementLink {
20
20
  label?: IText;
21
21
  sourceLabel?: IText;
22
22
  targetLabel?: IText;
23
- constructor(sourceElement: IElement, sourcePort: IPort, targetElement: IElement, targetPort: IPort, tempTargetPosition: IPosition, points?: IPosition[]);
23
+ constructor(id: string | null, sourceElement: IElement, sourcePort: IPort, targetElement?: IElement, targetPort?: IPort, tempTargetPosition?: IPosition, points?: IPosition[], path?: string, markerStart?: JSX.Element, markerEnd?: JSX.Element, markerDistanceFromPort?: number, markerSize?: number, label?: IText, sourceLabel?: IText, targetLabel?: IText);
24
24
  }
@@ -12,7 +12,7 @@ export default class Port implements IPort {
12
12
  label?: IText;
13
13
  renderShape?: React.ForwardRefExoticComponent<IPortProps & React.RefAttributes<SVGSVGElement>>;
14
14
  _eventEmitter: EventEmitter;
15
- constructor(x: number, y: number, label?: IText, shapeRenderer?: {
15
+ constructor(id: string | null, x: number, y: number, label?: IText, shapeRenderer?: {
16
16
  shape?: React.ForwardRefExoticComponent<IPortProps & React.RefAttributes<SVGSVGElement>>;
17
17
  customShapeWithJSX?: JSX.Element;
18
18
  positioningAnchor?: IPosition;
@@ -7,12 +7,13 @@ export default class Text implements IText {
7
7
  private readonly _id;
8
8
  content: string;
9
9
  editable: boolean;
10
+ selectable?: boolean;
10
11
  size: ISize;
11
12
  position?: IPosition;
12
13
  align?: TextAlign;
13
14
  fontSize?: number;
14
15
  border?: string;
15
16
  style?: IFlexboxType;
16
- constructor(content: string, width: number, height: number, editable: boolean, x?: number, y?: number, align?: TextAlign, fontSize?: number, border?: string, style?: IFlexboxType);
17
+ constructor(id: string | null, content: string, width: number, height: number, editable: boolean, selectable?: boolean, x?: number, y?: number, align?: TextAlign, fontSize?: number, border?: string, style?: IFlexboxType);
17
18
  get id(): string;
18
19
  }
@@ -8,4 +8,6 @@ export declare function pathDataToD(pathData: IPathCommand[], decimals?: number)
8
8
  export declare function createSmoothPathString(points: IPosition[], smoothing?: number, close?: boolean): string;
9
9
  export declare function dist(p1: IPosition, p2: IPosition): number;
10
10
  export declare function addPointToList(point: IPosition, listPoints: IPosition[], path: SVGPathElement): IPosition[];
11
+ export declare function getPointsFromPathData(dAttribute: string): IPosition[];
12
+ export declare function getPointsFromPathElement(pathElement: SVGPathElement): IPosition[];
11
13
  export {};