@sapui5/sap.suite.ui.commons 1.145.1 → 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 (214) 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 +83 -4
  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/CalculationBuilderInput.js +11 -0
  9. package/src/sap/suite/ui/commons/CalculationBuilderItem.js +16 -3
  10. package/src/sap/suite/ui/commons/CalculationBuilderValidationResult.js +1 -1
  11. package/src/sap/suite/ui/commons/CalculationBuilderVariable.js +1 -1
  12. package/src/sap/suite/ui/commons/CloudFilePicker.js +1 -1
  13. package/src/sap/suite/ui/commons/ControlProxy.js +7 -4
  14. package/src/sap/suite/ui/commons/MicroProcessFlow.js +1 -1
  15. package/src/sap/suite/ui/commons/MicroProcessFlowItem.js +1 -1
  16. package/src/sap/suite/ui/commons/ProcessFlowRenderer.js +3 -0
  17. package/src/sap/suite/ui/commons/collaboration/ContactHelper.js +5 -1
  18. package/src/sap/suite/ui/commons/collaboration/ContactPopover.fragment.xml +10 -10
  19. package/src/sap/suite/ui/commons/collaboration/MinimalContactPopover.fragment.xml +12 -10
  20. package/src/sap/suite/ui/commons/collaboration/ServiceContainer.js +12 -2
  21. package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
  22. package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
  23. package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
  24. package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
  25. package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
  26. package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
  27. package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
  28. package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
  29. package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
  30. package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
  31. package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +9 -6
  32. package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
  33. package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
  34. package/src/sap/suite/ui/commons/library.js +4 -4
  35. package/src/sap/suite/ui/commons/messagebundle.properties +16 -8
  36. package/src/sap/suite/ui/commons/messagebundle_ar.properties +11 -5
  37. package/src/sap/suite/ui/commons/messagebundle_bg.properties +11 -5
  38. package/src/sap/suite/ui/commons/messagebundle_ca.properties +10 -4
  39. package/src/sap/suite/ui/commons/messagebundle_cnr.properties +11 -5
  40. package/src/sap/suite/ui/commons/messagebundle_cs.properties +7 -1
  41. package/src/sap/suite/ui/commons/messagebundle_cy.properties +11 -5
  42. package/src/sap/suite/ui/commons/messagebundle_da.properties +10 -4
  43. package/src/sap/suite/ui/commons/messagebundle_de.properties +8 -2
  44. package/src/sap/suite/ui/commons/messagebundle_el.properties +11 -5
  45. package/src/sap/suite/ui/commons/messagebundle_en.properties +11 -5
  46. package/src/sap/suite/ui/commons/messagebundle_en_GB.properties +11 -5
  47. package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +9 -5
  48. package/src/sap/suite/ui/commons/messagebundle_es.properties +11 -5
  49. package/src/sap/suite/ui/commons/messagebundle_es_MX.properties +10 -4
  50. package/src/sap/suite/ui/commons/messagebundle_et.properties +6 -0
  51. package/src/sap/suite/ui/commons/messagebundle_fi.properties +10 -4
  52. package/src/sap/suite/ui/commons/messagebundle_fr.properties +11 -5
  53. package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +11 -5
  54. package/src/sap/suite/ui/commons/messagebundle_hi.properties +11 -5
  55. package/src/sap/suite/ui/commons/messagebundle_hr.properties +10 -4
  56. package/src/sap/suite/ui/commons/messagebundle_hu.properties +9 -3
  57. package/src/sap/suite/ui/commons/messagebundle_id.properties +12 -6
  58. package/src/sap/suite/ui/commons/messagebundle_it.properties +11 -5
  59. package/src/sap/suite/ui/commons/messagebundle_iw.properties +11 -5
  60. package/src/sap/suite/ui/commons/messagebundle_ja.properties +9 -3
  61. package/src/sap/suite/ui/commons/messagebundle_kk.properties +10 -4
  62. package/src/sap/suite/ui/commons/messagebundle_ko.properties +10 -4
  63. package/src/sap/suite/ui/commons/messagebundle_lt.properties +11 -5
  64. package/src/sap/suite/ui/commons/messagebundle_lv.properties +11 -5
  65. package/src/sap/suite/ui/commons/messagebundle_mk.properties +9 -3
  66. package/src/sap/suite/ui/commons/messagebundle_ms.properties +11 -5
  67. package/src/sap/suite/ui/commons/messagebundle_nl.properties +8 -2
  68. package/src/sap/suite/ui/commons/messagebundle_no.properties +10 -4
  69. package/src/sap/suite/ui/commons/messagebundle_pl.properties +11 -5
  70. package/src/sap/suite/ui/commons/messagebundle_pt.properties +11 -5
  71. package/src/sap/suite/ui/commons/messagebundle_pt_PT.properties +11 -5
  72. package/src/sap/suite/ui/commons/messagebundle_ro.properties +11 -5
  73. package/src/sap/suite/ui/commons/messagebundle_ru.properties +12 -6
  74. package/src/sap/suite/ui/commons/messagebundle_sh.properties +11 -5
  75. package/src/sap/suite/ui/commons/messagebundle_sk.properties +10 -4
  76. package/src/sap/suite/ui/commons/messagebundle_sl.properties +10 -4
  77. package/src/sap/suite/ui/commons/messagebundle_sr.properties +11 -5
  78. package/src/sap/suite/ui/commons/messagebundle_sv.properties +10 -4
  79. package/src/sap/suite/ui/commons/messagebundle_th.properties +11 -5
  80. package/src/sap/suite/ui/commons/messagebundle_tr.properties +8 -2
  81. package/src/sap/suite/ui/commons/messagebundle_uk.properties +14 -8
  82. package/src/sap/suite/ui/commons/messagebundle_vi.properties +11 -5
  83. package/src/sap/suite/ui/commons/messagebundle_zh_CN.properties +11 -5
  84. package/src/sap/suite/ui/commons/messagebundle_zh_TW.properties +11 -5
  85. package/src/sap/suite/ui/commons/networkgraph/Graph.js +149 -40
  86. package/src/sap/suite/ui/commons/networkgraph/GraphMap.js +25 -3
  87. package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +332 -13
  88. package/src/sap/suite/ui/commons/networkgraph/Line.js +110 -12
  89. package/src/sap/suite/ui/commons/networkgraph/Node.js +67 -5
  90. package/src/sap/suite/ui/commons/networkgraph/Utils.js +249 -10
  91. package/src/sap/suite/ui/commons/networkgraph/layout/NoopLayout.js +55 -8
  92. package/src/sap/suite/ui/commons/networkgraph/util/ConnectionPathUtils.js +34 -4
  93. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +230 -82
  94. package/src/sap/suite/ui/commons/networkgraph/util/DragDropManager.js +52 -50
  95. package/src/sap/suite/ui/commons/networkgraph/util/PortManager.js +12 -3
  96. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  97. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  98. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  99. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  100. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  101. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  102. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  103. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  104. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  105. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  106. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  107. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  108. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  109. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  110. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  111. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  112. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  113. package/src/sap/suite/ui/commons/themes/base/BusinessCard.less +5 -4
  114. package/src/sap/suite/ui/commons/themes/base/CalculationBuilder.less +33 -24
  115. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderExpression.less +40 -31
  116. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderInput.less +26 -10
  117. package/src/sap/suite/ui/commons/themes/base/CalculationBuilderItem.less +76 -63
  118. package/src/sap/suite/ui/commons/themes/base/ChartContainer.less +8 -11
  119. package/src/sap/suite/ui/commons/themes/base/ChartTile.less +5 -8
  120. package/src/sap/suite/ui/commons/themes/base/CollaborationPopover.less +116 -106
  121. package/src/sap/suite/ui/commons/themes/base/DateRangeScroller.less +5 -5
  122. package/src/sap/suite/ui/commons/themes/base/DateRangeSliderInternal.less +9 -10
  123. package/src/sap/suite/ui/commons/themes/base/FacetOverview.less +9 -10
  124. package/src/sap/suite/ui/commons/themes/base/FeedItemHeader.less +9 -12
  125. package/src/sap/suite/ui/commons/themes/base/FeedTile.less +23 -27
  126. package/src/sap/suite/ui/commons/themes/base/GenericTile2X2.less +15 -15
  127. package/src/sap/suite/ui/commons/themes/base/HeaderCell.less +7 -6
  128. package/src/sap/suite/ui/commons/themes/base/HeaderContainer.less +35 -37
  129. package/src/sap/suite/ui/commons/themes/base/ImageEditor.less +28 -10
  130. package/src/sap/suite/ui/commons/themes/base/ImageEditorContainer.less +29 -22
  131. package/src/sap/suite/ui/commons/themes/base/InfoTile.less +10 -4
  132. package/src/sap/suite/ui/commons/themes/base/InfoTileSize.less +5 -4
  133. package/src/sap/suite/ui/commons/themes/base/KpiTile.less +10 -11
  134. package/src/sap/suite/ui/commons/themes/base/LaunchTile.less +9 -8
  135. package/src/sap/suite/ui/commons/themes/base/LinkActionSheet.less +14 -43
  136. package/src/sap/suite/ui/commons/themes/base/MicroProcessFlow.less +51 -47
  137. package/src/sap/suite/ui/commons/themes/base/MonitoringContent.less +5 -5
  138. package/src/sap/suite/ui/commons/themes/base/NetworkGraph.less +57 -62
  139. package/src/sap/suite/ui/commons/themes/base/NetworkGroup.less +61 -65
  140. package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +58 -55
  141. package/src/sap/suite/ui/commons/themes/base/NetworkNode.less +3 -0
  142. package/src/sap/suite/ui/commons/themes/base/NetworkTooltip.less +21 -25
  143. package/src/sap/suite/ui/commons/themes/base/NoteTaker.less +13 -18
  144. package/src/sap/suite/ui/commons/themes/base/NoteTakerCard.less +26 -27
  145. package/src/sap/suite/ui/commons/themes/base/NoteTakerFeeder.less +22 -44
  146. package/src/sap/suite/ui/commons/themes/base/NumericTile.less +7 -5
  147. package/src/sap/suite/ui/commons/themes/base/PictureZoomIn.less +6 -5
  148. package/src/sap/suite/ui/commons/themes/base/ProcessFlow.less +57 -76
  149. package/src/sap/suite/ui/commons/themes/base/ProcessFlowConnection.less +71 -17
  150. package/src/sap/suite/ui/commons/themes/base/ProcessFlowConnectionLabel.less +9 -13
  151. package/src/sap/suite/ui/commons/themes/base/ProcessFlowLaneHeader.less +37 -96
  152. package/src/sap/suite/ui/commons/themes/base/ProcessFlowNode.less +219 -238
  153. package/src/sap/suite/ui/commons/themes/base/SemanticColorMixins.less +55 -0
  154. package/src/sap/suite/ui/commons/themes/base/SplitButton.less +7 -20
  155. package/src/sap/suite/ui/commons/themes/base/StatusIndicator.less +10 -9
  156. package/src/sap/suite/ui/commons/themes/base/TAccount.less +78 -73
  157. package/src/sap/suite/ui/commons/themes/base/TargetFilter.less +50 -58
  158. package/src/sap/suite/ui/commons/themes/base/ThingCollection.less +18 -13
  159. package/src/sap/suite/ui/commons/themes/base/ThreePanelThingViewer.less +14 -14
  160. package/src/sap/suite/ui/commons/themes/base/TileContent2X2.less +9 -13
  161. package/src/sap/suite/ui/commons/themes/base/Timeline.less +16 -19
  162. package/src/sap/suite/ui/commons/themes/base/TimelineItem.less +95 -103
  163. package/src/sap/suite/ui/commons/themes/base/UnifiedThingGroup.less +7 -9
  164. package/src/sap/suite/ui/commons/themes/base/UnifiedThingInspector.less +12 -9
  165. package/src/sap/suite/ui/commons/themes/base/VerticalNavigationBar.less +10 -15
  166. package/src/sap/suite/ui/commons/themes/base/ViewRepeater.less +8 -9
  167. package/src/sap/suite/ui/commons/themes/base/library.source.less +0 -2
  168. package/src/sap/suite/ui/commons/themes/sap_fiori_3/MicroProcessFlow.less +9 -3
  169. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowConnection.less +14 -7
  170. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowConnectionLabel.less +38 -35
  171. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowLaneHeader.less +29 -30
  172. package/src/sap/suite/ui/commons/themes/sap_fiori_3/ProcessFlowNode.less +158 -102
  173. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/MicroProcessFlow.less +9 -3
  174. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowConnection.less +14 -7
  175. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowConnectionLabel.less +38 -35
  176. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowLaneHeader.less +30 -31
  177. package/src/sap/suite/ui/commons/themes/sap_fiori_3_dark/ProcessFlowNode.less +157 -101
  178. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowConnection.less +14 -7
  179. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowConnectionLabel.less +38 -35
  180. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowLaneHeader.less +30 -31
  181. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcb/ProcessFlowNode.less +147 -101
  182. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowConnection.less +14 -7
  183. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowConnectionLabel.less +38 -35
  184. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowLaneHeader.less +30 -31
  185. package/src/sap/suite/ui/commons/themes/sap_fiori_3_hcw/ProcessFlowNode.less +158 -102
  186. package/src/sap/suite/ui/commons/themes/sap_horizon/MicroProcessFlow.less +5 -0
  187. package/src/sap/suite/ui/commons/themes/sap_horizon/NetworkLine.less +12 -8
  188. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowConnection.less +17 -10
  189. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowConnectionLabel.less +154 -133
  190. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowLaneHeader.less +30 -32
  191. package/src/sap/suite/ui/commons/themes/sap_horizon/ProcessFlowNode.less +113 -214
  192. package/src/sap/suite/ui/commons/themes/sap_horizon/TimelineItem.less +43 -39
  193. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/MicroProcessFlow.less +5 -0
  194. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/NetworkLine.less +12 -12
  195. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowConnection.less +17 -10
  196. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowConnectionLabel.less +154 -133
  197. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowLaneHeader.less +30 -31
  198. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/ProcessFlowNode.less +114 -216
  199. package/src/sap/suite/ui/commons/themes/sap_horizon_dark/TimelineItem.less +41 -39
  200. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/MicroProcessFlow.less +4 -4
  201. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowConnection.less +17 -10
  202. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowConnectionLabel.less +153 -131
  203. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowLaneHeader.less +29 -30
  204. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/ProcessFlowNode.less +159 -103
  205. package/src/sap/suite/ui/commons/themes/sap_horizon_hcb/TimelineItem.less +41 -39
  206. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/MicroProcessFlow.less +4 -4
  207. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowConnection.less +16 -9
  208. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowConnectionLabel.less +153 -131
  209. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowLaneHeader.less +29 -30
  210. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/ProcessFlowNode.less +157 -101
  211. package/src/sap/suite/ui/commons/themes/sap_horizon_hcw/TimelineItem.less +41 -39
  212. package/src/sap/suite/ui/commons/windowmessages/CollaborationMessageConsumer.js +3 -3
  213. package/src/sap/suite/ui/commons/themes/base/DateRangeSlider.less +0 -3
  214. package/src/sap/suite/ui/commons/themes/base/MonitoringTile.less +0 -3
@@ -14,11 +14,12 @@ sap.ui.define([
14
14
  "sap/ui/events/KeyCodes",
15
15
  "sap/ui/dom/containsOrEquals",
16
16
  "sap/base/Log",
17
- "sap/ui/core/Lib",
18
- "sap/ui/core/Element"
19
- ], function (jQuery, BaseObject, Group, Node, Line, KeyCodes, containsOrEquals, Log, CoreLib, Element) {
17
+ "sap/ui/core/Lib"
18
+ ], function (jQuery, BaseObject, Group, Node, Line, KeyCodes, containsOrEquals, Log, CoreLib) {
20
19
  "use strict";
21
20
 
21
+ const oResourceBundle = CoreLib.getResourceBundleFor("sap.suite.ui.commons");
22
+
22
23
  var mDirections = {
23
24
  LEFT: "left",
24
25
  RIGHT: "right",
@@ -74,6 +75,13 @@ sap.ui.define([
74
75
  this._oFocusPosition = null;
75
76
  this._oWrapperDom = null;
76
77
  this.isFromFullscreen = null;
78
+ this._oAltNode = null;
79
+ this._oAltConnectors = null;
80
+ this._oAltAnnouncement = null;
81
+ this._oAssociatedControl = null;
82
+ this._oAssociatedContainer = null;
83
+ this._oAssociatedDelegate = null;
84
+ this._bCtrlAltDown = false;
77
85
  }
78
86
  });
79
87
 
@@ -124,6 +132,14 @@ sap.ui.define([
124
132
  this._iColumns = aRow.length;
125
133
  }
126
134
  }, this);
135
+
136
+ const oControl = this._oGraph.getAssociatedControl();
137
+ if (oControl !== this._oAssociatedControl) {
138
+ this._updateAssociatedDelegate(oControl);
139
+ }
140
+ this._oAltNode = null;
141
+ this._oAltConnectors = null;
142
+ this._oAltAnnouncement = null;
127
143
  };
128
144
 
129
145
  KeyboardNavigator.prototype.setWrapperDom = function (oDom) {
@@ -229,6 +245,12 @@ sap.ui.define([
229
245
  KeyboardNavigator.prototype.onkeydown = function (oEvent) {
230
246
  var oItem, oBtn,
231
247
  oFocus = this.getFocus();
248
+
249
+ // On Windows, Ctrl+Alt = AltGr — browsers strip ctrlKey/altKey from the character keydown.
250
+ if (oEvent.keyCode === KeyCodes.ALT && oEvent.ctrlKey) {
251
+ this._bCtrlAltDown = true;
252
+ }
253
+
232
254
  if (!oFocus) {
233
255
  return;
234
256
  }
@@ -256,11 +278,7 @@ sap.ui.define([
256
278
  }
257
279
  oEvent.stopPropagation();
258
280
  } else if (oEvent.keyCode === KeyCodes.F6) {
259
- if (oItem && oBtn) {
260
- oFocus.button = null;
261
- this._oGraph.setFocus(oFocus);
262
- }
263
- this._handleArrow(oEvent, oEvent.shiftKey ? mDirections.LEFT : mDirections.RIGHT);
281
+ this._handleF6(oEvent);
264
282
  } else if (oEvent.keyCode === KeyCodes.F7 && !oEvent.shiftKey) {
265
283
  if (oItem && oBtn) {
266
284
  oFocus.button = null;
@@ -272,12 +290,24 @@ sap.ui.define([
272
290
  this._onCtrlPlus(oEvent);
273
291
  } else if (oEvent.ctrlKey && (oEvent.keyCode === KeyCodes.SLASH || oEvent.keyCode === KeyCodes.NUMPAD_MINUS)) {
274
292
  this._onCtrlMinus(oEvent);
275
- } else if(oEvent.ctrlKey && oEvent.altKey && oEvent.keyCode === KeyCodes.P) {
276
- var oAssociatedControl = this._oGraph.getAssociatedControl();
293
+ } else if (this._bCtrlAltDown && oEvent.keyCode === KeyCodes.P) {
294
+ this._bCtrlAltDown = false;
295
+ const oAssociatedControl = this._oGraph.getAssociatedControl();
277
296
  if (oAssociatedControl) {
278
297
  oAssociatedControl.focus();
279
298
  oItem._setFocus(false);
280
299
  }
300
+ oEvent.preventDefault();
301
+ oEvent.stopPropagation();
302
+ } else if (oEvent.altKey && !oEvent.ctrlKey && !oEvent.shiftKey && oItem instanceof Node) {
303
+ if (oEvent.keyCode === KeyCodes.PLUS || oEvent.keyCode === KeyCodes.NUMPAD_PLUS) {
304
+ this._handleAltAnnounce(oEvent, oItem);
305
+ } else {
306
+ const iDigitIndex = this._getAltDigitIndex(oEvent.keyCode);
307
+ if (iDigitIndex >= 0) {
308
+ this._handleAltConnectorNavigation(oEvent, oItem, iDigitIndex);
309
+ }
310
+ }
281
311
  }
282
312
  };
283
313
 
@@ -285,6 +315,59 @@ sap.ui.define([
285
315
  /* Private methods */
286
316
  /* =========================================================== */
287
317
 
318
+ KeyboardNavigator.prototype._getAltDigitIndex = function (iKeyCode) {
319
+ if (iKeyCode >= KeyCodes.DIGIT_1 && iKeyCode <= KeyCodes.DIGIT_9) {
320
+ return iKeyCode - KeyCodes.DIGIT_1;
321
+ }
322
+ if (iKeyCode >= KeyCodes.NUMPAD_1 && iKeyCode <= KeyCodes.NUMPAD_9) {
323
+ return iKeyCode - KeyCodes.NUMPAD_1;
324
+ }
325
+ return -1;
326
+ };
327
+
328
+ /**
329
+ * Handles F6 / Shift+F6 — skip to next/previous visible group regardless of what is focused.
330
+ * @private
331
+ */
332
+ KeyboardNavigator.prototype._handleF6 = function (oEvent) {
333
+ const bBackward = oEvent.shiftKey,
334
+ oFocus = this.getFocus(),
335
+ oItem = oFocus ? oFocus.item : null,
336
+ bIsRtl = this._oGraph._bIsRtl,
337
+ aGroups = this._oGraph.getGroups().filter(function (oGroup) {
338
+ return !oGroup.isHidden() && oGroup.getVisible();
339
+ }).sort(function (oA, oB) {
340
+ // Top-to-bottom, then by reading direction (RTL: descending x, LTR: ascending x)
341
+ const iDeltaY = oA.getY() - oB.getY();
342
+ if (iDeltaY !== 0) { return iDeltaY; }
343
+ const iDeltaX = oA.getX() - oB.getX();
344
+ return bIsRtl ? -iDeltaX : iDeltaX;
345
+ });
346
+
347
+ if (aGroups.length === 0) {
348
+ return;
349
+ }
350
+
351
+ let iCurrentIndex = -1;
352
+ if (oItem instanceof Group) {
353
+ iCurrentIndex = aGroups.indexOf(oItem);
354
+ } else if (oItem instanceof Node && oItem._oGroup) {
355
+ iCurrentIndex = aGroups.indexOf(oItem._oGroup);
356
+ }
357
+
358
+ const iTargetIndex = bBackward
359
+ ? (iCurrentIndex > 0 ? iCurrentIndex - 1 : aGroups.length - 1)
360
+ : (iCurrentIndex < aGroups.length - 1 ? iCurrentIndex + 1 : 0);
361
+
362
+ // Ensure setFocus lands on the group header, not the menu button
363
+ if (this._oGraph._oFocus) {
364
+ this._oGraph._oFocus.groupInFocused = false;
365
+ }
366
+ this._oGraph.setFocus({ item: aGroups[iTargetIndex], button: null });
367
+ oEvent.preventDefault();
368
+ oEvent.stopPropagation();
369
+ };
370
+
288
371
  KeyboardNavigator.prototype._handleEnter = function () {
289
372
  var oItem, oBtn,
290
373
  oFocus = this.getFocus();
@@ -372,9 +455,32 @@ sap.ui.define([
372
455
  }
373
456
  };
374
457
 
458
+ /**
459
+ * Fires the nodeAdded event and shifts focus to the newly added node after re-render.
460
+ * Only active when DnD is enabled.
461
+ * @private
462
+ */
463
+ KeyboardNavigator.prototype._handleAddNode = function (oEvent) {
464
+ if (!this._oGraph._isDnDEnabled()) {
465
+ return;
466
+ }
467
+ this._oGraph.fireEvent("nodeAdded", {}, false);
468
+ const fnFocus = () => {
469
+ this._oGraph.detachGraphReady(fnFocus);
470
+ const aNodes = this._oGraph.getNodes();
471
+ if (aNodes.length) {
472
+ this._oGraph.setFocus({ item: aNodes.at(-1), button: null });
473
+ }
474
+ };
475
+ this._oGraph.attachGraphReady(fnFocus);
476
+ oEvent.preventDefault();
477
+ oEvent.stopPropagation();
478
+ };
479
+
375
480
  KeyboardNavigator.prototype._handleTab = function (oEvent, sDirection) {
376
- var oResourceBundle = CoreLib.getResourceBundleFor("sap.suite.ui.commons");
377
- this._oWrapperDom.setAttribute("aria-live","assertive");
481
+ const oFocus = this.getFocus(),
482
+ bBackward = sDirection === mDirections.LEFT;
483
+ this._oWrapperDom.setAttribute("aria-live", "assertive");
378
484
  this._oGraph._setAriaLabelForWrapper(oResourceBundle.getText("NETWORK_GRAPH_ACCESSIBILITY_LABEL"));
379
485
  if (this._ignoreEvent(oEvent)) {
380
486
  this._oWrapperDom.setAttribute("aria-live","off");
@@ -386,6 +492,12 @@ sap.ui.define([
386
492
  }
387
493
  return;
388
494
  } else {
495
+ if (sDirection === mDirections.LEFT && this._bWrapperHighlighted && !this.getFocus()) {
496
+ this._oWrapperDom.classList.add("sapSuiteUiCommonsNetworkGraphContentFocusHidden");
497
+ this._bWrapperHighlighted = false;
498
+ return;
499
+ }
500
+ this._bWrapperHighlighted = false;
389
501
  this._oWrapperDom.classList.add("sapSuiteUiCommonsNetworkGraphContentFocusHidden");
390
502
  }
391
503
 
@@ -396,7 +508,118 @@ sap.ui.define([
396
508
  return;
397
509
  }
398
510
 
399
- this._moveItemFocus(oEvent, sDirection);
511
+ if (oFocus?.item instanceof Node) {
512
+ const bMoved = this._navigateFromNode(oFocus.item, bBackward);
513
+ if (!bMoved && bBackward) {
514
+ const oGroup = oFocus.item._oGroup;
515
+ if (oGroup) {
516
+ this._oGraph.setFocus({ item: oGroup, button: Group.BUTTONS.COLLAPSE });
517
+ oEvent.preventDefault();
518
+ oEvent.stopPropagation();
519
+ } else {
520
+ this._moveItemFocus(oEvent, mDirections.LEFT);
521
+ }
522
+ return;
523
+ }
524
+ } else if (oFocus?.item instanceof Line) {
525
+ this._navigateFromConnector(oFocus.item, bBackward);
526
+ } else {
527
+ this._moveItemFocus(oEvent, sDirection);
528
+ return;
529
+ }
530
+
531
+ oEvent.preventDefault();
532
+ oEvent.stopPropagation();
533
+ };
534
+
535
+ /**
536
+ * Navigate from a node to its first connector.
537
+ * @returns {boolean} True if focus moved to a connector, false otherwise
538
+ * @private
539
+ */
540
+ KeyboardNavigator.prototype._navigateFromNode = function (oNode, bBackward) {
541
+ const aLines = bBackward ? oNode.getParentLines() : oNode.getChildLines();
542
+ const aVisibleLines = this._getVisibleLines(aLines, bBackward);
543
+
544
+ if (aVisibleLines.length > 0) {
545
+ this._oGraph.setFocus({
546
+ item: aVisibleLines[0],
547
+ button: null
548
+ });
549
+ return true;
550
+ }
551
+ return false;
552
+ };
553
+
554
+ /**
555
+ * Navigate from a connector to its connected node
556
+ * @param {Line} oLine - The connector to navigate from
557
+ * @param {boolean} bBackward - True for source node, false for target node
558
+ * @private
559
+ */
560
+ KeyboardNavigator.prototype._navigateFromConnector = function (oLine, bBackward) {
561
+ const oNode = bBackward ? oLine.getFromNode() : oLine.getToNode();
562
+
563
+ if (oNode && !oNode.isHidden()) {
564
+ this._oGraph.setFocus({
565
+ item: oNode,
566
+ button: null
567
+ });
568
+ }
569
+ };
570
+
571
+ /**
572
+ * Returns visible lines sorted top-to-bottom.
573
+ * @param {Array} aLines - Array of lines to filter and sort
574
+ * @param {boolean} bSortBySource - If true, sort by source node Y position; otherwise by target node
575
+ * @private
576
+ */
577
+ KeyboardNavigator.prototype._getVisibleLines = function (aLines, bSortBySource) {
578
+ if (!aLines || aLines.length === 0) {
579
+ return [];
580
+ }
581
+
582
+ const aVisibleLines = aLines.filter(function (oLine) {
583
+ return !oLine.isHidden() && !oLine._isIgnored() && oLine.getVisible();
584
+ });
585
+
586
+ const fnGetSortY = (oLine) => {
587
+ const oNode = bSortBySource ? oLine.getFromNode() : oLine.getToNode();
588
+ if (oNode && !oNode.isHidden()) {
589
+ return oNode.getY();
590
+ }
591
+ const aCoords = oLine.getCoordinates();
592
+ return (aCoords && aCoords.length > 0) ? aCoords[0].getY() : 0;
593
+ };
594
+ return aVisibleLines.sort((oLine1, oLine2) => fnGetSortY(oLine1) - fnGetSortY(oLine2));
595
+ };
596
+
597
+ KeyboardNavigator.prototype._handleAltAnnounce = function (oEvent, oNode) {
598
+ if (this._oAltNode !== oNode) {
599
+ this._oAltNode = oNode;
600
+ this._oAltConnectors = oNode._getAltNavigationConnectors();
601
+ const { aIncomingConnectors, aOutgoingConnectors, aConnectors } = this._oAltConnectors;
602
+ this._oAltAnnouncement = (aIncomingConnectors.length >= 2 || aOutgoingConnectors.length >= 2)
603
+ ? oNode._getAltConnectorsAnnouncement(aConnectors)
604
+ : null;
605
+ }
606
+ if (!this._oAltAnnouncement) { return; }
607
+ this._oGraph._setAccessibilityTitle(this._oAltAnnouncement);
608
+ oEvent.preventDefault();
609
+ oEvent.stopPropagation();
610
+ };
611
+
612
+ KeyboardNavigator.prototype._handleAltConnectorNavigation = function (oEvent, oNode, iIndex) {
613
+ if (this._oAltNode !== oNode || !this._oAltConnectors) {
614
+ this._oAltNode = oNode;
615
+ this._oAltConnectors = oNode._getAltNavigationConnectors();
616
+ }
617
+ const { aConnectors } = this._oAltConnectors;
618
+ if (iIndex < aConnectors.length) {
619
+ this._oGraph.setFocus({ item: aConnectors[iIndex].line, button: null });
620
+ oEvent.preventDefault();
621
+ oEvent.stopPropagation();
622
+ }
400
623
  };
401
624
 
402
625
  KeyboardNavigator.prototype._handleTabOverLinesWithButtons = function (oEvent, sDirection) {
@@ -624,12 +847,64 @@ sap.ui.define([
624
847
  return;
625
848
  }
626
849
 
850
+ const oFocus = this.getFocus();
851
+ const oItem = oFocus.item;
852
+ if (oItem instanceof Line) {
853
+ if (sDirection === mDirections.UP || sDirection === mDirections.DOWN) {
854
+ this._navigateBetweenConnectors(oEvent, sDirection);
855
+ return;
856
+ }
857
+ }
858
+
859
+ // For all other cases, use default behavior
627
860
  this._moveItemFocus(oEvent, sDirection, true);
628
861
  };
629
862
 
863
+ /**
864
+ * Navigate between multiple connectors from the same source node
865
+ * @private
866
+ */
867
+ KeyboardNavigator.prototype._navigateBetweenConnectors = function (oEvent, sDirection) {
868
+ const oFocus = this.getFocus(),
869
+ oLine = oFocus.item;
870
+
871
+ if (!(oLine instanceof Line)) {
872
+ return;
873
+ }
874
+
875
+ // ↑/↓ navigates among the outgoing connectors of this line's source node,
876
+ // giving a consistent vertical ordering regardless of which connector is focused.
877
+ const oSourceNode = oLine.getFromNode();
878
+ if (!oSourceNode) {
879
+ return;
880
+ }
881
+
882
+ const aVisibleLines = this._getVisibleLines(oSourceNode.getChildLines());
883
+ if (aVisibleLines.length <= 1) {
884
+ return;
885
+ }
886
+
887
+ const iCurrentIndex = aVisibleLines.indexOf(oLine);
888
+ if (iCurrentIndex === -1) {
889
+ return;
890
+ }
891
+
892
+ const iTargetIndex = sDirection === mDirections.DOWN ? iCurrentIndex + 1 : iCurrentIndex - 1;
893
+ if (iTargetIndex >= 0 && iTargetIndex < aVisibleLines.length) {
894
+ this._oGraph.setFocus({
895
+ item: aVisibleLines[iTargetIndex],
896
+ button: null
897
+ });
898
+ }
899
+
900
+ oEvent.preventDefault();
901
+ oEvent.stopPropagation();
902
+ };
903
+
630
904
  KeyboardNavigator.prototype._moveItemFocus = function (oEvent, sDirection, bStopOnLast) {
631
905
  var oFocus,
632
906
  bBackTab = (sDirection === mDirections.LEFT && oEvent.key === "Tab"),
907
+ bHadFocus = !!this.getFocus(),
633
908
  oPosition,
634
909
  oNewItem,
635
910
  aBtns;
@@ -667,6 +942,11 @@ sap.ui.define([
667
942
  if (oEvent && oNewItem) {
668
943
  oEvent.preventDefault();
669
944
  oEvent.stopPropagation();
945
+ } else if (bBackTab && !oNewItem && bHadFocus) {
946
+ this._oWrapperDom.classList.remove("sapSuiteUiCommonsNetworkGraphContentFocusHidden");
947
+ this._bWrapperHighlighted = true;
948
+ oEvent.preventDefault();
949
+ oEvent.stopPropagation();
670
950
  }
671
951
  };
672
952
 
@@ -815,6 +1095,45 @@ sap.ui.define([
815
1095
  oEvent.stopPropagation();
816
1096
  };
817
1097
 
1098
+ KeyboardNavigator.prototype._updateAssociatedDelegate = function (oControl) {
1099
+ if (this._oAssociatedContainer) {
1100
+ this._oAssociatedContainer.removeEventDelegate(this._oAssociatedDelegate);
1101
+ this._oAssociatedContainer = null;
1102
+ this._oAssociatedDelegate = null;
1103
+ }
1104
+ const oContainer = oControl && oControl.getParent();
1105
+ if (oContainer) {
1106
+ this._oAssociatedDelegate = {
1107
+ onkeydown: (oEvent) => {
1108
+ if (oEvent.keyCode === KeyCodes.ALT && oEvent.ctrlKey) {
1109
+ this._bCtrlAltDown = true;
1110
+ }
1111
+
1112
+ if (oEvent.shiftKey && oEvent.keyCode === KeyCodes.F10) {
1113
+ this._oGraph._restoreFocusToGraph();
1114
+ oEvent.preventDefault();
1115
+ oEvent.stopPropagation();
1116
+ } else if (oEvent.keyCode === KeyCodes.INSERT || (this._bCtrlAltDown && oEvent.keyCode === KeyCodes.N)) {
1117
+ this._bCtrlAltDown = false;
1118
+ this._handleAddNode(oEvent);
1119
+ }
1120
+ }
1121
+ };
1122
+ this._oAssociatedContainer = oContainer;
1123
+ oContainer.addEventDelegate(this._oAssociatedDelegate);
1124
+ }
1125
+ this._oAssociatedControl = oControl;
1126
+ };
1127
+
1128
+ KeyboardNavigator.prototype.destroy = function () {
1129
+ if (this._oAssociatedContainer) {
1130
+ this._oAssociatedContainer.removeEventDelegate(this._oAssociatedDelegate);
1131
+ this._oAssociatedContainer = null;
1132
+ this._oAssociatedDelegate = null;
1133
+ }
1134
+ BaseObject.prototype.destroy.apply(this, arguments);
1135
+ };
1136
+
818
1137
  KeyboardNavigator.prototype._ignoreEvent = function (oEvent) {
819
1138
  return !containsOrEquals(this._oWrapperDom, oEvent.target);
820
1139
  };
@@ -191,16 +191,19 @@ sap.ui.define([
191
191
  }
192
192
  }
193
193
  },
194
- renderer: function (oRM, oControl) {
195
- // NOTE: this render is considered to be called only for single item invalidation
196
- // whole graph has different render path
197
- var sHtml = oControl._render({
198
- renderManager: oRM
199
- });
200
- this.oRm = oRM;
194
+ renderer: {
195
+ apiVersion: 2,
196
+ render (oRM, oControl) {
197
+ // NOTE: this render is considered to be called only for single item invalidation
198
+ // whole graph has different render path
199
+ var sHtml = oControl._render({
200
+ renderManager: oRM
201
+ });
202
+ this.oRm = oRM;
201
203
 
202
- if (sHtml) {
203
- oRM.unsafeHtml(sHtml);
204
+ if (sHtml) {
205
+ oRM.unsafeHtml(sHtml);
206
+ }
204
207
  }
205
208
  },
206
209
  onAfterRendering: function () {
@@ -880,7 +883,11 @@ sap.ui.define([
880
883
  Line.prototype._getAccessibilityLabel = function (oGraph) {
881
884
  const aSentenceParts = [];
882
885
  const sConnectionType = this.getConnectionType();
883
- const sConnectionTypeText = oGraph.getConnectionTypeMapping()[sConnectionType];
886
+ const oMapping = oGraph.getConnectionTypeMapping();
887
+ // In RTL mode, left and right sides of nodes are semantically swapped
888
+ const bRTL = this.getParent()._bIsRtl;
889
+ const sResolvedType = bRTL ? (Utils.mRTLSwap[sConnectionType] || sConnectionType) : sConnectionType;
890
+ const sConnectionTypeText = oMapping[sResolvedType];
884
891
  const sFromNodeTitle = this.getFromNode().getTitle();
885
892
  const sFromNodeText = sFromNodeTitle ? sFromNodeTitle : this.getFromNode().getAltText();
886
893
  const sToNodeTitle = this.getToNode().getTitle();
@@ -1181,7 +1188,7 @@ sap.ui.define([
1181
1188
  }
1182
1189
  } else {
1183
1190
  /** @deprecated As of 1.120 */
1184
- {
1191
+ {
1185
1192
  $arrow.css("fill", sBackgroundColor);
1186
1193
  $arrow.css("stroke", sBorderColor);
1187
1194
  this.$("path").css("stroke", sBorderColor);
@@ -1902,6 +1909,9 @@ sap.ui.define([
1902
1909
  fRemainingDistance,
1903
1910
  i;
1904
1911
 
1912
+ // Threshold to detect if arrow is too close to a vertex/bend (10px)
1913
+ var fVertexThreshold = 10;
1914
+
1905
1915
  if (sDirection === "forward") {
1906
1916
  // Travel from source towards target
1907
1917
  for (i = 0; i < iLastIndex; i++) {
@@ -1953,7 +1963,95 @@ sap.ui.define([
1953
1963
  fRatio = 1 - fRatio; // Reverse the ratio for backward direction
1954
1964
  }
1955
1965
 
1956
- // Calculate the exact coordinates that are 44px away from the anchor
1966
+ // Check if arrow position is too close to a vertex (bend point)
1967
+ var fDistanceToStart = fRatio * fSegmentLength;
1968
+ var fDistanceToEnd = (1 - fRatio) * fSegmentLength;
1969
+ var fAdjustedSegmentLength;
1970
+
1971
+ // Strategy: When arrow is too close to a bend, prefer moving AWAY from the anchor
1972
+ // to avoid overlap with node/port. This means:
1973
+ // - For "forward" direction (from source): prefer moving to next segment (away from source)
1974
+ // - For "backward" direction (from target): prefer moving to previous segment (away from target)
1975
+
1976
+ if (sDirection === "forward") {
1977
+ // Arrow traveling from source: prefer moving forward (away from source) when near bend
1978
+ if (fDistanceToEnd < fVertexThreshold && iSegmentIndex + 1 < iLastIndex) {
1979
+ // Too close to end of segment - move to next segment (preferred)
1980
+ fAdjustedSegmentLength = Math.sqrt(
1981
+ Math.pow(oCoords[iSegmentIndex + 2].getX() - oCoords[iSegmentIndex + 1].getX(), 2) +
1982
+ Math.pow(oCoords[iSegmentIndex + 2].getY() - oCoords[iSegmentIndex + 1].getY(), 2)
1983
+ );
1984
+
1985
+ if (fAdjustedSegmentLength > fVertexThreshold) {
1986
+ // Move arrow to start of next segment plus threshold
1987
+ iSegmentIndex = iSegmentIndex + 1;
1988
+ fRatio = fVertexThreshold / fAdjustedSegmentLength;
1989
+ fSegmentLength = fAdjustedSegmentLength;
1990
+ } else {
1991
+ // Next segment too short, stay on current segment away from vertex
1992
+ fRatio = Math.max(0, (fSegmentLength - fVertexThreshold) / fSegmentLength);
1993
+ }
1994
+ } else if (fDistanceToStart < fVertexThreshold) {
1995
+ // Too close to start of segment - only move back if critically close to source anchor
1996
+ // This is less preferred as it moves closer to the source node/port
1997
+ if (fDistanceToStart < 5 && iSegmentIndex > 0) {
1998
+ // Only if extremely close (< 5px) and previous segment exists
1999
+ fAdjustedSegmentLength = Math.sqrt(
2000
+ Math.pow(oCoords[iSegmentIndex].getX() - oCoords[iSegmentIndex - 1].getX(), 2) +
2001
+ Math.pow(oCoords[iSegmentIndex].getY() - oCoords[iSegmentIndex - 1].getY(), 2)
2002
+ );
2003
+
2004
+ if (fAdjustedSegmentLength > fVertexThreshold) {
2005
+ iSegmentIndex = iSegmentIndex - 1;
2006
+ fRatio = (fAdjustedSegmentLength - fVertexThreshold) / fAdjustedSegmentLength;
2007
+ fSegmentLength = fAdjustedSegmentLength;
2008
+ }
2009
+ } else {
2010
+ // Stay on current segment, move away from start vertex
2011
+ fRatio = Math.min(1, fVertexThreshold / fSegmentLength);
2012
+ }
2013
+ }
2014
+ } else if (sDirection === "backward") {
2015
+ // Arrow traveling from target: prefer moving backward (away from target) when near bend
2016
+ if (fDistanceToStart < fVertexThreshold && iSegmentIndex > 0) {
2017
+ // Too close to start of segment - move to previous segment (preferred)
2018
+ fAdjustedSegmentLength = Math.sqrt(
2019
+ Math.pow(oCoords[iSegmentIndex].getX() - oCoords[iSegmentIndex - 1].getX(), 2) +
2020
+ Math.pow(oCoords[iSegmentIndex].getY() - oCoords[iSegmentIndex - 1].getY(), 2)
2021
+ );
2022
+
2023
+ if (fAdjustedSegmentLength > fVertexThreshold) {
2024
+ // Move arrow to end of previous segment minus threshold
2025
+ iSegmentIndex = iSegmentIndex - 1;
2026
+ fRatio = (fAdjustedSegmentLength - fVertexThreshold) / fAdjustedSegmentLength;
2027
+ fSegmentLength = fAdjustedSegmentLength;
2028
+ } else {
2029
+ // Previous segment too short, stay on current segment away from vertex
2030
+ fRatio = Math.min(1, fVertexThreshold / fSegmentLength);
2031
+ }
2032
+ } else if (fDistanceToEnd < fVertexThreshold) {
2033
+ // Too close to end of segment - only move forward if critically close to target anchor
2034
+ // This is less preferred as it moves closer to the target node/port
2035
+ if (fDistanceToEnd < 5 && iSegmentIndex + 1 < iLastIndex) {
2036
+ // Only if extremely close (< 5px) and next segment exists
2037
+ fAdjustedSegmentLength = Math.sqrt(
2038
+ Math.pow(oCoords[iSegmentIndex + 2].getX() - oCoords[iSegmentIndex + 1].getX(), 2) +
2039
+ Math.pow(oCoords[iSegmentIndex + 2].getY() - oCoords[iSegmentIndex + 1].getY(), 2)
2040
+ );
2041
+
2042
+ if (fAdjustedSegmentLength > fVertexThreshold) {
2043
+ iSegmentIndex = iSegmentIndex + 1;
2044
+ fRatio = fVertexThreshold / fAdjustedSegmentLength;
2045
+ fSegmentLength = fAdjustedSegmentLength;
2046
+ }
2047
+ } else {
2048
+ // Stay on current segment, move away from end vertex
2049
+ fRatio = Math.max(0, (fSegmentLength - fVertexThreshold) / fSegmentLength);
2050
+ }
2051
+ }
2052
+ }
2053
+
2054
+ // Calculate the exact coordinates with adjusted position
1957
2055
  var fExactX = oCoords[iSegmentIndex].getX() + (oCoords[iSegmentIndex + 1].getX() - oCoords[iSegmentIndex].getX()) * fRatio;
1958
2056
  var fExactY = oCoords[iSegmentIndex].getY() + (oCoords[iSegmentIndex + 1].getY() - oCoords[iSegmentIndex].getY()) * fRatio;
1959
2057
 
@@ -1001,10 +1001,10 @@ sap.ui.define([
1001
1001
  }, false);
1002
1002
 
1003
1003
  let { style: sBorderColor, class: sBorderClass } = this._getStatusStyle({
1004
- "border-color": ElementBase.ColorType.Border,
1004
+ "outline-color": ElementBase.ColorType.Border,
1005
1005
  "background-color": this.getSelected() ? ElementBase.ColorType.SelectedBackground : "",
1006
- "border-width": ElementBase.ColorType.BorderWidth,
1007
- "border-style": ElementBase.ColorType.BorderStyle
1006
+ "outline-width": ElementBase.ColorType.BorderWidth,
1007
+ "outline-style": ElementBase.ColorType.BorderStyle
1008
1008
  }, false);
1009
1009
 
1010
1010
  mOptions.renderManager.openStart("div", sId + "-wrapperwithbuttons");
@@ -2754,9 +2754,71 @@ sap.ui.define([
2754
2754
  aSentenceParts.push(oResourceBundle.getText("NETWORK_GRAPH_NAVIGATION_SHIFT_TAB_TO_INCOMING"));
2755
2755
  }
2756
2756
 
2757
+ const { aIncomingConnectors, aOutgoingConnectors } = this._getAltNavigationConnectors();
2758
+ if (aIncomingConnectors.length >= 2 || aOutgoingConnectors.length >= 2) {
2759
+ aSentenceParts.push(oResourceBundle.getText("NETWORK_GRAPH_NAVIGATION_ALT_CONNECTORS"));
2760
+ }
2761
+
2757
2762
  return `${sLabel}. ${aSentenceParts.join(". ")}.`;
2758
2763
  };
2759
2764
 
2765
+ Node.prototype._getAltNavigationConnectors = function () {
2766
+ const iThisX = this.getX();
2767
+ const fnDir = (oNode) => oNode?.getX() < iThisX ? "left" : "right";
2768
+ const fnActive = (oLine) => oLine.getVisible() && !oLine.isHidden() && !oLine._isIgnored();
2769
+
2770
+ // Incoming: all valid lines, sorted top-to-bottom by source node Y, then by node key for stability
2771
+ const aIncomingConnectors = this.getParentLines()
2772
+ .filter((oLine) => fnActive(oLine) && oLine.getFromNode())
2773
+ .sort((a, b) => {
2774
+ const iY = a.getFromNode().getY() - b.getFromNode().getY();
2775
+ return iY !== 0 ? iY : a.getFromNode().getKey().localeCompare(b.getFromNode().getKey());
2776
+ })
2777
+ .map((oLine) => ({ line: oLine, type: "incoming", direction: fnDir(oLine.getFromNode()) }));
2778
+
2779
+ // Outgoing: all valid lines, sorted top-to-bottom by target node Y, then by node key for stability
2780
+ const aOutgoingConnectors = this.getChildLines()
2781
+ .filter((oLine) => fnActive(oLine) && oLine.getToNode())
2782
+ .sort((a, b) => {
2783
+ const iY = a.getToNode().getY() - b.getToNode().getY();
2784
+ return iY !== 0 ? iY : a.getToNode().getKey().localeCompare(b.getToNode().getKey());
2785
+ })
2786
+ .map((oLine) => ({ line: oLine, type: "outgoing", direction: fnDir(oLine.getToNode()) }));
2787
+
2788
+ const aConnectors = ["left", "right"].flatMap((sDir) => [
2789
+ ...aIncomingConnectors.filter((o) => o.direction === sDir),
2790
+ ...aOutgoingConnectors.filter((o) => o.direction === sDir)
2791
+ ]);
2792
+
2793
+ return { aIncomingConnectors, aOutgoingConnectors, aConnectors };
2794
+ };
2795
+
2796
+ Node.prototype._getAltConnectorsAnnouncement = function (aConnectors) {
2797
+ const oGraph = this.getParent();
2798
+ const oMapping = oGraph.getConnectionTypeMapping();
2799
+ const bRTL = oGraph._bIsRtl;
2800
+ return aConnectors.map((oConnector, i) => {
2801
+ const oLine = oConnector.line;
2802
+ const sConnectionType = oLine.getConnectionType();
2803
+ const sResolvedType = bRTL ? (Utils.mRTLSwap[sConnectionType] || sConnectionType) : sConnectionType;
2804
+ const sConnectionTypeText = oMapping[sResolvedType] || sResolvedType;
2805
+ const sFromNodeTitle = oLine.getFromNode().getTitle() || oLine.getFromNode().getAltText();
2806
+ const sToNodeTitle = oLine.getToNode().getTitle() || oLine.getToNode().getAltText();
2807
+ // Determine the physical port side from connection type (Left key = left port, Right key = right port)
2808
+ const sSide = oConnector.type === "outgoing"
2809
+ ? (sResolvedType.startsWith("Left") ? "left" : "right")
2810
+ : (sResolvedType.endsWith("Left") ? "left" : "right");
2811
+ return oResourceBundle.getText("NETWORK_GRAPH_NAVIGATION_ALT_CONNECTOR_ANNOUNCE", [
2812
+ oConnector.type,
2813
+ sSide,
2814
+ sConnectionTypeText,
2815
+ sFromNodeTitle,
2816
+ sToNodeTitle,
2817
+ i + 1
2818
+ ]);
2819
+ }).join(". ");
2820
+ };
2821
+
2760
2822
  Node.prototype._setStatusColors = function(sType) {
2761
2823
  var fnSetAttrColor = function(item, sStatus) {
2762
2824
  if (sStatus && item) {
@@ -2818,10 +2880,10 @@ sap.ui.define([
2818
2880
  $titleText = this.$().find(".sapSuiteUiCommonsNetworkGraphDivNodeTitleText");
2819
2881
 
2820
2882
  if(SemanticColorType.hasOwnProperty(sBackgroundColor)){
2821
- $wrapper.addClass(Utils.SEMANTIC_CLASS_NAME.BORDER + sBackgroundColor);
2883
+ $wrapper.addClass(Utils.SEMANTIC_CLASS_NAME.OUTLINE + sBackgroundColor);
2822
2884
  } else {
2823
2885
  /** @deprecated As of 1.120 */
2824
- $wrapper.css("border-color", sBorderColor);
2886
+ $wrapper.css("outline-color", sBorderColor);
2825
2887
  }
2826
2888
 
2827
2889
  let sFocusColor = this._getColor(ElementBase.ColorType[sType + "Focus"])