@metadev/daga 3.1.4 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.esm.js CHANGED
@@ -807,6 +807,64 @@ const numberOfRows = s => {
807
807
  return ((_a = s.match(/\n/g)) === null || _a === undefined ? undefined : _a.length) || 0;
808
808
  };
809
809
 
810
+ /******************************************************************************
811
+ Copyright (c) Microsoft Corporation.
812
+
813
+ Permission to use, copy, modify, and/or distribute this software for any
814
+ purpose with or without fee is hereby granted.
815
+
816
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
817
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
818
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
819
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
820
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
821
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
822
+ PERFORMANCE OF THIS SOFTWARE.
823
+ ***************************************************************************** */
824
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
825
+
826
+
827
+ function __rest(s, e) {
828
+ var t = {};
829
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
830
+ t[p] = s[p];
831
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
832
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
833
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
834
+ t[p[i]] = s[p[i]];
835
+ }
836
+ return t;
837
+ }
838
+
839
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
840
+ var e = new Error(message);
841
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
842
+ };
843
+
844
+ /**
845
+ * Converts a configuration for a look into an easier to consult object of fully qualified looks for each case.
846
+ *
847
+ * @param lookConfig A look configuration object
848
+ * @returns An object with four keys for a look with each possible state of being selected or not and being highlighted or not.
849
+ */
850
+ const extractLooksFromConfig = lookConfig => {
851
+ const {
852
+ selected,
853
+ highlighted
854
+ } = lookConfig,
855
+ rest = __rest(lookConfig, ["selected", "highlighted"]);
856
+ const defaultLook = rest;
857
+ const selectedLook = Object.assign(Object.assign({}, defaultLook), selected);
858
+ const highlightedLook = Object.assign(Object.assign({}, defaultLook), highlighted);
859
+ const selectedAndHighlightedLook = Object.assign(Object.assign(Object.assign({}, defaultLook), highlighted), selected);
860
+ return {
861
+ defaultLook,
862
+ selectedLook,
863
+ highlightedLook,
864
+ selectedAndHighlightedLook
865
+ };
866
+ };
867
+
810
868
  /**
811
869
  * Represents a collection of diagram entities of a type that exists as part of a diagram model.
812
870
  * @public
@@ -955,6 +1013,10 @@ const DEFAULT_PRIORITY = 0;
955
1013
  * @see DiagramCanvas
956
1014
  */
957
1015
  class DiagramElement {
1016
+ /**
1017
+ * Identifier that uniquely identifies this element within its diagram model. Cannot be an empty string.
1018
+ * @public
1019
+ */
958
1020
  get id() {
959
1021
  return this._id;
960
1022
  }
@@ -1223,7 +1285,6 @@ class ValueSet {
1223
1285
  constructor(propertySet, rootElement) {
1224
1286
  this.displayedProperties = [];
1225
1287
  this.hiddenProperties = [];
1226
- // TODO JC: make this private after reviewing how it's used from React
1227
1288
  this.values = {};
1228
1289
  this.valueSets = {};
1229
1290
  /**
@@ -1508,7 +1569,7 @@ class ValueSet {
1508
1569
  this.values[key] = structuredClone(property.defaultValue);
1509
1570
  }
1510
1571
  if (rootAttribute !== undefined && rootAttribute !== null) {
1511
- if (property.defaultValue !== undefined) {
1572
+ if (property.defaultValue !== undefined && !equals(this.values[key], property.defaultValue)) {
1512
1573
  this.setRootElementValue(rootAttribute, this.values[key]);
1513
1574
  } else {
1514
1575
  this.values[key] = this.getRootElementValue(rootAttribute);
@@ -1626,6 +1687,34 @@ const diff = (a, b) => {
1626
1687
  }
1627
1688
  return [aDiff, bDiff];
1628
1689
  };
1690
+ /**
1691
+ * Calculates the differences between the two given values of a valueset and returns two objects containing the differences in each relative to the other.
1692
+ *
1693
+ * @param a An object.
1694
+ * @param b An object.
1695
+ * @param valueSet A ValueSet to use as reference for the keys and types of each property.
1696
+ * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1697
+ */
1698
+ const diffProperties = (a, b, valueSet) => {
1699
+ const aDiff = {};
1700
+ const bDiff = {};
1701
+ for (const key in valueSet.propertySet.propertyMap) {
1702
+ if (valueSet.propertySet.propertyMap[key].type === Type.Object) {
1703
+ const diffAB = diffProperties(a[key], b[key], valueSet.getSubValueSet(key));
1704
+ // only add the key if differences are detected
1705
+ if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1706
+ aDiff[key] = diffAB[0];
1707
+ bDiff[key] = diffAB[1];
1708
+ }
1709
+ } else {
1710
+ if (!equals(a[key], b[key])) {
1711
+ aDiff[key] = a[key];
1712
+ bDiff[key] = b[key];
1713
+ }
1714
+ }
1715
+ }
1716
+ return [aDiff, bDiff];
1717
+ };
1629
1718
  /**
1630
1719
  * Checks if the given value is an object.
1631
1720
  * @public
@@ -1641,16 +1730,24 @@ const isObject = x => x !== undefined && x !== null && x.constructor === Object;
1641
1730
  */
1642
1731
  const DIAGRAM_CONNECTION_TYPE_DEFAULTS = {
1643
1732
  name: '',
1644
- width: 1,
1645
- shape: LineShape.Straight,
1646
- style: LineStyle.Solid,
1647
1733
  label: null,
1648
- defaultStartMarkerLook: null,
1649
- defaultEndMarkerLook: null,
1734
+ look: {
1735
+ lookType: 'connection-look',
1736
+ color: '#000000',
1737
+ thickness: 1,
1738
+ shape: LineShape.Straight,
1739
+ style: LineStyle.Solid,
1740
+ selected: {
1741
+ color: '#AA00AA'
1742
+ },
1743
+ highlighted: {
1744
+ thickness: 2
1745
+ }
1746
+ },
1747
+ startMarkerLook: undefined,
1748
+ endMarkerLook: undefined,
1650
1749
  startTypes: [],
1651
1750
  endTypes: [],
1652
- color: '#000000',
1653
- selectedColor: '#000000',
1654
1751
  properties: []
1655
1752
  };
1656
1753
  /**
@@ -1663,16 +1760,38 @@ class DiagramConnectionType {
1663
1760
  const values = Object.assign(Object.assign({}, DIAGRAM_CONNECTION_TYPE_DEFAULTS), options);
1664
1761
  this.id = values.id;
1665
1762
  this.name = values.name;
1666
- this.width = values.width;
1667
- this.shape = values.shape;
1668
- this.style = values.style;
1669
1763
  this.label = values.label;
1670
- this.defaultStartMarkerLook = values.defaultStartMarkerLook;
1671
- this.defaultEndMarkerLook = values.defaultEndMarkerLook;
1764
+ const looks = extractLooksFromConfig(values.look);
1765
+ this.defaultLook = looks.defaultLook;
1766
+ this.selectedLook = looks.selectedLook;
1767
+ this.highlightedLook = looks.highlightedLook;
1768
+ this.selectedAndHighlightedLook = looks.selectedAndHighlightedLook;
1769
+ if (values.startMarkerLook !== undefined) {
1770
+ const startMarkerLooks = extractLooksFromConfig(values.startMarkerLook);
1771
+ this.defaultStartMarkerLook = startMarkerLooks.defaultLook;
1772
+ this.selectedStartMarkerLook = startMarkerLooks.selectedLook;
1773
+ this.highlightedStartMarkerLook = startMarkerLooks.highlightedLook;
1774
+ this.selectedAndHighlightedStartMarkerLook = startMarkerLooks.selectedAndHighlightedLook;
1775
+ } else {
1776
+ this.defaultStartMarkerLook = null;
1777
+ this.selectedStartMarkerLook = null;
1778
+ this.highlightedStartMarkerLook = null;
1779
+ this.selectedAndHighlightedStartMarkerLook = null;
1780
+ }
1781
+ if (values.endMarkerLook !== undefined) {
1782
+ const endMarkerLooks = extractLooksFromConfig(values.endMarkerLook);
1783
+ this.defaultEndMarkerLook = endMarkerLooks.defaultLook;
1784
+ this.selectedEndMarkerLook = endMarkerLooks.selectedLook;
1785
+ this.highlightedEndMarkerLook = endMarkerLooks.highlightedLook;
1786
+ this.selectedAndHighlightedEndMarkerLook = endMarkerLooks.selectedAndHighlightedLook;
1787
+ } else {
1788
+ this.defaultEndMarkerLook = null;
1789
+ this.selectedEndMarkerLook = null;
1790
+ this.highlightedEndMarkerLook = null;
1791
+ this.selectedAndHighlightedEndMarkerLook = null;
1792
+ }
1672
1793
  this.startTypes = values.startTypes;
1673
1794
  this.endTypes = values.endTypes;
1674
- this.color = values.color;
1675
- this.selectedColor = values.selectedColor;
1676
1795
  this.propertySet = new PropertySet(values.properties);
1677
1796
  }
1678
1797
  canStartFromType(type) {
@@ -1688,6 +1807,27 @@ class DiagramConnectionType {
1688
1807
  * @see DiagramPort
1689
1808
  */
1690
1809
  class DiagramConnection extends DiagramElement {
1810
+ get type() {
1811
+ return this._type;
1812
+ }
1813
+ set type(type) {
1814
+ var _a, _b;
1815
+ (_b = (_a = this.model.canvas) === null || _a === undefined ? undefined : _a.userSelection) === null || _b === undefined ? undefined : _b.openInPropertyEditor(undefined);
1816
+ this._type = type;
1817
+ if (this.valueSet) {
1818
+ this.valueSet = new ValueSet(type.propertySet, this);
1819
+ }
1820
+ this.updateInView();
1821
+ }
1822
+ get typeString() {
1823
+ return this.type.id;
1824
+ }
1825
+ set typeString(typeString) {
1826
+ const type = this.model.connections.types.get(typeString);
1827
+ if (type) {
1828
+ this.type = type;
1829
+ }
1830
+ }
1691
1831
  /**
1692
1832
  * Name of this connection. Alias for this connection's middle label.
1693
1833
  * @public
@@ -1698,10 +1838,127 @@ class DiagramConnection extends DiagramElement {
1698
1838
  set name(name) {
1699
1839
  this.middleLabel = name;
1700
1840
  }
1841
+ /**
1842
+ * Current look of the connection.
1843
+ * @private
1844
+ */
1845
+ get look() {
1846
+ if (this.selected) {
1847
+ if (this.highlighted) {
1848
+ return this._selectedAndHighlightedLook !== undefined ? this._selectedAndHighlightedLook : this.type.selectedAndHighlightedLook;
1849
+ } else {
1850
+ return this._selectedLook !== undefined ? this._selectedLook : this.type.selectedLook;
1851
+ }
1852
+ } else {
1853
+ if (this.highlighted) {
1854
+ return this._highlightedLook !== undefined ? this._highlightedLook : this.type.highlightedLook;
1855
+ } else {
1856
+ return this._defaultLook !== undefined ? this._defaultLook : this.type.defaultLook;
1857
+ }
1858
+ }
1859
+ }
1860
+ /**
1861
+ * Sets the look configuration of the connection to override the one determined by the type.
1862
+ * `undefined` resets it to the one determined by the type.
1863
+ * @private
1864
+ */
1865
+ set look(look) {
1866
+ if (look) {
1867
+ const looks = extractLooksFromConfig(look);
1868
+ this._defaultLook = Object.assign(Object.assign({}, this._defaultLook), looks.defaultLook);
1869
+ this._selectedLook = Object.assign(Object.assign({}, this._selectedLook), looks.selectedLook);
1870
+ this._highlightedLook = Object.assign(Object.assign({}, this._highlightedLook), looks.highlightedLook);
1871
+ this._selectedAndHighlightedLook = Object.assign(Object.assign({}, this._selectedAndHighlightedLook), looks.selectedAndHighlightedLook);
1872
+ } else {
1873
+ this._defaultLook = look;
1874
+ this._selectedLook = look;
1875
+ this._highlightedLook = look;
1876
+ this._selectedAndHighlightedLook = look;
1877
+ }
1878
+ }
1879
+ /**
1880
+ * Current look of the start marker.
1881
+ * @private
1882
+ */
1883
+ get startMarkerLook() {
1884
+ if (this.selected) {
1885
+ if (this.highlighted) {
1886
+ return this._selectedAndHighlightedStartMarkerLook !== undefined ? this._selectedAndHighlightedStartMarkerLook : this.type.selectedAndHighlightedStartMarkerLook;
1887
+ } else {
1888
+ return this._selectedStartMarkerLook !== undefined ? this._selectedStartMarkerLook : this.type.selectedStartMarkerLook;
1889
+ }
1890
+ } else {
1891
+ if (this.highlighted) {
1892
+ return this._highlightedStartMarkerLook !== undefined ? this._highlightedStartMarkerLook : this.type.highlightedStartMarkerLook;
1893
+ } else {
1894
+ return this._defaultStartMarkerLook !== undefined ? this._defaultStartMarkerLook : this.type.defaultStartMarkerLook;
1895
+ }
1896
+ }
1897
+ }
1898
+ /**
1899
+ * Sets the look configuration of the start marker to override the one determined by the type.
1900
+ * `null` stands for no marker and `undefined` resets it to the one determined by the type.
1901
+ * @private
1902
+ */
1903
+ set startMarkerLook(startMarkerLook) {
1904
+ if (startMarkerLook) {
1905
+ const looks = extractLooksFromConfig(startMarkerLook);
1906
+ this._defaultStartMarkerLook = Object.assign(Object.assign({}, this._defaultStartMarkerLook), looks.defaultLook);
1907
+ this._selectedStartMarkerLook = Object.assign(Object.assign({}, this._selectedStartMarkerLook), looks.selectedLook);
1908
+ this._highlightedStartMarkerLook = Object.assign(Object.assign({}, this._highlightedStartMarkerLook), looks.highlightedLook);
1909
+ this._selectedAndHighlightedStartMarkerLook = Object.assign(Object.assign({}, this._selectedAndHighlightedStartMarkerLook), looks.selectedAndHighlightedLook);
1910
+ } else {
1911
+ this._defaultStartMarkerLook = startMarkerLook;
1912
+ this._selectedStartMarkerLook = startMarkerLook;
1913
+ this._highlightedStartMarkerLook = startMarkerLook;
1914
+ this._selectedAndHighlightedStartMarkerLook = startMarkerLook;
1915
+ }
1916
+ }
1917
+ /**
1918
+ * Current look of the end marker.
1919
+ * @private
1920
+ */
1921
+ get endMarkerLook() {
1922
+ if (this.selected) {
1923
+ if (this.highlighted) {
1924
+ return this._selectedAndHighlightedEndMarkerLook !== undefined ? this._selectedAndHighlightedEndMarkerLook : this.type.selectedAndHighlightedEndMarkerLook;
1925
+ } else {
1926
+ return this._selectedEndMarkerLook !== undefined ? this._selectedEndMarkerLook : this.type.selectedEndMarkerLook;
1927
+ }
1928
+ } else {
1929
+ if (this.highlighted) {
1930
+ return this._highlightedEndMarkerLook !== undefined ? this._highlightedEndMarkerLook : this.type.highlightedEndMarkerLook;
1931
+ } else {
1932
+ return this._defaultEndMarkerLook !== undefined ? this._defaultEndMarkerLook : this.type.defaultEndMarkerLook;
1933
+ }
1934
+ }
1935
+ }
1936
+ /**
1937
+ * Sets the look configuration of the end marker to override the one determined by the type.
1938
+ * `null` stands for no marker and `undefined` resets it to the one determined by the type.
1939
+ * @private
1940
+ */
1941
+ set endMarkerLook(endMarkerLook) {
1942
+ if (endMarkerLook) {
1943
+ const looks = extractLooksFromConfig(endMarkerLook);
1944
+ this._defaultEndMarkerLook = Object.assign(Object.assign({}, this._defaultEndMarkerLook), looks.defaultLook);
1945
+ this._selectedEndMarkerLook = Object.assign(Object.assign({}, this._selectedEndMarkerLook), looks.selectedLook);
1946
+ this._highlightedEndMarkerLook = Object.assign(Object.assign({}, this._highlightedEndMarkerLook), looks.highlightedLook);
1947
+ this._selectedAndHighlightedEndMarkerLook = Object.assign(Object.assign({}, this._selectedAndHighlightedEndMarkerLook), looks.selectedAndHighlightedLook);
1948
+ } else {
1949
+ this._defaultEndMarkerLook = endMarkerLook;
1950
+ this._selectedEndMarkerLook = endMarkerLook;
1951
+ this._highlightedEndMarkerLook = endMarkerLook;
1952
+ this._selectedAndHighlightedEndMarkerLook = endMarkerLook;
1953
+ }
1954
+ }
1701
1955
  constructor(model, type, start, end, id) {
1702
1956
  if (model.connections.get(id) !== undefined) {
1703
1957
  throw new Error(`DiagramConnection with id "${id}" already exists`);
1704
1958
  }
1959
+ if (!id) {
1960
+ throw new Error(`DiagramConnection cannot have an empty or null id`);
1961
+ }
1705
1962
  super(model, id);
1706
1963
  /**
1707
1964
  * Coordinates of the start point of this connection.
@@ -1733,11 +1990,9 @@ class DiagramConnection extends DiagramElement {
1733
1990
  * @public
1734
1991
  */
1735
1992
  this.points = [];
1736
- this.type = type;
1993
+ this._type = type;
1737
1994
  this.valueSet = new ValueSet(type.propertySet, this);
1738
1995
  this.originalData = {};
1739
- this.startMarkerLook = type.defaultStartMarkerLook;
1740
- this.endMarkerLook = type.defaultEndMarkerLook;
1741
1996
  this.setStart(start);
1742
1997
  this.setEnd(end);
1743
1998
  }
@@ -1767,11 +2022,11 @@ class DiagramConnection extends DiagramElement {
1767
2022
  if (start !== undefined) {
1768
2023
  start.outgoingConnections.push(this);
1769
2024
  this.startDirection = start === null || start === undefined ? undefined : start.direction;
1770
- this.startCoords = (start === null || start === undefined ? undefined : start.coords) || [0, 0];
2025
+ this.startCoords = (start === null || start === undefined ? undefined : start.connectionPoint) || [0, 0];
1771
2026
  }
1772
2027
  } else {
1773
2028
  this.startDirection = start === null || start === undefined ? undefined : start.direction;
1774
- this.startCoords = (start === null || start === undefined ? undefined : start.coords) || [0, 0];
2029
+ this.startCoords = (start === null || start === undefined ? undefined : start.connectionPoint) || [0, 0];
1775
2030
  }
1776
2031
  this.updateInView();
1777
2032
  }
@@ -1790,11 +2045,11 @@ class DiagramConnection extends DiagramElement {
1790
2045
  if (end !== undefined) {
1791
2046
  end.incomingConnections.push(this);
1792
2047
  this.endDirection = end === null || end === undefined ? undefined : end.direction;
1793
- this.endCoords = (end === null || end === undefined ? undefined : end.coords) || [0, 0];
2048
+ this.endCoords = (end === null || end === undefined ? undefined : end.connectionPoint) || [0, 0];
1794
2049
  }
1795
2050
  } else {
1796
2051
  this.endDirection = end === null || end === undefined ? undefined : end.direction;
1797
- this.endCoords = (end === null || end === undefined ? undefined : end.coords) || [0, 0];
2052
+ this.endCoords = (end === null || end === undefined ? undefined : end.connectionPoint) || [0, 0];
1798
2053
  }
1799
2054
  this.updateInView();
1800
2055
  }
@@ -1812,6 +2067,10 @@ class DiagramConnection extends DiagramElement {
1812
2067
  // alternative start port not valid, it is the same as the end port
1813
2068
  continue checkAlternativeStartPorts;
1814
2069
  }
2070
+ if (!alternativeStartPort.allowsOutgoing) {
2071
+ // alternative start port not valid, it doesn't allow outgoing connections
2072
+ continue checkAlternativeStartPorts;
2073
+ }
1815
2074
  {
1816
2075
  for (const connection of alternativeStartPort.outgoingConnections) {
1817
2076
  if (connection !== this && connection.end === this.end) {
@@ -1839,24 +2098,28 @@ class DiagramConnection extends DiagramElement {
1839
2098
  const alternativeEndPortsSortedByDistanceAscending = this.end.rootElement.ports.map(p => [p, p.distanceTo(this.start.coords)]).sort((a, b) => a[1] - b[1]).map(a => a[0]);
1840
2099
  checkAlternativeEndPorts: for (const alternativeEndPort of alternativeEndPortsSortedByDistanceAscending) {
1841
2100
  if (alternativeEndPort === this.start) {
1842
- // alternative start port not valid, it is the same as the end port
2101
+ // alternative end port not valid, it is the same as the end port
2102
+ continue checkAlternativeEndPorts;
2103
+ }
2104
+ if (!alternativeEndPort.allowsIncoming) {
2105
+ // alternative end port not valid, it doesn't allow incoming connections
1843
2106
  continue checkAlternativeEndPorts;
1844
2107
  }
1845
2108
  {
1846
2109
  for (const connection of alternativeEndPort.incomingConnections) {
1847
2110
  if (connection !== this && connection.start === this.start) {
1848
- // alternative start port not valid, there is a connection whose start and end matches the alternative end port and this connection's start
2111
+ // alternative end port not valid, there is a connection whose start and end matches the alternative end port and this connection's start
1849
2112
  continue checkAlternativeEndPorts;
1850
2113
  }
1851
2114
  }
1852
2115
  for (const connection of alternativeEndPort.outgoingConnections) {
1853
2116
  if (connection !== this && connection.end === this.start) {
1854
- // alternative start port not valid, there is a connection whose start and end matches the alternative end port and this connection's start
2117
+ // alternative end port not valid, there is a connection whose start and end matches the alternative end port and this connection's start
1855
2118
  continue checkAlternativeEndPorts;
1856
2119
  }
1857
2120
  }
1858
2121
  }
1859
- // found a valid start port
2122
+ // found a valid end port
1860
2123
  if (alternativeEndPort === this.end) {
1861
2124
  break checkAlternativeEndPorts;
1862
2125
  } else {
@@ -1902,7 +2165,7 @@ class DiagramConnectionSet extends DiagramElementSet {
1902
2165
  * @param type The type of the connection given as either the type itself or the id of the type.
1903
2166
  * @param start The start port of the connection.
1904
2167
  * @param end The end port of the connection.
1905
- * @param id The id of the connection.
2168
+ * @param id The id of the connection. Cannot be an empty string.
1906
2169
  * @returns The instanced connection.
1907
2170
  */
1908
2171
  new(type, start, end, id) {
@@ -2228,30 +2491,6 @@ const getTopPadding$1 = config => {
2228
2491
  }
2229
2492
  };
2230
2493
 
2231
- /**
2232
- * Default values of the look of a diagram section.
2233
- * @private
2234
- * @see DIAGRAM_SECTION_DEFAULTS
2235
- */
2236
- const DIAGRAM_SECTION_LOOK_DEFAULTS = {
2237
- lookType: 'shaped-look',
2238
- shape: ClosedShape.Rectangle,
2239
- fillColor: '#FFFFFF',
2240
- borderColor: '#000000',
2241
- selectedFillColor: '#FFFFFF',
2242
- selectedBorderColor: '#000000'
2243
- };
2244
- /**
2245
- * Default values of the parameters of a diagram section.
2246
- * @private
2247
- * @see DiagramSection
2248
- */
2249
- const DIAGRAM_SECTION_DEFAULTS = {
2250
- label: null,
2251
- ports: [],
2252
- look: DIAGRAM_SECTION_LOOK_DEFAULTS,
2253
- priority: DEFAULT_PRIORITY
2254
- };
2255
2494
  /**
2256
2495
  * Default value of the default width of a diagram section.
2257
2496
  * @private
@@ -2276,6 +2515,41 @@ const DIAGRAM_SECTION_MIN_WIDTH = 1;
2276
2515
  * @see DiagramSection
2277
2516
  */
2278
2517
  const DIAGRAM_SECTION_MIN_HEIGHT = 1;
2518
+ /**
2519
+ * A grid of sections which a node has.
2520
+ * @public
2521
+ * @see DiagramNode
2522
+ * @see SectionGridConfig
2523
+ */
2524
+ class DiagramSectionGrid {
2525
+ constructor(options) {
2526
+ this.margin = options.margin || 0;
2527
+ this.defaultWidths = options.defaultWidths || null;
2528
+ this.defaultHeights = options.defaultHeights || null;
2529
+ this.minWidths = options.minWidths || null;
2530
+ this.minHeights = options.minHeights || null;
2531
+ this.sections = [];
2532
+ for (const sectionRow of options.sections) {
2533
+ const sectionList = [];
2534
+ this.sections.push(sectionList);
2535
+ for (const section of sectionRow) {
2536
+ sectionList.push(new DiagramSectionType(section));
2537
+ }
2538
+ }
2539
+ }
2540
+ }
2541
+ class DiagramSectionType {
2542
+ constructor(options) {
2543
+ this.label = options.label || null;
2544
+ this.ports = options.ports || [];
2545
+ this.priority = options.priority || DEFAULT_PRIORITY;
2546
+ const looks = extractLooksFromConfig(options.look || DIAGRAM_NODE_LOOK_DEFAULTS);
2547
+ this.defaultLook = looks.defaultLook;
2548
+ this.selectedLook = looks.selectedLook;
2549
+ this.highlightedLook = looks.highlightedLook;
2550
+ this.selectedAndHighlightedLook = looks.selectedAndHighlightedLook;
2551
+ }
2552
+ }
2279
2553
  /**
2280
2554
  * A section of a node which can have connections and display a property of the node.
2281
2555
  * @public
@@ -2297,10 +2571,52 @@ class DiagramSection extends DiagramElement {
2297
2571
  this.label.text = name;
2298
2572
  }
2299
2573
  }
2574
+ /**
2575
+ * Current look of this port.
2576
+ * @private
2577
+ */
2578
+ get look() {
2579
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2580
+ if (this.selected) {
2581
+ if (this.highlighted) {
2582
+ return this._selectedAndHighlightedLook !== undefined ? this._selectedAndHighlightedLook : ((_a = this.type) === null || _a === undefined ? undefined : _a.selectedAndHighlightedLook) || ((_b = this.node) === null || _b === undefined ? undefined : _b.look);
2583
+ } else {
2584
+ return this._selectedLook !== undefined ? this._selectedLook : ((_c = this.type) === null || _c === undefined ? undefined : _c.selectedLook) || ((_d = this.node) === null || _d === undefined ? undefined : _d.look);
2585
+ }
2586
+ } else {
2587
+ if (this.highlighted) {
2588
+ return this._highlightedLook !== undefined ? this._highlightedLook : ((_e = this.type) === null || _e === undefined ? undefined : _e.highlightedLook) || ((_f = this.node) === null || _f === undefined ? undefined : _f.look);
2589
+ } else {
2590
+ return this._defaultLook !== undefined ? this._defaultLook : ((_g = this.type) === null || _g === undefined ? undefined : _g.defaultLook) || ((_h = this.node) === null || _h === undefined ? undefined : _h.look);
2591
+ }
2592
+ }
2593
+ }
2594
+ /**
2595
+ * Sets the look configuration of the look to override the one determined by the type.
2596
+ * `undefined` resets it to the one determined by the type.
2597
+ * @private
2598
+ */
2599
+ set look(look) {
2600
+ if (look) {
2601
+ const looks = extractLooksFromConfig(look);
2602
+ this._defaultLook = Object.assign(Object.assign({}, this._defaultLook), looks.defaultLook);
2603
+ this._selectedLook = Object.assign(Object.assign({}, this._selectedLook), looks.selectedLook);
2604
+ this._highlightedLook = Object.assign(Object.assign({}, this._highlightedLook), looks.highlightedLook);
2605
+ this._selectedAndHighlightedLook = Object.assign(Object.assign({}, this._selectedAndHighlightedLook), looks.selectedAndHighlightedLook);
2606
+ } else {
2607
+ this._defaultLook = look;
2608
+ this._selectedLook = look;
2609
+ this._highlightedLook = look;
2610
+ this._selectedAndHighlightedLook = look;
2611
+ }
2612
+ }
2300
2613
  constructor(model, node, indexXInNode, indexYInNode, coords, width, height, id) {
2301
2614
  if (model.sections.get(id) !== undefined) {
2302
2615
  throw new Error(`DiagramSection with id "${id}" already exists`);
2303
2616
  }
2617
+ if (!id) {
2618
+ throw new Error(`DiagramSection cannot have an empty or null id`);
2619
+ }
2304
2620
  super(model, id);
2305
2621
  /**
2306
2622
  * Ports of this section.
@@ -2339,7 +2655,7 @@ class DiagramSection extends DiagramElement {
2339
2655
  decorator.raise();
2340
2656
  }
2341
2657
  }
2342
- getConfig() {
2658
+ get type() {
2343
2659
  var _a, _b, _c, _d, _e;
2344
2660
  return (_e = (_d = (_c = (_b = (_a = this.node) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.sectionGrid) === null || _c === undefined ? undefined : _c.sections) === null || _d === undefined ? undefined : _d[this.indexYInNode]) === null || _e === undefined ? undefined : _e[this.indexXInNode];
2345
2661
  }
@@ -2353,7 +2669,7 @@ class DiagramSection extends DiagramElement {
2353
2669
  }
2354
2670
  getPriority() {
2355
2671
  var _a, _b, _c, _d, _e, _f;
2356
- return ((_f = (_e = (_d = (_c = (_b = (_a = this.node) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.sectionGrid) === null || _c === undefined ? undefined : _c.sections) === null || _d === undefined ? undefined : _d[this.indexYInNode]) === null || _e === undefined ? undefined : _e[this.indexXInNode]) === null || _f === undefined ? undefined : _f.priority) || DIAGRAM_SECTION_DEFAULTS.priority;
2672
+ return ((_f = (_e = (_d = (_c = (_b = (_a = this.node) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.sectionGrid) === null || _c === undefined ? undefined : _c.sections) === null || _d === undefined ? undefined : _d[this.indexYInNode]) === null || _e === undefined ? undefined : _e[this.indexXInNode]) === null || _f === undefined ? undefined : _f.priority) || DEFAULT_PRIORITY;
2357
2673
  }
2358
2674
  /**
2359
2675
  * Get the port of this section which is closest to the given coordinates.
@@ -2504,7 +2820,6 @@ class DiagramSection extends DiagramElement {
2504
2820
  * @public
2505
2821
  */
2506
2822
  setGeometry(geometry) {
2507
- var _a, _b, _c, _d, _e, _f;
2508
2823
  const oldCoordsX = [this.coords[0], this.coords[0] + this.width];
2509
2824
  const oldCoordsY = [this.coords[1], this.coords[1] + this.height];
2510
2825
  this.coords = [...geometry.coords];
@@ -2517,10 +2832,11 @@ class DiagramSection extends DiagramElement {
2517
2832
  port.move(translatePoint(port.coords, oldCoordsX, oldCoordsY, newCoordsX, newCoordsY));
2518
2833
  }
2519
2834
  // Set label's dimensions as a function of ours.
2835
+ const type = this.type;
2520
2836
  if (this.label) {
2521
- this.label.coords = [this.coords[0] + getLeftMargin((_a = this.getConfig()) === null || _a === undefined ? undefined : _a.label), this.coords[1] + getTopMargin((_b = this.getConfig()) === null || _b === undefined ? undefined : _b.label)];
2522
- this.label.width = this.width - getLeftMargin((_c = this.getConfig()) === null || _c === undefined ? undefined : _c.label) - getRightMargin((_d = this.getConfig()) === null || _d === undefined ? undefined : _d.label);
2523
- this.label.height = this.height - getTopMargin((_e = this.getConfig()) === null || _e === undefined ? undefined : _e.label) - getBottomMargin((_f = this.getConfig()) === null || _f === undefined ? undefined : _f.label);
2837
+ this.label.coords = [this.coords[0] + getLeftMargin(type === null || type === undefined ? undefined : type.label), this.coords[1] + getTopMargin(type === null || type === undefined ? undefined : type.label)];
2838
+ this.label.width = this.width - getLeftMargin(type === null || type === undefined ? undefined : type.label) - getRightMargin(type === null || type === undefined ? undefined : type.label);
2839
+ this.label.height = this.height - getTopMargin(type === null || type === undefined ? undefined : type.label) - getBottomMargin(type === null || type === undefined ? undefined : type.label);
2524
2840
  this.label.updateInView();
2525
2841
  }
2526
2842
  // Move decorators to match the new coords.
@@ -2558,25 +2874,25 @@ class DiagramSectionSet extends DiagramElementSet {
2558
2874
  if (sectionPorts && sectionPorts.length > 0) {
2559
2875
  for (let i = 0; i < sectionPorts.length; ++i) {
2560
2876
  const portConfig = sectionPorts[i];
2561
- const port = this.model.ports.new(section, [section.coords[0] + (((_e = portConfig === null || portConfig === undefined ? undefined : portConfig.coords) === null || _e === undefined ? undefined : _e[0]) || 0), section.coords[1] + (((_f = portConfig === null || portConfig === undefined ? undefined : portConfig.coords) === null || _f === undefined ? undefined : _f[1]) || 0)], portConfig === null || portConfig === undefined ? undefined : portConfig.direction, `${section.id}_${i}`);
2562
- if (portConfig.label) {
2563
- const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), portConfig.label);
2877
+ const port = this.model.ports.new(portConfig.type !== undefined ? this.model.ports.types.get(portConfig.type) : undefined, section, [section.coords[0] + (portConfig.coords[0] || 0), section.coords[1] + (portConfig.coords[1] || 0)], portConfig.connectionPoint !== undefined ? [section.coords[0] + (portConfig.connectionPoint[0] || 0), section.coords[1] + (portConfig.connectionPoint[1] || 0)] : undefined, portConfig === null || portConfig === undefined ? undefined : portConfig.direction, `${section.id}_${i}`);
2878
+ if ((_e = port.type) === null || _e === undefined ? undefined : _e.label) {
2879
+ const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), (_f = port.type) === null || _f === undefined ? undefined : _f.label);
2880
+ const labelWidth = 6 * labelConfiguration.fontSize + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
2881
+ const labelHeight = labelConfiguration.fontSize + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
2564
2882
  let labelCoords;
2565
2883
  switch (port.direction) {
2566
- case Side.Top:
2567
- case Side.Left:
2568
- labelCoords = [port.coords[0] - labelConfiguration.fontSize, port.coords[1] - labelConfiguration.fontSize];
2569
- break;
2570
2884
  case Side.Bottom:
2571
- labelCoords = [port.coords[0] - labelConfiguration.fontSize, port.coords[1] + labelConfiguration.fontSize];
2572
- break;
2885
+ case Side.Left:
2573
2886
  case Side.Right:
2574
- labelCoords = [port.coords[0] + labelConfiguration.fontSize, port.coords[1] - labelConfiguration.fontSize];
2887
+ labelCoords = [port.coords[0] - labelWidth / 2, port.coords[1] - labelHeight - getBottomMargin(labelConfiguration)];
2888
+ break;
2889
+ case Side.Top:
2890
+ labelCoords = [port.coords[0] - labelWidth / 2, port.coords[1] + getTopMargin(labelConfiguration)];
2575
2891
  break;
2576
2892
  default:
2577
2893
  labelCoords = port.coords;
2578
2894
  }
2579
- this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
2895
+ this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelWidth, labelHeight, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
2580
2896
  }
2581
2897
  }
2582
2898
  }
@@ -2621,8 +2937,14 @@ const DIAGRAM_NODE_LOOK_DEFAULTS = {
2621
2937
  shape: ClosedShape.Rectangle,
2622
2938
  fillColor: '#FFFFFF',
2623
2939
  borderColor: '#000000',
2624
- selectedFillColor: '#FFFFFF',
2625
- selectedBorderColor: '#000000'
2940
+ borderThickness: 1,
2941
+ selected: {
2942
+ fillColor: '#FFAAFF',
2943
+ borderColor: '#AA00AA'
2944
+ },
2945
+ highlighted: {
2946
+ borderThickness: 3
2947
+ }
2626
2948
  };
2627
2949
  /**
2628
2950
  * Default values of the parameters of a diagram node.
@@ -2670,8 +2992,12 @@ class DiagramNodeType {
2670
2992
  this.topPadding = getTopPadding(values);
2671
2993
  this.label = values.label;
2672
2994
  this.ports = values.ports;
2673
- this.sectionGrid = values.sectionGrid;
2674
- this.look = values.look;
2995
+ this.sectionGrid = values.sectionGrid ? new DiagramSectionGrid(values.sectionGrid) : null;
2996
+ const looks = extractLooksFromConfig(values.look);
2997
+ this.defaultLook = looks.defaultLook;
2998
+ this.selectedLook = looks.selectedLook;
2999
+ this.highlightedLook = looks.highlightedLook;
3000
+ this.selectedAndHighlightedLook = looks.selectedAndHighlightedLook;
2675
3001
  this.isUnique = values.isUnique;
2676
3002
  this.canBeParentless = values.canBeParentless;
2677
3003
  this.childrenTypes = values.childrenTypes;
@@ -2687,6 +3013,27 @@ class DiagramNodeType {
2687
3013
  * @see DiagramSection
2688
3014
  */
2689
3015
  class DiagramNode extends DiagramElement {
3016
+ get type() {
3017
+ return this._type;
3018
+ }
3019
+ set type(type) {
3020
+ var _a, _b;
3021
+ (_b = (_a = this.model.canvas) === null || _a === undefined ? undefined : _a.userSelection) === null || _b === undefined ? undefined : _b.openInPropertyEditor(undefined);
3022
+ this._type = type;
3023
+ if (this.valueSet) {
3024
+ this.valueSet = new ValueSet(type.propertySet, this);
3025
+ }
3026
+ this.updateInView();
3027
+ }
3028
+ get typeString() {
3029
+ return this.type.id;
3030
+ }
3031
+ set typeString(typeString) {
3032
+ const type = this.model.nodes.types.get(typeString);
3033
+ if (type) {
3034
+ this.type = type;
3035
+ }
3036
+ }
2690
3037
  /**
2691
3038
  * Name of this node. Alias for this node's label's text.
2692
3039
  * @public
@@ -2700,10 +3047,51 @@ class DiagramNode extends DiagramElement {
2700
3047
  this.label.text = name;
2701
3048
  }
2702
3049
  }
3050
+ /**
3051
+ * Current look of this port.
3052
+ * @private
3053
+ */
3054
+ get look() {
3055
+ if (this.selected) {
3056
+ if (this.highlighted) {
3057
+ return this._selectedAndHighlightedLook !== undefined ? this._selectedAndHighlightedLook : this.type.selectedAndHighlightedLook;
3058
+ } else {
3059
+ return this._selectedLook !== undefined ? this._selectedLook : this.type.selectedLook;
3060
+ }
3061
+ } else {
3062
+ if (this.highlighted) {
3063
+ return this._highlightedLook !== undefined ? this._highlightedLook : this.type.highlightedLook;
3064
+ } else {
3065
+ return this._defaultLook !== undefined ? this._defaultLook : this.type.defaultLook;
3066
+ }
3067
+ }
3068
+ }
3069
+ /**
3070
+ * Sets the look configuration of the look to override the one determined by the type.
3071
+ * `undefined` resets it to the one determined by the type.
3072
+ * @private
3073
+ */
3074
+ set look(look) {
3075
+ if (look) {
3076
+ const looks = extractLooksFromConfig(look);
3077
+ this._defaultLook = Object.assign(Object.assign({}, this._defaultLook), looks.defaultLook);
3078
+ this._selectedLook = Object.assign(Object.assign({}, this._selectedLook), looks.selectedLook);
3079
+ this._highlightedLook = Object.assign(Object.assign({}, this._highlightedLook), looks.highlightedLook);
3080
+ this._selectedAndHighlightedLook = Object.assign(Object.assign({}, this._selectedAndHighlightedLook), looks.selectedAndHighlightedLook);
3081
+ } else {
3082
+ this._defaultLook = look;
3083
+ this._selectedLook = look;
3084
+ this._highlightedLook = look;
3085
+ this._selectedAndHighlightedLook = look;
3086
+ }
3087
+ }
2703
3088
  constructor(model, type, coords = [0, 0], id) {
2704
3089
  if (model.nodes.get(id) !== undefined) {
2705
3090
  throw new Error(`DiagramNode with id "${id}" already exists`);
2706
3091
  }
3092
+ if (!id) {
3093
+ throw new Error(`DiagramNode cannot have an empty or null id`);
3094
+ }
2707
3095
  super(model, id);
2708
3096
  /**
2709
3097
  * Nodes contained within this node.
@@ -2730,7 +3118,7 @@ class DiagramNode extends DiagramElement {
2730
3118
  * @public
2731
3119
  */
2732
3120
  this.geometryTimestamp = null;
2733
- this.type = type;
3121
+ this._type = type;
2734
3122
  this.valueSet = new ValueSet(type.propertySet, this);
2735
3123
  this.originalData = {};
2736
3124
  this.coords = coords;
@@ -3209,11 +3597,11 @@ class DiagramNodeSet extends DiagramElementSet {
3209
3597
  * @public
3210
3598
  * @param type The type of the node given as either the type itself or the id of the type.
3211
3599
  * @param coords The coordinates of the top left corner of the node in the diagram.
3212
- * @param id The id of the node.
3600
+ * @param id The id of the node. Cannot be an empty string.
3213
3601
  * @returns The instanced node.
3214
3602
  */
3215
3603
  new(type, coords, id) {
3216
- var _a, _b, _c, _d, _e;
3604
+ var _a, _b, _c, _d, _e, _f, _g;
3217
3605
  let nodeType;
3218
3606
  if (type instanceof DiagramNodeType) {
3219
3607
  nodeType = type;
@@ -3244,25 +3632,26 @@ class DiagramNodeSet extends DiagramElementSet {
3244
3632
  if (nodeType.ports.length > 0) {
3245
3633
  for (let i = 0; i < nodeType.ports.length; ++i) {
3246
3634
  const portConfig = nodeType.ports[i];
3247
- const port = this.model.ports.new(node, [node.coords[0] + portConfig.coords[0], node.coords[1] + portConfig.coords[1]], portConfig.direction, `${node.id}_${i}`);
3248
- if (portConfig.label) {
3249
- const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), portConfig.label);
3635
+ const portType = portConfig.type !== undefined ? this.model.ports.types.get(portConfig.type) : undefined;
3636
+ const port = this.model.ports.new(portType, node, [node.coords[0] + portConfig.coords[0], node.coords[1] + portConfig.coords[1]], portConfig.connectionPoint !== undefined ? [node.coords[0] + (portConfig.connectionPoint[0] || 0), node.coords[1] + (portConfig.connectionPoint[1] || 0)] : undefined, portConfig.direction, `${node.id}_${i}`);
3637
+ if ((_e = port.type) === null || _e === undefined ? undefined : _e.label) {
3638
+ const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), (_f = port.type) === null || _f === undefined ? undefined : _f.label);
3639
+ const labelWidth = 6 * labelConfiguration.fontSize + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
3640
+ const labelHeight = labelConfiguration.fontSize + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
3250
3641
  let labelCoords;
3251
3642
  switch (port.direction) {
3252
- case Side.Top:
3253
- case Side.Left:
3254
- labelCoords = [port.coords[0] - labelConfiguration.fontSize, port.coords[1] - labelConfiguration.fontSize];
3255
- break;
3256
3643
  case Side.Bottom:
3257
- labelCoords = [port.coords[0] - labelConfiguration.fontSize, port.coords[1] + labelConfiguration.fontSize];
3258
- break;
3644
+ case Side.Left:
3259
3645
  case Side.Right:
3260
- labelCoords = [port.coords[0] + labelConfiguration.fontSize, port.coords[1] - labelConfiguration.fontSize];
3646
+ labelCoords = [port.coords[0] - labelWidth / 2, port.coords[1] - labelHeight - getBottomMargin(labelConfiguration)];
3647
+ break;
3648
+ case Side.Top:
3649
+ labelCoords = [port.coords[0] - labelWidth / 2, port.coords[1] + getTopMargin(labelConfiguration)];
3261
3650
  break;
3262
3651
  default:
3263
3652
  labelCoords = port.coords;
3264
3653
  }
3265
- this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
3654
+ this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelWidth, labelHeight, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
3266
3655
  }
3267
3656
  }
3268
3657
  }
@@ -3272,7 +3661,7 @@ class DiagramNodeSet extends DiagramElementSet {
3272
3661
  this.model.fields.new(node, [node.coords[0] + getLeftMargin(labelConfiguration), node.coords[1] + getTopMargin(labelConfiguration)], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, node.width - getLeftMargin(labelConfiguration) - getRightMargin(labelConfiguration), node.height - getTopMargin(labelConfiguration) - getBottomMargin(labelConfiguration), labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
3273
3662
  }
3274
3663
  node.valueSet.resetValues();
3275
- (_e = node.model.canvas) === null || _e === undefined ? undefined : _e.fitNodeInView(node.id);
3664
+ (_g = node.model.canvas) === null || _g === undefined ? undefined : _g.fitNodeInView(node.id);
3276
3665
  return node;
3277
3666
  }
3278
3667
  remove(id) {
@@ -3440,16 +3829,59 @@ const getTopPadding = config => {
3440
3829
  }
3441
3830
  };
3442
3831
 
3832
+ /**
3833
+ * Default values of the look of a diagram port.
3834
+ * @private
3835
+ * @see DIAGRAM_NODE_TYPE_DEFAULTS
3836
+ */
3837
+ const DIAGRAM_PORT_LOOK_DEFAULTS = {
3838
+ lookType: 'shaped-look',
3839
+ shape: ClosedShape.Ellipse,
3840
+ fillColor: 'transparent',
3841
+ borderColor: 'transparent',
3842
+ borderThickness: 0,
3843
+ selected: {
3844
+ fillColor: 'rgba(255, 0, 255, 0.5)'
3845
+ },
3846
+ highlighted: {
3847
+ fillColor: 'rgba(0, 255, 255, 0.5)'
3848
+ }
3849
+ };
3850
+ const DIAGRAM_PORT_LOOKS = extractLooksFromConfig(DIAGRAM_PORT_LOOK_DEFAULTS);
3443
3851
  /**
3444
3852
  * Default values of the parameters of a diagram port.
3445
3853
  * @private
3446
3854
  * @see DiagramPort
3447
3855
  */
3448
- const DIAGRAM_PORT_DEFAULTS = {
3449
- radius: 12,
3450
- highlightedColor: 'cyan',
3451
- selectedColor: 'violet'
3856
+ const DIAGRAM_PORT_TYPE_DEFAULTS = {
3857
+ name: '',
3858
+ label: null,
3859
+ allowsOutgoing: true,
3860
+ allowsIncoming: true,
3861
+ width: 24,
3862
+ look: DIAGRAM_PORT_LOOK_DEFAULTS
3452
3863
  };
3864
+ /**
3865
+ * A port type, which holds properties that ports of this type share in common.
3866
+ * @public
3867
+ * @see PortTypeConfig
3868
+ */
3869
+ class DiagramPortType {
3870
+ constructor(options) {
3871
+ const values = Object.assign(Object.assign({}, DIAGRAM_PORT_TYPE_DEFAULTS), options);
3872
+ this.id = values.id;
3873
+ this.name = values.name;
3874
+ this.label = values.label;
3875
+ this.allowsOutgoing = values.allowsOutgoing;
3876
+ this.allowsIncoming = values.allowsIncoming;
3877
+ this.width = values.width;
3878
+ const looks = extractLooksFromConfig(values.look);
3879
+ this.defaultLook = looks.defaultLook;
3880
+ this.selectedLook = looks.selectedLook;
3881
+ this.highlightedLook = looks.highlightedLook;
3882
+ this.selectedAndHighlightedLook = looks.selectedAndHighlightedLook;
3883
+ }
3884
+ }
3453
3885
  /**
3454
3886
  * A port which is part of a node or section and at which connections can start or end.
3455
3887
  * @public
@@ -3458,10 +3890,115 @@ const DIAGRAM_PORT_DEFAULTS = {
3458
3890
  * @see DiagramSection
3459
3891
  */
3460
3892
  class DiagramPort extends DiagramElement {
3461
- constructor(model, rootElement, coords, direction, id) {
3893
+ get type() {
3894
+ return this._type;
3895
+ }
3896
+ set type(type) {
3897
+ this._type = type;
3898
+ this.updateInView();
3899
+ }
3900
+ get typeString() {
3901
+ var _a;
3902
+ return (_a = this.type) === null || _a === undefined ? undefined : _a.id;
3903
+ }
3904
+ set typeString(typeString) {
3905
+ if (typeString === undefined) {
3906
+ this.type = undefined;
3907
+ } else {
3908
+ const type = this.model.ports.types.get(typeString);
3909
+ if (type) {
3910
+ this.type = type;
3911
+ }
3912
+ }
3913
+ }
3914
+ /**
3915
+ * Whether this port can be used as a connection start point.
3916
+ */
3917
+ get allowsOutgoing() {
3918
+ var _a, _b;
3919
+ return ((_a = this.type) === null || _a === undefined ? undefined : _a.allowsOutgoing) !== undefined ? (_b = this.type) === null || _b === undefined ? undefined : _b.allowsOutgoing : true;
3920
+ }
3921
+ /**
3922
+ * Whether this port can be used as a connection end point.
3923
+ */
3924
+ get allowsIncoming() {
3925
+ var _a, _b;
3926
+ return ((_a = this.type) === null || _a === undefined ? undefined : _a.allowsIncoming) !== undefined ? (_b = this.type) === null || _b === undefined ? undefined : _b.allowsIncoming : true;
3927
+ }
3928
+ /**
3929
+ * Name of this port. Alias for this port's label's text.
3930
+ * @public
3931
+ */
3932
+ get name() {
3933
+ var _a;
3934
+ return ((_a = this.label) === null || _a === undefined ? undefined : _a.text) || '';
3935
+ }
3936
+ set name(name) {
3937
+ if (this.label) {
3938
+ this.label.text = name;
3939
+ }
3940
+ }
3941
+ /**
3942
+ * Current look of this port.
3943
+ * @private
3944
+ */
3945
+ get look() {
3946
+ var _a, _b, _c, _d;
3947
+ if (this.selected) {
3948
+ if (this.highlighted) {
3949
+ return this._selectedAndHighlightedLook !== undefined ? this._selectedAndHighlightedLook : (_a = this.type || DIAGRAM_PORT_LOOKS) === null || _a === undefined ? undefined : _a.selectedAndHighlightedLook;
3950
+ } else {
3951
+ return this._selectedLook !== undefined ? this._selectedLook : (_b = this.type || DIAGRAM_PORT_LOOKS) === null || _b === undefined ? undefined : _b.selectedLook;
3952
+ }
3953
+ } else {
3954
+ if (this.highlighted) {
3955
+ return this._highlightedLook !== undefined ? this._highlightedLook : (_c = this.type || DIAGRAM_PORT_LOOKS) === null || _c === undefined ? undefined : _c.highlightedLook;
3956
+ } else {
3957
+ return this._defaultLook !== undefined ? this._defaultLook : (_d = this.type || DIAGRAM_PORT_LOOKS) === null || _d === undefined ? undefined : _d.defaultLook;
3958
+ }
3959
+ }
3960
+ }
3961
+ /**
3962
+ * Sets the look configuration of the look to override the one determined by the type.
3963
+ * `undefined` resets it to the one determined by the type.
3964
+ * @private
3965
+ */
3966
+ set look(look) {
3967
+ if (look) {
3968
+ const looks = extractLooksFromConfig(look);
3969
+ this._defaultLook = Object.assign(Object.assign({}, this._defaultLook), looks.defaultLook);
3970
+ this._selectedLook = Object.assign(Object.assign({}, this._selectedLook), looks.selectedLook);
3971
+ this._highlightedLook = Object.assign(Object.assign({}, this._highlightedLook), looks.highlightedLook);
3972
+ this._selectedAndHighlightedLook = Object.assign(Object.assign({}, this._selectedAndHighlightedLook), looks.selectedAndHighlightedLook);
3973
+ } else {
3974
+ this._defaultLook = look;
3975
+ this._selectedLook = look;
3976
+ this._highlightedLook = look;
3977
+ this._selectedAndHighlightedLook = look;
3978
+ }
3979
+ }
3980
+ /**
3981
+ * Current width of this port.
3982
+ * @private
3983
+ */
3984
+ get width() {
3985
+ var _a;
3986
+ return ((_a = this.type) === null || _a === undefined ? undefined : _a.width) || DIAGRAM_PORT_TYPE_DEFAULTS.width;
3987
+ }
3988
+ /**
3989
+ * Current height of this port. Same as the width.
3990
+ * @private
3991
+ */
3992
+ get height() {
3993
+ return this.width;
3994
+ }
3995
+ constructor(model, type, rootElement, coords, connectionPoint, direction, id) {
3462
3996
  if (model.ports.get(id) !== undefined) {
3463
3997
  throw new Error(`DiagramPort with id "${id}" already exists`);
3464
3998
  }
3999
+ if (!id) {
4000
+ throw new Error(`DiagramPort cannot have an empty or null id`);
4001
+ }
3465
4002
  super(model, id);
3466
4003
  /**
3467
4004
  * Connections that start at this port.
@@ -3473,8 +4010,10 @@ class DiagramPort extends DiagramElement {
3473
4010
  * @public
3474
4011
  */
3475
4012
  this.incomingConnections = [];
4013
+ this._type = type;
3476
4014
  this.rootElement = rootElement;
3477
4015
  this.coords = coords;
4016
+ this.connectionPoint = connectionPoint || coords;
3478
4017
  this.direction = direction;
3479
4018
  }
3480
4019
  get removed() {
@@ -3487,6 +4026,9 @@ class DiagramPort extends DiagramElement {
3487
4026
  raise() {
3488
4027
  var _a;
3489
4028
  (_a = this.select()) === null || _a === undefined ? undefined : _a.raise();
4029
+ if (this.label) {
4030
+ this.label.raise();
4031
+ }
3490
4032
  for (const connection of this.incomingConnections) {
3491
4033
  connection.raise();
3492
4034
  }
@@ -3535,6 +4077,8 @@ class DiagramPort extends DiagramElement {
3535
4077
  move(coords) {
3536
4078
  const coordDifferences = [coords[0] - this.coords[0], coords[1] - this.coords[1]];
3537
4079
  this.coords = coords;
4080
+ this.connectionPoint[0] = this.connectionPoint[0] + coordDifferences[0];
4081
+ this.connectionPoint[1] = this.connectionPoint[1] + coordDifferences[1];
3538
4082
  for (const connection of this.outgoingConnections) {
3539
4083
  connection.setStart(this);
3540
4084
  }
@@ -3557,14 +4101,19 @@ class DiagramPortSet extends DiagramElementSet {
3557
4101
  */
3558
4102
  constructor(model) {
3559
4103
  super();
4104
+ /**
4105
+ * Set of the possible types of port that the ports of this set can have.
4106
+ * @public
4107
+ */
4108
+ this.types = new DiagramEntitySet();
3560
4109
  this.model = model;
3561
4110
  }
3562
4111
  /**
3563
4112
  * Instance a new port and add it to this set. This method is normally called when instancing an element with a port and it is rarely called by itself.
3564
4113
  * @private
3565
4114
  */
3566
- new(rootElement, coords, direction, id) {
3567
- const port = new DiagramPort(this.model, rootElement, coords, direction, id);
4115
+ new(type, rootElement, coords, connectionPoint, direction, id) {
4116
+ const port = new DiagramPort(this.model, type, rootElement, coords, connectionPoint, direction, id);
3568
4117
  super.add(port);
3569
4118
  port.updateInView();
3570
4119
  // add this port to its root element
@@ -3673,13 +4222,14 @@ class DagaImporter {
3673
4222
  }
3674
4223
  let portCounter = 0;
3675
4224
  for (const port of section.ports || []) {
3676
- const newPort = new DiagramPort(model, newSection, port.coords, port.direction, port.id);
4225
+ const newPortType = port.type !== undefined ? model.ports.types.get(port.type) : undefined;
4226
+ const newPort = new DiagramPort(model, newPortType, newSection, port.coords, port.connectionPoint, port.direction, port.id);
3677
4227
  newSection.ports.push(newPort);
3678
4228
  model.ports.add(newPort);
3679
4229
  if (port.label) {
3680
4230
  // add port label
3681
- if (newNodeType.ports.length > portCounter && newNodeType.ports[portCounter].label) {
3682
- const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), newNodeType.ports[portCounter].label);
4231
+ if (newNodeType.ports.length > portCounter && (newPortType === null || newPortType === undefined ? undefined : newPortType.label)) {
4232
+ const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), newPortType === null || newPortType === undefined ? undefined : newPortType.label);
3683
4233
  let labelCoords;
3684
4234
  switch (newPort.direction) {
3685
4235
  case Side.Top:
@@ -3719,13 +4269,14 @@ class DagaImporter {
3719
4269
  }
3720
4270
  let portCounter = 0;
3721
4271
  for (const port of node.ports || []) {
3722
- const newPort = new DiagramPort(model, newNode, port.coords, port.direction, port.id);
4272
+ const newPortType = port.type !== undefined ? model.ports.types.get(port.type) : undefined;
4273
+ const newPort = new DiagramPort(model, newPortType, newNode, port.coords, port.connectionPoint, port.direction, port.id);
3723
4274
  newNode.ports.push(newPort);
3724
4275
  model.ports.add(newPort);
3725
4276
  if (port.label) {
3726
4277
  // add port label
3727
- if (newNodeType.ports.length > portCounter && newNodeType.ports[portCounter].label) {
3728
- const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), newNodeType.ports[portCounter].label);
4278
+ if (newNodeType.ports.length > portCounter && (newPortType === null || newPortType === undefined ? undefined : newPortType.label)) {
4279
+ const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), newPortType === null || newPortType === undefined ? undefined : newPortType.label);
3729
4280
  let labelCoords;
3730
4281
  switch (newPort.direction) {
3731
4282
  case Side.Top:
@@ -3767,6 +4318,8 @@ class DagaImporter {
3767
4318
  newNode.valueSet.setTimestamps(node.collabMeta.dataTimestamps);
3768
4319
  }
3769
4320
  newNode.updateInView();
4321
+ // raise node to sort the render order of the node and its components
4322
+ newNode.raise();
3770
4323
  return newNode;
3771
4324
  }
3772
4325
  return undefined;
@@ -3789,6 +4342,8 @@ class DagaImporter {
3789
4342
  newConnection.valueSet.setTimestamps(connection.collabMeta.dataTimestamps);
3790
4343
  }
3791
4344
  newConnection.updateInView();
4345
+ // raise connection just in case it is necessary to sort the render order
4346
+ newConnection.raise();
3792
4347
  return newConnection;
3793
4348
  }
3794
4349
  return undefined;
@@ -5046,7 +5601,10 @@ class DiagramHighlightedEvent extends DiagramEvent {
5046
5601
  class DiagramDecorator extends DiagramElement {
5047
5602
  constructor(model, rootElement, coords, width, height, priority, html, id) {
5048
5603
  if (model.objects.get(id) !== undefined) {
5049
- throw new Error(`DiagramObject with id "${id}" already exists`);
5604
+ throw new Error(`DiagramDecorator with id "${id}" already exists`);
5605
+ }
5606
+ if (!id) {
5607
+ throw new Error(`DiagramDecorator cannot have an empty or null id`);
5050
5608
  }
5051
5609
  super(model, id);
5052
5610
  this.rootElement = rootElement;
@@ -5095,7 +5653,14 @@ class DiagramDecoratorSet extends DiagramElementSet {
5095
5653
  }
5096
5654
  /**
5097
5655
  * Instance a new decorator and add it to this set.
5098
- * @private
5656
+ * @public
5657
+ * @param coords The coordinates of the top left corner of the decorator in the diagram.
5658
+ * @param width The dimension of the decorator along the x axis.
5659
+ * @param height The dimension of the decorator along the y axis.
5660
+ * @param priority The priority of the decorator. Used when filtering by priority.
5661
+ * @param html The html contents of the decorator.
5662
+ * @param id The id of the decorator. Cannot be an empty string.
5663
+ * @returns The instanced decorator.
5099
5664
  */
5100
5665
  new(rootElement, coords, width, height, priority, html, id) {
5101
5666
  const decorator = new DiagramDecorator(this.model, rootElement, coords, width, height, priority, html, id);
@@ -5132,6 +5697,9 @@ class DiagramObject extends DiagramElement {
5132
5697
  if (model.objects.get(id) !== undefined) {
5133
5698
  throw new Error(`DiagramObject with id "${id}" already exists`);
5134
5699
  }
5700
+ if (!id) {
5701
+ throw new Error(`DiagramObject cannot have an empty or null id`);
5702
+ }
5135
5703
  super(model, id);
5136
5704
  this.coords = coords;
5137
5705
  this.width = width;
@@ -5178,7 +5746,14 @@ class DiagramObjectSet extends DiagramElementSet {
5178
5746
  }
5179
5747
  /**
5180
5748
  * Instance a new object and add it to this set.
5181
- * @private
5749
+ * @public
5750
+ * @param coords The coordinates of the top left corner of the object in the diagram.
5751
+ * @param width The dimension of the object along the x axis.
5752
+ * @param height The dimension of the object along the y axis.
5753
+ * @param priority The priority of the object. Used when filtering by priority.
5754
+ * @param html The html contents of the object.
5755
+ * @param id The id of the object. Cannot be an empty string.
5756
+ * @returns The instanced object.
5182
5757
  */
5183
5758
  new(coords, width, height, priority, html, id) {
5184
5759
  const object = new DiagramObject(this.model, coords, width, height, priority, html, id);
@@ -5281,6 +5856,68 @@ class DiagramModel {
5281
5856
  }
5282
5857
  }
5283
5858
 
5859
+ /**
5860
+ * Checks if the given mouse event was produced with a secondary button press.
5861
+ * @private
5862
+ * @param event A mouse event.
5863
+ * @returns `true` if the given mouse event was produced with a secondary button press, `false` otherwise.
5864
+ */
5865
+ const isSecondaryButton = event => {
5866
+ return !!event.button;
5867
+ };
5868
+ /**
5869
+ * Get the SVG path of a diagram connection.
5870
+ * @private
5871
+ * @see linePath
5872
+ */
5873
+ const getConnectionPath = (shape, startCoords, endCoords, startDirection, endDirection, width, startMarkerWidth, endMarkerWidth) => {
5874
+ return linePath(shape, [startCoords, endCoords], startDirection, endDirection, Math.max(
5875
+ // reasonable value for the minimumDistanceBeforeTurn relative to the line width
5876
+ 10, startMarkerWidth || 0, endMarkerWidth || 0) * width);
5877
+ };
5878
+ const setCursorStyle = style => {
5879
+ if (!style) {
5880
+ d3.select('body').style('cursor', CursorStyle.Auto);
5881
+ } else {
5882
+ d3.select('body').style('cursor', style);
5883
+ }
5884
+ };
5885
+ const getRelatedNodeOrItself = element => {
5886
+ if (element instanceof DiagramNode) {
5887
+ return element;
5888
+ }
5889
+ if (element instanceof DiagramSection) {
5890
+ return element.node || element;
5891
+ }
5892
+ return element.rootElement instanceof DiagramNode || element.rootElement instanceof DiagramSection || element.rootElement instanceof DiagramPort ? getRelatedNodeOrItself(element.rootElement) : element;
5893
+ };
5894
+ const initializeLook = selection => {
5895
+ selection.filter('.shaped-look').append('path');
5896
+ selection.filter('.image-look').append('image').attr('preserveAspectRatio', 'none');
5897
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'top-left-image').attr('preserveAspectRatio', 'none');
5898
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'top-image').attr('preserveAspectRatio', 'none');
5899
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'top-right-image').attr('preserveAspectRatio', 'none');
5900
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'left-image').attr('preserveAspectRatio', 'none');
5901
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'center-image').attr('preserveAspectRatio', 'none');
5902
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'right-image').attr('preserveAspectRatio', 'none');
5903
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-left-image').attr('preserveAspectRatio', 'none');
5904
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-image').attr('preserveAspectRatio', 'none');
5905
+ selection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-right-image').attr('preserveAspectRatio', 'none');
5906
+ };
5907
+ const updateLook = selection => {
5908
+ selection.filter('.shaped-look').select('path').attr('d', d => generalClosedPath(d.look.shape, 0, 0, d.width, d.height)).attr('fill', d => d.look.fillColor).attr('stroke', d => d.look.borderColor).attr('stroke-width', d => `${d.look.borderThickness}px`);
5909
+ selection.filter('.image-look').select('image').attr('x', 0).attr('y', 0).attr('width', d => d.width).attr('height', d => d.height).attr('href', d => d.look.backgroundImage);
5910
+ selection.filter('.stretchable-image-look').select('image.top-left-image').attr('x', 0).attr('y', 0).attr('width', d => d.look.leftMargin).attr('height', d => d.look.topMargin).attr('href', d => d.look.backgroundImageTopLeft);
5911
+ selection.filter('.stretchable-image-look').select('image.top-image').attr('x', d => d.look.leftMargin).attr('y', 0).attr('width', d => d.width - d.look.rightMargin - d.look.leftMargin).attr('height', d => d.look.topMargin).attr('href', d => d.look.backgroundImageTop);
5912
+ selection.filter('.stretchable-image-look').select('image.top-right-image').attr('x', d => d.width - d.look.rightMargin).attr('y', 0).attr('width', d => d.look.rightMargin).attr('height', d => d.look.topMargin).attr('href', d => d.look.backgroundImageTopRight);
5913
+ selection.filter('.stretchable-image-look').select('image.left-image').attr('x', 0).attr('y', d => d.look.topMargin).attr('width', d => d.look.leftMargin).attr('height', d => d.height - d.look.bottomMargin - d.look.topMargin).attr('href', d => d.look.backgroundImageLeft);
5914
+ selection.filter('.stretchable-image-look').select('image.center-image').attr('x', d => d.look.leftMargin).attr('y', d => d.look.topMargin).attr('width', d => d.width - d.look.rightMargin - d.look.leftMargin).attr('height', d => d.height - d.look.bottomMargin - d.look.topMargin).attr('href', d => d.look.backgroundImageCenter);
5915
+ selection.filter('.stretchable-image-look').select('image.right-image').attr('x', d => d.width - d.look.rightMargin).attr('y', d => d.look.topMargin).attr('width', d => d.look.rightMargin).attr('height', d => d.height - d.look.bottomMargin - d.look.topMargin).attr('href', d => d.look.backgroundImageRight);
5916
+ selection.filter('.stretchable-image-look').select('image.bottom-left-image').attr('x', 0).attr('y', d => d.height - d.look.bottomMargin).attr('width', d => d.look.leftMargin).attr('height', d => d.look.bottomMargin).attr('href', d => d.look.backgroundImageBottomLeft);
5917
+ selection.filter('.stretchable-image-look').select('image.bottom-image').attr('x', d => d.look.leftMargin).attr('y', d => d.height - d.look.bottomMargin).attr('width', d => d.width - d.look.rightMargin - d.look.leftMargin).attr('height', d => d.look.bottomMargin).attr('href', d => d.look.backgroundImageBottom);
5918
+ selection.filter('.stretchable-image-look').select('image.bottom-right-image').attr('x', d => d.width - d.look.rightMargin).attr('y', d => d.height - d.look.bottomMargin).attr('width', d => d.look.rightMargin).attr('height', d => d.look.bottomMargin).attr('href', d => d.look.backgroundImageBottomRight);
5919
+ };
5920
+
5284
5921
  const CONTEXT_MENU_MENU_RADIUS = 96;
5285
5922
  const CONTEXT_MENU_BUTTON_RADIUS = 32;
5286
5923
  const CONTEXT_MENU_TOTAL_RADIUS = CONTEXT_MENU_MENU_RADIUS + CONTEXT_MENU_BUTTON_RADIUS;
@@ -5531,7 +6168,7 @@ class DagaExporter {
5531
6168
  return result;
5532
6169
  }
5533
6170
  exportNode(node, includeCollabMeta = false) {
5534
- var _a, _b, _c, _d;
6171
+ var _a, _b, _c, _d, _e, _f;
5535
6172
  const children = [];
5536
6173
  for (const child of node.children) {
5537
6174
  children.push(this.exportNode(child, includeCollabMeta));
@@ -5542,9 +6179,11 @@ class DagaExporter {
5542
6179
  for (const port of section.ports) {
5543
6180
  ports.push(Object.assign({
5544
6181
  id: port.id,
6182
+ type: (_a = port.type) === null || _a === undefined ? undefined : _a.id,
5545
6183
  coords: roundPoint(port.coords),
6184
+ connectionPoint: roundPoint(port.connectionPoint),
5546
6185
  direction: port.direction,
5547
- label: ((_a = port.label) === null || _a === undefined ? undefined : _a.text) || ''
6186
+ label: ((_b = port.label) === null || _b === undefined ? undefined : _b.text) || ''
5548
6187
  }, includeCollabMeta ? {
5549
6188
  collabMeta: Object.assign({
5550
6189
  removed: port.removed,
@@ -5556,7 +6195,7 @@ class DagaExporter {
5556
6195
  sections.push(Object.assign({
5557
6196
  id: section.id,
5558
6197
  ports,
5559
- label: ((_b = section.label) === null || _b === undefined ? undefined : _b.text) || '',
6198
+ label: ((_c = section.label) === null || _c === undefined ? undefined : _c.text) || '',
5560
6199
  indexXInNode: section.indexXInNode,
5561
6200
  indexYInNode: section.indexYInNode,
5562
6201
  coords: roundPoint(section.coords),
@@ -5574,9 +6213,11 @@ class DagaExporter {
5574
6213
  for (const port of node.ports) {
5575
6214
  ports.push(Object.assign({
5576
6215
  id: port.id,
6216
+ type: (_d = port.type) === null || _d === undefined ? undefined : _d.id,
5577
6217
  coords: roundPoint(port.coords),
6218
+ connectionPoint: roundPoint(port.connectionPoint),
5578
6219
  direction: port.direction,
5579
- label: ((_c = port.label) === null || _c === undefined ? undefined : _c.text) || ''
6220
+ label: ((_e = port.label) === null || _e === undefined ? undefined : _e.text) || ''
5580
6221
  }, includeCollabMeta ? {
5581
6222
  collabMeta: Object.assign({
5582
6223
  removed: port.removed,
@@ -5591,7 +6232,7 @@ class DagaExporter {
5591
6232
  children,
5592
6233
  sections,
5593
6234
  ports,
5594
- label: ((_d = node.label) === null || _d === undefined ? undefined : _d.text) || '',
6235
+ label: ((_f = node.label) === null || _f === undefined ? undefined : _f.text) || '',
5595
6236
  coords: roundPoint(node.coords),
5596
6237
  width: node.width,
5597
6238
  height: node.height,
@@ -5871,7 +6512,7 @@ class DiagramUserSelection extends DiagramElementSet {
5871
6512
  }
5872
6513
  }
5873
6514
  makeUpdateValuesAction() {
5874
- var _a, _b;
6515
+ var _a, _b, _c;
5875
6516
  if (this.propertyEditorSelection === undefined || this.propertyEditorValues === undefined) {
5876
6517
  return;
5877
6518
  }
@@ -5883,7 +6524,7 @@ class DiagramUserSelection extends DiagramElementSet {
5883
6524
  }
5884
6525
  const from = this.propertyEditorValues;
5885
6526
  const to = structuredClone((_b = this.propertyEditorSelection) === null || _b === undefined ? undefined : _b.valueSet.getValues());
5886
- const [fromDiff, toDiff] = diff(from, to);
6527
+ const [fromDiff, toDiff] = diffProperties(from, to, (_c = this.propertyEditorSelection) === null || _c === undefined ? undefined : _c.valueSet);
5887
6528
  const currentAction = new UpdateValuesAction(this.canvas, previousSelectionId, fromDiff, toDiff);
5888
6529
  currentAction.do();
5889
6530
  this.canvas.actionStack.add(currentAction);
@@ -5967,6 +6608,13 @@ class DiagramCanvas {
5967
6608
  this.model.nodes.types.add(nodeType);
5968
6609
  }
5969
6610
  }
6611
+ // load port types
6612
+ if (config.portTypes) {
6613
+ for (const portTypeConfig of config.portTypes) {
6614
+ const portType = new DiagramPortType(Object.assign(Object.assign({}, config.portTypeDefaults), portTypeConfig));
6615
+ this.model.ports.types.add(portType);
6616
+ }
6617
+ }
5970
6618
  // load connection types
5971
6619
  if (config.connectionTypes) {
5972
6620
  for (const connectionTypeConfig of config.connectionTypes) {
@@ -6219,9 +6867,10 @@ class DiagramCanvas {
6219
6867
  }
6220
6868
  }
6221
6869
  center() {
6870
+ var _a;
6222
6871
  // if there are no nodes, we have nothing to do here
6223
6872
  if (this.model.nodes.length > 0) {
6224
- const canvasViewBoundingBox = this.selectCanvasView().select('rect').node().getBBox();
6873
+ const canvasViewBoundingBox = (_a = this.selectCanvasView().select('rect').node()) === null || _a === undefined ? undefined : _a.getBBox();
6225
6874
  const nonRemovedNodes = this.model.nodes.all();
6226
6875
  const minimumX = Math.min(...nonRemovedNodes.map(n => n.coords[0]));
6227
6876
  const maximumX = Math.max(...nonRemovedNodes.map(n => n.coords[0] + n.width));
@@ -6298,7 +6947,7 @@ class DiagramCanvas {
6298
6947
  updateNodesInView(...ids) {
6299
6948
  let updateSelection = this.selectCanvasElements().selectAll('g.diagram-node').data(this.model.nodes.filter(e => this.priorityThreshold !== undefined ? e.getPriority() >= this.priorityThreshold : true), d => d.id);
6300
6949
  const exitSelection = updateSelection.exit();
6301
- const enterSelection = updateSelection.enter().append('g').attr('id', d => d.id).attr('class', d => `diagram-node${d.type.resizableX ? ' resizable-x' : ''}${d.type.resizableY ? ' resizable-y' : ''} ${d.type.look.lookType}`);
6950
+ const enterSelection = updateSelection.enter().append('g').attr('id', d => d.id).attr('class', d => `diagram-node${d.type.resizableX ? ' resizable-x' : ''}${d.type.resizableY ? ' resizable-y' : ''} ${d.type.defaultLook.lookType}`);
6302
6951
  if (ids && ids.length > 0) {
6303
6952
  updateSelection = updateSelection.filter(d => ids.includes(d.id));
6304
6953
  }
@@ -6360,17 +7009,7 @@ class DiagramCanvas {
6360
7009
  }
6361
7010
  this.secondaryButton = false;
6362
7011
  }));
6363
- enterSelection.filter('.shaped-look').append('path');
6364
- enterSelection.filter('.image-look').append('image').attr('preserveAspectRatio', 'none');
6365
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'top-left-image').attr('preserveAspectRatio', 'none');
6366
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'top-image').attr('preserveAspectRatio', 'none');
6367
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'top-right-image').attr('preserveAspectRatio', 'none');
6368
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'left-image').attr('preserveAspectRatio', 'none');
6369
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'center-image').attr('preserveAspectRatio', 'none');
6370
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'right-image').attr('preserveAspectRatio', 'none');
6371
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-left-image').attr('preserveAspectRatio', 'none');
6372
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-image').attr('preserveAspectRatio', 'none');
6373
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-right-image').attr('preserveAspectRatio', 'none');
7012
+ initializeLook(enterSelection);
6374
7013
  enterSelection.filter('.resizable-x').append('line').attr('class', 'left-resizer').attr('stroke', 'transparent').attr('stroke-width', `${RESIZER_THICKNESS}px`).on(Events.MouseOver, (_event, d) => {
6375
7014
  if (this.canUserPerformAction(DiagramActions.StretchNode) && d.type.resizableX && !d.removed) {
6376
7015
  setCursorStyle(CursorStyle.EWResize);
@@ -6508,17 +7147,7 @@ class DiagramCanvas {
6508
7147
  setCursorStyle();
6509
7148
  }));
6510
7149
  mergeSelection.attr('transform', d => `translate(${d.coords[0]},${d.coords[1]})`).attr('opacity', d => d.removed ? 0.5 : 1);
6511
- mergeSelection.filter('.shaped-look').select('path').attr('d', d => generalClosedPath(d.type.look.shape, 0, 0, d.width, d.height)).attr('fill', d => d.selected ? d.type.look.selectedFillColor : d.type.look.fillColor).attr('stroke', d => d.selected ? d.type.look.selectedBorderColor : d.type.look.borderColor).attr('stroke-width', d => `${d.highlighted ? 3 : 1}px`);
6512
- mergeSelection.filter('.image-look').select('image').attr('x', 0).attr('y', 0).attr('width', d => d.width).attr('height', d => d.height).attr('href', d => d.selected ? d.type.look.selectedBackgroundImage : d.type.look.backgroundImage);
6513
- mergeSelection.filter('.stretchable-image-look').select('image.top-left-image').attr('x', 0).attr('y', 0).attr('width', d => d.type.look.leftMargin).attr('height', d => d.type.look.topMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageTopLeft : d.type.look.backgroundImageTopLeft);
6514
- mergeSelection.filter('.stretchable-image-look').select('image.top-image').attr('x', d => d.type.look.leftMargin).attr('y', 0).attr('width', d => d.width - d.type.look.rightMargin - d.type.look.leftMargin).attr('height', d => d.type.look.topMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageTop : d.type.look.backgroundImageTop);
6515
- mergeSelection.filter('.stretchable-image-look').select('image.top-right-image').attr('x', d => d.width - d.type.look.rightMargin).attr('y', 0).attr('width', d => d.type.look.rightMargin).attr('height', d => d.type.look.topMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageTopRight : d.type.look.backgroundImageTopRight);
6516
- mergeSelection.filter('.stretchable-image-look').select('image.left-image').attr('x', 0).attr('y', d => d.type.look.topMargin).attr('width', d => d.type.look.leftMargin).attr('height', d => d.height - d.type.look.bottomMargin - d.type.look.topMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageLeft : d.type.look.backgroundImageLeft);
6517
- mergeSelection.filter('.stretchable-image-look').select('image.center-image').attr('x', d => d.type.look.leftMargin).attr('y', d => d.type.look.topMargin).attr('width', d => d.width - d.type.look.rightMargin - d.type.look.leftMargin).attr('height', d => d.height - d.type.look.bottomMargin - d.type.look.topMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageCenter : d.type.look.backgroundImageCenter);
6518
- mergeSelection.filter('.stretchable-image-look').select('image.right-image').attr('x', d => d.width - d.type.look.rightMargin).attr('y', d => d.type.look.topMargin).attr('width', d => d.type.look.rightMargin).attr('height', d => d.height - d.type.look.bottomMargin - d.type.look.topMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageRight : d.type.look.backgroundImageRight);
6519
- mergeSelection.filter('.stretchable-image-look').select('image.bottom-left-image').attr('x', 0).attr('y', d => d.height - d.type.look.bottomMargin).attr('width', d => d.type.look.leftMargin).attr('height', d => d.type.look.bottomMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageBottomLeft : d.type.look.backgroundImageBottomLeft);
6520
- mergeSelection.filter('.stretchable-image-look').select('image.bottom-image').attr('x', d => d.type.look.leftMargin).attr('y', d => d.height - d.type.look.bottomMargin).attr('width', d => d.width - d.type.look.rightMargin - d.type.look.leftMargin).attr('height', d => d.type.look.bottomMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageBottom : d.type.look.backgroundImageBottom);
6521
- mergeSelection.filter('.stretchable-image-look').select('image.bottom-right-image').attr('x', d => d.width - d.type.look.rightMargin).attr('y', d => d.height - d.type.look.bottomMargin).attr('width', d => d.type.look.rightMargin).attr('height', d => d.type.look.bottomMargin).attr('href', d => d.selected ? d.type.look.selectedBackgroundImageBottomRight : d.type.look.backgroundImageBottomRight);
7150
+ updateLook(mergeSelection);
6522
7151
  mergeSelection.filter('.resizable-x').select('line.left-resizer').attr('x1', RESIZER_THICKNESS / 2).attr('x2', RESIZER_THICKNESS / 2).attr('y1', 0).attr('y2', d => d.height);
6523
7152
  mergeSelection.filter('.resizable-y').select('line.top-resizer').attr('x1', 0).attr('x2', d => d.width).attr('y1', RESIZER_THICKNESS / 2).attr('y2', RESIZER_THICKNESS / 2);
6524
7153
  mergeSelection.filter('.resizable-x').select('line.right-resizer').attr('x1', d => d.width - RESIZER_THICKNESS / 2).attr('x2', d => d.width - RESIZER_THICKNESS / 2).attr('y1', 0).attr('y2', d => d.height);
@@ -6528,8 +7157,8 @@ class DiagramCanvas {
6528
7157
  let updateSelection = this.selectCanvasElements().selectAll('g.diagram-section').data(this.model.sections.filter(e => this.priorityThreshold !== undefined ? e.getPriority() >= this.priorityThreshold : true), d => d.id);
6529
7158
  const exitSelection = updateSelection.exit();
6530
7159
  const enterSelection = updateSelection.enter().append('g').attr('id', d => d.id).attr('class', d => {
6531
- var _a, _b, _c, _d, _e, _f;
6532
- return `diagram-section${((_b = (_a = d.node) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.resizableX) ? ' resizable-x' : ''}${((_d = (_c = d.node) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.resizableY) ? ' resizable-y' : ''} ${(_f = (_e = d.getConfig()) === null || _e === undefined ? undefined : _e.look) === null || _f === undefined ? undefined : _f.lookType}`;
7160
+ var _a, _b, _c, _d, _e;
7161
+ return `diagram-section${((_b = (_a = d.node) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.resizableX) ? ' resizable-x' : ''}${((_d = (_c = d.node) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.resizableY) ? ' resizable-y' : ''} ${(_e = d.look) === null || _e === undefined ? undefined : _e.lookType}`;
6533
7162
  });
6534
7163
  if (ids && ids.length > 0) {
6535
7164
  updateSelection = updateSelection.filter(d => ids.includes(d.id));
@@ -6609,17 +7238,7 @@ class DiagramCanvas {
6609
7238
  }
6610
7239
  this.secondaryButton = false;
6611
7240
  }));
6612
- enterSelection.filter('.shaped-look').append('path');
6613
- enterSelection.filter('.image-look').append('image').attr('preserveAspectRatio', 'none');
6614
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'top-left-image').attr('preserveAspectRatio', 'none');
6615
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'top-image').attr('preserveAspectRatio', 'none');
6616
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'top-right-image').attr('preserveAspectRatio', 'none');
6617
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'left-image').attr('preserveAspectRatio', 'none');
6618
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'center-image').attr('preserveAspectRatio', 'none');
6619
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'right-image').attr('preserveAspectRatio', 'none');
6620
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-left-image').attr('preserveAspectRatio', 'none');
6621
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-image').attr('preserveAspectRatio', 'none');
6622
- enterSelection.filter('.stretchable-image-look').append('image').attr('class', 'bottom-right-image').attr('preserveAspectRatio', 'none');
7241
+ initializeLook(enterSelection);
6623
7242
  enterSelection.filter('.resizable-x').append('line').attr('class', 'left-resizer').attr('stroke', 'transparent').attr('stroke-width', `${RESIZER_THICKNESS}px`).on(Events.MouseOver, (_event, d) => {
6624
7243
  var _a, _b;
6625
7244
  if (this.canUserPerformAction(DiagramActions.StretchSection) && ((_b = (_a = d.node) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.resizableX) && !d.removed) {
@@ -6777,146 +7396,7 @@ class DiagramCanvas {
6777
7396
  setCursorStyle();
6778
7397
  }));
6779
7398
  mergeSelection.attr('transform', d => `translate(${d.coords[0]},${d.coords[1]})`).attr('opacity', d => d.removed ? 0.5 : 1);
6780
- mergeSelection.filter('.shaped-look').select('path').attr('d', d => {
6781
- var _a;
6782
- return generalClosedPath(((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).shape, 0, 0, d.width, d.height);
6783
- }).attr('fill', d => {
6784
- var _a, _b;
6785
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedFillColor : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).fillColor;
6786
- }).attr('stroke', d => {
6787
- var _a, _b;
6788
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBorderColor : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).borderColor;
6789
- }).attr('stroke-width', d => `${d.highlighted ? 3 : 1}px`);
6790
- mergeSelection.filter('.image-look').select('image').attr('x', 0).attr('y', 0).attr('width', d => d.width).attr('height', d => d.height).attr('href', d => {
6791
- var _a, _b;
6792
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImage : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImage;
6793
- });
6794
- mergeSelection.filter('.stretchable-image-look').select('image.top-left-image').attr('x', 0).attr('y', 0).attr('width', d => {
6795
- var _a;
6796
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).leftMargin;
6797
- }).attr('height', d => {
6798
- var _a;
6799
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).topMargin;
6800
- }).attr('href', d => {
6801
- var _a, _b;
6802
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageTopLeft : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageTopLeft;
6803
- });
6804
- mergeSelection.filter('.stretchable-image-look').select('image.top-image').attr('x', d => {
6805
- var _a;
6806
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).leftMargin;
6807
- }).attr('y', 0).attr('width', d => {
6808
- var _a, _b;
6809
- return d.width - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin - ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).leftMargin;
6810
- }).attr('height', d => {
6811
- var _a;
6812
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).topMargin;
6813
- }).attr('href', d => {
6814
- var _a, _b;
6815
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageTop : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageTop;
6816
- });
6817
- mergeSelection.filter('.stretchable-image-look').select('image.top-right-image').attr('x', d => {
6818
- var _a;
6819
- return d.width - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin;
6820
- }).attr('y', 0).attr('width', d => {
6821
- var _a;
6822
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin;
6823
- }).attr('height', d => {
6824
- var _a;
6825
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).topMargin;
6826
- }).attr('href', d => {
6827
- var _a, _b;
6828
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageTopRight : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageTopRight;
6829
- });
6830
- mergeSelection.filter('.stretchable-image-look').select('image.left-image').attr('x', 0).attr('y', d => {
6831
- var _a;
6832
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).topMargin;
6833
- }).attr('width', d => {
6834
- var _a;
6835
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).leftMargin;
6836
- }).attr('height', d => {
6837
- var _a, _b;
6838
- return d.height - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin - ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).topMargin;
6839
- }).attr('href', d => {
6840
- var _a, _b;
6841
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageLeft : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageLeft;
6842
- });
6843
- mergeSelection.filter('.stretchable-image-look').select('image.center-image').attr('x', d => {
6844
- var _a;
6845
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).leftMargin;
6846
- }).attr('y', d => {
6847
- var _a;
6848
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).topMargin;
6849
- }).attr('width', d => {
6850
- var _a, _b;
6851
- return d.width - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin - ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).leftMargin;
6852
- }).attr('height', d => {
6853
- var _a, _b;
6854
- return d.height - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin - ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).topMargin;
6855
- }).attr('href', d => {
6856
- var _a, _b;
6857
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageCenter : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageCenter;
6858
- });
6859
- mergeSelection.filter('.stretchable-image-look').select('image.right-image').attr('x', d => {
6860
- var _a;
6861
- return d.width - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin;
6862
- }).attr('y', d => {
6863
- var _a;
6864
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).topMargin;
6865
- }).attr('width', d => {
6866
- var _a;
6867
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin;
6868
- }).attr('height', d => {
6869
- var _a, _b;
6870
- return d.height - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin - ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).topMargin;
6871
- }).attr('href', d => {
6872
- var _a, _b;
6873
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageRight : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageRight;
6874
- });
6875
- mergeSelection.filter('.stretchable-image-look').select('image.bottom-left-image').attr('x', 0).attr('y', d => {
6876
- var _a;
6877
- return d.height - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin;
6878
- }).attr('width', d => {
6879
- var _a;
6880
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).leftMargin;
6881
- }).attr('height', d => {
6882
- var _a;
6883
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin;
6884
- }).attr('href', d => {
6885
- var _a, _b;
6886
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageBottomLeft : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageBottomLeft;
6887
- });
6888
- mergeSelection.filter('.stretchable-image-look').select('image.bottom-image').attr('x', d => {
6889
- var _a;
6890
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).leftMargin;
6891
- }).attr('y', d => {
6892
- var _a;
6893
- return d.height - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin;
6894
- }).attr('width', d => {
6895
- var _a, _b;
6896
- return d.width - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin - ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).leftMargin;
6897
- }).attr('height', d => {
6898
- var _a;
6899
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin;
6900
- }).attr('href', d => {
6901
- var _a, _b;
6902
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageBottom : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageBottom;
6903
- });
6904
- mergeSelection.filter('.stretchable-image-look').select('image.bottom-right-image').attr('x', d => {
6905
- var _a;
6906
- return d.width - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin;
6907
- }).attr('y', d => {
6908
- var _a;
6909
- return d.height - ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin;
6910
- }).attr('width', d => {
6911
- var _a;
6912
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).rightMargin;
6913
- }).attr('height', d => {
6914
- var _a;
6915
- return ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).bottomMargin;
6916
- }).attr('href', d => {
6917
- var _a, _b;
6918
- return d.selected ? ((_a = d.getConfig()) === null || _a === undefined ? undefined : _a.look).selectedBackgroundImageBottomRight : ((_b = d.getConfig()) === null || _b === undefined ? undefined : _b.look).backgroundImageBottomRight;
6919
- });
7399
+ updateLook(mergeSelection);
6920
7400
  mergeSelection.filter('.resizable-x').select('line.left-resizer').attr('x1', RESIZER_THICKNESS / 2).attr('x2', RESIZER_THICKNESS / 2).attr('y1', 0).attr('y2', d => d.height);
6921
7401
  mergeSelection.filter('.resizable-y').select('line.top-resizer').attr('x1', 0).attr('x2', d => d.width).attr('y1', RESIZER_THICKNESS / 2).attr('y2', RESIZER_THICKNESS / 2);
6922
7402
  mergeSelection.filter('.resizable-x').select('line.right-resizer').attr('x1', d => d.width - RESIZER_THICKNESS / 2).attr('x2', d => d.width - RESIZER_THICKNESS / 2).attr('y1', 0).attr('y2', d => d.height);
@@ -6925,21 +7405,29 @@ class DiagramCanvas {
6925
7405
  updatePortsInView(...ids) {
6926
7406
  let updateSelection = this.selectCanvasElements().selectAll('g.diagram-port').data(this.model.ports.filter(e => this.priorityThreshold !== undefined ? e.getPriority() >= this.priorityThreshold : true), d => d.id);
6927
7407
  const exitSelection = updateSelection.exit();
6928
- const enterSelection = updateSelection.enter().append('g').attr('id', d => d.id).attr('class', 'diagram-port');
7408
+ const enterSelection = updateSelection.enter().append('g').attr('id', d => d.id).attr('class', d => `diagram-port ${d.look.lookType}`);
6929
7409
  if (ids && ids.length > 0) {
6930
7410
  updateSelection = updateSelection.filter(d => ids.includes(d.id));
6931
7411
  }
6932
7412
  const mergeSelection = enterSelection.merge(updateSelection);
6933
7413
  exitSelection.remove();
6934
7414
  enterSelection.on(Events.MouseOver, (_event, d) => {
6935
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
7415
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
6936
7416
  if (!this.unfinishedConnection && !this.dragging) {
6937
7417
  // if there is an unfinished connection, the port will be highlighted automatically if the pointer is close
6938
7418
  this.userHighlight.focusOn(d);
6939
7419
  this.diagramEvent$.next(new DiagramHighlightedEvent(d));
6940
7420
  }
6941
7421
  if (this.unfinishedConnection) {
6942
- const canConnectionFinishAtThisPort = this.unfinishedConnection.type.canStartFromType(((_c = (_b = (_a = this.unfinishedConnection.start) === null || _a === undefined ? undefined : _a.getNode()) === null || _b === undefined ? undefined : _b.type) === null || _c === undefined ? undefined : _c.id) || '') && this.unfinishedConnection.type.canFinishOnType(((_e = (_d = d.getNode()) === null || _d === undefined ? undefined : _d.type) === null || _e === undefined ? undefined : _e.id) || '') || this.unfinishedConnection.type.canStartFromType(((_g = (_f = d.getNode()) === null || _f === undefined ? undefined : _f.type) === null || _g === undefined ? undefined : _g.id) || '') && this.unfinishedConnection.type.canFinishOnType(((_k = (_j = (_h = this.unfinishedConnection.start) === null || _h === undefined ? undefined : _h.getNode()) === null || _j === undefined ? undefined : _j.type) === null || _k === undefined ? undefined : _k.id) || '');
7422
+ const canConnectionFinishAtThisPort =
7423
+ // can start at the starting port
7424
+ this.unfinishedConnection.type.canStartFromType(((_c = (_b = (_a = this.unfinishedConnection.start) === null || _a === undefined ? undefined : _a.getNode()) === null || _b === undefined ? undefined : _b.type) === null || _c === undefined ? undefined : _c.id) || '') && ((_d = this.unfinishedConnection.start) === null || _d === undefined ? undefined : _d.allowsOutgoing) &&
7425
+ // can end at the ending port
7426
+ this.unfinishedConnection.type.canFinishOnType(((_f = (_e = d.getNode()) === null || _e === undefined ? undefined : _e.type) === null || _f === undefined ? undefined : _f.id) || '') && d.allowsIncoming ||
7427
+ // can start at the ending port
7428
+ this.unfinishedConnection.type.canStartFromType(((_h = (_g = d.getNode()) === null || _g === undefined ? undefined : _g.type) === null || _h === undefined ? undefined : _h.id) || '') && d.allowsOutgoing &&
7429
+ // can end at the starting port
7430
+ this.unfinishedConnection.type.canFinishOnType(((_l = (_k = (_j = this.unfinishedConnection.start) === null || _j === undefined ? undefined : _j.getNode()) === null || _k === undefined ? undefined : _k.type) === null || _l === undefined ? undefined : _l.id) || '') && ((_m = this.unfinishedConnection.start) === null || _m === undefined ? undefined : _m.allowsIncoming);
6943
7431
  if (!canConnectionFinishAtThisPort) {
6944
7432
  setCursorStyle(CursorStyle.NoDrop);
6945
7433
  }
@@ -7004,7 +7492,7 @@ class DiagramCanvas {
7004
7492
  if (this.canUserPerformAction(DiagramActions.AddConnection) && !d.removed) {
7005
7493
  if (this.unfinishedConnection !== undefined) {
7006
7494
  const endCoords = [event.x, event.y];
7007
- (_a = this.unfinishedConnectionTracer) === null || _a === undefined ? undefined : _a.attr('d', getConnectionPath(this.unfinishedConnection.type.shape, this.unfinishedConnection.startCoords, endCoords, this.unfinishedConnection.startDirection, this.unfinishedConnection.endDirection, this.unfinishedConnection.type.width, (_b = this.unfinishedConnection.startMarkerLook) === null || _b === undefined ? undefined : _b.markerWidth, (_c = this.unfinishedConnection.endMarkerLook) === null || _c === undefined ? undefined : _c.markerWidth));
7495
+ (_a = this.unfinishedConnectionTracer) === null || _a === undefined ? undefined : _a.attr('d', getConnectionPath(this.unfinishedConnection.look.shape, this.unfinishedConnection.startCoords, endCoords, this.unfinishedConnection.startDirection, this.unfinishedConnection.endDirection, this.unfinishedConnection.look.thickness, (_b = this.unfinishedConnection.startMarkerLook) === null || _b === undefined ? undefined : _b.width, (_c = this.unfinishedConnection.endMarkerLook) === null || _c === undefined ? undefined : _c.width));
7008
7496
  const unfinishedConnectionGhostNode = (_d = this.unfinishedConnectionTracer) === null || _d === undefined ? undefined : _d.node();
7009
7497
  if (unfinishedConnectionGhostNode) {
7010
7498
  let margin = 2;
@@ -7076,8 +7564,10 @@ class DiagramCanvas {
7076
7564
  }
7077
7565
  this.secondaryButton = false;
7078
7566
  }));
7079
- enterSelection.append('circle');
7080
- mergeSelection.attr('transform', d => `translate(${d.coords[0]},${d.coords[1]})`).attr('opacity', d => d.removed ? 0.5 : 1).select('circle').attr('cx', 0).attr('cy', 0).attr('r', DIAGRAM_PORT_DEFAULTS.radius).attr('fill', d => d.selected ? DIAGRAM_PORT_DEFAULTS.selectedColor : DIAGRAM_PORT_DEFAULTS.highlightedColor).attr('opacity', d => d.highlighted || d.selected ? 0.5 : 0);
7567
+ enterSelection.filter('.image-look').append('image');
7568
+ initializeLook(enterSelection);
7569
+ mergeSelection.attr('transform', d => `translate(${d.coords[0] - d.width / 2},${d.coords[1] - d.width / 2})`).attr('opacity', d => d.removed ? 0.5 : 1);
7570
+ updateLook(mergeSelection);
7081
7571
  }
7082
7572
  updateConnectionsInView(...ids) {
7083
7573
  const connectionList = this.model.connections.filter(e => this.priorityThreshold !== undefined ? e.getPriority() >= this.priorityThreshold : true);
@@ -7150,14 +7640,14 @@ class DiagramCanvas {
7150
7640
  enterSelection.select('g.diagram-connection-end-label').append('text').style('user-select', 'none');
7151
7641
  mergeSelection.attr('opacity', d => d.removed ? 0.5 : 1).select('path.diagram-connection-path').attr('d', d => {
7152
7642
  var _a, _b;
7153
- return getConnectionPath(d.type.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.type.width, (_a = d.startMarkerLook) === null || _a === undefined ? undefined : _a.markerWidth, (_b = d.endMarkerLook) === null || _b === undefined ? undefined : _b.markerWidth);
7154
- }).attr('marker-start', d => `url(#${d.id}-start-marker)`).attr('marker-end', d => `url(#${d.id}-end-marker)`).attr('stroke', d => d.selected ? d.type.selectedColor : d.type.color).attr('stroke-width', d => `${d.highlighted ? d.type.width + 1 : d.type.width}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.type.style, d.type.width)).attr('fill', 'none');
7643
+ return getConnectionPath(d.look.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.look.thickness, (_a = d.startMarkerLook) === null || _a === undefined ? undefined : _a.width, (_b = d.endMarkerLook) === null || _b === undefined ? undefined : _b.width);
7644
+ }).attr('marker-start', d => `url(#${d.id}-start-marker)`).attr('marker-end', d => `url(#${d.id}-end-marker)`).attr('stroke', d => d.look.color).attr('stroke-width', d => `${d.look.thickness}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.look.style, d.look.thickness)).attr('fill', 'none');
7155
7645
  mergeSelection.select('path.diagram-connection-path-box').attr('d', d => {
7156
7646
  var _a, _b;
7157
- return getConnectionPath(d.type.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.type.width, (_a = d.startMarkerLook) === null || _a === undefined ? undefined : _a.markerWidth, (_b = d.endMarkerLook) === null || _b === undefined ? undefined : _b.markerWidth);
7647
+ return getConnectionPath(d.look.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.look.thickness, (_a = d.startMarkerLook) === null || _a === undefined ? undefined : _a.width, (_b = d.endMarkerLook) === null || _b === undefined ? undefined : _b.width);
7158
7648
  }).attr('stroke', 'transparent')
7159
7649
  // allow generating pointer events even when it is transparent
7160
- .attr('pointer-events', 'stroke').attr('stroke-width', d => `${d.type.width + CONNECTION_PATH_BOX_THICKNESS}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.type.style, d.type.width)).attr('fill', 'none');
7650
+ .attr('pointer-events', 'stroke').attr('stroke-width', d => `${d.look.thickness + CONNECTION_PATH_BOX_THICKNESS}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.look.style, d.look.thickness)).attr('fill', 'none');
7161
7651
  mergeSelection.data().forEach(connection => {
7162
7652
  this.updateConnectionLabelsInView(connection);
7163
7653
  this.updateConnectionMarkersInView(connection);
@@ -7366,7 +7856,7 @@ class DiagramCanvas {
7366
7856
  const boundingWidth = !connection.startLabel ? 0 : startLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
7367
7857
  const boundingHeight = !connection.startLabel ? 0 : startLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
7368
7858
  const pathStartLabelPoint = pathNode.getPointAtLength(Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
7369
- connectionSelection.select('g.diagram-connection-start-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.selected ? connection.type.selectedColor : connection.type.color).attr('stroke', 'none');
7859
+ connectionSelection.select('g.diagram-connection-start-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
7370
7860
  connectionSelection.select('g.diagram-connection-start-label').attr('transform', `translate(${pathStartLabelPoint.x},${pathStartLabelPoint.y})`);
7371
7861
  }
7372
7862
  // bind middle labels
@@ -7377,7 +7867,7 @@ class DiagramCanvas {
7377
7867
  const boundingWidth = !connection.middleLabel ? 0 : middleLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
7378
7868
  const boundingHeight = !connection.middleLabel ? 0 : middleLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
7379
7869
  const pathMiddleLabelPoint = pathNode.getPointAtLength(pathLength / 2);
7380
- connectionSelection.select('g.diagram-connection-middle-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.selected ? connection.type.selectedColor : connection.type.color).attr('stroke', 'none');
7870
+ connectionSelection.select('g.diagram-connection-middle-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
7381
7871
  connectionSelection.select('g.diagram-connection-middle-label').attr('transform', `translate(${pathMiddleLabelPoint.x},${pathMiddleLabelPoint.y})`);
7382
7872
  }
7383
7873
  // bind end labels
@@ -7388,7 +7878,7 @@ class DiagramCanvas {
7388
7878
  const boundingWidth = !connection.endLabel ? 0 : endLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
7389
7879
  const boundingHeight = !connection.endLabel ? 0 : endLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
7390
7880
  const pathEndLabelPoint = pathNode.getPointAtLength(pathLength - Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
7391
- connectionSelection.select('g.diagram-connection-end-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.selected ? connection.type.selectedColor : connection.type.color).attr('stroke', 'none');
7881
+ connectionSelection.select('g.diagram-connection-end-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
7392
7882
  connectionSelection.select('g.diagram-connection-end-label').attr('transform', `translate(${pathEndLabelPoint.x},${pathEndLabelPoint.y})`);
7393
7883
  }
7394
7884
  }
@@ -7398,18 +7888,18 @@ class DiagramCanvas {
7398
7888
  const startMarkerSelection = connectionSelection.select('marker.diagram-connection-start-marker');
7399
7889
  const endMarkerSelection = connectionSelection.select('marker.diagram-connection-end-marker');
7400
7890
  if (connection.startMarkerLook !== null) {
7401
- startMarkerSelection.attr('orient', 'auto-start-reverse').attr('markerWidth', connection.startMarkerLook.markerWidth).attr('markerHeight', connection.startMarkerLook.markerHeight).attr('refX', connection.startMarkerLook.markerRefX).attr('refY', connection.startMarkerLook.markerRefY).select('image').attr('href', connection.selected ? connection.startMarkerLook.selectedImage : connection.startMarkerLook.image).attr('width', connection.startMarkerLook.markerWidth).attr('height', connection.startMarkerLook.markerHeight);
7891
+ startMarkerSelection.attr('orient', 'auto-start-reverse').attr('markerWidth', connection.startMarkerLook.width).attr('markerHeight', connection.startMarkerLook.height).attr('refX', connection.startMarkerLook.refX).attr('refY', connection.startMarkerLook.refY).select('image').attr('href', connection.startMarkerLook.image).attr('width', connection.startMarkerLook.width).attr('height', connection.startMarkerLook.height);
7402
7892
  } else {
7403
7893
  startMarkerSelection.attr('orient', 'auto-start-reverse').attr('markerWidth', 0).attr('markerHeight', 0);
7404
7894
  }
7405
7895
  if (connection.endMarkerLook !== null) {
7406
- endMarkerSelection.attr('orient', 'auto-start-reverse').attr('markerWidth', connection.endMarkerLook.markerWidth).attr('markerHeight', connection.endMarkerLook.markerHeight).attr('refX', connection.endMarkerLook.markerRefX).attr('refY', connection.endMarkerLook.markerRefY).select('image').attr('href', connection.selected ? connection.endMarkerLook.selectedImage : connection.endMarkerLook.image).attr('width', connection.endMarkerLook.markerWidth).attr('height', connection.endMarkerLook.markerHeight);
7896
+ endMarkerSelection.attr('orient', 'auto-start-reverse').attr('markerWidth', connection.endMarkerLook.width).attr('markerHeight', connection.endMarkerLook.height).attr('refX', connection.endMarkerLook.refX).attr('refY', connection.endMarkerLook.refY).select('image').attr('href', connection.endMarkerLook.image).attr('width', connection.endMarkerLook.width).attr('height', connection.endMarkerLook.height);
7407
7897
  } else {
7408
7898
  endMarkerSelection.attr('orient', 'auto-start-reverse').attr('markerWidth', 0).attr('markerHeight', 0);
7409
7899
  }
7410
7900
  }
7411
7901
  fitFieldRootInView(id) {
7412
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
7902
+ var _a, _b, _c;
7413
7903
  const field = this.model.fields.get(id);
7414
7904
  if (!field) {
7415
7905
  return;
@@ -7451,8 +7941,9 @@ class DiagramCanvas {
7451
7941
  if (fieldDimensions[1] < minimumFieldHeight) {
7452
7942
  fieldDimensions[1] = minimumFieldHeight;
7453
7943
  }
7454
- let stretchX = fieldDimensions[0] + getLeftMargin((_c = (_b = field.rootElement) === null || _b === undefined ? undefined : _b.getConfig()) === null || _c === undefined ? undefined : _c.label) + getRightMargin((_e = (_d = field.rootElement) === null || _d === undefined ? undefined : _d.getConfig()) === null || _e === undefined ? undefined : _e.label) - field.rootElement.width;
7455
- let stretchY = fieldDimensions[1] + getTopMargin((_g = (_f = field.rootElement) === null || _f === undefined ? undefined : _f.getConfig()) === null || _g === undefined ? undefined : _g.label) + getBottomMargin((_j = (_h = field.rootElement) === null || _h === undefined ? undefined : _h.getConfig()) === null || _j === undefined ? undefined : _j.label) - field.rootElement.height;
7944
+ const type = field.rootElement.type;
7945
+ let stretchX = fieldDimensions[0] + getLeftMargin(type === null || type === undefined ? undefined : type.label) + getRightMargin(type === null || type === undefined ? undefined : type.label) - field.rootElement.width;
7946
+ let stretchY = fieldDimensions[1] + getTopMargin(type === null || type === undefined ? undefined : type.label) + getBottomMargin(type === null || type === undefined ? undefined : type.label) - field.rootElement.height;
7456
7947
  if (this.snapToGrid) {
7457
7948
  stretchX = Math.ceil(stretchX / this.gridSize) * this.gridSize;
7458
7949
  stretchY = Math.ceil(stretchY / this.gridSize) * this.gridSize;
@@ -7464,8 +7955,8 @@ class DiagramCanvas {
7464
7955
  if (field.rootElement.height + stretchY < (field.rootElement.getMinHeight() || 0)) {
7465
7956
  stretchY = (field.rootElement.getMinHeight() || 0) - field.rootElement.height;
7466
7957
  }
7467
- (_k = field.rootElement.node) === null || _k === undefined ? undefined : _k.stretchSections(Side.Right, stretchX, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
7468
- (_l = field.rootElement.node) === null || _l === undefined ? undefined : _l.stretchSections(Side.Bottom, stretchY, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
7958
+ (_b = field.rootElement.node) === null || _b === undefined ? undefined : _b.stretchSections(Side.Right, stretchX, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
7959
+ (_c = field.rootElement.node) === null || _c === undefined ? undefined : _c.stretchSections(Side.Bottom, stretchY, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
7469
7960
  }
7470
7961
  }
7471
7962
  fitNodeInView(id) {
@@ -7508,39 +7999,41 @@ class DiagramCanvas {
7508
7999
  // User actions
7509
8000
  startConnection(port) {
7510
8001
  var _a, _b, _c, _d;
7511
- if (this.connectionType && (this.connectionType.canStartFromType(((_b = (_a = port.getNode()) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.id) || '') || this.connectionType.canFinishOnType(((_d = (_c = port.getNode()) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.id) || ''))) {
7512
- this.unfinishedConnection = new DiagramConnection(this.model, this.connectionType, port, undefined, UNFINISHED_CONNECTION_ID);
7513
- } else {
7514
- if (this.inferConnectionType) {
7515
- let differentConnectionType = this.model.connections.types.all().find(t => {
7516
- var _a, _b;
7517
- return t.canStartFromType(((_b = (_a = port.getNode()) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.id) || '');
7518
- });
7519
- if (differentConnectionType === undefined) {
7520
- differentConnectionType = this.model.connections.types.all().find(t => {
8002
+ if (port.allowsOutgoing || port.allowsIncoming) {
8003
+ if (this.connectionType && (this.connectionType.canStartFromType(((_b = (_a = port.getNode()) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.id) || '') && port.allowsOutgoing || this.connectionType.canFinishOnType(((_d = (_c = port.getNode()) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.id) || '') && port.allowsIncoming)) {
8004
+ this.unfinishedConnection = new DiagramConnection(this.model, this.connectionType, port, undefined, UNFINISHED_CONNECTION_ID);
8005
+ } else {
8006
+ if (this.inferConnectionType) {
8007
+ let differentConnectionType = this.model.connections.types.all().find(t => {
7521
8008
  var _a, _b;
7522
- return t.canFinishOnType(((_b = (_a = port.getNode()) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.id) || '');
8009
+ return port.allowsOutgoing && t.canStartFromType(((_b = (_a = port.getNode()) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.id) || '');
7523
8010
  });
7524
- }
7525
- if (differentConnectionType !== undefined) {
7526
- this.unfinishedConnection = new DiagramConnection(this.model, differentConnectionType, port, undefined, UNFINISHED_CONNECTION_ID);
8011
+ if (differentConnectionType === undefined) {
8012
+ differentConnectionType = this.model.connections.types.all().find(t => {
8013
+ var _a, _b;
8014
+ return port.allowsIncoming && t.canFinishOnType(((_b = (_a = port.getNode()) === null || _a === undefined ? undefined : _a.type) === null || _b === undefined ? undefined : _b.id) || '');
8015
+ });
8016
+ }
8017
+ if (differentConnectionType !== undefined) {
8018
+ this.unfinishedConnection = new DiagramConnection(this.model, differentConnectionType, port, undefined, UNFINISHED_CONNECTION_ID);
8019
+ }
7527
8020
  }
7528
8021
  }
7529
8022
  }
7530
8023
  }
7531
8024
  finishConnection(port) {
7532
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
8025
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
7533
8026
  this.userHighlight.clear();
7534
8027
  if (this.unfinishedConnection !== undefined) {
7535
8028
  if (this.unfinishedConnection.start !== port) {
7536
- if (this.unfinishedConnection.type.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === undefined ? undefined : _a.start) === null || _b === undefined ? undefined : _b.getNode()) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.id) || '') && this.unfinishedConnection.type.canFinishOnType(((_f = (_e = port.getNode()) === null || _e === undefined ? undefined : _e.type) === null || _f === undefined ? undefined : _f.id) || '')) {
7537
- const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, (_g = this.unfinishedConnection.start) === null || _g === undefined ? undefined : _g.id, port.id);
8029
+ if (this.unfinishedConnection.type.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === undefined ? undefined : _a.start) === null || _b === undefined ? undefined : _b.getNode()) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === undefined ? undefined : _e.start) === null || _f === undefined ? undefined : _f.allowsOutgoing) && this.unfinishedConnection.type.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === undefined ? undefined : _g.type) === null || _h === undefined ? undefined : _h.id) || '') && port.allowsIncoming) {
8030
+ const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, (_j = this.unfinishedConnection.start) === null || _j === undefined ? undefined : _j.id, port.id);
7538
8031
  // clean up the previous unfinished connection
7539
8032
  this.dropConnection();
7540
8033
  addConnectionAction.do();
7541
8034
  this.actionStack.add(addConnectionAction);
7542
- } else if (this.unfinishedConnection.type.canFinishOnType(((_l = (_k = (_j = (_h = this.unfinishedConnection) === null || _h === undefined ? undefined : _h.start) === null || _j === undefined ? undefined : _j.getNode()) === null || _k === undefined ? undefined : _k.type) === null || _l === undefined ? undefined : _l.id) || '') && this.unfinishedConnection.type.canStartFromType(((_o = (_m = port.getNode()) === null || _m === undefined ? undefined : _m.type) === null || _o === undefined ? undefined : _o.id) || '')) {
7543
- const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, port.id, (_p = this.unfinishedConnection.start) === null || _p === undefined ? undefined : _p.id);
8035
+ } else if (this.unfinishedConnection.type.canFinishOnType(((_o = (_m = (_l = (_k = this.unfinishedConnection) === null || _k === undefined ? undefined : _k.start) === null || _l === undefined ? undefined : _l.getNode()) === null || _m === undefined ? undefined : _m.type) === null || _o === undefined ? undefined : _o.id) || '') && ((_q = (_p = this.unfinishedConnection) === null || _p === undefined ? undefined : _p.start) === null || _q === undefined ? undefined : _q.allowsIncoming) && this.unfinishedConnection.type.canStartFromType(((_s = (_r = port.getNode()) === null || _r === undefined ? undefined : _r.type) === null || _s === undefined ? undefined : _s.id) || '') && port.allowsOutgoing) {
8036
+ const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, port.id, (_t = this.unfinishedConnection.start) === null || _t === undefined ? undefined : _t.id);
7544
8037
  // clean up the previous unfinished connection
7545
8038
  this.dropConnection();
7546
8039
  addConnectionAction.do();
@@ -7548,19 +8041,19 @@ class DiagramCanvas {
7548
8041
  } else {
7549
8042
  if (this.inferConnectionType) {
7550
8043
  let differentConnectionType = this.model.connections.types.all().find(t => {
7551
- var _a, _b, _c, _d, _e, _f;
7552
- return t.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === undefined ? undefined : _a.start) === null || _b === undefined ? undefined : _b.getNode()) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.id) || '') && t.canFinishOnType(((_f = (_e = port.getNode()) === null || _e === undefined ? undefined : _e.type) === null || _f === undefined ? undefined : _f.id) || '');
8044
+ var _a, _b, _c, _d, _e, _f, _g, _h;
8045
+ return t.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === undefined ? undefined : _a.start) === null || _b === undefined ? undefined : _b.getNode()) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === undefined ? undefined : _e.start) === null || _f === undefined ? undefined : _f.allowsOutgoing) && t.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === undefined ? undefined : _g.type) === null || _h === undefined ? undefined : _h.id) || '') && port.allowsIncoming;
7553
8046
  });
7554
8047
  let invertConnection = false;
7555
8048
  if (differentConnectionType === undefined) {
7556
8049
  differentConnectionType = this.model.connections.types.all().find(t => {
7557
- var _a, _b, _c, _d, _e, _f;
7558
- return t.canFinishOnType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === undefined ? undefined : _a.start) === null || _b === undefined ? undefined : _b.getNode()) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.id) || '') && t.canStartFromType(((_f = (_e = port.getNode()) === null || _e === undefined ? undefined : _e.type) === null || _f === undefined ? undefined : _f.id) || '');
8050
+ var _a, _b, _c, _d, _e, _f, _g, _h;
8051
+ return t.canFinishOnType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === undefined ? undefined : _a.start) === null || _b === undefined ? undefined : _b.getNode()) === null || _c === undefined ? undefined : _c.type) === null || _d === undefined ? undefined : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === undefined ? undefined : _e.start) === null || _f === undefined ? undefined : _f.allowsIncoming) && t.canStartFromType(((_h = (_g = port.getNode()) === null || _g === undefined ? undefined : _g.type) === null || _h === undefined ? undefined : _h.id) || '') && port.allowsOutgoing;
7559
8052
  });
7560
8053
  invertConnection = true;
7561
8054
  }
7562
8055
  if (differentConnectionType !== undefined) {
7563
- const addConnectionAction = new AddConnectionAction(this, differentConnectionType, invertConnection ? port.id : (_q = this.unfinishedConnection.start) === null || _q === undefined ? undefined : _q.id, invertConnection ? (_r = this.unfinishedConnection.start) === null || _r === undefined ? undefined : _r.id : port.id);
8056
+ const addConnectionAction = new AddConnectionAction(this, differentConnectionType, invertConnection ? port.id : (_u = this.unfinishedConnection.start) === null || _u === undefined ? undefined : _u.id, invertConnection ? (_v = this.unfinishedConnection.start) === null || _v === undefined ? undefined : _v.id : port.id);
7564
8057
  // clean up the previous unfinished connection
7565
8058
  this.dropConnection();
7566
8059
  addConnectionAction.do();
@@ -7794,41 +8287,6 @@ class DiagramCanvas {
7794
8287
  }
7795
8288
  }
7796
8289
  DiagramCanvas.canvasCount = 0;
7797
- /**
7798
- * Checks if the given mouse event was produced with a secondary button press.
7799
- * @private
7800
- * @param event A mouse event.
7801
- * @returns `true` if the given mouse event was produced with a secondary button press, `false` otherwise.
7802
- */
7803
- const isSecondaryButton = event => {
7804
- return !!event.button;
7805
- };
7806
- /**
7807
- * Get the SVG path of a diagram connection.
7808
- * @private
7809
- * @see linePath
7810
- */
7811
- const getConnectionPath = (shape, startCoords, endCoords, startDirection, endDirection, width, startMarkerWidth, endMarkerWidth) => {
7812
- return linePath(shape, [startCoords, endCoords], startDirection, endDirection, Math.max(
7813
- // reasonable value for the minimumDistanceBeforeTurn relative to the line width
7814
- 10, startMarkerWidth || 0, endMarkerWidth || 0) * width);
7815
- };
7816
- const setCursorStyle = style => {
7817
- if (!style) {
7818
- d3.select('body').style('cursor', CursorStyle.Auto);
7819
- } else {
7820
- d3.select('body').style('cursor', style);
7821
- }
7822
- };
7823
- const getRelatedNodeOrItself = element => {
7824
- if (element instanceof DiagramNode) {
7825
- return element;
7826
- }
7827
- if (element instanceof DiagramSection) {
7828
- return element.node || element;
7829
- }
7830
- return element.rootElement instanceof DiagramNode || element.rootElement instanceof DiagramSection || element.rootElement instanceof DiagramPort ? getRelatedNodeOrItself(element.rootElement) : element;
7831
- };
7832
8290
 
7833
8291
  const VERSION = '0.0.1';
7834
8292
  /**
@@ -8709,4 +9167,4 @@ const getLocationsOfNodes = model => {
8709
9167
  return locations;
8710
9168
  };
8711
9169
 
8712
- export { ACTION_STACK_SIZE, ActionStack, AddConnectionAction, AddNodeAction, AdjacencyLayout, ApplyLayoutAction, BreadthAdjacencyLayout, BreadthLayout, ClosedShape, CollabClient, Corner, CursorStyle, DIAGRAM_FIELD_DEFAULTS, DagaExporter, DagaImporter, DiagramActionMethod, DiagramActions, DiagramCanvas, DiagramConnection, DiagramConnectionSet, DiagramConnectionType, DiagramContextMenu, DiagramDecorator, DiagramDecoratorSet, DiagramDoubleClickEvent, DiagramElement, DiagramElementSet, DiagramEntitySet, DiagramEvent, DiagramEvents, DiagramField, DiagramFieldSet, DiagramHighlightedEvent, DiagramModel, DiagramNode, DiagramNodeSet, DiagramNodeType, DiagramObject, DiagramObjectSet, DiagramPort, DiagramPortSet, DiagramSecondaryClickEvent, DiagramSection, DiagramSectionSet, DiagramSelectionEvent, DiagramUserHighlight, DiagramUserSelection, DragEvents, EditFieldAction, Events, ForceLayout, HorizontalAlign, HorizontalLayout, Keys, LineShape, LineStyle, MoveAction, PasteAction, PriorityLayout, Property, PropertySet, RemoveAction, SetGeometryAction, SetParentAction, Side, TreeLayout, Type, UpdateValuesAction, ValueSet, VerticalAlign, VerticalLayout, ZoomEvents, addIfNotExists, diff, equals, filterByOnlyAncestors, filterByOnlyDescendants, generalClosedPath, getBottomMargin, getBottomPadding$1 as getBottomPadding, getLeftMargin, getLeftPadding$1 as getLeftPadding, getLocationsOfNodes, getRightMargin, getRightPadding$1 as getRightPadding, getTopMargin, getTopPadding$1 as getTopPadding, isObject, layouts, linePath, lineStyleDasharray, removeIfExists, setCursorStyle };
9170
+ export { ACTION_STACK_SIZE, ActionStack, AddConnectionAction, AddNodeAction, AdjacencyLayout, ApplyLayoutAction, BreadthAdjacencyLayout, BreadthLayout, ClosedShape, CollabClient, Corner, CursorStyle, DIAGRAM_FIELD_DEFAULTS, DagaExporter, DagaImporter, DiagramActionMethod, DiagramActions, DiagramCanvas, DiagramConnection, DiagramConnectionSet, DiagramConnectionType, DiagramContextMenu, DiagramDecorator, DiagramDecoratorSet, DiagramDoubleClickEvent, DiagramElement, DiagramElementSet, DiagramEntitySet, DiagramEvent, DiagramEvents, DiagramField, DiagramFieldSet, DiagramHighlightedEvent, DiagramModel, DiagramNode, DiagramNodeSet, DiagramNodeType, DiagramObject, DiagramObjectSet, DiagramPort, DiagramPortSet, DiagramPortType, DiagramSecondaryClickEvent, DiagramSection, DiagramSectionSet, DiagramSelectionEvent, DiagramUserHighlight, DiagramUserSelection, DragEvents, EditFieldAction, Events, ForceLayout, HorizontalAlign, HorizontalLayout, Keys, LineShape, LineStyle, MoveAction, PasteAction, PriorityLayout, Property, PropertySet, RemoveAction, SetGeometryAction, SetParentAction, Side, TreeLayout, Type, UpdateValuesAction, ValueSet, VerticalAlign, VerticalLayout, ZoomEvents, addIfNotExists, diff, equals, filterByOnlyAncestors, filterByOnlyDescendants, generalClosedPath, getBottomMargin, getBottomPadding$1 as getBottomPadding, getLeftMargin, getLeftPadding$1 as getLeftPadding, getLocationsOfNodes, getRightMargin, getRightPadding$1 as getRightPadding, getTopMargin, getTopPadding$1 as getTopPadding, isObject, layouts, linePath, lineStyleDasharray, removeIfExists, setCursorStyle };