lightning-base-components 1.21.2-alpha → 1.21.4-alpha

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 (357) hide show
  1. package/metadata/raptor.json +77 -1
  2. package/package.json +108 -15
  3. package/scopedImports/@salesforce-label-LightningDatatable.showActions.js +1 -1
  4. package/scopedImports/@salesforce-label-LightningForm.controllerFieldsMessage.js +1 -0
  5. package/scopedImports/@salesforce-label-LightningForm.dependentFieldsHeader.js +1 -0
  6. package/scopedImports/@salesforce-label-LightningForm.dependentFieldsListHeading.js +1 -0
  7. package/scopedImports/@salesforce-label-LightningForm.generalDependentFieldsMessage.js +1 -0
  8. package/scopedImports/@salesforce-label-LightningForm.learnMore.js +1 -0
  9. package/scopedImports/@salesforce-label-LightningForm.okButton.js +1 -0
  10. package/scopedImports/@salesforce-label-LightningLookup.modalCancel.js +1 -0
  11. package/scopedImports/@salesforce-label-LightningLookup.modalSelect.js +1 -0
  12. package/scopedImports/@salesforce-label-LightningProgressIndicator.currentStage.js +1 -1
  13. package/scopedImports/@salesforce-label-LightningProgressIndicator.errorStage.js +1 -0
  14. package/scopedImports/@salesforce-label-LightningProgressIndicator.stageComplete.js +1 -1
  15. package/scopedImports/@salesforce-label-LightningProgressIndicator.stageNotStarted.js +1 -1
  16. package/scopedImports/@salesforce-label-LightningRichTextEditor.colorPicker.js +1 -0
  17. package/src/lightning/accordion/accordion-section.slds.css +3 -3
  18. package/src/lightning/accordion/accordion.slds.css +1 -2
  19. package/src/lightning/accordionSection/accordion-section.slds.css +3 -3
  20. package/src/lightning/accordionSection/accordionSection.js +3 -1
  21. package/src/lightning/accordionSection/button.slds.css +1 -1
  22. package/src/lightning/avatar/avatar.html +1 -0
  23. package/src/lightning/badge/badge.html +3 -3
  24. package/src/lightning/badge/badge.js +1 -0
  25. package/src/lightning/badge/badge.js-meta.xml +3 -0
  26. package/src/lightning/baseCombobox/base-combobox.slds.css +11 -6
  27. package/src/lightning/baseCombobox/baseCombobox.html +5 -2
  28. package/src/lightning/baseCombobox/baseCombobox.js +5 -18
  29. package/src/lightning/baseCombobox/baseCombobox.js-meta.xml +6 -0
  30. package/src/lightning/baseCombobox/input-text.slds.css +41 -68
  31. package/src/lightning/baseCombobox/keyboard.js +12 -4
  32. package/src/lightning/baseCombobox/listbox.slds.css +51 -99
  33. package/src/lightning/baseCombobox/spinner.slds.css +62 -62
  34. package/src/lightning/baseComboboxFormattedText/baseComboboxFormattedText.js-meta.xml +6 -0
  35. package/src/lightning/baseComboboxItem/baseComboboxItem.js +10 -6
  36. package/src/lightning/baseComboboxItem/baseComboboxItem.js-meta.xml +6 -0
  37. package/src/lightning/baseComboboxItem/listbox.slds.css +51 -99
  38. package/src/lightning/baseFormattedText/baseFormattedText.js +2 -2
  39. package/src/lightning/button/__docs__/button.md +2 -1
  40. package/src/lightning/button/button.js +5 -5
  41. package/src/lightning/button/button.slds.css +1 -1
  42. package/src/lightning/buttonIcon/__docs__/buttonIcon.md +1 -0
  43. package/src/lightning/buttonIcon/button-icon.slds.css +1 -1
  44. package/src/lightning/buttonIcon/buttonIcon.html +1 -1
  45. package/src/lightning/buttonIcon/buttonIcon.js +18 -17
  46. package/src/lightning/buttonIconStateful/button-icon-stateful.slds.css +4 -2
  47. package/src/lightning/buttonIconStateful/button-icon.slds.css +1 -1
  48. package/src/lightning/buttonIconStateful/button.slds.css +1 -1
  49. package/src/lightning/buttonMenu/button-icon.slds.css +1 -1
  50. package/src/lightning/buttonMenu/button-menu.slds.css +8 -2
  51. package/src/lightning/buttonMenu/button.slds.css +1 -1
  52. package/src/lightning/buttonMenu/buttonMenu.css +5 -0
  53. package/src/lightning/buttonMenu/buttonMenu.js +2 -0
  54. package/src/lightning/buttonStateful/button-stateful.slds.css +6 -2
  55. package/src/lightning/buttonStateful/button.slds.css +1 -1
  56. package/src/lightning/buttonStateful/buttonStateful.js +4 -1
  57. package/src/lightning/calendar/calendar.js-meta.xml +6 -0
  58. package/src/lightning/calendar/calendar.slds.css +9 -2
  59. package/src/lightning/colorPickerCustom/color-picker-custom.slds.css +22 -23
  60. package/src/lightning/colorPickerCustom/colorPickerCustom.js +12 -0
  61. package/src/lightning/colorPickerCustom/input-text.slds.css +41 -68
  62. package/src/lightning/colorPickerPanel/color-picker-panel.slds.css +9 -10
  63. package/src/lightning/colorPickerPanel/colorPickerPanel.js +11 -1
  64. package/src/lightning/colorPickerPanel/popover.slds.css +0 -2
  65. package/src/lightning/combobox/combobox.html +1 -0
  66. package/src/lightning/combobox/combobox.slds.css +1 -2
  67. package/src/lightning/combobox/form-element.slds.css +54 -54
  68. package/src/lightning/datatable/__examples__disabled/customComponentWrapper/customComponentWrapper.html +11 -0
  69. package/src/lightning/datatable/__examples__disabled/customComponentWrapper/customComponentWrapper.js +25 -0
  70. package/src/lightning/datatable/__examples__disabled/customComponentWrapper/generateData.js +15 -0
  71. package/src/lightning/datatable/__examples__disabled/customDatatableWrapper/customDatatableWrapper.js +89 -0
  72. package/src/lightning/datatable/__examples__disabled/customDatatypeDeleteRowBtn/customDatatypeDeleteRowBtn.html +6 -0
  73. package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeDeleteRowBtn/customDatatypeDeleteRowBtn.js +1 -16
  74. package/src/lightning/datatable/__examples__disabled/customDatatypeLink/customDatatypeLink.html +9 -0
  75. package/src/lightning/datatable/__examples__disabled/customDatatypeRowOrderingBtn/customDatatypeRowOrderingBtn.html +3 -0
  76. package/src/lightning/datatable/__examples__disabled/customDatatypeRowOrderingBtn/customDatatypeRowOrderingBtn.js +3 -0
  77. package/src/lightning/datatable/__examples__disabled/customDatatypeTable/customNumber.html +3 -0
  78. package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customNumberEdit.html +2 -0
  79. package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/deleteRow.html +3 -2
  80. package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/iconPill.html +1 -1
  81. package/src/lightning/datatable/{__examples__/customDatatypeRowOrderingBtn/customDatatypeRowOrderingBtn.html → __examples__disabled/customNestedComponent/customNestedComponent.html} +2 -2
  82. package/src/lightning/datatable/__examples__disabled/customNestedComponent/customNestedComponent.js +12 -0
  83. package/src/lightning/datatable/__examples__disabled/myCustomTypeDatatable/customInput.html +4 -0
  84. package/src/lightning/datatable/__examples__disabled/myCustomTypeDatatable/myCustomTypeDatatable.js +17 -0
  85. package/src/lightning/datatable/__examples__disabled/myCustomTypeDatatable/nestedSimpleComponentParent.html +7 -0
  86. package/src/lightning/datatable/__examples__disabled/simpleComponentNested/simpleComponentNested.html +9 -0
  87. package/src/lightning/datatable/__examples__disabled/simpleComponentNested/simpleComponentNested.js +6 -0
  88. package/src/lightning/datatable/autoWidthStrategy.js +145 -217
  89. package/src/lightning/datatable/columnResizer.js +80 -190
  90. package/src/lightning/datatable/columnWidthManager.js +128 -243
  91. package/src/lightning/datatable/columns.js +192 -283
  92. package/src/lightning/datatable/datagrid.slds.css +187 -0
  93. package/src/lightning/datatable/datatable.js +647 -614
  94. package/src/lightning/datatable/errors.js +19 -28
  95. package/src/lightning/datatable/fixedWidthStrategy.js +27 -49
  96. package/src/lightning/datatable/headerActions.js +10 -42
  97. package/src/lightning/datatable/indexes.js +42 -0
  98. package/src/lightning/datatable/infiniteLoading.js +27 -46
  99. package/src/lightning/datatable/inlineEdit.js +311 -322
  100. package/src/lightning/datatable/keyboard.js +490 -510
  101. package/src/lightning/datatable/renderManager.js +10 -11
  102. package/src/lightning/datatable/resizeObserver.js +10 -67
  103. package/src/lightning/datatable/rowLevelActions.js +7 -6
  104. package/src/lightning/datatable/rowNumber.js +41 -79
  105. package/src/lightning/datatable/rowSelection.js +236 -291
  106. package/src/lightning/datatable/rowSelectionShared.js +26 -33
  107. package/src/lightning/datatable/rows.js +264 -476
  108. package/src/lightning/datatable/sort.js +27 -82
  109. package/src/lightning/datatable/templates/div/div.css +2 -57
  110. package/src/lightning/datatable/templates/div/div.html +25 -10
  111. package/src/lightning/datatable/templates/div/div.lbc.native.css +3 -0
  112. package/src/lightning/datatable/templates/div/div.lbc.synthetic.css +80 -0
  113. package/src/lightning/datatable/templates/table/table.html +16 -5
  114. package/src/lightning/datatable/tree.js +17 -35
  115. package/src/lightning/datatable/types.js +10 -31
  116. package/src/lightning/datatable/utils.js +54 -29
  117. package/src/lightning/datatable/virtualization.js +2 -5
  118. package/src/lightning/datatable/widthManagerShared.js +24 -41
  119. package/src/lightning/datatable/wrapText.js +45 -77
  120. package/src/lightning/datepicker/datepicker.js +32 -9
  121. package/src/lightning/datepicker/datepicker.js-meta.xml +6 -0
  122. package/src/lightning/datepicker/form-element.slds.css +54 -54
  123. package/src/lightning/datepicker/input-text.slds.css +41 -68
  124. package/src/lightning/datetimepicker/datetimepicker.js-meta.xml +6 -0
  125. package/src/lightning/datetimepicker/form-element.slds.css +54 -54
  126. package/src/lightning/datetimepicker/input-text.slds.css +41 -68
  127. package/src/lightning/dualListbox/dual-listbox.slds.css +7 -2
  128. package/src/lightning/dualListbox/dualListbox.js +7 -8
  129. package/src/lightning/dualListbox/form-element.slds.css +54 -54
  130. package/src/lightning/dualListbox/listbox.slds.css +51 -99
  131. package/src/lightning/dynamicIcon/dynamic-icon-strength.slds.css +1 -2
  132. package/src/lightning/dynamicIcon/dynamic-icon-trend.slds.css +1 -2
  133. package/src/lightning/formattedDateTime/formattedDateTime.js +7 -62
  134. package/src/lightning/formattedDateTime/formattedDateTime.js-meta.xml +3 -0
  135. package/src/lightning/formattedLocation/formattedLocation.html +1 -3
  136. package/src/lightning/formattedLocation/formattedLocation.js +3 -25
  137. package/src/lightning/formattedLookup/events.js +2 -4
  138. package/src/lightning/formattedName/formattedName.js +3 -2
  139. package/src/lightning/formattedName/formattedName.js-meta.xml +3 -0
  140. package/src/lightning/formattedNumber/formattedNumber.js +5 -51
  141. package/src/lightning/formattedNumber/formattedNumber.js-meta.xml +3 -0
  142. package/src/lightning/formattedRichText/formattedRichText.js +5 -5
  143. package/src/lightning/formattedRichText/linkTextNodes.js +58 -0
  144. package/src/lightning/formattedRichText/richTextConfig.js +1 -0
  145. package/src/lightning/groupedCombobox/form-element.slds.css +54 -54
  146. package/src/lightning/groupedCombobox/grouped-combobox.slds.css +0 -2
  147. package/src/lightning/groupedCombobox/groupedCombobox.js-meta.xml +1 -1
  148. package/src/lightning/groupedCombobox/input-text.slds.css +41 -68
  149. package/src/lightning/helptext/button-icon.slds.css +1 -1
  150. package/src/lightning/helptext/form-element.slds.css +54 -54
  151. package/src/lightning/helptext/helptext.css +7 -0
  152. package/src/lightning/helptext/helptext.js +3 -4
  153. package/src/lightning/icon/icon.html +1 -1
  154. package/src/lightning/icon/icon.slds.css +12 -25
  155. package/src/lightning/input/form-element.slds.css +54 -54
  156. package/src/lightning/input/input.html +5 -0
  157. package/src/lightning/inputAddress/addressFormat.js +31 -4
  158. package/src/lightning/inputAddress/fieldsLayout.js +6 -0
  159. package/src/lightning/inputAddress/form-element.slds.css +54 -54
  160. package/src/lightning/inputAddress/input-address.slds.css +1 -2
  161. package/src/lightning/inputAddress/input-text.slds.css +41 -68
  162. package/src/lightning/inputAddress/inputAddress.html +19 -1
  163. package/src/lightning/inputAddress/inputAddress.js +75 -3
  164. package/src/lightning/inputAddress/inputAddress.js-meta.xml +3 -0
  165. package/src/lightning/inputLocation/form-element.slds.css +54 -54
  166. package/src/lightning/inputLocation/input-location.slds.css +1 -2
  167. package/src/lightning/inputLocation/input-text.slds.css +41 -68
  168. package/src/lightning/inputName/form-element.slds.css +54 -54
  169. package/src/lightning/inputName/input-text.slds.css +41 -68
  170. package/src/lightning/interactiveDialogBase/interactive-dialog-base.slds.css +0 -3
  171. package/src/lightning/interactiveDialogBase/interactiveDialogBase.js-meta.xml +6 -0
  172. package/src/lightning/internationalizationLibrary/address/AddressFormat.js +553 -610
  173. package/src/lightning/lookupAddress/form-element.slds.css +54 -54
  174. package/src/lightning/lookupAddress/listbox.slds.css +51 -99
  175. package/src/lightning/lookupAddress/location.js +2 -0
  176. package/src/lightning/lookupAddress/lookup-address.slds.css +0 -2
  177. package/src/lightning/lookupAddress/lookupAddress.html +6 -1
  178. package/src/lightning/lookupAddress/lookupAddress.js +40 -10
  179. package/src/lightning/menuDivider/menu-divider.slds.css +0 -2
  180. package/src/lightning/menuItem/menu-item.slds.css +8 -2
  181. package/src/lightning/menuSubheader/menu-subheader.slds.css +1 -2
  182. package/src/lightning/modal/__docs__/modal.md +10 -1
  183. package/src/lightning/modal/__modalUtils__/modalContainerTestConstants.js +3 -7
  184. package/src/lightning/modal/__modalUtils__/modalContainerTestMethods.js +39 -133
  185. package/src/lightning/modal/__modalUtils__/modalContainerTestMockData.js +1 -1
  186. package/src/lightning/modal/modal.js +1 -1
  187. package/src/lightning/modalBase/modal-base.slds.css +3 -3
  188. package/src/lightning/modalBase/modalBase.html +15 -10
  189. package/src/lightning/modalBase/modalBase.js +131 -154
  190. package/src/lightning/modalBase/modalBase.js-meta.xml +6 -0
  191. package/src/lightning/modalBody/modal-body.slds.css +1 -2
  192. package/src/lightning/modalBody/modalBody.css +6 -0
  193. package/src/lightning/modalFooter/modal-footer.slds.css +2 -2
  194. package/src/lightning/modalFooter/modalFooter.js +0 -21
  195. package/src/lightning/modalHeader/modal-header.slds.css +1 -2
  196. package/src/lightning/modalHeader/modalHeader.html +16 -4
  197. package/src/lightning/modalHeader/modalHeader.js +61 -36
  198. package/src/lightning/overlay/overlay.js-meta.xml +6 -0
  199. package/src/lightning/pill/link.html +1 -0
  200. package/src/lightning/pill/pill.slds.css +32 -58
  201. package/src/lightning/pill/plain.html +1 -0
  202. package/src/lightning/pill/plainLink.html +1 -0
  203. package/src/lightning/pillContainer/button.slds.css +1 -1
  204. package/src/lightning/pillContainer/listbox.slds.css +51 -99
  205. package/src/lightning/pillContainer/pill-container.slds.css +6 -10
  206. package/src/lightning/pillContainer/pill.slds.css +32 -58
  207. package/src/lightning/popup/popover.slds.css +0 -2
  208. package/src/lightning/primitiveBubble/primitiveBubble.js +42 -0
  209. package/src/lightning/primitiveBubble/primitiveBubble.js-meta.xml +6 -0
  210. package/src/lightning/primitiveButton/primitiveButoon.js-meta.xml +6 -0
  211. package/src/lightning/primitiveCellCheckbox/checkbox.css +2 -0
  212. package/src/lightning/primitiveColorpickerButton/color-picker-button.slds.css +16 -38
  213. package/src/lightning/primitiveCustomCell/primitiveCustomCell.js +26 -1
  214. package/src/lightning/primitiveDatatableCell/primitiveDatatableCell.js +1 -1
  215. package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.html +1 -1
  216. package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.js +13 -0
  217. package/src/lightning/primitiveHeaderFactory/nonsortableHeader.css +1 -0
  218. package/src/lightning/primitiveHeaderFactory/nonsortableHeader.html +19 -6
  219. package/src/lightning/primitiveHeaderFactory/selectableHeader.css +2 -0
  220. package/src/lightning/primitiveHeaderFactory/sortableHeader.html +3 -1
  221. package/src/lightning/primitiveIcon/icon.slds.css +12 -25
  222. package/src/lightning/primitiveIcon/primitiveIcon.js-meta.xml +6 -0
  223. package/src/lightning/primitiveIframe/primitiveIframe.js +3 -1
  224. package/src/lightning/primitiveInputCheckbox/form-element.slds.css +54 -54
  225. package/src/lightning/primitiveInputCheckbox/primitiveInputCheckbox.js +5 -2
  226. package/src/lightning/primitiveInputCheckbox/primitiveInputCheckbox.js-meta.xml +6 -0
  227. package/src/lightning/primitiveInputCheckboxButton/form-element.slds.css +54 -54
  228. package/src/lightning/primitiveInputCheckboxButton/input-checkbox-button.slds.css +6 -4
  229. package/src/lightning/primitiveInputCheckboxButton/primitiveInputCheckboxButton.js +5 -2
  230. package/src/lightning/primitiveInputCheckboxButton/primitiveInputCheckboxButton.js-meta.xml +6 -0
  231. package/src/lightning/primitiveInputColor/form-element.slds.css +54 -54
  232. package/src/lightning/primitiveInputColor/input-color.slds.css +2 -3
  233. package/src/lightning/primitiveInputColor/input-text.slds.css +41 -68
  234. package/src/lightning/primitiveInputColor/primitiveInputColor.js +5 -2
  235. package/src/lightning/primitiveInputColor/primitiveInputColor.js-meta.xml +6 -0
  236. package/src/lightning/primitiveInputFile/button.slds.css +1 -1
  237. package/src/lightning/primitiveInputFile/form-element.slds.css +54 -54
  238. package/src/lightning/primitiveInputFile/input-file.slds.css +1 -4
  239. package/src/lightning/primitiveInputFile/primitiveInputFile.js +4 -2
  240. package/src/lightning/primitiveInputFile/primitiveInputFile.js-meta.xml +6 -0
  241. package/src/lightning/primitiveInputRadio/primitiveInputRadio.js +4 -2
  242. package/src/lightning/primitiveInputSimple/form-element.slds.css +54 -54
  243. package/src/lightning/primitiveInputSimple/input-text.slds.css +41 -68
  244. package/src/lightning/primitiveInputSimple/primitiveInputSimple.js-meta.xml +6 -0
  245. package/src/lightning/primitiveInputToggle/form-element.slds.css +54 -54
  246. package/src/lightning/primitiveInputToggle/input-toggle.slds.css +50 -27
  247. package/src/lightning/primitiveInputToggle/primitiveInputToggle.js +5 -2
  248. package/src/lightning/primitiveInputToggle/primitiveInputToggle.js-meta.xml +6 -0
  249. package/src/lightning/primitiveResizeHandler/primitiveResizeHandler.css +11 -0
  250. package/src/lightning/primitiveResizeHandler/primitiveResizeHandler.html +2 -1
  251. package/src/lightning/primitiveResizeHandler/primitiveResizeHandler.js +1 -0
  252. package/src/lightning/progressBar/progress-bar.slds.css +8 -10
  253. package/src/lightning/progressRing/progress-ring.slds.css +0 -23
  254. package/src/lightning/progressStep/base.html +5 -6
  255. package/src/lightning/progressStep/progressStep.js +15 -23
  256. package/src/lightning/prompt/__docs__/prompt.md +1 -1
  257. package/src/lightning/radioGroup/form-element.slds.css +54 -54
  258. package/src/lightning/radioGroup/radioGroup.html +1 -2
  259. package/src/lightning/radioGroup/radioGroup.js +1 -0
  260. package/src/lightning/routingService/routingService.js +31 -5
  261. package/src/lightning/select/form-element.slds.css +54 -54
  262. package/src/lightning/select/select.slds.css +4 -2
  263. package/src/lightning/shadowBaseClassPrivate/shadowBaseClassPrivate.js +0 -2
  264. package/src/lightning/sldsCommon/sldsCommon.css +134 -98
  265. package/src/lightning/sldsUtilsAlignment/sldsUtilsAlignment.css +1 -1
  266. package/src/lightning/sldsUtilsBox/sldsUtilsBox.css +14 -13
  267. package/src/lightning/sldsUtilsGrid/sldsUtilsGrid.css +95 -92
  268. package/src/lightning/sldsUtilsHyphenation/sldsUtilsHyphenation.css +1 -1
  269. package/src/lightning/sldsUtilsMargin/sldsUtilsMargin.css +77 -75
  270. package/src/lightning/sldsUtilsPadding/sldsUtilsPadding.css +73 -73
  271. package/src/lightning/sldsUtilsSizing/sldsUtilsSizing.css +552 -558
  272. package/src/lightning/sldsUtilsVisibility/sldsUtilsVisibility.css +5 -1
  273. package/src/lightning/spinner/spinner.slds.css +62 -62
  274. package/src/lightning/staticMap/staticMap.js +3 -2
  275. package/src/lightning/tab/tab.js +10 -5
  276. package/src/lightning/tab/tab.js-meta.xml +3 -0
  277. package/src/lightning/tab/tab.slds.css +14 -7
  278. package/src/lightning/tabBar/tab-bar.slds.css +16 -6
  279. package/src/lightning/tabBar/tabBar.js +10 -5
  280. package/src/lightning/tabset/__docs__/tabset.md +24 -1
  281. package/src/lightning/tabset/tabset.html +2 -0
  282. package/src/lightning/tabset/tabset.js +25 -38
  283. package/src/lightning/tabset/tabset.js-meta.xml +3 -0
  284. package/src/lightning/tabset/tabset.slds.css +0 -2
  285. package/src/lightning/textarea/form-element.slds.css +54 -54
  286. package/src/lightning/textarea/textarea.js +11 -2
  287. package/src/lightning/textarea/textarea.slds.css +22 -9
  288. package/src/lightning/timepicker/form-element.slds.css +54 -54
  289. package/src/lightning/timepicker/timepicker.js-meta.xml +6 -0
  290. package/src/lightning/timepicker/timepicker.slds.css +2 -2
  291. package/src/lightning/toast/__docs__/toast.md +20 -22
  292. package/src/lightning/toast/button-icon.slds.css +1 -1
  293. package/src/lightning/toast/icon.slds.css +12 -25
  294. package/src/lightning/toast/toast.js +15 -12
  295. package/src/lightning/toast/toast.slds.css +6 -18
  296. package/src/lightning/toastContainer/__docs__/toastContainer.md +3 -2
  297. package/src/lightning/toastContainer/toast.slds.css +6 -18
  298. package/src/lightning/toastContainer/toastContainer.js +25 -17
  299. package/src/lightning/tooltipLibrary/tooltipLibrary.js +36 -24
  300. package/src/lightning/tree/tree.js +2 -0
  301. package/src/lightning/utils/classSet.js +9 -3
  302. package/src/lightning/utilsPrivate/formatUtils.js +158 -0
  303. package/src/lightning/utilsPrivate/textUtils.js +16 -0
  304. package/src/lightning/utilsPrivate/utilsPrivate.js +56 -15
  305. package/src/lightning/utilsPrivate/validationUtils.js +59 -0
  306. package/src/lightning/verticalNavigation/vertical-navigation.slds.css +14 -0
  307. package/src/lightning/verticalNavigation/verticalNavigation.css +1 -1
  308. package/src/lightning/verticalNavigation/verticalNavigation.html +1 -1
  309. package/src/lightning/verticalNavigation/verticalNavigation.js +66 -28
  310. package/src/lightning/verticalNavigation/verticalNavigation.js-meta.xml +3 -0
  311. package/src/lightning/verticalNavigationItem/vertical-navigation-item.slds.css +63 -0
  312. package/src/lightning/verticalNavigationItem/verticalNavigationItem.css +2 -3
  313. package/src/lightning/verticalNavigationItem/verticalNavigationItem.js +29 -15
  314. package/src/lightning/verticalNavigationItem/verticalNavigationItem.js-meta.xml +3 -0
  315. package/src/lightning/verticalNavigationItem/verticalNavigationItem.lbc.native.css +2 -0
  316. package/src/lightning/verticalNavigationItem/verticalNavigationItem.lbc.synthetic.css +3 -0
  317. package/src/lightning/verticalNavigationItemBadge/badge.slds.css +76 -0
  318. package/src/lightning/verticalNavigationItemBadge/vertical-navigation-item.slds.css +63 -0
  319. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.css +2 -3
  320. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.html +1 -1
  321. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.js +28 -15
  322. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.js-meta.xml +3 -0
  323. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.lbc.native.css +5 -0
  324. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.lbc.synthetic.css +3 -0
  325. package/src/lightning/verticalNavigationItemIcon/vertical-navigation-item.slds.css +63 -0
  326. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.css +2 -3
  327. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.js +29 -15
  328. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.js-meta.xml +3 -0
  329. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.lbc.native.css +3 -0
  330. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.lbc.synthetic.css +3 -0
  331. package/src/lightning/verticalNavigationOverflow/button.slds.css +503 -0
  332. package/src/lightning/verticalNavigationOverflow/vertical-navigation-item.slds.css +63 -0
  333. package/src/lightning/verticalNavigationOverflow/vertical-navigation-section.slds.css +17 -0
  334. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.css +2 -1
  335. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.html +2 -0
  336. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.js +18 -13
  337. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.js-meta.xml +3 -0
  338. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.lbc.native.css +5 -0
  339. package/src/lightning/verticalNavigationSection/vertical-navigation-section.slds.css +13 -15
  340. package/src/lightning/verticalNavigationSection/verticalNavigationSection.js-meta.xml +3 -0
  341. package/src/lightning/datatable/__examples__/customDatatableWrapper/customDatatableWrapper.js +0 -158
  342. package/src/lightning/datatable/__examples__/customDatatypeDeleteRowBtn/customDatatypeDeleteRowBtn.html +0 -6
  343. package/src/lightning/datatable/__examples__/customDatatypeLink/customDatatypeLink.html +0 -9
  344. package/src/lightning/datatable/__examples__/customDatatypeRowOrderingBtn/customDatatypeRowOrderingBtn.js +0 -40
  345. package/src/lightning/datatable/__examples__/customDatatypeTable/customNumber.html +0 -3
  346. package/src/lightning/datatable/inlineEditShared.js +0 -26
  347. package/src/lightning/datatable/resizeSensor.js +0 -244
  348. package/src/lightning/formattedRichText/linkify.js +0 -43
  349. package/src/lightning/utilsPrivate/smartSetAttribute.js +0 -19
  350. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatableWrapper/customDatatableWrapper.html +0 -0
  351. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeLink/customDatatypeLink.js +0 -0
  352. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeNumber/customDatatypeNumber.html +0 -0
  353. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeNumber/customDatatypeNumber.js +0 -0
  354. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customDatatypeTable.js +0 -0
  355. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customLink.html +0 -0
  356. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customName.html +0 -0
  357. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/orderingButtons.html +0 -0
@@ -1,28 +1,21 @@
1
- import {
2
- isCustomerColumn,
3
- generateColKeyValue,
4
- getStateColumnIndex,
5
- } from './columns';
1
+ import { getShadowActiveElements, isRTL } from 'lightning/utilsPrivate';
2
+ import { getCellFromIndexes, HEADER_ROW_KEY, getRowByKey } from './indexes';
6
3
  import {
7
4
  hasTreeDataType,
8
5
  getStateTreeColumn,
9
6
  fireRowToggleEvent,
10
7
  } from './tree';
11
- import { isCellEditable, getRowByKey } from './rows';
12
- import { isRTL, getShadowActiveElements } from 'lightning/utilsPrivate';
8
+ import { generateColKeyValue, getStateColumnIndex } from './columns';
9
+ import { isCellEditable } from './rows';
13
10
  import { findFirstVisibleIndex } from './virtualization';
14
-
15
- import { escapeDoubleQuotes } from './utils';
16
-
17
- // Indicator/flag for a header row
18
- const HEADER_ROW = 'HEADER';
11
+ import { getColDataSelector, getRowDataSelector, getScrollerY } from './utils';
19
12
 
20
13
  // SLDS Class for Focus
21
14
  export const FOCUS_CLASS = 'slds-has-focus';
22
15
 
23
16
  // Keyboard Navigation Modes
24
- const NAVIGATION_MODE = 'NAVIGATION';
25
- const ACTION_MODE = 'ACTION';
17
+ export const KEYBOARD_NAVIGATION_MODE = 'NAVIGATION';
18
+ export const KEYBOARD_ACTION_MODE = 'ACTION';
26
19
 
27
20
  // Pixel Values
28
21
  const TOP_MARGIN = 80;
@@ -40,43 +33,23 @@ const TAB = 9;
40
33
  const SPACE = 32;
41
34
 
42
35
  // Navigation Direction
43
- const NAVIGATION_DIR = (() => {
44
- if (isRTL()) {
45
- return {
46
- RIGHT: -1,
47
- LEFT: 1,
48
- USE_CURRENT: 0,
49
- RESET: 2,
50
- TAB_FORWARD: -1,
51
- TAB_BACKWARD: 1,
52
- };
53
- }
54
-
55
- return {
56
- RIGHT: 1,
57
- LEFT: -1,
58
- USE_CURRENT: 0,
59
- RESET: 2,
60
- TAB_FORWARD: 1,
61
- TAB_BACKWARD: -1,
62
- };
63
- })();
64
-
65
- // Selectors
66
- const SELECTORS = {
67
- headerRow: {
68
- default: `thead > :nth-child(1)`,
69
- roleBased: `[role="grid"] > [role="rowgroup"]:nth-child(1) > [role="row"]`,
70
- },
71
- dataRowRowGroup: {
72
- default: `tbody`,
73
- roleBased: `[role="grid"] > [role="rowgroup"]:nth-child(2)`,
74
- },
75
- cell: {
76
- default: ['td', 'th'],
77
- roleBased: ['rowheader', 'gridcell', 'columnheader'],
78
- },
79
- };
36
+ export const NAVIGATION_DIR = isRTL()
37
+ ? {
38
+ RIGHT: -1,
39
+ LEFT: 1,
40
+ USE_CURRENT: 0,
41
+ RESET: 2,
42
+ TAB_FORWARD: -1,
43
+ TAB_BACKWARD: 1,
44
+ }
45
+ : {
46
+ RIGHT: 1,
47
+ LEFT: -1,
48
+ USE_CURRENT: 0,
49
+ RESET: 2,
50
+ TAB_FORWARD: 1,
51
+ TAB_BACKWARD: -1,
52
+ };
80
53
 
81
54
  /***************************** KEYDOWN HANDLERS *****************************/
82
55
 
@@ -94,7 +67,7 @@ const SELECTORS = {
94
67
  */
95
68
  export function handleKeydownOnCell(event) {
96
69
  event.stopPropagation();
97
- reactToKeyboardInActionMode(this.template, this.state, event);
70
+ reactToKeyboardInActionMode(this, event);
98
71
  }
99
72
 
100
73
  /**
@@ -115,13 +88,10 @@ export function handleKeydownOnCell(event) {
115
88
  * @param {Event} event
116
89
  */
117
90
  export function handleKeydownOnTable(event) {
118
- const targetTagName = event.target.tagName.toLowerCase();
119
- const targetRole = event.target.getAttribute('role');
120
-
121
91
  // Checks if the keydown happened on a cell element and not
122
92
  // on an actionable element when in Action Mode.
123
- if (isCellElement(targetTagName, targetRole)) {
124
- reactToKeyboardInNavMode(this.template, this.state, event);
93
+ if (isCellElement(event.target)) {
94
+ reactToKeyboardInNavMode(this, event);
125
95
  }
126
96
  }
127
97
 
@@ -129,280 +99,309 @@ export function handleKeydownOnTable(event) {
129
99
  * Changes the datatable state based on the keyboard event sent from the cell component.
130
100
  * The result of those changes may trigger a re-render on the table
131
101
  *
132
- * @param {Node} template The custom element root `this.template`
133
- * @param {Object} state Datatable state
102
+ * @param {Object} dt - The datatable instance
134
103
  * @param {Event} event Custom DOM event sent by the cell
135
104
  * @returns {Object} Mutated state
136
105
  */
137
- function reactToKeyboardInActionMode(template, state, event) {
106
+ function reactToKeyboardInActionMode(dt, event) {
107
+ const { state, template } = dt;
138
108
  switch (event.detail.keyCode) {
139
109
  case ARROW_LEFT:
140
- return reactToArrowLeft(template, state, event);
110
+ reactToArrowLeft(state, template, event);
111
+ break;
141
112
  case ARROW_RIGHT:
142
- return reactToArrowRight(template, state, event);
113
+ reactToArrowRight(state, template, event);
114
+ break;
143
115
  case ARROW_UP:
144
- return reactToArrowUp(template, state, event);
116
+ reactToArrowUp(state, template, event);
117
+ break;
145
118
  case ARROW_DOWN:
146
- return reactToArrowDown(template, state, event);
119
+ reactToArrowDown(state, template, event);
120
+ break;
147
121
  case ENTER:
148
122
  case SPACE:
149
- return reactToEnter(template, state, event);
123
+ reactToEnter(state, template, event);
124
+ break;
150
125
  case ESCAPE:
151
- return reactToEscape(template, state, event);
126
+ reactToEscape(state, template, event);
127
+ break;
152
128
  case TAB:
153
- return reactToTab(template, state, event);
129
+ reactToTab(state, template, event);
130
+ break;
154
131
  default:
155
- return state;
132
+ break;
156
133
  }
157
134
  }
158
135
 
159
- function reactToKeyboardInNavMode(element, state, event) {
136
+ function reactToKeyboardInNavMode(dt, event) {
137
+ const { state, template } = dt;
138
+ const {
139
+ activeCell: { colKeyValue, rowKeyValue },
140
+ } = state;
141
+ const { keyCode, shiftKey } = event;
160
142
  const syntheticEvent = {
161
143
  detail: {
162
- rowKeyValue: state.activeCell.rowKeyValue,
163
- colKeyValue: state.activeCell.colKeyValue,
164
- keyCode: event.keyCode,
165
- shiftKey: event.shiftKey,
144
+ colKeyValue,
145
+ rowKeyValue,
146
+ keyCode,
147
+ shiftKey,
166
148
  },
167
149
  preventDefault: () => {},
168
150
  stopPropagation: () => {},
169
151
  };
170
-
171
152
  // We need event.preventDefault so that actions like arrow up or down
172
153
  // does not scroll the table but instead sets focus on the right cells
173
154
  switch (event.keyCode) {
174
155
  case ARROW_LEFT:
175
156
  event.preventDefault();
176
- return reactToArrowLeft(element, state, syntheticEvent);
157
+ reactToArrowLeft(state, template, syntheticEvent);
158
+ break;
177
159
  case ARROW_RIGHT:
178
160
  event.preventDefault();
179
- return reactToArrowRight(element, state, syntheticEvent);
161
+ reactToArrowRight(state, template, syntheticEvent);
162
+ break;
180
163
  case ARROW_UP:
181
164
  event.preventDefault();
182
- return reactToArrowUp(element, state, syntheticEvent);
165
+ reactToArrowUp(state, template, syntheticEvent);
166
+ break;
183
167
  case ARROW_DOWN:
184
168
  event.preventDefault();
185
- return reactToArrowDown(element, state, syntheticEvent);
169
+ reactToArrowDown(state, template, syntheticEvent);
170
+ break;
186
171
  case ENTER:
187
172
  case SPACE:
188
173
  event.preventDefault();
189
- return reactToEnter(element, state, syntheticEvent);
174
+ reactToEnter(state, template, syntheticEvent);
175
+ break;
190
176
  case ESCAPE:
191
177
  // td, th or div[role=gridcell/rowheader] is the active element in the
192
178
  // action mode if cell doesn't have action elements; hence this can be
193
179
  // reached and we should react to escape as exiting from action mode
194
180
  syntheticEvent.detail.keyEvent = event;
195
- return reactToEscape(element, state, syntheticEvent);
181
+ reactToEscape(state, template, syntheticEvent);
182
+ break;
196
183
  case TAB:
197
- return reactToTab(element, state, syntheticEvent);
184
+ reactToTab(state, template, syntheticEvent);
185
+ break;
198
186
  default:
199
- return state;
187
+ break;
200
188
  }
201
189
  }
202
190
 
203
- function moveFromCellToRow(element, state) {
204
- setBlurActiveCell(element, state);
205
- setRowNavigationMode(state);
206
- setFocusActiveRow(element, state);
207
- }
208
-
209
- function reactToArrowLeft(element, state, event) {
191
+ function reactToArrowLeft(state, template, event) {
210
192
  const { rowKeyValue, colKeyValue } = event.detail;
211
193
  const { colIndex } = getIndexesByKeys(state, rowKeyValue, colKeyValue);
212
- const { columns } = state;
213
-
214
194
  // Move from navigation mode to row mode when user
215
195
  // arrows left when in nav mode and on the first column
216
196
  if (colIndex === 0 && canBeRowNavigationMode(state)) {
217
- moveFromCellToRow(element, state);
197
+ // Tracked state change.
198
+ // Move from cell to row.
199
+ setBlurActiveCell(state, template);
200
+ // Untracked state change.
201
+ setRowNavigationMode(state);
202
+ // Tracked state change.
203
+ setFocusActiveRow(state, template);
218
204
  } else {
219
205
  const nextColIndex = getNextIndexLeft(state, colIndex);
220
-
221
206
  if (nextColIndex === undefined) {
222
207
  return;
223
208
  }
224
-
225
- setBlurActiveCell(element, state);
226
-
227
- // update activeCell
209
+ setBlurActiveCell(state, template);
210
+ // Untracked state change.
211
+ // Update activeCell.
228
212
  state.activeCell = {
229
213
  rowKeyValue,
230
214
  colKeyValue: generateColKeyValue(
231
- columns[nextColIndex],
215
+ state.columns[nextColIndex],
232
216
  nextColIndex
233
217
  ),
234
218
  };
235
- setFocusActiveCell(element, state, NAVIGATION_DIR.LEFT);
219
+ // Tracked state change.
220
+ setFocusActiveCell(state, template, NAVIGATION_DIR.LEFT);
236
221
  }
237
222
  }
238
223
 
239
- function reactToArrowRight(element, state, event) {
224
+ function reactToArrowRight(state, template, event) {
240
225
  const { rowKeyValue, colKeyValue } = event.detail;
241
226
  const { colIndex } = getIndexesByKeys(state, rowKeyValue, colKeyValue);
242
227
  const nextColIndex = getNextIndexRight(state, colIndex);
243
- const { columns } = state;
244
-
245
228
  if (nextColIndex === undefined) {
246
229
  return;
247
230
  }
248
-
249
- setBlurActiveCell(element, state);
250
-
251
- // update activeCell
231
+ setBlurActiveCell(state, template);
232
+ // Untracked state change.
233
+ // Update activeCell.
252
234
  state.activeCell = {
253
235
  rowKeyValue,
254
- colKeyValue: generateColKeyValue(columns[nextColIndex], nextColIndex),
236
+ colKeyValue: generateColKeyValue(
237
+ state.columns[nextColIndex],
238
+ nextColIndex
239
+ ),
255
240
  };
256
- setFocusActiveCell(element, state, NAVIGATION_DIR.RIGHT);
241
+ setFocusActiveCell(state, template, NAVIGATION_DIR.RIGHT);
257
242
  }
258
243
 
259
- function reactToArrowUp(element, state, event) {
244
+ function reactToArrowUp(state, template, event) {
260
245
  const { rowKeyValue, colKeyValue, keyEvent } = event.detail;
261
246
  const { rowIndex } = getIndexesByKeys(state, rowKeyValue, colKeyValue);
262
247
  const nextRowIndex = getNextIndexUp(state, rowIndex);
263
- const { rows } = state;
264
-
265
- if (nextRowIndex === undefined) {
266
- return;
267
- }
268
-
269
- if (state.hideTableHeader && nextRowIndex === -1) {
248
+ if (
249
+ nextRowIndex === undefined ||
250
+ (state.hideTableHeader && nextRowIndex === -1)
251
+ ) {
270
252
  return;
271
253
  }
272
254
 
273
255
  if (keyEvent) {
274
256
  keyEvent.stopPropagation();
275
257
  }
276
-
277
- setBlurActiveCell(element, state);
278
-
279
- // update activeCell
258
+ // Tracked state change.
259
+ setBlurActiveCell(state, template);
260
+ // Untracked state change.
261
+ // Update activeCell.
280
262
  state.activeCell = {
281
- rowKeyValue: nextRowIndex !== -1 ? rows[nextRowIndex].key : HEADER_ROW,
263
+ rowKeyValue:
264
+ nextRowIndex === -1 ? HEADER_ROW_KEY : state.rows[nextRowIndex].key,
282
265
  colKeyValue,
283
266
  };
284
- setFocusActiveCell(element, state, NAVIGATION_DIR.USE_CURRENT);
267
+ // Tracked state change.
268
+ setFocusActiveCell(state, template, NAVIGATION_DIR.USE_CURRENT);
285
269
  }
286
270
 
287
- function reactToArrowDown(element, state, event) {
271
+ function reactToArrowDown(state, template, event) {
288
272
  const { rowKeyValue, colKeyValue, keyEvent } = event.detail;
289
273
  const { rowIndex } = getIndexesByKeys(state, rowKeyValue, colKeyValue);
290
274
  const nextRowIndex = getNextIndexDown(state, rowIndex);
291
- const { rows } = state;
292
-
293
- if (nextRowIndex === undefined) {
294
- return;
295
- }
296
-
297
- if (state.hideTableHeader && nextRowIndex === -1) {
275
+ if (
276
+ nextRowIndex === undefined ||
277
+ (state.hideTableHeader && nextRowIndex === -1)
278
+ ) {
298
279
  return;
299
280
  }
300
281
 
301
282
  if (keyEvent) {
302
283
  keyEvent.stopPropagation();
303
284
  }
304
-
305
- setBlurActiveCell(element, state);
306
-
307
- // update activeCell
285
+ // Tracked state change.
286
+ setBlurActiveCell(state, template);
287
+ // Untracked state change.
288
+ // Update activeCell.
308
289
  state.activeCell = {
309
- rowKeyValue: nextRowIndex !== -1 ? rows[nextRowIndex].key : HEADER_ROW,
290
+ rowKeyValue:
291
+ nextRowIndex === -1 ? HEADER_ROW_KEY : state.rows[nextRowIndex].key,
310
292
  colKeyValue,
311
293
  };
312
- setFocusActiveCell(element, state, NAVIGATION_DIR.USE_CURRENT);
294
+ setFocusActiveCell(state, template, NAVIGATION_DIR.USE_CURRENT);
313
295
  }
314
296
 
315
- function reactToEnter(element, state, event) {
316
- if (state.keyboardMode === NAVIGATION_MODE) {
317
- state.keyboardMode = ACTION_MODE;
297
+ function reactToEnter(state, template, event) {
298
+ if (state.keyboardMode === KEYBOARD_NAVIGATION_MODE) {
299
+ // Untracked state change.
300
+ state.keyboardMode = KEYBOARD_ACTION_MODE;
301
+ const { keyCode, keyEvent } = event.detail;
318
302
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
319
-
320
- const actionsMap = {};
321
- actionsMap[SPACE] = 'space';
322
- actionsMap[ENTER] = 'enter';
323
-
324
- if (event.detail.keyEvent) {
325
- event.detail.keyEvent.preventDefault();
303
+ if (keyEvent) {
304
+ keyEvent.preventDefault();
326
305
  }
327
- setModeActiveCell(element, state, {
328
- action: actionsMap[event.detail.keyCode],
329
- });
330
- updateTabIndex(state, rowIndex, colIndex, -1);
306
+ const info = { action: undefined };
307
+ if (keyCode === SPACE) {
308
+ info.action = 'space';
309
+ } else if (keyCode === ENTER) {
310
+ info.action = 'enter';
311
+ }
312
+ // Tracked state changes.
313
+ setModeActiveCell(state, template, info);
314
+ updateCellTabIndex(state, rowIndex, colIndex, -1);
331
315
  }
332
316
  }
333
317
 
334
- function reactToEscape(element, state, event) {
335
- if (state.keyboardMode === ACTION_MODE) {
318
+ function reactToEscape(state, template, event) {
319
+ if (state.keyboardMode === KEYBOARD_ACTION_MODE) {
336
320
  // When the table is in action mode this event shouldn't bubble
337
321
  // because if the table in inside a modal it should prevent the modal closes
338
322
  event.detail.keyEvent.stopPropagation();
339
- state.keyboardMode = NAVIGATION_MODE;
340
- setModeActiveCell(element, state);
341
- setFocusActiveCell(element, state, NAVIGATION_DIR.RESET);
323
+ // Untracked state change.
324
+ state.keyboardMode = KEYBOARD_NAVIGATION_MODE;
325
+ // Tracked state changes.
326
+ setModeActiveCell(state, template);
327
+ setFocusActiveCell(state, template, NAVIGATION_DIR.RESET);
342
328
  }
343
329
  }
344
330
 
345
- function reactToTab(element, state, event) {
331
+ function reactToTab(state, template, event) {
346
332
  event.preventDefault();
347
333
  event.stopPropagation();
348
334
 
349
- const { shiftKey } = event.detail;
350
- const direction = getTabDirection(shiftKey);
335
+ const { detail } = event;
336
+ const direction = getTabDirection(detail.shiftKey);
351
337
  const isExitCell = isActiveCellAnExitCell(state, direction);
352
338
 
353
- // if in ACTION mode
354
- if (state.keyboardMode === ACTION_MODE) {
355
- // if not on last or first cell, tab through each cell of the grid
339
+ // If in ACTION mode.
340
+ if (state.keyboardMode === KEYBOARD_ACTION_MODE) {
341
+ // If not on last or first cell, tab through each cell of the grid.
356
342
  if (isExitCell === false) {
357
- // prevent default key event in action mode when actually moving within the grid
358
- if (event.detail.keyEvent) {
359
- event.detail.keyEvent.preventDefault();
343
+ // Prevent default key event in action mode when actually moving within the grid.
344
+ const { keyEvent } = detail;
345
+ if (keyEvent) {
346
+ keyEvent.preventDefault();
360
347
  }
361
- // tab in proper direction based on shift key press
348
+ // Tab in proper direction based on shift key press.
362
349
  if (direction === 'BACKWARD') {
363
- reactToTabBackward(element, state);
350
+ reactToTabBackward(state, template);
364
351
  } else {
365
- reactToTabForward(element, state);
352
+ reactToTabForward(state, template);
366
353
  }
367
354
  } else {
368
- // exit ACTION mode
369
- state.keyboardMode = NAVIGATION_MODE;
370
- setModeActiveCell(element, state);
355
+ // Untracked state change.
356
+ // Exit ACTION mode.
357
+ state.keyboardMode = KEYBOARD_NAVIGATION_MODE;
358
+ // Tracked state change.
359
+ setModeActiveCell(state, template);
360
+ // Untracked state change.
371
361
  state.isExitingActionMode = true;
372
362
  }
373
363
  } else {
364
+ // Untracked state change.
374
365
  state.isExitingActionMode = true;
375
366
  }
376
367
  }
377
368
 
378
- export function reactToTabForward(element, state) {
379
- const { nextRowIndex, nextColIndex } = getNextIndexOnTab(state, 'FORWARD');
380
- const { columns, rows } = state;
381
-
382
- setBlurActiveCell(element, state);
383
-
384
- // update activeCell
369
+ export function reactToTabForward(state, template) {
370
+ const { nextColIndex, nextRowIndex } = getNextIndexOnTab(state, 'FORWARD');
371
+ // Tracked state change.
372
+ setBlurActiveCell(state, template);
373
+ // Untracked state change.
374
+ // Update activeCell.
385
375
  state.activeCell = {
386
- rowKeyValue: nextRowIndex !== -1 ? rows[nextRowIndex].key : HEADER_ROW,
387
- colKeyValue: generateColKeyValue(columns[nextColIndex], nextColIndex),
376
+ rowKeyValue:
377
+ nextRowIndex === -1 ? HEADER_ROW_KEY : state.rows[nextRowIndex].key,
378
+ colKeyValue: generateColKeyValue(
379
+ state.columns[nextColIndex],
380
+ nextColIndex
381
+ ),
388
382
  };
389
- setFocusActiveCell(element, state, NAVIGATION_DIR.TAB_FORWARD, {
383
+ // Tracked state change.
384
+ setFocusActiveCell(state, template, NAVIGATION_DIR.TAB_FORWARD, {
390
385
  action: 'tab',
391
386
  });
392
387
  }
393
388
 
394
- export function reactToTabBackward(element, state) {
395
- const { nextRowIndex, nextColIndex } = getNextIndexOnTab(state, 'BACKWARD');
396
- const { columns, rows } = state;
397
-
398
- setBlurActiveCell(element, state);
399
-
400
- // update activeCell
389
+ export function reactToTabBackward(state, template) {
390
+ const { nextColIndex, nextRowIndex } = getNextIndexOnTab(state, 'BACKWARD');
391
+ // Tracked state change.
392
+ setBlurActiveCell(state, template);
393
+ // Untracked state change.
394
+ // Update activeCell.
401
395
  state.activeCell = {
402
- rowKeyValue: nextRowIndex !== -1 ? rows[nextRowIndex].key : HEADER_ROW,
403
- colKeyValue: generateColKeyValue(columns[nextColIndex], nextColIndex),
396
+ rowKeyValue:
397
+ nextRowIndex === -1 ? HEADER_ROW_KEY : state.rows[nextRowIndex].key,
398
+ colKeyValue: generateColKeyValue(
399
+ state.columns[nextColIndex],
400
+ nextColIndex
401
+ ),
404
402
  };
405
- setFocusActiveCell(element, state, NAVIGATION_DIR.TAB_BACKWARD, {
403
+ // Tracked state change.
404
+ setFocusActiveCell(state, template, NAVIGATION_DIR.TAB_BACKWARD, {
406
405
  action: 'tab',
407
406
  });
408
407
  }
@@ -413,20 +412,16 @@ function getTabDirection(shiftKey) {
413
412
 
414
413
  /**
415
414
  * Retrieve the next index values for row & column when tab is pressed
416
- * @param {object} state - datatable state
417
- * @param {string} direction - 'FORWARD' or 'BACKWARD'
418
- * @returns {object} - nextRowIndex, nextColIndex values, isExitCell boolean
415
+ * @param {Object} state - datatable state
416
+ * @param {String} direction - 'FORWARD' or 'BACKWARD'
417
+ * @returns {Object} - nextRowIndex, nextColIndex values, isExitCell boolean
419
418
  */
420
- function getNextIndexOnTab(state, direction) {
419
+ function getNextIndexOnTab(state, direction = 'FORWARD') {
421
420
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
422
-
423
421
  // decide which function to use based on the value of direction
424
- const nextTabFunc = {
425
- FORWARD: getNextIndexOnTabForward,
426
- BACKWARD: getNextIndexOnTabBackward,
427
- };
428
-
429
- return nextTabFunc[direction](state, rowIndex, colIndex);
422
+ return direction === 'BACKWARD'
423
+ ? getNextIndexOnTabBackward(state, rowIndex, colIndex)
424
+ : getNextIndexOnTabForward(state, rowIndex, colIndex);
430
425
  }
431
426
 
432
427
  function getNextIndexOnTabForward(state, rowIndex, colIndex) {
@@ -471,105 +466,91 @@ function getNextIndexOnTabBackward(state, rowIndex, colIndex) {
471
466
  * and will remove the user from row mode and place them in navigation mode
472
467
  * Arrow Left: If cell is expanded, this will collapse the expanded row
473
468
  *
474
- * @param {*} datatable - The datatable component/instance
475
- * @param {*} state - The datatable state object
476
- * @param {*} event - The keydown event
469
+ * @param {Object} dt - The datatable instance
470
+ * @param {Object} event - The keydown event
477
471
  * @returns Mutated state
478
472
  */
479
- export function reactToKeyboardOnRow(datatable, state, event) {
473
+ export function reactToKeyboardOnRow(dt, event) {
474
+ const { state, template } = dt;
480
475
  // TODO: Adapt this selector to also work in a role-based table once tree-grid is also migrated
476
+ const { localName } = event.target;
481
477
  if (
482
- isRowNavigationMode(state) &&
483
- event.target.localName.indexOf('tr') !== -1
478
+ localName &&
479
+ localName.indexOf('tr') !== -1 &&
480
+ isRowNavigationMode(state)
484
481
  ) {
485
- const element = datatable.template;
486
482
  switch (event.detail.keyCode) {
487
483
  case ARROW_LEFT:
488
- return reactToArrowLeftOnRow.call(
489
- datatable,
490
- element,
491
- state,
492
- event
493
- );
484
+ reactToArrowLeftOnRow(dt, state, template, event);
485
+ break;
494
486
  case ARROW_RIGHT:
495
- return reactToArrowRightOnRow.call(
496
- datatable,
497
- element,
498
- state,
499
- event
500
- );
487
+ reactToArrowRightOnRow(dt, state, template, event);
488
+ break;
501
489
  case ARROW_UP:
502
- return reactToArrowUpOnRow.call(
503
- datatable,
504
- element,
505
- state,
506
- event
507
- );
490
+ reactToArrowUpOnRow(dt, state, template, event);
491
+ break;
508
492
  case ARROW_DOWN:
509
- return reactToArrowDownOnRow.call(
510
- datatable,
511
- element,
512
- state,
513
- event
514
- );
493
+ reactToArrowDownOnRow(dt, state, template, event);
494
+ break;
515
495
  default:
516
- return state;
496
+ break;
517
497
  }
518
498
  }
519
- return state;
520
499
  }
521
500
 
522
- function reactToArrowLeftOnRow(element, state, event) {
501
+ function reactToArrowLeftOnRow(dt, state, template, event) {
523
502
  const { rowKeyValue, rowHasChildren, rowExpanded, rowLevel } = event.detail;
524
- // check if row needs to be collapsed
525
- // if not go to parent and focus there
503
+ // Check if row needs to be collapsed.
504
+ // If not, go to parent and focus there.
526
505
  if (rowHasChildren && rowExpanded) {
527
- fireRowToggleEvent.call(this, rowKeyValue, rowExpanded);
506
+ fireRowToggleEvent(dt, rowKeyValue, rowExpanded);
528
507
  } else if (rowLevel > 1) {
529
508
  const treeColumn = getStateTreeColumn(state);
530
509
  if (treeColumn) {
531
- const colKeyValue = treeColumn.colKeyValue;
510
+ const { colKeyValue } = treeColumn;
532
511
  const { rowIndex } = getIndexesByKeys(
533
512
  state,
534
513
  rowKeyValue,
535
514
  colKeyValue
536
515
  );
537
- const parentIndex = getRowParent(state, rowLevel, rowIndex);
516
+ const parentIndex = getRowParentIndex(state, rowLevel, rowIndex);
538
517
  if (parentIndex !== -1) {
539
- const rows = state.rows;
540
- setBlurActiveRow(element, state);
541
- // update activeCell for the row
518
+ // Tracked state change.
519
+ setBlurActiveRow(state, template);
520
+ // Untracked state change.
521
+ // Update activeCell for the row.
542
522
  state.activeCell = {
543
- rowKeyValue: rows[parentIndex].key,
523
+ rowKeyValue: state.rows[parentIndex].key,
544
524
  colKeyValue,
545
525
  };
546
- setFocusActiveRow(element, state);
526
+ // Tracked state change.
527
+ setFocusActiveRow(state, template);
547
528
  }
548
529
  }
549
530
  }
550
531
  }
551
532
 
552
- function moveFromRowToCell(element, state) {
553
- setBlurActiveRow(element, state);
554
- unsetRowNavigationMode(state);
555
- setFocusActiveCell(element, state, NAVIGATION_DIR.USE_CURRENT);
556
- }
557
-
558
- function reactToArrowRightOnRow(element, state, event) {
533
+ function reactToArrowRightOnRow(dt, state, template, event) {
559
534
  const { rowKeyValue, rowHasChildren, rowExpanded } = event.detail;
560
- // check if row needs to be expanded
561
- // expand row if has children and is collapsed
562
- // otherwise make this.state.rowMode = false
563
- // move tabindex 0 to first cell in the row and focus there
535
+ // Check if row needs to be expanded.
536
+ // Expand row if has children and is collapsed.
537
+ // Otherwise, make this.state.rowMode = false.
538
+ // Move tabIndex 0 to first cell in the row and focus there.
564
539
  if (rowHasChildren && !rowExpanded) {
565
- fireRowToggleEvent.call(this, rowKeyValue, rowExpanded);
540
+ fireRowToggleEvent(dt, rowKeyValue, rowExpanded);
566
541
  } else {
567
- moveFromRowToCell(element, state);
542
+ // Tracked state change.
543
+ // Move from row to cell.
544
+ setBlurActiveRow(state, template);
545
+ // Untracked state change.
546
+ unsetRowNavigationMode(state);
547
+ // Tracked state change.
548
+ setFocusActiveCell(state, template, NAVIGATION_DIR.USE_CURRENT);
568
549
  }
569
550
  }
570
551
 
571
- function reactToArrowUpOnRow(element, state, event) {
572
- // move tabindex 0 one row down
552
+ function reactToArrowUpOnRow(state, template, event) {
553
+ // Move tabIndex 0 one row down.
573
554
  const { rowKeyValue, keyEvent } = event.detail;
574
555
  const treeColumn = getStateTreeColumn(state);
575
556
 
@@ -577,24 +558,26 @@ function reactToArrowUpOnRow(element, state, event) {
577
558
  keyEvent.preventDefault();
578
559
 
579
560
  if (treeColumn) {
580
- const colKeyValue = treeColumn.colKeyValue;
561
+ const { colKeyValue } = treeColumn;
581
562
  const { rowIndex } = getIndexesByKeys(state, rowKeyValue, colKeyValue);
582
563
  const prevRowIndex = getNextIndexUpWrapped(state, rowIndex);
583
- const { rows } = state;
584
564
  if (prevRowIndex !== -1) {
585
- setBlurActiveRow(element, state);
586
- // update activeCell for the row
565
+ // Tracked state change.
566
+ setBlurActiveRow(state, template);
567
+ // Untracked state change.
568
+ // Update activeCell for the row.
587
569
  state.activeCell = {
588
- rowKeyValue: rows[prevRowIndex].key,
570
+ rowKeyValue: state.rows[prevRowIndex].key,
589
571
  colKeyValue,
590
572
  };
591
- setFocusActiveRow(element, state);
573
+ // Tracked state change.
574
+ setFocusActiveRow(state, template);
592
575
  }
593
576
  }
594
577
  }
595
578
 
596
- function reactToArrowDownOnRow(element, state, event) {
597
- // move tabindex 0 one row down
579
+ function reactToArrowDownOnRow(state, template, event) {
580
+ // Move tabIndex 0 one row down.
598
581
  const { rowKeyValue, keyEvent } = event.detail;
599
582
  const treeColumn = getStateTreeColumn(state);
600
583
 
@@ -602,18 +585,20 @@ function reactToArrowDownOnRow(element, state, event) {
602
585
  keyEvent.preventDefault();
603
586
 
604
587
  if (treeColumn) {
605
- const colKeyValue = treeColumn.colKeyValue;
588
+ const { colKeyValue } = treeColumn;
606
589
  const { rowIndex } = getIndexesByKeys(state, rowKeyValue, colKeyValue);
607
590
  const nextRowIndex = getNextIndexDownWrapped(state, rowIndex);
608
- const { rows } = state;
609
591
  if (nextRowIndex !== -1) {
610
- setBlurActiveRow(element, state);
611
- // update activeCell for the row
592
+ // Tracked state change.
593
+ setBlurActiveRow(state, template);
594
+ // Untracked state change.
595
+ // Update activeCell for the row.
612
596
  state.activeCell = {
613
- rowKeyValue: rows[nextRowIndex].key,
597
+ rowKeyValue: state.rows[nextRowIndex].key,
614
598
  colKeyValue,
615
599
  };
616
- setFocusActiveRow(element, state);
600
+ // Tracked state change.
601
+ setFocusActiveRow(state, template);
617
602
  }
618
603
  }
619
604
  }
@@ -621,20 +606,24 @@ function reactToArrowDownOnRow(element, state, event) {
621
606
  /***************************** ACTIVE CELL *****************************/
622
607
 
623
608
  function getDefaultActiveCell(state) {
624
- const { columns, rows } = state;
625
- if (columns.length > 0) {
626
- let colIndex;
627
- const existCustomerColumn = columns.some((column, index) => {
628
- colIndex = index;
629
- return isCustomerColumn(column);
630
- });
631
-
609
+ const { columns } = state;
610
+ const { length: colCount } = columns;
611
+ if (colCount) {
612
+ let colIndex = 0;
613
+ let existCustomerColumn = false;
614
+ for (let i = 0; i < colCount; i += 1) {
615
+ colIndex = i;
616
+ if (columns[i].internal !== true) {
617
+ existCustomerColumn = true;
618
+ break;
619
+ }
620
+ }
632
621
  if (!existCustomerColumn) {
633
622
  colIndex = 0;
634
623
  }
635
-
624
+ const { rows } = state;
636
625
  return {
637
- rowKeyValue: rows.length > 0 ? rows[0].key : HEADER_ROW,
626
+ rowKeyValue: rows.length > 0 ? rows[0].key : HEADER_ROW_KEY,
638
627
  colKeyValue: generateColKeyValue(columns[colIndex], colIndex),
639
628
  };
640
629
  }
@@ -650,31 +639,35 @@ function setDefaultActiveCell(state) {
650
639
  * Given a datatable template and state, returns an LWC component reference that represents
651
640
  * the currently active cell in the table.
652
641
  *
653
- * @param {Object} template - A reference to the datatable's template
654
- * @param {Object} state - A reference to the datatable's state
642
+ * @param {Object} template - The datatable template
643
+ * @param {Object} state - The datatable state
655
644
  */
656
645
  export function getActiveCellElement(template, state) {
657
- if (state.activeCell) {
658
- const { rowKeyValue, colKeyValue } = state.activeCell;
659
- return getCellElementByKeys(template, rowKeyValue, colKeyValue);
660
- }
661
- return null;
646
+ const { activeCell } = state;
647
+ return activeCell
648
+ ? getCellElementByKeys(
649
+ template,
650
+ activeCell.rowKeyValue,
651
+ activeCell.colKeyValue
652
+ )
653
+ : null;
662
654
  }
663
655
 
664
656
  /**
665
657
  * Returns if the pair rowKeyValue, colKeyValue are the current activeCell values
666
658
  *
667
- * @param {object} state - datatable state
668
- * @param {string} rowKeyValue - the unique row key value
669
- * @param {string} colKeyValue {string} - the unique col key value
670
- * @returns {boolean} - true if rowKeyValue, colKeyValue are the current activeCell values.
659
+ * @param {Object} state - datatable state
660
+ * @param {String} rowKeyValue - the unique row key value
661
+ * @param {String} colKeyValue {string} - the unique col key value
662
+ * @returns {Boolean} - true if rowKeyValue, colKeyValue are the current activeCell values.
671
663
  */
672
664
  export function isActiveCell(state, rowKeyValue, colKeyValue) {
673
- if (state.activeCell) {
665
+ const { activeCell } = state;
666
+ if (activeCell) {
674
667
  const {
675
668
  rowKeyValue: currentRowKeyValue,
676
669
  colKeyValue: currentColKeyValue,
677
- } = state.activeCell;
670
+ } = activeCell;
678
671
  return (
679
672
  currentRowKeyValue === rowKeyValue &&
680
673
  currentColKeyValue === colKeyValue
@@ -683,41 +676,26 @@ export function isActiveCell(state, rowKeyValue, colKeyValue) {
683
676
  return false;
684
677
  }
685
678
 
686
- /**
687
- * Updates the current activeCell in the state with the new rowKeyValue, colKeyValue
688
- * @param {object} state - datatable state
689
- * @param {string} rowKeyValue - the unique row key value
690
- * @param {string} colKeyValue {string} - the unique col key value
691
- * @returns {object} state - mutated datatable state
692
- */
693
- export function updateActiveCell(state, rowKeyValue, colKeyValue) {
694
- state.activeCell = {
695
- rowKeyValue,
696
- colKeyValue,
697
- };
698
- return state;
699
- }
700
-
701
679
  /**
702
680
  * It check if in the current (data, columns) the activeCell still valid.
703
681
  * When data changed the activeCell could be removed, then we check if there is cellToFocusNext
704
682
  * which is calculated from previously focused cell, if so we sync to that
705
683
  * If active cell is still valid we keep it the same
706
684
  *
707
- * @param {object} state - datatable state
708
- * @returns {object} state - mutated datatable state
685
+ * @param {Object} state - The datatable state
709
686
  */
710
687
  export function syncActiveCell(state) {
711
- if (!state.activeCell || !stillValidActiveCell(state)) {
712
- if (state.activeCell && state.cellToFocusNext) {
713
- // there is previously focused cell
688
+ const { activeCell } = state;
689
+ if (!activeCell || !stillValidActiveCell(state)) {
690
+ // Untracked state changes.
691
+ if (activeCell && state.cellToFocusNext) {
692
+ // There is previously focused cell.
714
693
  setNextActiveCellFromPrev(state);
715
694
  } else {
716
- // there is no active cell or there is no previously focused cell
695
+ // There is no active cell or there is no previously focused cell.
717
696
  setDefaultActiveCell(state);
718
697
  }
719
698
  }
720
- return state;
721
699
  }
722
700
 
723
701
  /**
@@ -731,37 +709,38 @@ export function syncActiveCell(state) {
731
709
  */
732
710
  function setNextActiveCellFromPrev(state) {
733
711
  const { rowIndex, colIndex } = state.cellToFocusNext;
712
+ const { columns, rows } = state;
713
+ const { length: rowCount } = rows;
734
714
  let nextRowIndex = rowIndex;
735
- let nextColIndex = colIndex;
736
- const rowsCount = state.rows ? state.rows.length : 0;
737
- const colsCount = state.columns.length ? state.columns.length : 0;
738
-
739
- if (nextRowIndex > rowsCount - 1) {
715
+ if (nextRowIndex > rowCount - 1) {
740
716
  // row index not existing after update to new 5 > 5-1, 6 > 5-1,
741
- nextRowIndex = rowsCount - 1;
717
+ nextRowIndex = rowCount - 1;
742
718
  }
743
- if (nextColIndex > colsCount - 1) {
719
+ const { length: colCount } = columns;
720
+ let nextColIndex = colIndex;
721
+ if (nextColIndex > colCount - 1) {
744
722
  // col index not existing after update to new
745
- nextColIndex = colsCount - 1;
723
+ nextColIndex = colCount - 1;
746
724
  }
747
725
  const nextActiveCell = getCellFromIndexes(
748
726
  state,
749
727
  nextRowIndex,
750
728
  nextColIndex
751
729
  );
730
+ // Untracked state changes.
752
731
  if (nextActiveCell) {
753
732
  state.activeCell = nextActiveCell;
754
733
  } else {
755
734
  setDefaultActiveCell(state);
756
735
  }
757
- state.keyboardMode = NAVIGATION_MODE;
736
+ state.keyboardMode = KEYBOARD_NAVIGATION_MODE;
758
737
  }
759
738
 
760
739
  /**
761
740
  * Check if we're in an escape/exit cell (first or last of grid)
762
- * @param {object} state - datatable state
763
- * @param {string} direction - 'FORWARD' or 'BACKWARD'
764
- * @returns {boolean} - if the current cell is or isn't an exit cell
741
+ * @param {Object} state - The datatable state
742
+ * @param {String} direction - 'FORWARD' or 'BACKWARD'
743
+ * @returns {Boolean} - if the current cell is or isn't an exit cell
765
744
  */
766
745
  export function isActiveCellAnExitCell(state, direction) {
767
746
  // get next tab index values
@@ -790,60 +769,65 @@ export function getIndexesActiveCell(state) {
790
769
  return getIndexesByKeys(state, rowKeyValue, colKeyValue);
791
770
  }
792
771
 
793
- function setModeActiveCell(element, state, info) {
794
- const cellElement = getActiveCellElement(element, state);
772
+ function setModeActiveCell(state, template, info) {
773
+ const cellElement = getActiveCellElement(template, state);
795
774
  if (cellElement) {
796
775
  cellElement.setMode(state.keyboardMode, info);
797
776
  }
798
777
  }
799
778
 
800
779
  function stillValidActiveCell(state) {
801
- const {
802
- activeCell: { rowKeyValue, colKeyValue },
803
- } = state;
804
-
805
- let sortableColumns = state.columns.filter((column) => column.sortable);
806
-
807
- if (rowKeyValue === HEADER_ROW) {
808
- if (state.rows.length && sortableColumns.length === 0) {
809
- return false;
780
+ const { activeCell, indexes } = state;
781
+ const { rowKeyValue, colKeyValue } = activeCell;
782
+ if (rowKeyValue === HEADER_ROW_KEY) {
783
+ if (state.rows.length) {
784
+ const { columns } = state;
785
+ let sortable = false;
786
+ for (let colIndex = 0; colIndex < columns.length; colIndex += 1) {
787
+ if (columns[colIndex].sortable) {
788
+ sortable = true;
789
+ break;
790
+ }
791
+ }
792
+ if (!sortable) {
793
+ return false;
794
+ }
810
795
  }
811
796
  return state.headerIndexes[colKeyValue] !== undefined;
812
797
  }
813
- return !!(
814
- state.indexes[rowKeyValue] && state.indexes[rowKeyValue][colKeyValue]
815
- );
798
+ return !!(indexes[rowKeyValue] && indexes[rowKeyValue][colKeyValue]);
816
799
  }
817
800
 
818
801
  /***************************** FOCUS MANAGEMENT *****************************/
819
802
 
820
803
  /**
821
804
  * It set the focus to the current activeCell, this operation imply multiple changes
822
- * - update the tabindex of the activeCell
805
+ * - update the tabIndex of the activeCell
823
806
  * - set the current keyboard mode
824
807
  * - set the focus to the cell
825
- * @param {node} template - the custom element template `this.template`
826
- * @param {object} state - datatable state
827
- * @param {int} direction - direction (-1 left, 1 right and 0 for no direction) its used to know which actionable element to activate.
828
- * @param {object} info - extra information when setting the cell mode; currently only set when pressing tab
829
- * @param {boolean} shouldScroll - true if scrollTop should be adjusted when setting focus
808
+ * @param {Object} state - The datatable state
809
+ * @param {Node} template - The custom element template `this.template`
810
+ * @param {Integer} direction - The direction (-1 left, 1 right and 0 for no direction) its used to know which actionable element to activate.
811
+ * @param {Object} info - Extra information when setting the cell mode; currently only set when pressing tab
812
+ * @param {Boolean} [shouldScroll = true] - Whether scrollTop should be adjusted when setting focus
830
813
  */
831
814
  export function setFocusActiveCell(
832
- template,
833
815
  state,
816
+ template,
834
817
  direction,
835
818
  info,
836
819
  shouldScroll = true
837
820
  ) {
838
821
  const { keyboardMode } = state;
839
822
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
823
+ let cellElement = getActiveCellElement(template, state);
840
824
 
841
825
  state.activeCell.focused = !(info && isActiveCellValid(state));
842
- updateTabIndex(state, rowIndex, colIndex);
843
826
 
844
- let cellElement = getActiveCellElement(template, state);
827
+ updateCellTabIndex(state, rowIndex, colIndex);
828
+
845
829
  // if the cell wasn't found, but does exist in the table, scroll to where it should be
846
- if (!cellElement && isActiveCellValid(state) && shouldScroll) {
830
+ if (shouldScroll && !cellElement && isActiveCellValid(state)) {
847
831
  scrollToCell(state, template, rowIndex);
848
832
  }
849
833
 
@@ -883,15 +867,15 @@ export function setFocusActiveCell(
883
867
  /**
884
868
  * It blur to the current activeCell, this operation imply multiple changes
885
869
  * - blur the activeCell
886
- * - update the tabindex to -1
887
- * @param {node} template - the custom element root `this.template`
888
- * @param {object} state - datatable state
870
+ * - update the tabIndex to -1
871
+ * @param {Object} state - The datatable state
872
+ * @param {Node} template - The custom element root `this.template`
889
873
  */
890
- export function setBlurActiveCell(template, state) {
874
+ export function setBlurActiveCell(state, template) {
891
875
  if (state.activeCell) {
892
876
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
893
- let cellElement = getActiveCellElement(template, state);
894
877
  state.activeCell.focused = false;
878
+ let cellElement = getActiveCellElement(template, state);
895
879
  // eslint-disable-next-line @lwc/lwc/no-async-operation
896
880
  setTimeout(() => {
897
881
  // check cellElement; value may have changed
@@ -913,7 +897,7 @@ export function setBlurActiveCell(template, state) {
913
897
  cellElement.parentElement.classList.remove(FOCUS_CLASS);
914
898
  }
915
899
  }, 0);
916
- updateTabIndex(state, rowIndex, colIndex, -1);
900
+ updateCellTabIndex(state, rowIndex, colIndex, -1);
917
901
  }
918
902
  }
919
903
 
@@ -924,23 +908,26 @@ export function setBlurActiveCell(template, state) {
924
908
  * there is state.indexes
925
909
  * there is no previously set state.cellToFocusNext
926
910
  * Indexes are calculated as to what to focus on next
927
- * @param {object} state - datatable state
928
- * @param {object} template - datatable element
911
+ * @param {Object} state - The datatable state
912
+ * @param {Object} template - The datatable element
929
913
  */
930
914
  export function setCellToFocusFromPrev(state, template) {
931
915
  if (
932
916
  state.activeCell &&
933
- datatableHasFocus(state, template) &&
934
- state.indexes &&
935
- !state.cellToFocusNext
917
+ !state.cellToFocusNext &&
918
+ datatableHasFocus(state, template)
936
919
  ) {
920
+ const { length: rowCount } = state.rows;
921
+ const lastIndex = rowCount - 1;
922
+ const { length: colCount } = state.columns;
937
923
  let { rowIndex, colIndex } = getIndexesActiveCell(state);
938
924
  colIndex = 0; // default point to the first column
939
- if (state.rows && rowIndex === state.rows.length - 1) {
925
+ if (rowIndex === lastIndex) {
940
926
  // if it is last row, make it point to its previous row
941
- rowIndex = state.rows.length - 1;
942
- colIndex = state.columns ? state.columns.length - 1 : 0;
927
+ rowIndex = lastIndex;
928
+ colIndex = colCount ? colCount - 1 : 0;
943
929
  }
930
+ // Untracked state change.
944
931
  state.cellToFocusNext = {
945
932
  rowIndex,
946
933
  colIndex,
@@ -949,8 +936,8 @@ export function setCellToFocusFromPrev(state, template) {
949
936
  }
950
937
 
951
938
  /**
952
- * if the current new active still is valid (exists) then set the celltofocusnext to null
953
- * @param {object} state - datatable state
939
+ * If the current new active still is valid (exists) then set the celltofocusnext to null.
940
+ * @param {Object} state - The datatable state
954
941
  */
955
942
  export function updateCellToFocusFromPrev(state) {
956
943
  if (
@@ -958,29 +945,20 @@ export function updateCellToFocusFromPrev(state) {
958
945
  state.cellToFocusNext &&
959
946
  stillValidActiveCell(state)
960
947
  ) {
961
- // if the previous focus is there and valid, don't set the prevActiveFocusedCell
948
+ // If the previous focus is there and valid, don't set the prevActiveFocusedCell.
962
949
  state.cellToFocusNext = null;
963
950
  }
964
951
  }
965
952
 
966
- /**
967
- * reset celltofocusnext to null (used after render)
968
- * @param {object} state - datatable state
969
- */
970
- export function resetCellToFocusFromPrev(state) {
971
- state.cellToFocusNext = null;
972
- }
973
-
974
953
  /**
975
954
  * It adds and the focus classes to the th/td or div[role=gridcell/rowheader].
976
955
  *
977
- * @param {node} template - the custom element template `this.template`
978
- * @param {object} state - datatable state
956
+ * @param {Object} state - The datatable state
957
+ * @param {Node} template - The custom element template `this.template`
979
958
  */
980
- export function addFocusStylesToActiveCell(template, state) {
981
- const cellElement = getActiveCellElement(template, state);
959
+ export function addFocusStylesToActiveCell(state, template) {
982
960
  state.activeCell.focused = true;
983
-
961
+ const cellElement = getActiveCellElement(template, state);
984
962
  if (cellElement) {
985
963
  cellElement.parentElement.classList.add(FOCUS_CLASS);
986
964
  }
@@ -988,53 +966,54 @@ export function addFocusStylesToActiveCell(template, state) {
988
966
 
989
967
  /**
990
968
  * It set the focus to the row of current activeCell, this operation implies multiple changes
991
- * - update the tabindex of the activeCell
969
+ * - update the tabIndex of the activeCell
992
970
  * - set the current keyboard mode
993
971
  * - set the focus to the row
994
- * @param {node} template - the custom element root `this.template`
995
- * @param {object} state - datatable state
972
+ *
973
+ * @param {Object} state - The datatable state
974
+ * @param {Node} template - the custom element root `this.template`
996
975
  */
997
- function setFocusActiveRow(template, state) {
976
+ function setFocusActiveRow(state, template) {
998
977
  const { rowIndex } = getIndexesActiveCell(state);
999
- const row = getActiveCellRow(template, state);
978
+ const rowElement = getActiveCellRowElement(template, state);
1000
979
 
1001
- updateTabIndexRow(state, rowIndex);
980
+ updateRowTabIndex(state, rowIndex);
1002
981
  // eslint-disable-next-line @lwc/lwc/no-async-operation
1003
982
  setTimeout(() => {
1004
- row.focus({ preventScroll: true });
1005
- updateScrollTop(state, template, row);
983
+ rowElement.focus({ preventScroll: true });
984
+ updateScrollTop(state, template, rowElement);
1006
985
  }, 0);
1007
986
  }
1008
987
 
1009
988
  /**
1010
989
  * It blurs the active row, this operation implies multiple changes
1011
990
  * - blur the active row
1012
- * - update the tabindex to -1
1013
- * @param {node} template - the custom element root `this.template`
1014
- * @param {object} state - datatable state
991
+ * - update the tabIndex to -1
992
+ * @param {Object} state - The datatable state
993
+ * @param {Node} template - The custom element root `this.template`
1015
994
  */
1016
- function setBlurActiveRow(template, state) {
995
+ function setBlurActiveRow(state, template) {
1017
996
  if (state.activeCell) {
1018
997
  const { rowIndex } = getIndexesActiveCell(state);
1019
998
  // eslint-disable-next-line @lwc/lwc/no-async-operation
1020
999
  setTimeout(() => {
1021
- const row = getActiveCellRow(template, state);
1022
- if (document.activeElement === row) {
1023
- row.blur();
1000
+ const rowElement = getActiveCellRowElement(template, state);
1001
+ if (document.activeElement === rowElement) {
1002
+ rowElement.blur();
1024
1003
  }
1025
1004
  }, 0);
1026
- updateTabIndexRow(state, rowIndex, -1);
1005
+ updateRowTabIndex(state, rowIndex, -1);
1027
1006
  }
1028
1007
  }
1029
1008
 
1030
1009
  /**
1031
1010
  * This method is needed in IE11 where clicking on the cell (factory) makes the div or the span active element
1032
1011
  * It refocuses on the cell element td or th or div[role=gridcell/rowheader]
1033
- * @param {object} template - datatable element
1034
- * @param {object} state - datatable state
1035
- * @param {boolean} needsRefocusOnCellElement - flag indicating whether or not to refocus on the cell td/th or div[role=gridcell/rowheader]
1012
+ * @param {Object} state - The datatable state
1013
+ * @param {Object} template - The datatable element
1014
+ * @param {Boolean} needsRefocusOnCellElement - flag indicating whether or not to refocus on the cell td/th or div[role=gridcell/rowheader]
1036
1015
  */
1037
- export function refocusCellElement(template, state, needsRefocusOnCellElement) {
1016
+ export function refocusCellElement(state, template, needsRefocusOnCellElement) {
1038
1017
  if (needsRefocusOnCellElement) {
1039
1018
  const cellElement = getActiveCellElement(template, state);
1040
1019
  if (cellElement) {
@@ -1052,23 +1031,28 @@ export function refocusCellElement(template, state, needsRefocusOnCellElement) {
1052
1031
  }
1053
1032
 
1054
1033
  export function datatableHasFocus(state, template) {
1055
- return isFocusInside(template) || state.cellClicked;
1034
+ return state.cellClicked || isFocusInside(template);
1056
1035
  }
1057
1036
 
1058
1037
  function isFocusInside(currentTarget) {
1059
1038
  const activeElements = getShadowActiveElements();
1060
- return activeElements.some((element) => {
1061
- return currentTarget.contains(element);
1062
- });
1039
+ for (let i = 0, { length } = activeElements; i < length; i += 1) {
1040
+ if (currentTarget.contains(activeElements[i])) {
1041
+ return true;
1042
+ }
1043
+ }
1044
+ return false;
1063
1045
  }
1064
1046
 
1065
1047
  export function handleDatatableFocusIn(event) {
1066
1048
  const { state } = this;
1049
+
1050
+ // Untracked state change.
1067
1051
  state.isExitingActionMode = false;
1068
1052
 
1069
1053
  // workaround for delegatesFocus issue that focusin is called when not supposed to W-6220418
1070
1054
  if (isFocusInside(event.currentTarget)) {
1071
- if (!state.rowMode && state.activeCell) {
1055
+ if (state.activeCell && !state.rowMode) {
1072
1056
  state.activeCell.focused = true;
1073
1057
  const cellElement = getActiveCellElement(this.template, state);
1074
1058
  // we need to check because of the tree,
@@ -1085,17 +1069,17 @@ export function handleDatatableFocusIn(event) {
1085
1069
 
1086
1070
  export function handleDatatableFocusOut(event) {
1087
1071
  const { state } = this;
1072
+ const { currentTarget, relatedTarget } = event;
1073
+ const containsRelatedTarget =
1074
+ relatedTarget && currentTarget.contains(relatedTarget);
1088
1075
  // workarounds for delegatesFocus issues
1089
1076
  if (
1090
1077
  // needed for initial focus where relatedTarget is empty
1091
- !event.relatedTarget ||
1078
+ !relatedTarget ||
1092
1079
  // needed when clicked outside
1093
- (event.relatedTarget &&
1094
- !event.currentTarget.contains(event.relatedTarget)) ||
1080
+ (relatedTarget && !containsRelatedTarget) ||
1095
1081
  // needed when datatable leaves focus and related target is still within datatable W-6185154
1096
- (event.relatedTarget &&
1097
- event.currentTarget.contains(event.relatedTarget) &&
1098
- state.isExitingActionMode)
1082
+ (relatedTarget && containsRelatedTarget && state.isExitingActionMode)
1099
1083
  ) {
1100
1084
  if (state.activeCell && !state.rowMode) {
1101
1085
  const cellElement = getActiveCellElement(this.template, state);
@@ -1111,7 +1095,7 @@ export function handleDatatableFocusOut(event) {
1111
1095
 
1112
1096
  /**
1113
1097
  * This is needed to check if datatable has lost focus but cell has been clicked recently
1114
- * @param {object} state - datatable state
1098
+ * @param {Object} state - The datatable state
1115
1099
  */
1116
1100
  export function setCellClickedForFocus(state) {
1117
1101
  state.cellClicked = true;
@@ -1119,7 +1103,7 @@ export function setCellClickedForFocus(state) {
1119
1103
 
1120
1104
  /**
1121
1105
  * Once the dt regains focus there is no need to set this
1122
- * @param {object} state - datatable state
1106
+ * @param {Object} state - The datatable state
1123
1107
  */
1124
1108
  function resetCellClickedForFocus(state) {
1125
1109
  state.cellClicked = false;
@@ -1130,19 +1114,18 @@ function resetCellClickedForFocus(state) {
1130
1114
  /**
1131
1115
  * It update the tabIndex value of a cell in the state for the rowIndex, colIndex passed
1132
1116
  * as consequence of this change
1133
- * datatable is gonna re-render the cell affected with the new tabindex value
1117
+ * datatable is gonna re-render the cell affected with the new tabIndex value
1134
1118
  *
1135
- * @param {object} state - datatable state
1119
+ * @param {Object} state - The datatable state
1136
1120
  * @param {number} rowIndex - the row index
1137
1121
  * @param {number} colIndex - the column index
1138
- * @param {number} [index = 0] - the value for the tabindex
1122
+ * @param {number} [tabIndex = 0] - the value for the tabIndex
1139
1123
  */
1140
- export function updateTabIndex(state, rowIndex, colIndex, index = 0) {
1124
+ export function updateCellTabIndex(state, rowIndex, colIndex, tabIndex = 0) {
1141
1125
  if (isHeaderRow(rowIndex)) {
1142
- const { columns } = state;
1143
- columns[colIndex].tabIndex = index;
1126
+ state.columns[colIndex].tabIndex = tabIndex;
1144
1127
  } else {
1145
- state.rows[rowIndex].cells[colIndex].tabIndex = index;
1128
+ state.rows[rowIndex].cells[colIndex].tabIndex = tabIndex;
1146
1129
  }
1147
1130
  }
1148
1131
 
@@ -1151,50 +1134,47 @@ export function updateTabIndex(state, rowIndex, colIndex, index = 0) {
1151
1134
  * as consequence of this change
1152
1135
  * datatable is gonna re-render the row affected with the new tabindex value
1153
1136
  *
1154
- * @param {object} state - datatable state
1137
+ * @param {Object} state - The datatable state
1155
1138
  * @param {number} rowIndex - the row index
1156
1139
  * @param {number} [index = 0] - the value for the tabindex
1157
1140
  */
1158
- export function updateTabIndexRow(state, rowIndex, index = 0) {
1141
+ export function updateRowTabIndex(state, rowIndex, tabIndex = 0) {
1159
1142
  if (!isHeaderRow(rowIndex)) {
1160
1143
  // TODO what to do when rowIndex is header row
1161
- state.rows[rowIndex].tabIndex = index;
1144
+ state.rows[rowIndex].tabIndex = tabIndex;
1162
1145
  }
1163
1146
  }
1147
+
1164
1148
  /**
1165
- * It update the tabindex for the current activeCell.
1166
- * @param {object} state - datatable state
1149
+ * Updates the tabIndex for the current activeCell.
1150
+ *
1151
+ * @param {Object} state - The datatable state
1167
1152
  * @param {number} [index = 0] - the value for the tabindex
1168
- * @returns {object} state - mutated state
1169
1153
  */
1170
1154
  export function updateTabIndexActiveCell(state, index = 0) {
1171
1155
  if (state.activeCell && !stillValidActiveCell(state)) {
1156
+ // Untracked state change.
1172
1157
  syncActiveCell(state);
1173
1158
  }
1174
-
1175
- // we need to check again because maybe there is no active cell after sync
1159
+ // Tracked state change.
1160
+ // We need to check again because maybe there is no active cell after sync.
1176
1161
  updateActiveCellTabIndexAfterSync(state, index);
1177
- return state;
1178
1162
  }
1179
1163
 
1180
1164
  /**
1181
- * It updates the tabindex for the row of the current activeCell.
1182
- * This happens in rowMode of NAVIGATION_MODE
1183
- * @param {object} state - datatable state
1165
+ * It updates the tabIndex for the row of the current activeCell.
1166
+ * This happens in rowMode of KEYBOARD_NAVIGATION_MODE
1167
+ * @param {Object} state - The datatable state
1184
1168
  * @param {number} [index = 0] - the value for the tabindex
1185
- * @returns {object} state - mutated state
1186
1169
  */
1187
1170
  export function updateTabIndexActiveRow(state, index = 0) {
1188
1171
  if (state.activeCell && !stillValidActiveCell(state)) {
1172
+ // Untracked state change.
1189
1173
  syncActiveCell(state);
1190
1174
  }
1191
-
1192
- // we need to check again because maybe there is no active cell after sync
1193
- if (state.activeCell && isRowNavigationMode(state)) {
1194
- const { rowIndex } = getIndexesActiveCell(state);
1195
- updateTabIndexRow(state, rowIndex, index);
1196
- }
1197
- return state;
1175
+ // Tracked state change.
1176
+ // We need to check again because maybe there is no active cell after sync.
1177
+ updateActiveRowTabIndexAfterSync(state, index);
1198
1178
  }
1199
1179
 
1200
1180
  /***************************** INDEX COMPUTATIONS *****************************/
@@ -1208,7 +1188,7 @@ export function updateTabIndexActiveRow(state, index = 0) {
1208
1188
  * @returns {object} - {rowIndex, colIndex}
1209
1189
  */
1210
1190
  export function getIndexesByKeys(state, rowKeyValue, colKeyValue) {
1211
- if (rowKeyValue === HEADER_ROW) {
1191
+ if (rowKeyValue === HEADER_ROW_KEY) {
1212
1192
  return {
1213
1193
  rowIndex: -1,
1214
1194
  colIndex: state.headerIndexes[colKeyValue],
@@ -1239,42 +1219,48 @@ function getPrevColumnIndex(colIndex) {
1239
1219
  }
1240
1220
 
1241
1221
  function getNextIndexRight(state, colIndex) {
1242
- if (isRTL()) {
1243
- return getPrevColumnIndex(colIndex);
1244
- }
1245
-
1246
- return getNextColumnIndex(state.columns.length, colIndex);
1222
+ return isRTL()
1223
+ ? getPrevColumnIndex(colIndex)
1224
+ : getNextColumnIndex(state.columns.length, colIndex);
1247
1225
  }
1248
1226
 
1249
1227
  function getNextIndexLeft(state, colIndex) {
1250
- if (isRTL()) {
1251
- return getNextColumnIndex(state.columns.length, colIndex);
1252
- }
1253
- return getPrevColumnIndex(colIndex);
1228
+ return isRTL()
1229
+ ? getNextColumnIndex(state.columns.length, colIndex)
1230
+ : getPrevColumnIndex(colIndex);
1254
1231
  }
1255
1232
 
1256
1233
  function getNextIndexUpWrapped(state, rowIndex) {
1257
- const rowsCount = state.rows.length;
1258
- return rowIndex === 0 ? -1 : rowIndex === -1 ? rowsCount - 1 : rowIndex - 1;
1234
+ const { length: rowCount } = state.rows;
1235
+ return rowIndex === -1 ? rowCount - 1 : rowIndex - 1;
1259
1236
  }
1260
1237
 
1261
1238
  function getNextIndexDownWrapped(state, rowIndex) {
1262
- const rowsCount = state.rows.length;
1263
- return rowIndex + 1 < rowsCount ? rowIndex + 1 : -1;
1239
+ const { length: rowCount } = state.rows;
1240
+ return rowIndex + 1 < rowCount ? rowIndex + 1 : -1;
1264
1241
  }
1265
1242
 
1266
1243
  /***************************** ROW NAVIGATION MODE *****************************/
1267
1244
 
1268
1245
  function canBeRowNavigationMode(state) {
1269
- return state.keyboardMode === NAVIGATION_MODE && hasTreeDataType(state);
1246
+ return (
1247
+ state.keyboardMode === KEYBOARD_NAVIGATION_MODE &&
1248
+ hasTreeDataType(state)
1249
+ );
1270
1250
  }
1271
1251
 
1272
1252
  function isRowNavigationMode(state) {
1273
- return state.keyboardMode === NAVIGATION_MODE && state.rowMode === true;
1253
+ return (
1254
+ state.keyboardMode === KEYBOARD_NAVIGATION_MODE &&
1255
+ state.rowMode === true
1256
+ );
1274
1257
  }
1275
1258
 
1276
1259
  function setRowNavigationMode(state) {
1277
- if (hasTreeDataType(state) && state.keyboardMode === NAVIGATION_MODE) {
1260
+ if (
1261
+ hasTreeDataType(state) &&
1262
+ state.keyboardMode === KEYBOARD_NAVIGATION_MODE
1263
+ ) {
1278
1264
  state.rowMode = true;
1279
1265
  }
1280
1266
  }
@@ -1284,15 +1270,14 @@ export function unsetRowNavigationMode(state) {
1284
1270
  }
1285
1271
 
1286
1272
  /**
1287
- * If new set of columns doesnt have tree data, mark it to false, as it
1273
+ * If new set of columns doesn't have tree data, mark it to false, as it
1288
1274
  * could be true earlier
1289
1275
  * Else if it has tree data, check if rowMode is false
1290
- * Earlier it didnt have tree data, set rowMode to true to start
1276
+ * Earlier it didn't have tree data, set rowMode to true to start
1291
1277
  * if rowMode is false and earlier it has tree data, keep it false
1292
1278
  * if rowMode is true and it has tree data, keep it true
1293
- * @param {boolean} hadTreeDataTypePreviously - state object
1294
- * @param {object} state - state object
1295
- * @returns {object} state - mutated state
1279
+ * @param {Boolean} hadTreeDataTypePreviously - state object
1280
+ * @param {Object} state - The state object
1296
1281
  */
1297
1282
  export function updateRowNavigationMode(hadTreeDataTypePreviously, state) {
1298
1283
  if (!hasTreeDataType(state)) {
@@ -1300,15 +1285,14 @@ export function updateRowNavigationMode(hadTreeDataTypePreviously, state) {
1300
1285
  } else if (state.rowMode === false && !hadTreeDataTypePreviously) {
1301
1286
  state.rowMode = true;
1302
1287
  }
1303
- return state;
1304
1288
  }
1305
1289
 
1306
1290
  /***************************** HELPER FUNCTIONS *****************************/
1307
1291
 
1308
- export function isCellElement(tagName, role) {
1292
+ export function isCellElement(target) {
1293
+ const role = target.getAttribute('role');
1309
1294
  return (
1310
- SELECTORS.cell.default.includes(tagName) ||
1311
- SELECTORS.cell.roleBased.includes(role)
1295
+ role === 'gridcell' || role === 'columnheader' || role === 'rowheader'
1312
1296
  );
1313
1297
  }
1314
1298
 
@@ -1316,31 +1300,27 @@ function isHeaderRow(rowIndex) {
1316
1300
  return rowIndex === -1;
1317
1301
  }
1318
1302
 
1319
- export function getDataRow(rowKeyValue) {
1320
- return `[data-row-key-value="${escapeDoubleQuotes(rowKeyValue)}"]`;
1321
- }
1322
-
1323
- export function getCellElementByKeys(template, rowKeyValue, colKeyValue) {
1324
- const selector = `${getDataRow(
1325
- rowKeyValue
1326
- )} [data-col-key-value="${escapeDoubleQuotes(
1303
+ function getCellElementByKeys(template, rowKeyValue, colKeyValue) {
1304
+ const selector = `${getRowDataSelector(rowKeyValue)} ${getColDataSelector(
1327
1305
  colKeyValue
1328
- )}"] > :first-child`;
1306
+ )} > :first-child`;
1329
1307
  return template.querySelector(selector);
1330
1308
  }
1331
1309
 
1332
- function getActiveCellRow(template, state) {
1333
- if (state.activeCell) {
1334
- const { rowKeyValue } = state.activeCell;
1335
- const selector = getDataRow(rowKeyValue);
1336
- return template.querySelector(selector);
1310
+ function getActiveCellRowElement(template, state) {
1311
+ let result;
1312
+ const { activeCell } = state;
1313
+ if (activeCell) {
1314
+ result = template.querySelector(
1315
+ getRowDataSelector(activeCell.rowKeyValue)
1316
+ );
1337
1317
  }
1338
- return null;
1318
+ return result || null;
1339
1319
  }
1340
1320
 
1341
- export function getRowParent(state, rowLevel, rowIndex) {
1321
+ export function getRowParentIndex(state, rowLevel, rowIndex) {
1342
1322
  const parentIndex = rowIndex - 1;
1343
- const rows = state.rows;
1323
+ const { rows } = state;
1344
1324
  for (let i = parentIndex; i >= 0; i--) {
1345
1325
  if (rows[i].level === rowLevel - 1) {
1346
1326
  return i;
@@ -1349,19 +1329,8 @@ export function getRowParent(state, rowLevel, rowIndex) {
1349
1329
  return -1;
1350
1330
  }
1351
1331
 
1352
- function getCellFromIndexes(state, rowIndex, colIndex) {
1353
- const { columns, rows } = state;
1354
- if (columns.length > 0) {
1355
- return {
1356
- rowKeyValue: rowIndex === -1 ? HEADER_ROW : rows[rowIndex].key,
1357
- colKeyValue: generateColKeyValue(columns[colIndex], colIndex),
1358
- };
1359
- }
1360
- return undefined;
1361
- }
1362
-
1363
1332
  function updateScrollTop(state, template, element) {
1364
- const scrollableY = template.querySelector('.slds-scrollable_y');
1333
+ const scrollableY = getScrollerY(template);
1365
1334
  const scrollingParent = scrollableY.parentElement;
1366
1335
  const parentRect = scrollingParent.getBoundingClientRect();
1367
1336
  const findMeRect = element.getBoundingClientRect();
@@ -1383,22 +1352,21 @@ function scrollToCell(state, template, rowIndex) {
1383
1352
  scrollTop = Math.max(scrollTop - rowsInViewport * rowHeight, 0);
1384
1353
  }
1385
1354
 
1386
- const scrollableY = template.querySelector('.slds-scrollable_y');
1355
+ const scrollableY = getScrollerY(template);
1387
1356
  scrollableY.scrollTop = scrollTop;
1388
1357
  findFirstVisibleIndex(state, scrollTop);
1389
1358
  }
1390
1359
 
1391
1360
  export function isActiveCellEditable(state) {
1392
- const { activeCell, rows, columns } = state;
1393
- if (activeCell) {
1361
+ if (state.activeCell) {
1394
1362
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
1395
- return isCellEditable(rows[rowIndex], columns[colIndex]);
1363
+ return isCellEditable(state.rows[rowIndex], state.columns[colIndex]);
1396
1364
  }
1397
1365
  return false;
1398
1366
  }
1399
1367
 
1400
1368
  export function isValidCell(state, rowKeyValue, colKeyValue) {
1401
- if (rowKeyValue === HEADER_ROW) {
1369
+ if (rowKeyValue === HEADER_ROW_KEY) {
1402
1370
  return state.headerIndexes[colKeyValue] !== undefined;
1403
1371
  }
1404
1372
  const row = getRowByKey(state, rowKeyValue);
@@ -1408,16 +1376,28 @@ export function isValidCell(state, rowKeyValue, colKeyValue) {
1408
1376
  }
1409
1377
 
1410
1378
  function isActiveCellValid(state) {
1411
- if (state.activeCell) {
1412
- const { rowKeyValue, colKeyValue } = state.activeCell;
1413
- return isValidCell(state, rowKeyValue, colKeyValue);
1379
+ const { activeCell } = state;
1380
+ if (activeCell) {
1381
+ return isValidCell(
1382
+ state,
1383
+ activeCell.rowKeyValue,
1384
+ activeCell.colKeyValue
1385
+ );
1414
1386
  }
1415
1387
  return false;
1416
1388
  }
1417
1389
 
1418
- export function updateActiveCellTabIndexAfterSync(state, index = 0) {
1390
+ export function updateActiveCellTabIndexAfterSync(state, tabIndex = 0) {
1419
1391
  if (state.activeCell && !isRowNavigationMode(state)) {
1420
1392
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
1421
- updateTabIndex(state, rowIndex, colIndex, index);
1393
+ updateCellTabIndex(state, rowIndex, colIndex, tabIndex);
1394
+ }
1395
+ }
1396
+
1397
+ export function updateActiveRowTabIndexAfterSync(state, tabIndex = 0) {
1398
+ const { activeCell } = state;
1399
+ if (activeCell && isRowNavigationMode(state)) {
1400
+ const { rowIndex } = getIndexesActiveCell(state);
1401
+ updateRowTabIndex(state, rowIndex, tabIndex);
1422
1402
  }
1423
1403
  }