@sapui5/sap.suite.ui.commons 1.146.0 → 1.147.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/package.json +1 -1
  2. package/src/sap/suite/ui/commons/.library +1 -1
  3. package/src/sap/suite/ui/commons/AriaProperties.js +1 -1
  4. package/src/sap/suite/ui/commons/CalculationBuilder.js +56 -2
  5. package/src/sap/suite/ui/commons/CalculationBuilderExpression.js +87 -14
  6. package/src/sap/suite/ui/commons/CalculationBuilderFunction.js +1 -1
  7. package/src/sap/suite/ui/commons/CalculationBuilderGroup.js +1 -1
  8. package/src/sap/suite/ui/commons/CalculationBuilderItem.js +16 -3
  9. package/src/sap/suite/ui/commons/CalculationBuilderValidationResult.js +1 -1
  10. package/src/sap/suite/ui/commons/CalculationBuilderVariable.js +1 -1
  11. package/src/sap/suite/ui/commons/CloudFilePicker.js +1 -1
  12. package/src/sap/suite/ui/commons/MicroProcessFlow.js +1 -1
  13. package/src/sap/suite/ui/commons/MicroProcessFlowItem.js +1 -1
  14. package/src/sap/suite/ui/commons/collaboration/ContactPopover.fragment.xml +8 -8
  15. package/src/sap/suite/ui/commons/collaboration/MinimalContactPopover.fragment.xml +5 -5
  16. package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
  17. package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
  18. package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
  19. package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
  20. package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
  21. package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
  22. package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
  23. package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
  24. package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
  25. package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
  26. package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +1 -1
  27. package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
  28. package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
  29. package/src/sap/suite/ui/commons/library.js +4 -4
  30. package/src/sap/suite/ui/commons/messagebundle.properties +12 -8
  31. package/src/sap/suite/ui/commons/messagebundle_mk.properties +1 -1
  32. package/src/sap/suite/ui/commons/networkgraph/Graph.js +138 -27
  33. package/src/sap/suite/ui/commons/networkgraph/GraphMap.js +25 -3
  34. package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +332 -13
  35. package/src/sap/suite/ui/commons/networkgraph/Line.js +5 -1
  36. package/src/sap/suite/ui/commons/networkgraph/Node.js +67 -5
  37. package/src/sap/suite/ui/commons/networkgraph/Utils.js +10 -0
  38. package/src/sap/suite/ui/commons/networkgraph/util/ConnectionPathUtils.js +34 -4
  39. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +213 -74
  40. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  41. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  42. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  43. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  44. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  45. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  46. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  47. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  48. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  49. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  50. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  51. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  52. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  53. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  54. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  55. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  56. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  57. package/src/sap/suite/ui/commons/themes/base/BusinessCard.less +5 -4
  58. package/src/sap/suite/ui/commons/themes/base/CalculationBuilder.less +33 -24
  59. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderExpression.less +40 -31
  60. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderInput.less +26 -10
  61. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderItem.less +76 -63
  62. package/src/sap/suite/ui/commons/themes/base/ChartContainer.less +8 -11
  63. package/src/sap/suite/ui/commons/themes/base/ChartTile.less +5 -8
  64. package/src/sap/suite/ui/commons/themes/base/CollaborationPopover.less +116 -106
  65. package/src/sap/suite/ui/commons/themes/base/DateRangeScroller.less +5 -5
  66. package/src/sap/suite/ui/commons/themes/base/DateRangeSliderInternal.less +9 -10
  67. package/src/sap/suite/ui/commons/themes/base/FacetOverview.less +9 -10
  68. package/src/sap/suite/ui/commons/themes/base/FeedItemHeader.less +9 -12
  69. package/src/sap/suite/ui/commons/themes/base/FeedTile.less +23 -27
  70. package/src/sap/suite/ui/commons/themes/base/GenericTile2X2.less +15 -15
  71. package/src/sap/suite/ui/commons/themes/base/HeaderCell.less +7 -6
  72. package/src/sap/suite/ui/commons/themes/base/HeaderContainer.less +35 -37
  73. package/src/sap/suite/ui/commons/themes/base/ImageEditor.less +28 -10
  74. package/src/sap/suite/ui/commons/themes/base/ImageEditorContainer.less +29 -22
  75. package/src/sap/suite/ui/commons/themes/base/InfoTile.less +10 -4
  76. package/src/sap/suite/ui/commons/themes/base/InfoTileSize.less +5 -4
  77. package/src/sap/suite/ui/commons/themes/base/KpiTile.less +10 -11
  78. package/src/sap/suite/ui/commons/themes/base/LaunchTile.less +9 -8
  79. package/src/sap/suite/ui/commons/themes/base/LinkActionSheet.less +14 -43
  80. package/src/sap/suite/ui/commons/themes/base/MicroProcessFlow.less +51 -47
  81. package/src/sap/suite/ui/commons/themes/base/MonitoringContent.less +5 -5
  82. package/src/sap/suite/ui/commons/themes/base/NetworkGraph.less +57 -62
  83. package/src/sap/suite/ui/commons/themes/base/NetworkGroup.less +61 -65
  84. package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +58 -55
  85. package/src/sap/suite/ui/commons/themes/base/NetworkNode.less +3 -0
  86. package/src/sap/suite/ui/commons/themes/base/NetworkTooltip.less +21 -25
  87. package/src/sap/suite/ui/commons/themes/base/NoteTaker.less +13 -18
  88. package/src/sap/suite/ui/commons/themes/base/NoteTakerCard.less +26 -27
  89. package/src/sap/suite/ui/commons/themes/base/NoteTakerFeeder.less +22 -44
  90. package/src/sap/suite/ui/commons/themes/base/NumericTile.less +7 -5
  91. package/src/sap/suite/ui/commons/themes/base/PictureZoomIn.less +6 -5
  92. package/src/sap/suite/ui/commons/themes/base/ProcessFlow.less +57 -76
  93. package/src/sap/suite/ui/commons/themes/base/ProcessFlowConnection.less +71 -17
  94. package/src/sap/suite/ui/commons/themes/base/ProcessFlowConnectionLabel.less +9 -13
  95. package/src/sap/suite/ui/commons/themes/base/ProcessFlowLaneHeader.less +37 -96
  96. package/src/sap/suite/ui/commons/themes/base/ProcessFlowNode.less +219 -238
  97. package/src/sap/suite/ui/commons/themes/base/SemanticColorMixins.less +55 -0
  98. package/src/sap/suite/ui/commons/themes/base/SplitButton.less +7 -20
  99. package/src/sap/suite/ui/commons/themes/base/StatusIndicator.less +10 -9
  100. package/src/sap/suite/ui/commons/themes/base/TAccount.less +78 -73
  101. package/src/sap/suite/ui/commons/themes/base/TargetFilter.less +50 -58
  102. package/src/sap/suite/ui/commons/themes/base/ThingCollection.less +18 -13
  103. package/src/sap/suite/ui/commons/themes/base/ThreePanelThingViewer.less +14 -14
  104. package/src/sap/suite/ui/commons/themes/base/TileContent2X2.less +9 -13
  105. package/src/sap/suite/ui/commons/themes/base/Timeline.less +16 -19
  106. package/src/sap/suite/ui/commons/themes/base/TimelineItem.less +95 -103
  107. package/src/sap/suite/ui/commons/themes/base/UnifiedThingGroup.less +7 -9
  108. package/src/sap/suite/ui/commons/themes/base/UnifiedThingInspector.less +12 -9
  109. package/src/sap/suite/ui/commons/themes/base/VerticalNavigationBar.less +10 -15
  110. package/src/sap/suite/ui/commons/themes/base/ViewRepeater.less +8 -9
  111. package/src/sap/suite/ui/commons/themes/base/library.source.less +0 -2
  112. package/src/sap/suite/ui/commons/themes/sap_fiori_3/MicroProcessFlow.less +9 -3
  113. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowConnection.less +14 -7
  114. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowConnectionLabel.less +38 -35
  115. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowLaneHeader.less +29 -30
  116. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowNode.less +158 -102
  117. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/MicroProcessFlow.less +9 -3
  118. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowConnection.less +14 -7
  119. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowConnectionLabel.less +38 -35
  120. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowLaneHeader.less +30 -31
  121. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowNode.less +157 -101
  122. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowConnection.less +14 -7
  123. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowConnectionLabel.less +38 -35
  124. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowLaneHeader.less +30 -31
  125. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowNode.less +147 -101
  126. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowConnection.less +14 -7
  127. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowConnectionLabel.less +38 -35
  128. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowLaneHeader.less +30 -31
  129. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowNode.less +158 -102
  130. package/src/sap/suite/ui/commons/themes/sap_horizon/MicroProcessFlow.less +5 -0
  131. package/src/sap/suite/ui/commons/themes/sap_horizon/NetworkLine.less +12 -8
  132. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowConnection.less +17 -10
  133. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowConnectionLabel.less +154 -133
  134. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowLaneHeader.less +30 -32
  135. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowNode.less +113 -214
  136. package/src/sap/suite/ui/commons/themes/sap_horizon/TimelineItem.less +43 -39
  137. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/MicroProcessFlow.less +5 -0
  138. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/NetworkLine.less +12 -12
  139. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowConnection.less +17 -10
  140. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowConnectionLabel.less +154 -133
  141. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowLaneHeader.less +30 -31
  142. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowNode.less +114 -216
  143. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/TimelineItem.less +41 -39
  144. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/MicroProcessFlow.less +4 -4
  145. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowConnection.less +17 -10
  146. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowConnectionLabel.less +153 -131
  147. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowLaneHeader.less +29 -30
  148. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowNode.less +159 -103
  149. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/TimelineItem.less +41 -39
  150. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/MicroProcessFlow.less +4 -4
  151. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowConnection.less +16 -9
  152. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowConnectionLabel.less +153 -131
  153. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowLaneHeader.less +29 -30
  154. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowNode.less +157 -101
  155. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/TimelineItem.less +41 -39
  156. package/src/sap/suite/ui/commons/themes/base/DateRangeSlider.less +0 -3
  157. package/src/sap/suite/ui/commons/themes/base/MonitoringTile.less +0 -3
@@ -11,12 +11,32 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
11
11
  oComponentArrangement = library.networkgraph.ComponentArrangement;
12
12
  const DEFAULT_HORIZONTAL_SPACING = 240;
13
13
  const DEFAULT_VERTICAL_SPACING = 100;
14
+ const DRAG_DETECTION_THRESHOLD = 10;
14
15
 
15
16
  /**
16
17
  * Utility class for calculating node positions based on dependency relationships.
17
18
  * This utility arranges nodes based on their dependency relationships using topological sorting,
18
19
  * cycle detection, and layer-based positioning.
19
20
  *
21
+ * Why a node may be positioned incorrectly after recalculation:
22
+ * After each run, node positions are cached with a flag indicating whether the user moved
23
+ * them (<code>bIsUserPositioned</code>). On the next call, nodes flagged as user-positioned
24
+ * are preserved as-is, and the algorithm-placed nodes are recalculated. A node appears in the
25
+ * wrong place if it is unexpectedly treated as user-positioned, most commonly because
26
+ * <code>clearCache: true</code> was passed. It wipes the cache, but leaves the coordinates intact.
27
+ * So every node with non-zero coordinates is immediately re-classified as user-positioned
28
+ * and freezes, rather than being recalculated.
29
+ *
30
+ * Drag and drop recalculation - correct pattern:
31
+ * Call <code>resetNode(oNode)</code> for each dragged node, then call
32
+ * <code>calculatePositions</code> without <code>clearCache</code> (default <code>false</code>).
33
+ * <code>resetNode</code> evicts the node from the cache and zeros its coordinates, so only
34
+ * that node is repositioned; all the other nodes remain stable.
35
+ *
36
+ * Sentinel value:
37
+ * Coordinates <code>(0, 0)</code> mean "unpositioned". To place a node at the canvas origin,
38
+ * use <code>(0.1, 0.1)</code> or <code>(1, 1)</code> instead.
39
+ *
20
40
  * @namespace sap.suite.ui.commons.networkgraph.util.DependencyLayoutHelper
21
41
  * @public
22
42
  * @since 1.144
@@ -28,6 +48,26 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
28
48
  */
29
49
  _lastCalculated: new WeakMap(),
30
50
 
51
+ /**
52
+ * Evicts one or more nodes from the position cache and zeros their coordinates so the next
53
+ * <code>calculatePositions</code> call repositions them while all other nodes remain stable.
54
+ * To understand the use for drag and drop recalculation, see the class-level JSDoc for the full pattern.
55
+ *
56
+ * @param {sap.suite.ui.commons.networkgraph.Node|sap.suite.ui.commons.networkgraph.Node[]} vNode - A single node or an array of nodes to reset
57
+ * @public
58
+ */
59
+ resetNode: function (vNode) {
60
+ const aNodes = Array.isArray(vNode) ? vNode : [vNode];
61
+ aNodes.forEach((oNode) => {
62
+ if (!oNode || !oNode.setX || !oNode.setY) {
63
+ return;
64
+ }
65
+ this._lastCalculated.delete(oNode);
66
+ oNode.setX(0);
67
+ oNode.setY(0);
68
+ });
69
+ },
70
+
31
71
  /**
32
72
  * Calculates and sets positions for nodes without coordinates based on their dependency relationships.
33
73
  * Uses topological sorting (Kahn's algorithm) and DFS-based cycle detection to arrange nodes
@@ -39,7 +79,10 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
39
79
  * @param {number} [mConfig.horizontalSpacing=240] - Horizontal spacing between layers
40
80
  * @param {number} [mConfig.verticalSpacing=100] - Vertical spacing between nodes
41
81
  * @param {sap.suite.ui.commons.networkgraph.ComponentArrangement} [mConfig.componentArrangement=Horizontal] - Component arrangement: "Horizontal" or "Vertical"
42
- * @param {boolean} [mConfig.clearCache=false] - Clear the position cache to force recalculation of all nodes
82
+ * @param {boolean} [mConfig.clearCache=false] - Wipes the position cache; node coordinates are not modified.
83
+ * <code>_detectUserChanges</code> then re-classifies every non-zero node as user-positioned and freezes it.
84
+ * Use only to discard all layout history (e.g. switching <code>componentArrangement</code>).
85
+ * For drag and drop recalculation, use <code>resetNode()</code> with the default <code>clearCache: false</code>.
43
86
  * @public
44
87
  */
45
88
  calculatePositions: function (oGraph, mConfig) {
@@ -63,14 +106,17 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
63
106
  }
64
107
 
65
108
  try {
66
- this._detectUserChanges(oGraph);
109
+ this._detectUserChanges(oGraph, config.horizontalSpacing);
67
110
  this._buildDependencyGraph(oGraph);
68
111
  const aComponents = this._identifyComponents(oGraph);
69
112
  this._processComponents(aComponents, config);
70
113
  this._calculateCoordinates(oGraph, config);
71
114
  this._adjustHorizontalSpacingForNodeWidths(oGraph, config);
72
115
  this._adjustVerticalSpacingForNodeHeights(oGraph, config);
73
- this._storeFinalPositions(oGraph);
116
+ if (oGraph._bIsRtl) {
117
+ this._horizontalMirror(oGraph, config.horizontalSpacing);
118
+ }
119
+ this._storeFinalPositions(oGraph, config.horizontalSpacing);
74
120
  } catch (e) {
75
121
  Log.error("DependencyLayoutHelper error: " + e.message, e);
76
122
  throw new Error("DependencyLayoutHelper error: " + e.message);
@@ -96,11 +142,6 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
96
142
 
97
143
  aNodes.forEach((oNode) => {
98
144
  mNodeMap.set(oNode.getKey(), oNode);
99
- const fX = oNode.getX();
100
- const fY = oNode.getY();
101
- const oLastPos = this._lastCalculated.get(oNode);
102
- // Only preserve coordinates if they were original or user-dragged
103
- const bShouldPreserve = oLastPos?.bIsUserPositioned;
104
145
 
105
146
  oNode._layoutData = {
106
147
  layer: -1,
@@ -110,10 +151,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
110
151
  parallelNodes: [],
111
152
  backwardEdges: [],
112
153
  backwardEdgeLines: [],
113
- isBackwardSource: false,
114
- bShouldPreserve,
115
- userX: fX,
116
- userY: fY
154
+ isBackwardSource: false
117
155
  };
118
156
  });
119
157
 
@@ -279,8 +317,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
279
317
  const bIsIsolated =
280
318
  aComponentNodes.length === 1 &&
281
319
  aComponentNodes[0]._layoutData.incoming.length === 0 &&
282
- aComponentNodes[0]._layoutData.outgoing.length === 0 &&
283
- !aComponentNodes[0]._layoutData.bShouldPreserve;
320
+ aComponentNodes[0]._layoutData.outgoing.length === 0;
284
321
 
285
322
  if (bIsIsolated) {
286
323
  aIsolatedNodes.push(aComponentNodes[0]);
@@ -335,18 +372,17 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
335
372
  });
336
373
 
337
374
  if (aIsolatedNodes.length > 0) {
338
- const iRightSideOffset = iMaxLayerAcrossAll + 1;
339
-
340
- aIsolatedNodes.forEach((oNode, idx) => {
341
- if (bSideBySide) {
342
- oNode._layoutData.layer = Math.floor(idx / 2);
343
- oNode._layoutData.position = idx % 2;
344
- oNode._layoutData.componentOffset = iMaxLayerAcrossAll;
345
- } else {
346
- oNode._layoutData.layer = idx % 2;
347
- oNode._layoutData.position = Math.floor(idx / 2);
348
- oNode._layoutData.componentOffset = iRightSideOffset;
375
+ const iRightSideOffset = bSideBySide ? iMaxLayerAcrossAll : iMaxLayerAcrossAll + 1;
376
+ let iIsolatedIdx = 0;
377
+ aIsolatedNodes.forEach((oNode) => {
378
+ if (this._lastCalculated.get(oNode)?.bIsUserPositioned) {
379
+ return;
349
380
  }
381
+ const idx = iIsolatedIdx++;
382
+
383
+ oNode._layoutData.layer = Math.floor(idx / 2);
384
+ oNode._layoutData.position = idx % 2;
385
+ oNode._layoutData.componentOffset = iRightSideOffset;
350
386
  });
351
387
  }
352
388
  },
@@ -711,10 +747,10 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
711
747
  });
712
748
 
713
749
  aNodes.forEach((oNode) => {
714
- if (oNode._layoutData.bShouldPreserve) {
715
- const { userX, userY } = oNode._layoutData;
716
- oNode.setX(userX);
717
- oNode.setY(userY);
750
+ const oLastPos = this._lastCalculated.get(oNode);
751
+ if (oLastPos?.bIsUserPositioned) {
752
+ oNode.setX(oLastPos.x);
753
+ oNode.setY(oLastPos.y);
718
754
  }
719
755
  });
720
756
  },
@@ -731,16 +767,16 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
731
767
  let iMaxLayer = -1;
732
768
 
733
769
  aNodes.forEach((oNode) => {
734
- if (!oNode._layoutData.bShouldPreserve) {
735
- const iLayer =
736
- oNode._layoutData.layer + (oNode._layoutData.componentOffset || 0);
737
- iMaxLayer = Math.max(iMaxLayer, iLayer);
738
-
739
- if (oNode._iWidth) {
740
- const iWidth = oNode._iWidth;
741
- if (!mLayerWidths[iLayer] || mLayerWidths[iLayer] < iWidth) {
742
- mLayerWidths[iLayer] = iWidth;
743
- }
770
+ const iLayer =
771
+ oNode._layoutData.layer + (oNode._layoutData.componentOffset || 0);
772
+ // Skip nodes with unassigned layout
773
+ if (iLayer < 0) return;
774
+ iMaxLayer = Math.max(iMaxLayer, iLayer);
775
+
776
+ if (oNode._iWidth) {
777
+ const iWidth = oNode._iWidth;
778
+ if (!mLayerWidths[iLayer] || mLayerWidths[iLayer] < iWidth) {
779
+ mLayerWidths[iLayer] = iWidth;
744
780
  }
745
781
  }
746
782
  });
@@ -757,7 +793,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
757
793
  }
758
794
 
759
795
  aNodes.forEach((oNode) => {
760
- if (!oNode._layoutData.bShouldPreserve) {
796
+ if (!this._lastCalculated.get(oNode)?.bIsUserPositioned) {
761
797
  const iLayer =
762
798
  oNode._layoutData.layer + (oNode._layoutData.componentOffset || 0);
763
799
  const iOffset = mLayerOffsets[iLayer] || 0;
@@ -778,18 +814,18 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
778
814
  const mAllPositions = {};
779
815
 
780
816
  aNodes.forEach((oNode) => {
781
- if (!oNode._layoutData.bShouldPreserve) {
782
- const iPosition = oNode._layoutData.position;
783
- mAllPositions[iPosition] = true;
817
+ const iPosition = oNode._layoutData.position;
818
+ // Skip nodes with unassigned layout
819
+ if (iPosition < 0) return;
820
+ mAllPositions[iPosition] = true;
784
821
 
785
- if (oNode._iHeight) {
786
- const iHeight = oNode._iHeight;
787
- if (
788
- !mPositionHeights[iPosition] ||
789
- mPositionHeights[iPosition] < iHeight
790
- ) {
791
- mPositionHeights[iPosition] = iHeight;
792
- }
822
+ if (oNode._iHeight) {
823
+ const iHeight = oNode._iHeight;
824
+ if (
825
+ !mPositionHeights[iPosition] ||
826
+ mPositionHeights[iPosition] < iHeight
827
+ ) {
828
+ mPositionHeights[iPosition] = iHeight;
793
829
  }
794
830
  }
795
831
  });
@@ -809,7 +845,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
809
845
  });
810
846
 
811
847
  aNodes.forEach((oNode) => {
812
- if (!oNode._layoutData.bShouldPreserve) {
848
+ if (!this._lastCalculated.get(oNode)?.bIsUserPositioned) {
813
849
  const iPosition = oNode._layoutData.position;
814
850
  const iOffset = mPositionOffsets[iPosition] || 0;
815
851
  oNode.setY(oNode.getY() + iOffset);
@@ -822,19 +858,38 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
822
858
  * Only stores positions for nodes that were calculated (not original/dragged).
823
859
  *
824
860
  * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
861
+ * @param {number} iHSpacing - Horizontal spacing used as RTL mirror offset
825
862
  * @private
826
863
  */
827
- _storeFinalPositions: function (oGraph) {
864
+ _storeFinalPositions: function (oGraph, iHSpacing) {
828
865
  const aNodes = oGraph.getNodes();
866
+ const bIsRtl = oGraph._bIsRtl || false;
867
+
868
+ // Reuse fMaxX from _horizontalMirror to ensure consistent mirror/unmirror
869
+ let fMaxX = 0;
870
+ if (bIsRtl) {
871
+ fMaxX = oGraph._rtlMirrorMaxX || 0;
872
+ }
829
873
 
830
874
  aNodes.forEach((oNode) => {
831
- if (!oNode._layoutData.bShouldPreserve) {
832
- this._lastCalculated.set(oNode, {
833
- x: oNode.getX(),
834
- y: oNode.getY(),
835
- bIsUserPositioned: false
836
- });
875
+ const fCurrentX = oNode.getX();
876
+ const fCurrentY = oNode.getY();
877
+
878
+ // Always store in LTR space
879
+ let fLtrX = fCurrentX;
880
+ if (bIsRtl) {
881
+ const fNodeWidth = oNode._iWidth || 0;
882
+ fLtrX = fMaxX - fCurrentX - fNodeWidth + iHSpacing;
837
883
  }
884
+
885
+ const bIsUserPositioned = this._lastCalculated.get(oNode)?.bIsUserPositioned ?? false;
886
+
887
+ this._lastCalculated.set(oNode, {
888
+ x: fLtrX,
889
+ y: fCurrentY,
890
+ lastRtl: bIsRtl,
891
+ bIsUserPositioned
892
+ });
838
893
  });
839
894
  },
840
895
 
@@ -843,36 +898,120 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
843
898
  * Marks nodes with original coordinates and tracks drag operations.
844
899
  *
845
900
  * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
901
+ * @param {number} iHSpacing - Horizontal spacing used as RTL mirror offset
846
902
  * @private
847
903
  */
848
- _detectUserChanges: function (oGraph) {
904
+ _detectUserChanges: function (oGraph, iHSpacing) {
849
905
  const aNodes = oGraph.getNodes();
906
+ const bIsRtl = oGraph._bIsRtl || false;
907
+
908
+ // Use stored fMaxX from previous mirror operation if available, otherwise calculate.
909
+ // We need it both when in RTL mode AND when switching RTL→LTR (to detect pre-switch drags).
910
+ let fMaxX = oGraph._rtlMirrorMaxX || 0;
911
+ if (bIsRtl && !fMaxX) {
912
+ aNodes.forEach((n) => {
913
+ const fRight = n.getX() + (n._iWidth || 0);
914
+ if (fRight > fMaxX) fMaxX = fRight;
915
+ });
916
+ }
850
917
 
851
918
  aNodes.forEach((oNode) => {
852
- const fX = oNode.getX();
853
- const fY = oNode.getY();
854
- // Constraint: Nodes with coordinates (0,0) or negative values are treated as unpositioned.
855
- // For origin positioning, use (0.1, 0.1) or (1, 1).
856
- const bHasCoordinates = fX !== undefined && fY !== undefined && (fX !== 0 || fY !== 0);
919
+ const fCurrentX = oNode.getX();
920
+ const fCurrentY = oNode.getY();
921
+ // (0,0) is the sentinel for "unpositioned": resetNode() sets coordinates to (0,0)
922
+ // so the algorithm treats the node as if it were never placed.
923
+ // To legitimately position a node at the canvas origin, use (0.1, 0.1) or (1, 1).
924
+ const bHasCoordinates = fCurrentX !== undefined && fCurrentY !== undefined && (fCurrentX !== 0 || fCurrentY !== 0);
857
925
  const oLastPos = this._lastCalculated.get(oNode);
858
926
 
859
- if (!oLastPos && bHasCoordinates) {
860
- // First time seeing this node with coordinates - mark as original
927
+ // Convert current position to LTR coordinates for comparison
928
+ let fLtrX = fCurrentX;
929
+ if (bIsRtl) {
930
+ const fNodeWidth = oNode._iWidth || 0;
931
+ fLtrX = fMaxX - fCurrentX - fNodeWidth + iHSpacing;
932
+ }
933
+
934
+ if (oLastPos && !bHasCoordinates) {
935
+ // Coordinates were cleared (sentinel value 0,0) — evict cache so the algorithm
936
+ // repositions this node on the next layout pass.
937
+ this._lastCalculated.delete(oNode);
938
+ } else if (!oLastPos && bHasCoordinates) {
939
+ // No cache entry + non-zero coords: node has model-provided position (first call).
940
+ // Treated as user-positioned → preserved. Use resetNode() to opt a node out.
861
941
  this._lastCalculated.set(oNode, {
862
- x: fX,
863
- y: fY,
942
+ x: fLtrX,
943
+ y: fCurrentY,
944
+ lastRtl: bIsRtl,
864
945
  bIsUserPositioned: true
865
946
  });
866
947
  } else if (oLastPos) {
867
- // Check if user dragged it
868
- if (fX !== oLastPos.x || fY !== oLastPos.y) {
869
- oLastPos.x = fX;
870
- oLastPos.y = fY;
871
- oLastPos.bIsUserPositioned = true;
948
+ const bModeChanged = (oLastPos.lastRtl !== bIsRtl);
949
+
950
+ if (bModeChanged) {
951
+ const bPrevRtl = oLastPos.lastRtl;
952
+ let fLtrXBeforeSwitch;
953
+
954
+ if (bPrevRtl) {
955
+ const fNodeWidth = oNode._iWidth || 0;
956
+ fLtrXBeforeSwitch = fMaxX - fCurrentX - fNodeWidth + iHSpacing;
957
+ } else {
958
+ fLtrXBeforeSwitch = fCurrentX;
959
+ }
960
+
961
+ const fDeltaX = Math.abs(fLtrXBeforeSwitch - oLastPos.x);
962
+ const fDeltaY = Math.abs(fCurrentY - oLastPos.y);
963
+
964
+ if (fDeltaX > DRAG_DETECTION_THRESHOLD || fDeltaY > DRAG_DETECTION_THRESHOLD) {
965
+ oLastPos.x = fLtrXBeforeSwitch;
966
+ oLastPos.y = fCurrentY;
967
+ oLastPos.bIsUserPositioned = true;
968
+ }
969
+
970
+ oLastPos.lastRtl = bIsRtl;
971
+ } else {
972
+ const fDeltaX = Math.abs(fLtrX - oLastPos.x);
973
+ const fDeltaY = Math.abs(fCurrentY - oLastPos.y);
974
+
975
+ if (fDeltaX > DRAG_DETECTION_THRESHOLD || fDeltaY > DRAG_DETECTION_THRESHOLD) {
976
+ oLastPos.x = fLtrX;
977
+ oLastPos.y = fCurrentY;
978
+ oLastPos.bIsUserPositioned = true;
979
+ }
872
980
  }
873
981
  }
874
982
  });
875
983
  },
984
+
985
+ /**
986
+ * Mirrors all node X positions horizontally for RTL layout.
987
+ *
988
+ * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
989
+ * @param {number} iHSpacing - Horizontal spacing used as left-side padding offset after mirroring
990
+ * @private
991
+ */
992
+ _horizontalMirror: function (oGraph, iHSpacing) {
993
+ const aNodes = oGraph.getNodes();
994
+
995
+ // Find the rightmost edge of all nodes
996
+ let fMaxX = 0;
997
+ aNodes.forEach((oNode) => {
998
+ const fX = oNode.getX();
999
+ const fWidth = oNode._iWidth || 0;
1000
+ const fRightEdge = fX + fWidth;
1001
+ if (fRightEdge > fMaxX) {
1002
+ fMaxX = fRightEdge;
1003
+ }
1004
+ });
1005
+
1006
+ oGraph._rtlMirrorMaxX = fMaxX;
1007
+
1008
+ aNodes.forEach((oNode) => {
1009
+ const fCurrentX = oNode.getX();
1010
+ const fWidth = oNode._iWidth || 0;
1011
+ const fMirroredX = fMaxX - fCurrentX - fWidth + iHSpacing;
1012
+ oNode.setX(fMirroredX);
1013
+ });
1014
+ }
876
1015
  };
877
1016
 
878
1017
  return DependencyLayoutHelper;
@@ -30,7 +30,7 @@ sap.ui.define([
30
30
  * @extends sap.suite.ui.commons.statusindicator.SimpleShape
31
31
  *
32
32
  * @author SAP SE
33
- * @version 1.146.0
33
+ * @version 1.147.0
34
34
  * @since 1.50
35
35
  *
36
36
  * @constructor
@@ -36,7 +36,7 @@ sap.ui.define([
36
36
  * @extends sap.suite.ui.commons.statusindicator.Shape
37
37
  *
38
38
  * @author SAP SE
39
- * @version 1.146.0
39
+ * @version 1.147.0
40
40
  * @since 1.50
41
41
  *
42
42
  * @constructor
@@ -21,7 +21,7 @@ sap.ui.define([
21
21
  * @extends sap.ui.core.Control
22
22
  *
23
23
  * @author SAP SE
24
- * @version 1.146.0
24
+ * @version 1.147.0
25
25
  * @since 1.50
26
26
  *
27
27
  * @constructor
@@ -23,7 +23,7 @@ sap.ui.define([
23
23
  * @extends sap.ui.core.Control
24
24
  *
25
25
  * @author SAP SE
26
- * @version 1.146.0
26
+ * @version 1.147.0
27
27
  * @since 1.50
28
28
  *
29
29
  * @constructor
@@ -23,7 +23,7 @@ sap.ui.define([
23
23
  * @extends sap.suite.ui.commons.statusindicator.CustomShape
24
24
  *
25
25
  * @author SAP SE
26
- * @version 1.146.0
26
+ * @version 1.147.0
27
27
  * @since 1.60.0
28
28
  *
29
29
  * @constructor
@@ -29,7 +29,7 @@ sap.ui.define([
29
29
  * @extends sap.suite.ui.commons.statusindicator.SimpleShape
30
30
  *
31
31
  * @author SAP SE
32
- * @version 1.146.0
32
+ * @version 1.147.0
33
33
  * @since 1.50
34
34
  *
35
35
  * @constructor
@@ -28,7 +28,7 @@ sap.ui.define([
28
28
  * @extends sap.ui.core.Control
29
29
  *
30
30
  * @author SAP SE
31
- * @version 1.146.0
31
+ * @version 1.147.0
32
32
  * @since 1.50
33
33
  *
34
34
  * @constructor
@@ -29,7 +29,7 @@ sap.ui.define(
29
29
  * @extends sap.suite.ui.commons.statusindicator.SimpleShape
30
30
  *
31
31
  * @author SAP SE
32
- * @version 1.146.0
32
+ * @version 1.147.0
33
33
  * @since 1.50
34
34
  *
35
35
  * @constructor
@@ -42,7 +42,7 @@ sap.ui.define([
42
42
  * @extends sap.ui.core.Control
43
43
  *
44
44
  * @author SAP SE
45
- * @version 1.146.0
45
+ * @version 1.147.0
46
46
  * @since 1.50
47
47
  *
48
48
  * @constructor
@@ -30,7 +30,7 @@ sap.ui.define([
30
30
  * @extends sap.ui.core.Control
31
31
  *
32
32
  * @author SAP SE
33
- * @version 1.146.0
33
+ * @version 1.147.0
34
34
  * @since 1.50
35
35
  *
36
36
  * @constructor
@@ -30,7 +30,7 @@ sap.ui.define([
30
30
  * @extends sap.suite.ui.commons.statusindicator.Shape
31
31
  *
32
32
  * @author SAP SE
33
- * @version 1.146.0
33
+ * @version 1.147.0
34
34
  * @since 1.50
35
35
  *
36
36
  * @constructor
@@ -49,7 +49,7 @@ sap.ui.define([
49
49
  * @extends sap.ui.core.Control
50
50
  *
51
51
  * @author SAP SE
52
- * @version 1.146.0
52
+ * @version 1.147.0
53
53
  * @since 1.50
54
54
  *
55
55
  * @constructor
@@ -56,7 +56,7 @@ sap.ui.define([
56
56
  * @extends sap.ui.core.Control
57
57
  *
58
58
  * @author SAP SE
59
- * @version 1.146.0
59
+ * @version 1.147.0
60
60
  * @since 1.58.0
61
61
  *
62
62
  * @constructor
@@ -41,7 +41,7 @@ sap.ui.define([
41
41
  * @extends sap.ui.core.Control
42
42
  *
43
43
  * @author SAP SE
44
- * @version 1.146.0
44
+ * @version 1.147.0
45
45
  * @since 1.58.0
46
46
  *
47
47
  * @constructor
@@ -41,7 +41,7 @@ sap.ui.define([
41
41
  * @extends sap.ui.core.Control
42
42
  *
43
43
  * @author SAP SE
44
- * @version 1.146.0
44
+ * @version 1.147.0
45
45
  * @since 1.58.0
46
46
  *
47
47
  * @constructor
@@ -24,7 +24,7 @@ sap.ui.define([
24
24
  * @extends sap.ui.core.Control
25
25
  *
26
26
  * @author SAP SE
27
- * @version 1.146.0
27
+ * @version 1.147.0
28
28
  * @since 1.58.0
29
29
  *
30
30
  * @constructor
@@ -65,7 +65,7 @@ sap.ui.define([
65
65
  * @extends sap.m.Panel
66
66
  *
67
67
  * @author SAP SE
68
- * @version 1.146.0
68
+ * @version 1.147.0
69
69
  * @since 1.58.0
70
70
  *
71
71
  * @constructor
@@ -1,6 +1,7 @@
1
- /* ============================================= */
2
- /* CSS for control sap.suite.ui.commons/BusinessCard.control */
3
- /* ============================================= */
1
+ /* ================================================== */
2
+ /* CSS for control sap.suite.ui.commons/BusinessCard */
3
+ /* Base theme */
4
+ /* ================================================== */
4
5
 
5
6
  .suiteUiCard {
6
7
  border: solid @sapUiLightBorder 1px;
@@ -50,4 +51,4 @@
50
51
 
51
52
  .suiteUiCardDesc {
52
53
  width: 100%;
53
- }
54
+ }