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,164 +1,143 @@
1
1
  import { LightningElement, api, track, unwrap } from 'lwc';
2
- import tableTemplate from './templates/table/table.html';
3
2
  import divTemplate from './templates/div/div.html';
4
- import { classSet } from 'lightning/utils';
3
+ import tableTemplate from './templates/table/table.html';
4
+ import labelAriaLiveActionMode from '@salesforce/label/LightningDatatable.ariaLiveActionMode';
5
+ import labelAriaLiveNavigationMode from '@salesforce/label/LightningDatatable.ariaLiveNavigationMode';
6
+ import { EVENTS as FORMATTED_LOOKUP_EVENTS } from 'lightning/formattedLookup';
7
+ import { generateUniqueId } from 'lightning/inputUtils';
5
8
  import {
9
+ classSetToString,
10
+ isSafari,
6
11
  normalizeBoolean,
7
12
  normalizeString,
8
- isIE11,
9
- isSafari,
10
13
  synchronizeAttrs,
11
14
  } from 'lightning/utilsPrivate';
12
15
  import { LightningDatatableResizeObserver } from './resizeObserver';
13
16
  import { ColumnWidthManager } from './columnWidthManager';
14
17
  import { getDefaultState } from './state';
15
- import { getColumns, normalizeColumns, generateHeaderIndexes } from './columns';
18
+ import { normalizeColumns, generateHeaderIndexes } from './columns';
19
+ import {
20
+ getCustomerColumnWidths,
21
+ getResizerDefaultState,
22
+ resizeColumnWithDelta,
23
+ setMaxColumnWidth,
24
+ setMinColumnWidth,
25
+ setResizeColumnDisabled,
26
+ setResizeStep,
27
+ updateColumnWidthsMetadata,
28
+ } from './columnResizer';
29
+ import { setErrors } from './errors';
16
30
  import {
17
- setData,
18
- getData,
19
- updateRowsAndCellIndexes,
20
31
  setKeyField,
21
- getKeyField,
22
- hasValidKeyField,
32
+ updateRowsAndCellIndexes,
23
33
  updateCellClassForRoleBasedMode,
24
34
  recomputeCellStyles,
25
35
  } from './rows';
26
36
  import {
27
- isResizeColumnDisabled,
28
- setResizeColumnDisabled,
29
- getResizeStep,
30
- setResizeStep,
31
- getMinColumnWidth,
32
- setMinColumnWidth,
33
- getMaxColumnWidth,
34
- setMaxColumnWidth,
35
- getColumnsWidths,
36
- resizeColumnWithDelta,
37
- getCustomerColumnWidths,
38
- getCSSWidthStyleOfTable,
39
- updateColumnWidthsMetadata,
40
- getResizerDefaultState,
41
- } from './columnResizer';
37
+ handleCellButtonClick,
38
+ handleLoadDynamicActions,
39
+ handleRowActionTriggered,
40
+ } from './rowLevelActions';
41
+ import { setRowNumberOffset } from './rowNumber';
42
42
  import {
43
- syncSelectedRowsKeys,
43
+ handleDeselectAllRows,
44
+ handleDeselectRow,
44
45
  handleRowSelectionChange,
45
- updateBulkSelectionState,
46
- getMaxRowSelection,
47
- setMaxRowSelection,
48
- getSelectedRowsKeys,
49
- setSelectedRowsKeys,
50
46
  handleSelectAllRows,
51
- handleDeselectAllRows,
52
47
  handleSelectRow,
53
- handleDeselectRow,
54
- getHideSelectAllCheckbox,
55
- getCurrentSelectionLength,
48
+ setMaxRowSelection,
49
+ setSelectedRowsKeys,
50
+ syncSelectedRowsKeys,
51
+ updateBulkSelectionState,
56
52
  } from './rowSelection';
57
53
  import {
58
- syncActiveCell,
59
- handleKeydownOnCell,
60
- updateActiveCell,
61
- setBlurActiveCell,
62
- setFocusActiveCell,
63
- isActiveCell,
64
- updateTabIndex,
65
- getIndexesByKeys,
66
- updateTabIndexActiveCell,
67
- updateTabIndexActiveRow,
68
- unsetRowNavigationMode,
69
- updateRowNavigationMode,
70
- handleDatatableFocusOut,
71
- handleDatatableFocusIn,
72
- updateTabIndexRow,
73
- getIndexesActiveCell,
74
- reactToKeyboardOnRow,
75
- setCellToFocusFromPrev,
76
- updateCellToFocusFromPrev,
77
- resetCellToFocusFromPrev,
78
- datatableHasFocus,
79
- setCellClickedForFocus,
80
- handleKeydownOnTable,
81
- addFocusStylesToActiveCell,
82
- refocusCellElement,
83
- isCellElement,
84
- getActiveCellElement,
85
- getDataRow,
86
- FOCUS_CLASS,
87
- updateActiveCellTabIndexAfterSync,
88
- } from './keyboard';
54
+ getCurrentSelectionLength,
55
+ getSelectedRowsKeys,
56
+ } from './rowSelectionShared';
89
57
  import {
90
- getRowNumberOffset,
91
- setRowNumberOffset,
92
- hasRowNumberColumn,
93
- setShowRowNumberColumn,
94
- } from './rowNumber';
58
+ handleHeaderActionMenuClosed,
59
+ handleHeaderActionTriggered,
60
+ handleHeaderActionMenuOpening,
61
+ updateHeaderInternalActions,
62
+ } from './headerActions';
95
63
  import {
96
64
  handleLoadMoreCheck,
97
- isInfiniteLoadingEnabled,
98
- setInfiniteLoading,
65
+ handlePrefetch,
66
+ setEnableInfiniteLoading,
67
+ setLoading,
99
68
  getLoadMoreOffset,
100
69
  setLoadMoreOffset,
101
- isLoading,
102
- setLoading,
103
- handlePrefetch,
104
70
  } from './infiniteLoading';
105
-
106
- import {
107
- handleRowActionTriggered,
108
- handleLoadDynamicActions,
109
- handleCellButtonClick,
110
- } from './rowLevelActions';
111
71
  import {
112
- getSortedBy,
113
- setSortedBy,
114
- getSortedDirection,
115
- setSortedDirection,
116
- getDefaultSortDirection,
117
- setDefaultSortDirection,
118
- updateSorting,
119
- } from './sort';
120
- import {
121
- updateHeaderActions,
122
- handleHeaderActionTriggered,
123
- handleHeaderActionMenuOpening,
124
- handleHeaderActionMenuClosed,
125
- } from './headerActions';
126
- import { setWrapTextMaxLines } from './wrapText';
127
- import {
128
- isInlineEditTriggered,
129
72
  cancelInlineEdit,
73
+ closeInlineEdit,
74
+ getDirtyValues,
130
75
  handleEditCell,
131
76
  handleInlineEditFinish,
132
- handleMassCheckboxChange,
133
77
  handleInlineEditPanelScroll,
134
- getDirtyValues,
135
- setDirtyValues,
136
- closeInlineEdit,
78
+ handleMassCheckboxChange,
79
+ isInlineEditTriggered,
137
80
  openInlineEditOnActiveCell,
81
+ setDirtyValues,
138
82
  } from './inlineEdit';
83
+ import {
84
+ addFocusStylesToActiveCell,
85
+ datatableHasFocus,
86
+ FOCUS_CLASS,
87
+ getActiveCellElement,
88
+ getIndexesActiveCell,
89
+ getIndexesByKeys,
90
+ handleDatatableFocusIn,
91
+ handleDatatableFocusOut,
92
+ handleKeydownOnCell,
93
+ handleKeydownOnTable,
94
+ isActiveCell,
95
+ isCellElement,
96
+ KEYBOARD_ACTION_MODE,
97
+ KEYBOARD_NAVIGATION_MODE,
98
+ reactToKeyboardOnRow,
99
+ refocusCellElement,
100
+ setBlurActiveCell,
101
+ setCellClickedForFocus,
102
+ setCellToFocusFromPrev,
103
+ setFocusActiveCell,
104
+ syncActiveCell,
105
+ unsetRowNavigationMode,
106
+ updateActiveCellTabIndexAfterSync,
107
+ updateCellTabIndex,
108
+ updateCellToFocusFromPrev,
109
+ updateTabIndexActiveCell,
110
+ updateTabIndexActiveRow,
111
+ updateRowNavigationMode,
112
+ updateRowTabIndex,
113
+ } from './keyboard';
139
114
  import {
140
115
  isViewportRenderingEnabled,
141
116
  setViewportRendering,
142
- getDTWrapperHeight,
143
117
  setVirtualize,
144
118
  RenderManager,
145
119
  } from './renderManager';
120
+ import {
121
+ setDefaultSortDirection,
122
+ setSortedBy,
123
+ setSortedDirection,
124
+ updateSorting,
125
+ } from './sort';
126
+ import {
127
+ getGridContainerFromScrollerY,
128
+ getRowDataSelector,
129
+ getScrollerXFromScrollerY,
130
+ getScrollerY,
131
+ } from './utils';
132
+ import { setWrapTextMaxLines } from './wrapText';
146
133
  import {
147
134
  handleVariableRowHeights,
148
135
  resetRowHeights,
149
136
  resetTableHeight,
150
137
  findFirstVisibleIndex,
151
138
  } from './virtualization';
152
- import { EVENTS as FORMATTED_LOOKUP_EVENTS } from 'lightning/formattedLookup';
153
-
154
139
  import { hasTreeDataType } from './tree';
155
- import { setErrors, getTableError, getErrors } from './errors';
156
-
157
- import { generateUniqueId } from 'lightning/inputUtils';
158
140
  import DatatableTypes from './types';
159
- import labelAriaLiveNavigationMode from '@salesforce/label/LightningDatatable.ariaLiveNavigationMode';
160
- import labelAriaLiveActionMode from '@salesforce/label/LightningDatatable.ariaLiveActionMode';
161
- import { styleToString } from './utils';
162
141
 
163
142
  const i18n = {
164
143
  ariaLiveNavigationMode: labelAriaLiveNavigationMode,
@@ -202,36 +181,43 @@ export default class LightningDatatable extends LightningElement {
202
181
 
203
182
  // Private Variables
204
183
  _actionsMinHeightStyle = ''; // Min height required while actions menu is opened
205
- _columns = [];
206
- _columnWidthsMode = 'fixed';
184
+ _checkboxColumnHeaderId = null;
185
+ _columnWidthManager;
207
186
  _customerSelectedRows = null;
208
187
  _datatableId = generateUniqueId('lgt-datatable');
209
188
  _draftValues = [];
210
189
  _isResizing = false; // Whether resizing is in progress
211
190
  _lastRenderedRow = null; // last rendered row, used for UTAM
212
191
  _privateTypes = {};
213
- _privateWidthObserver = null; // Instance of LightningDatatableResizeObserver
214
- _renderMode = 'table';
192
+ _rawColumns = [];
193
+ _renderConfig;
194
+ _renderManager;
195
+ _renderMode = 'default';
215
196
  _shouldResetFocus = false; // used to ensure focus isn't lost from changes in renderedRows
216
197
  _suppressBottomBar = false;
217
- _checkboxColumnHeaderId;
198
+ _widthObserver = null; // Instance of LightningDatatableResizeObserver
218
199
 
219
200
  /************************* PUBLIC PROPERTIES *************************/
220
201
 
221
202
  /**
222
203
  * Public property for passing `aria-label` down to the child table element.
223
204
  */
224
- ariaLabel = null;
205
+ @api ariaLabel = null;
225
206
 
226
207
  /**
227
208
  * Public property for passing `aria-labelledby` down to the child table element.
228
209
  */
229
- ariaLabelledBy = null;
210
+ @api ariaLabelledBy = null;
211
+
212
+ /**
213
+ * Public property for passing `aria-describedby` down to the child table element.
214
+ */
215
+ ariaDescribedBy = null;
230
216
 
231
217
  /**
232
218
  * Specifies how column widths are calculated. Set to 'fixed' for columns with equal widths.
233
219
  * Set to 'auto' for column widths that are based on the width of the column content and the table width. The default is 'fixed'.
234
- * @type {string}
220
+ * @type {String}
235
221
  * @default fixed
236
222
  */
237
223
  @api
@@ -240,17 +226,18 @@ export default class LightningDatatable extends LightningElement {
240
226
  }
241
227
 
242
228
  set columnWidthsMode(value) {
229
+ const { widthsData } = this;
243
230
  const normalizedValue = normalizeString(value, {
244
231
  fallbackValue: 'fixed',
245
232
  validValues: ['fixed', 'auto'],
246
233
  });
234
+ // Untracked state change.
247
235
  this._columnWidthManager.columnWidthMode = normalizedValue;
248
-
249
- const { state, widthsData } = this;
250
236
  if (widthsData.columnWidthsMode !== normalizedValue) {
251
- this._columnWidthManager.handleWidthModeChange(getColumns(state));
237
+ // Tracked state changes.
238
+ this._columnWidthManager.handleWidthModeChange(this.state.columns);
252
239
  }
253
-
240
+ // Untracked state change.
254
241
  widthsData.columnWidthsMode = normalizedValue;
255
242
  }
256
243
 
@@ -258,43 +245,47 @@ export default class LightningDatatable extends LightningElement {
258
245
  * Array of the columns object that's used to define the data types.
259
246
  * Required properties include 'label', 'fieldName', and 'type'. The default type is 'text'.
260
247
  * See the Documentation tab for more information.
261
- * @type {array}
248
+ * @type {Array}
262
249
  */
263
250
  @api
264
251
  get columns() {
265
- return this._columns;
252
+ return this._rawColumns;
266
253
  }
267
254
 
268
255
  set columns(value) {
269
- this._columns = Array.isArray(value) ? value : [];
270
- this.updateColumns(this._columns);
271
- this._columnWidthManager.handleColumnsChange(getColumns(this.state));
256
+ const _rawColumns = Array.isArray(value) ? value : [];
257
+ this._rawColumns = _rawColumns;
258
+ this.updateColumns(this._rawColumns);
259
+ this._columnWidthManager.handleColumnsChange(this.state.columns);
272
260
  }
273
261
 
274
262
  /**
275
263
  * The array of data to be displayed.
276
- * @type {array}
264
+ * @type {Array}
277
265
  */
278
266
  @api
279
267
  // eslint-disable-next-line @lwc/lwc/valid-api
280
268
  get data() {
281
- return getData(this.state);
269
+ return this.state.data;
282
270
  }
283
271
 
284
272
  set data(value) {
273
+ const { state } = this;
274
+ const { data: previousData } = state;
285
275
  const data = Array.isArray(value) ? value : [];
286
276
 
287
- const previousData = getData(this.state);
288
- const columns = getColumns(this.state);
289
- this._columnWidthManager.handleDataChange(previousData, data, columns);
290
-
291
- // set data in state
292
- setData(this.state, value);
277
+ // Untracked state change.
278
+ state.data = data;
279
+ this._columnWidthManager.handleDataChange(
280
+ previousData,
281
+ data,
282
+ state.columns
283
+ );
293
284
 
294
285
  // do necessary updates since rows have changed
295
- if (hasValidKeyField(this.state)) {
286
+ if (this.hasValidKeyField) {
296
287
  this.updateRowsState();
297
- resetTableHeight(this.state);
288
+ resetTableHeight(state);
298
289
  }
299
290
  if (this._customerSelectedRows) {
300
291
  this.setSelectedRows(this._customerSelectedRows);
@@ -305,22 +296,23 @@ export default class LightningDatatable extends LightningElement {
305
296
  * Specifies the default sorting direction on an unsorted column.
306
297
  * Valid options include 'asc' and 'desc'.
307
298
  * The default is 'asc' for sorting in ascending order.
308
- * @type {string}
299
+ * @type {String}
309
300
  * @default asc
310
301
  */
311
302
  @api
312
303
  get defaultSortDirection() {
313
- return getDefaultSortDirection(this.state);
304
+ return this.state.defaultSortDirection;
314
305
  }
315
306
 
316
307
  set defaultSortDirection(value) {
317
- setDefaultSortDirection(this.state, value);
318
- updateSorting(this.state);
308
+ const { state } = this;
309
+ setDefaultSortDirection(state, value);
310
+ updateSorting(state);
319
311
  }
320
312
 
321
313
  /**
322
314
  * The current values per row that are provided during inline edit.
323
- * @type {object}
315
+ * @type {Object}
324
316
  */
325
317
  @api
326
318
  get draftValues() {
@@ -328,41 +320,44 @@ export default class LightningDatatable extends LightningElement {
328
320
  }
329
321
 
330
322
  set draftValues(value) {
323
+ const { state } = this;
331
324
  this._draftValues = value;
332
- setDirtyValues(this.state, value);
325
+ setDirtyValues(state, value);
333
326
 
334
- if (hasValidKeyField(this.state)) {
335
- this.updateRowsAndCellIndexes(this.state);
327
+ if (this.hasValidKeyField) {
328
+ this.updateRowsAndCells();
336
329
  }
337
330
 
338
- updateActiveCellTabIndexAfterSync(this.state);
331
+ updateActiveCellTabIndexAfterSync(state);
339
332
  }
340
333
 
341
334
  /**
342
335
  * If present, you can load a subset of data and then display more
343
336
  * when users scroll to the end of the table.
344
337
  * Use with the onloadmore event handler to retrieve more data.
345
- * @type {boolean}
338
+ * @type {Boolean}
346
339
  * @default false
347
340
  */
348
341
  @api
349
342
  get enableInfiniteLoading() {
350
- return isInfiniteLoadingEnabled(this.state);
343
+ return this.state.enableInfiniteLoading;
351
344
  }
352
345
 
353
346
  set enableInfiniteLoading(value) {
354
- setInfiniteLoading(this.state, value);
355
- handlePrefetch.call(this, this.template, this.state);
347
+ const { state } = this;
348
+ // Untracked state change.
349
+ setEnableInfiniteLoading(state, value);
350
+ handlePrefetch.call(this);
356
351
  }
357
352
 
358
353
  /**
359
354
  * Specifies an object containing information about cell level, row level, and table level errors.
360
355
  * When it's set, error messages are displayed on the table accordingly.
361
- * @type {object}
356
+ * @type {Object}
362
357
  */
363
358
  @api
364
359
  get errors() {
365
- return getErrors(this.state);
360
+ return this.state.errors;
366
361
  }
367
362
 
368
363
  set errors(value) {
@@ -372,7 +367,7 @@ export default class LightningDatatable extends LightningElement {
372
367
 
373
368
  /**
374
369
  * If present, the checkbox column for row selection is hidden.
375
- * @type {boolean}
370
+ * @type {Boolean}
376
371
  * @default false
377
372
  */
378
373
  @api
@@ -387,17 +382,17 @@ export default class LightningDatatable extends LightningElement {
387
382
  this._columnWidthManager.handleCheckboxColumnChange(
388
383
  state.hideCheckboxColumn,
389
384
  normalizedValue,
390
- getColumns(state)
385
+ state.columns
391
386
  );
392
-
393
- this.state.hideCheckboxColumn = normalizedValue;
387
+ // Untracked state changes.
388
+ state.hideCheckboxColumn = normalizedValue;
394
389
  // update the columns metadata again to update the status.
395
- this.updateColumns(this._columns);
390
+ this.updateColumns(this._rawColumns);
396
391
  }
397
392
 
398
393
  /**
399
394
  * If present, the table header is hidden.
400
- * @type {boolean}
395
+ * @type {Boolean}
401
396
  * @default false
402
397
  */
403
398
  @api
@@ -406,12 +401,13 @@ export default class LightningDatatable extends LightningElement {
406
401
  }
407
402
 
408
403
  set hideTableHeader(value) {
404
+ // Untracked state change.
409
405
  this.state.hideTableHeader = normalizeBoolean(value);
410
406
  }
411
407
 
412
408
  /**
413
- * If present, the table header is wrapped up to 3 lines.
414
- * @type {boolean}
409
+ * If present, the table header is wrapped.
410
+ * @type {Boolean}
415
411
  * @default false
416
412
  */
417
413
  @api
@@ -420,37 +416,42 @@ export default class LightningDatatable extends LightningElement {
420
416
  }
421
417
 
422
418
  set wrapTableHeader(value) {
419
+ // Untracked state change.
423
420
  this.state.wrapTableHeader = normalizeBoolean(value);
424
421
  }
425
422
 
426
423
  /**
427
424
  * If present, a spinner is shown to indicate that more data is loading.
428
- * @type {boolean}
425
+ * @type {Boolean}
429
426
  * @default false
430
427
  */
431
428
  @api
432
429
  get isLoading() {
433
- return isLoading(this.state);
430
+ return this.state.isLoading;
434
431
  }
435
432
 
436
433
  set isLoading(value) {
434
+ // Tracked state change.
437
435
  setLoading(this.state, value);
438
436
  }
439
437
 
440
438
  /**
441
439
  * Required for better performance. Associates each row with a unique ID.
442
440
  * key-field is case sensitive and must match the value you provide in the data array.
443
- * @type {string}
441
+ * @type {String}
444
442
  * @required
445
443
  */
446
444
  @api
447
445
  get keyField() {
448
- return getKeyField(this.state);
446
+ return this.state.keyField;
449
447
  }
450
448
 
451
449
  set keyField(value) {
452
- setKeyField(this.state, value);
453
- setDirtyValues(this.state, this._draftValues);
450
+ const { state } = this;
451
+ // Untracked state change.
452
+ setKeyField(state, value);
453
+ // Tracked state change.
454
+ setDirtyValues(state, this._draftValues);
454
455
  this.updateRowsState();
455
456
  }
456
457
 
@@ -458,7 +459,7 @@ export default class LightningDatatable extends LightningElement {
458
459
  * Determines when to trigger infinite loading based on
459
460
  * how many pixels the table's scroll position is from the bottom of the table.
460
461
  * The default is 20.
461
- * @type {number}
462
+ * @type {Number}
462
463
  * @default 20
463
464
  */
464
465
  @api
@@ -473,34 +474,38 @@ export default class LightningDatatable extends LightningElement {
473
474
  /**
474
475
  * The maximum width for all columns.
475
476
  * The default is 1000px.
476
- * @type {number}
477
+ * @type {Number}
477
478
  * @default 1000px
478
479
  */
479
480
  @api
480
481
  get maxColumnWidth() {
481
- return getMaxColumnWidth(this.widthsData);
482
+ return this.widthsData.maxColumnWidth;
482
483
  }
483
484
 
484
485
  set maxColumnWidth(value) {
485
- const { state, widthsData } = this;
486
- setMaxColumnWidth(getColumns(state), widthsData, value);
487
- this._columnWidthManager.maxColumnWidth = this.maxColumnWidth;
486
+ const { widthsData } = this;
487
+ // Tracked state changes.
488
+ setMaxColumnWidth(this.state.columns, widthsData, value);
489
+ // Untracked state change.
490
+ this._columnWidthManager.maxColumnWidth = widthsData.maxColumnWidth;
488
491
  }
489
492
 
490
493
  /**
491
494
  * The maximum number of rows that can be selected. Value should be a positive integer
492
495
  * Checkboxes are used for selection by default,
493
496
  * and radio buttons are used when maxRowSelection is 1.
494
- * @type {number}
497
+ * @type {Number}
495
498
  */
496
499
  @api
497
500
  get maxRowSelection() {
498
- return getMaxRowSelection(this.state);
501
+ return this.state.maxRowSelection;
499
502
  }
500
503
 
501
504
  set maxRowSelection(value) {
502
- const previousSelectionLength = getCurrentSelectionLength(this.state);
503
- setMaxRowSelection(this.state, value);
505
+ const { state } = this;
506
+ const previousSelectionLength = getCurrentSelectionLength(state);
507
+ // A mix of tracked and untracked state changes.
508
+ setMaxRowSelection(state, value);
504
509
  if (previousSelectionLength > 0) {
505
510
  this.fireSelectedRowsChange(this.getSelectedRows());
506
511
  }
@@ -509,26 +514,28 @@ export default class LightningDatatable extends LightningElement {
509
514
  /**
510
515
  * The minimum width for all columns.
511
516
  * The default is 50px.
512
- * @type {number}
517
+ * @type {Number}
513
518
  * @default 50px
514
519
  */
515
520
  @api
516
521
  get minColumnWidth() {
517
- return getMinColumnWidth(this.widthsData);
522
+ return this.widthsData.minColumnWidth;
518
523
  }
519
524
 
520
525
  set minColumnWidth(value) {
521
- const { state, widthsData } = this;
522
- setMinColumnWidth(getColumns(state), widthsData, value);
523
- this._columnWidthManager.minColumnWidth = this.minColumnWidth;
526
+ const { widthsData } = this;
527
+ // Tracked state change.
528
+ setMinColumnWidth(this.state.columns, widthsData, value);
529
+ // Untracked state change.
530
+ this._columnWidthManager.minColumnWidth = widthsData.minColumnWidth;
524
531
  }
525
532
 
526
533
  /**
527
534
  * @typedef RenderManagerConfig
528
- * @type {object}
529
- * @property {boolean} viewportRendering - Specifies whether to defer rendering of rows outside the viewport until the user begins scrolling. To use this feature, create a fixed-height container element for lightning-datatable.
530
- * @property {number} rowHeight - Specifies the height of a row, in px
531
- * @property {string} virtualize - specifies whether to enable virtualization. This requires the "role-based" render mode and a fixed-height container for lightning-datatable
535
+ * @type {Object}
536
+ * @property {Boolean} viewportRendering - Specifies whether to defer rendering of rows outside the viewport until the user begins scrolling. To use this feature, create a fixed-height container element for lightning-datatable.
537
+ * @property {Number} rowHeight - Specifies the height of a row, in px
538
+ * @property {String} virtualize - specifies whether to enable virtualization. This requires the "role-based" render mode and a fixed-height container for lightning-datatable
532
539
  */
533
540
 
534
541
  /**
@@ -543,7 +550,7 @@ export default class LightningDatatable extends LightningElement {
543
550
  }
544
551
 
545
552
  set renderConfig(value) {
546
- if (typeof value === 'object' && !isIE11) {
553
+ if (typeof value === 'object') {
547
554
  setViewportRendering(this.state, value.viewportRendering);
548
555
 
549
556
  this._renderManager.configure(
@@ -578,63 +585,69 @@ export default class LightningDatatable extends LightningElement {
578
585
  }
579
586
 
580
587
  set renderMode(value) {
588
+ const { _renderConfig, state } = this;
581
589
  this._renderMode = normalizeString(value, {
582
590
  fallbackValue: 'default',
583
591
  validValues: ['default', 'role-based'],
584
592
  });
585
- this.state.renderModeRoleBased = this._renderMode === 'role-based';
586
- this._columnWidthManager.setRenderMode(this.renderMode);
587
- if (this._renderConfig) {
588
- setVirtualize(this.state, this._renderConfig.virtualize);
593
+ state.renderModeRoleBased = this._renderMode === 'role-based';
594
+ if (_renderConfig) {
595
+ setVirtualize(state, _renderConfig.virtualize);
589
596
  }
590
- updateCellClassForRoleBasedMode(this.state);
597
+ updateCellClassForRoleBasedMode(state);
591
598
  }
592
599
 
593
600
  /**
594
601
  * If present, column resizing is disabled.
595
- * @type {boolean}
602
+ * @type {Boolean}
596
603
  * @default false
597
604
  */
598
605
  @api
599
606
  get resizeColumnDisabled() {
600
- return isResizeColumnDisabled(this.widthsData);
607
+ return this.widthsData.resizeColumnDisabled;
601
608
  }
602
609
 
603
610
  set resizeColumnDisabled(value) {
611
+ // Untracked state change.
604
612
  setResizeColumnDisabled(this.widthsData, value);
605
613
  }
606
614
 
607
615
  /**
608
616
  * The width to resize the column when a user presses left or right arrow.
609
617
  * The default is 10px.
610
- * @type {number}
618
+ * @type {Number}
611
619
  * @default 10px
612
620
  */
613
621
  @api
614
622
  get resizeStep() {
615
- return getResizeStep(this.widthsData);
623
+ return this.widthsData.resizeStep;
616
624
  }
617
625
 
618
626
  set resizeStep(value) {
627
+ // Tracked state change.
619
628
  setResizeStep(this.widthsData, value);
620
629
  }
621
630
 
622
631
  /**
623
632
  * Determines where to start counting the row number.
624
633
  * The default is 0.
625
- * @type {number}
634
+ * @type {Number}
626
635
  * @default 0
627
636
  */
628
637
  @api
629
638
  get rowNumberOffset() {
630
- return getRowNumberOffset(this.state);
639
+ return this.state.rowNumberOffset;
631
640
  }
632
641
 
633
642
  set rowNumberOffset(value) {
634
- const { state, widthsData } = this;
643
+ const { state } = this;
644
+ // Untracked state change.
635
645
  setRowNumberOffset(state, value);
636
-
637
- this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
646
+ // Tracked state changes.
647
+ this._columnWidthManager.handleRowNumberOffsetChange(
648
+ state,
649
+ this.widthsData
650
+ );
638
651
  }
639
652
 
640
653
  /**
@@ -653,61 +666,63 @@ export default class LightningDatatable extends LightningElement {
653
666
 
654
667
  /**
655
668
  * If present, the row numbers are shown in the first column.
656
- * @type {boolean}
669
+ * @type {Boolean}
657
670
  * @default false
658
671
  */
659
672
  @api
660
673
  get showRowNumberColumn() {
661
- return hasRowNumberColumn(this.state);
674
+ return this.state.showRowNumberColumn;
662
675
  }
663
676
 
664
677
  set showRowNumberColumn(value) {
665
- const { state, _columns } = this;
666
-
678
+ const { state, _rawColumns } = this;
679
+ // A mix of tracked and untracked state changes.
667
680
  this._columnWidthManager.handleRowNumberColumnChange(
668
- getRowNumberOffset(state),
681
+ state.rowNumberOffset,
669
682
  value,
670
- getColumns(state)
683
+ state.columns
671
684
  );
672
-
673
- setShowRowNumberColumn(state, value);
674
- this.updateColumns(_columns);
685
+ // Untracked state change.
686
+ state.showRowNumberColumn = normalizeBoolean(value);
687
+ this.updateColumns(_rawColumns);
675
688
  }
676
689
 
677
690
  /**
678
691
  * The column key or fieldName that controls the sorting order.
679
692
  * Sort the data using the onsort event handler.
680
- * @type {string}
693
+ * @type {String}
681
694
  */
682
695
  @api
683
696
  get sortedBy() {
684
- return getSortedBy(this.state);
697
+ return this.state.sortedBy;
685
698
  }
686
699
 
687
700
  set sortedBy(value) {
688
- setSortedBy(this.state, value);
689
- updateSorting(this.state);
701
+ const { state } = this;
702
+ setSortedBy(state, value);
703
+ updateSorting(state);
690
704
  }
691
705
 
692
706
  /**
693
707
  * Specifies the sorting direction.
694
708
  * Sort the data using the onsort event handler.
695
709
  * Valid options include 'asc' and 'desc'.
696
- * @type {string}
710
+ * @type {String}
697
711
  */
698
712
  @api
699
713
  get sortedDirection() {
700
- return getSortedDirection(this.state);
714
+ return this.state.sortedDirection;
701
715
  }
702
716
 
703
717
  set sortedDirection(value) {
704
- setSortedDirection(this.state, value);
705
- updateSorting(this.state);
718
+ const { state } = this;
719
+ setSortedDirection(state, value);
720
+ updateSorting(state);
706
721
  }
707
722
 
708
723
  /**
709
724
  * If present, the footer that displays the Save and Cancel buttons is hidden during inline editing.
710
- * @type {boolean}
725
+ * @type {Boolean}
711
726
  * @default false
712
727
  */
713
728
  @api
@@ -723,7 +738,7 @@ export default class LightningDatatable extends LightningElement {
723
738
  * This value specifies the number of lines after which the
724
739
  * content will be cut off and hidden. It must be at least 1 or more.
725
740
  * The text in the last line is truncated and shown with an ellipsis.
726
- * @type {integer}
741
+ * @type {Integer}
727
742
  */
728
743
  @api
729
744
  get wrapTextMaxLines() {
@@ -732,26 +747,32 @@ export default class LightningDatatable extends LightningElement {
732
747
 
733
748
  set wrapTextMaxLines(value) {
734
749
  const { state } = this;
750
+ // Untracked state changes.
735
751
  setWrapTextMaxLines(state, value);
736
752
  this._columnWidthManager.wrapTextMaxLines = state.wrapTextMaxLines;
737
- this.updateRowsAndCellIndexes(state);
753
+ this.updateRowsAndCells();
738
754
  }
739
755
 
740
756
  /************************** PUBLIC METHODS ***************************/
741
757
 
742
758
  /**
743
759
  * Returns data in each selected row.
744
- * @returns {array} An array of data in each selected row.
760
+ * @returns {Array} An array of data in each selected row.
745
761
  */
746
762
  @api
747
763
  getSelectedRows() {
748
- const data = unwrap(getData(this.state));
749
- return this.state.rows.reduce((prev, row, index) => {
764
+ const { state } = this;
765
+ const data = unwrap(state.data);
766
+ const { rows } = state;
767
+ const selectedRows = [];
768
+ for (let i = 0, { length: rowCount } = rows; i < rowCount; i += 1) {
769
+ const row = rows[i];
750
770
  if (row.isSelected) {
751
- prev.push(data[index]);
771
+ // Collect tracked data.
772
+ selectedRows.push(data[i]);
752
773
  }
753
- return prev;
754
- }, []);
774
+ }
775
+ return selectedRows;
755
776
  }
756
777
 
757
778
  /**
@@ -786,22 +807,23 @@ export default class LightningDatatable extends LightningElement {
786
807
  }
787
808
 
788
809
  get computedTableContainerClass() {
789
- return classSet({
790
- 'slds-table_header-fixed_container': !this.hideTableHeader,
810
+ return classSetToString({
811
+ 'slds-table_header-fixed_container': !this.state.hideTableHeader,
791
812
  'slds-scrollable_x': !this._isResizing,
792
- }).toString();
813
+ });
793
814
  }
794
815
 
795
816
  get computedTableClass() {
796
- const headerType = this.hideTableHeader ? 'hidden' : 'fixed';
797
- return classSet(
798
- `slds-table slds-table_header-${headerType} slds-table_bordered slds-table_edit`
799
- )
800
- .add({
801
- 'slds-table_resizable-cols': this.hasResizebleColumns,
802
- 'slds-tree slds-table_tree': hasTreeDataType(this.state),
803
- })
804
- .toString();
817
+ const { state } = this;
818
+ const headerType = state.hideTableHeader ? 'hidden' : 'fixed';
819
+ return classSetToString({
820
+ 'slds-table': true,
821
+ [`slds-table_header-${headerType}`]: true,
822
+ 'slds-table_bordered': true,
823
+ 'slds-table_edit': true,
824
+ 'slds-table_resizable-cols': !this.widthsData.resizeColumnDisabled,
825
+ 'slds-tree slds-table_tree': hasTreeDataType(state),
826
+ });
805
827
  }
806
828
 
807
829
  get computedTableRole() {
@@ -809,14 +831,15 @@ export default class LightningDatatable extends LightningElement {
809
831
  }
810
832
 
811
833
  get computedTableStyle() {
812
- const tableLayout =
813
- this._columnWidthManager.isAutoResizingUpdateQueued()
814
- ? 'auto'
815
- : 'fixed';
816
- return styleToString([
817
- `table-layout:${tableLayout}`,
818
- getCSSWidthStyleOfTable(this.widthsData),
819
- ]);
834
+ const tableLayout = this._columnWidthManager.isAutoResizingUpdateQueued
835
+ ? 'auto'
836
+ : 'fixed';
837
+ let style = `table-layout: ${tableLayout};`;
838
+ const { tableWidth } = this.widthsData;
839
+ if (tableWidth) {
840
+ style += `width: ${tableWidth}px;`;
841
+ }
842
+ return style;
820
843
  }
821
844
 
822
845
  /**
@@ -826,25 +849,23 @@ export default class LightningDatatable extends LightningElement {
826
849
  * virtualization is enabled
827
850
  */
828
851
  get computedTbodyStyle() {
829
- const style = {};
830
- const { firstVisibleIndex, bufferSize, virtualize, tableHeight } =
831
- this.state;
832
- if (
833
- hasRowNumberColumn(this.state) &&
834
- getRowNumberOffset(this.state) >= 0
835
- ) {
852
+ const { state } = this;
853
+ const { rowNumberOffset } = state;
854
+ let style = '';
855
+ if (state.showRowNumberColumn && rowNumberOffset >= 0) {
856
+ const { firstVisibleIndex, bufferSize } = state;
836
857
  const firstRenderedRow = Math.max(
837
858
  firstVisibleIndex - bufferSize,
838
859
  0
839
860
  );
840
- const rowNumber = firstRenderedRow + getRowNumberOffset(this.state);
841
- style['counter-reset'] = `row-number ${rowNumber}`;
861
+ const rowNumber = firstRenderedRow + rowNumberOffset;
862
+ style += `counter-reset: row-number ${rowNumber};`;
842
863
  }
843
- if (virtualize) {
844
- style.position = 'relative';
845
- style.height = `${tableHeight}px`;
864
+ if (state.virtualize) {
865
+ const { tableHeight } = state;
866
+ style += `position:relative;height:${tableHeight}px`;
846
867
  }
847
- return styleToString(style);
868
+ return style;
848
869
  }
849
870
 
850
871
  /**
@@ -857,35 +878,30 @@ export default class LightningDatatable extends LightningElement {
857
878
  * is overflowing horizontally, we need to set the width in order
858
879
  * to be able to view the remaining columns on scroll.
859
880
  */
860
- get computedScrollerStyle() {
881
+ get computedScrollerYStyle() {
861
882
  const minHeight = this._actionsMinHeightStyle
862
883
  ? `${this._actionsMinHeightStyle};`
863
884
  : '';
864
- if (this._columnWidthManager.isAutoResizingUpdateQueued()) {
885
+ if (this._columnWidthManager.isAutoResizingUpdateQueued) {
865
886
  return `${minHeight}overflow-x:auto`;
866
887
  }
867
- return `${minHeight}${getCSSWidthStyleOfTable(this.widthsData)}`;
888
+ const { tableWidth } = this.widthsData;
889
+ return tableWidth ? `width: ${tableWidth}px;` : '';
868
890
  }
869
891
 
870
- get scrollerXStyles() {
871
- const styles = {
872
- height: '100%',
873
- };
874
-
892
+ get computedScrollerXStyle() {
893
+ let style = 'height: 100%;';
875
894
  if (this.showStatusBar) {
876
- styles['padding-bottom'] = '3rem';
895
+ style += 'padding-bottom: 3rem;';
877
896
  }
878
-
879
- if (this._columnWidthManager.isAutoResizingUpdateQueued()) {
880
- styles['overflow-x'] = 'auto';
897
+ if (this._columnWidthManager.isAutoResizingUpdateQueued) {
898
+ style += 'overflow-x: auto;';
881
899
  }
882
-
883
- if (this.wrapTableHeader) {
900
+ if (this.state.wrapTableHeader) {
884
901
  // increase padding from 2rem to 3rem on the top when header wraps
885
- styles['padding-top'] = '3rem';
902
+ style += 'padding-top: 3rem;';
886
903
  }
887
-
888
- return styleToString(styles);
904
+ return style;
889
905
  }
890
906
 
891
907
  /**
@@ -898,23 +914,19 @@ export default class LightningDatatable extends LightningElement {
898
914
  }
899
915
 
900
916
  get computedAriaLiveClassForNavMode() {
901
- const keyboardMode = this.state.keyboardMode;
902
- return classSet()
903
- .add({
904
- 'slds-hide': keyboardMode !== 'NAVIGATION',
905
- 'slds-assistive-text': keyboardMode === 'NAVIGATION',
906
- })
907
- .toString();
917
+ const isNavMode = this.state.keyboardMode === KEYBOARD_NAVIGATION_MODE;
918
+ return classSetToString({
919
+ 'slds-hide': !isNavMode,
920
+ 'slds-assistive-text': isNavMode,
921
+ });
908
922
  }
909
923
 
910
924
  get computedAriaLiveClassForActionMode() {
911
- const keyboardMode = this.state.keyboardMode;
912
- return classSet()
913
- .add({
914
- 'slds-hide': keyboardMode !== 'ACTION',
915
- 'slds-assistive-text': keyboardMode === 'ACTION',
916
- })
917
- .toString();
925
+ const isActionMode = this.state.keyboardMode === KEYBOARD_ACTION_MODE;
926
+ return classSetToString({
927
+ 'slds-hide': !isActionMode,
928
+ 'slds-assistive-text': isActionMode,
929
+ });
918
930
  }
919
931
 
920
932
  /**
@@ -927,7 +939,7 @@ export default class LightningDatatable extends LightningElement {
927
939
  }
928
940
 
929
941
  get hasValidKeyField() {
930
- if (hasValidKeyField(this.state)) {
942
+ if (typeof this.state.keyField === 'string') {
931
943
  return true;
932
944
  }
933
945
  // eslint-disable-next-line no-console
@@ -937,12 +949,8 @@ export default class LightningDatatable extends LightningElement {
937
949
  return false;
938
950
  }
939
951
 
940
- get numberOfColumns() {
941
- return getColumns(this.state).length;
942
- }
943
-
944
952
  get hasResizebleColumns() {
945
- return !isResizeColumnDisabled(this.widthsData);
953
+ return !this.widthsData.resizeColumnDisabled;
946
954
  }
947
955
 
948
956
  get privateTypes() {
@@ -954,16 +962,17 @@ export default class LightningDatatable extends LightningElement {
954
962
  }
955
963
 
956
964
  get renderedRows() {
957
- const { virtualize, rows, renderedRowCount } = this.state;
965
+ const { state } = this;
966
+ const { virtualize, rows, renderedRowCount } = state;
958
967
  if (virtualize) {
959
968
  const { firstIndex, lastIndex } =
960
- this._renderManager.getRenderedRange(this.state);
969
+ this._renderManager.getRenderedRange(state);
961
970
  this._lastRenderedRow = lastIndex + 1; // UTAM rows are 1-indexed
962
971
  // we shouldn't lose focus from re-renders caused by a change in renderedRows
963
972
  this._shouldResetFocus = true;
964
973
  return rows.slice(firstIndex, lastIndex);
965
974
  }
966
- if (this.viewportRendering && !isIE11) {
975
+ if (this.viewportRendering) {
967
976
  this._lastRenderedRow = renderedRowCount;
968
977
  return rows.slice(0, renderedRowCount);
969
978
  }
@@ -972,15 +981,15 @@ export default class LightningDatatable extends LightningElement {
972
981
  }
973
982
 
974
983
  get showSelectAllCheckbox() {
975
- return !getHideSelectAllCheckbox(this.state);
984
+ return this.state.maxRowSelection !== 1;
976
985
  }
977
986
 
978
987
  get showStatusBar() {
979
- return isInlineEditTriggered(this.state) && !this.suppressBottomBar;
988
+ return !this._suppressBottomBar && isInlineEditTriggered(this.state);
980
989
  }
981
990
 
982
991
  get tableError() {
983
- return getTableError(this.state);
992
+ return this.state.errors.table;
984
993
  }
985
994
 
986
995
  get i18n() {
@@ -998,109 +1007,88 @@ export default class LightningDatatable extends LightningElement {
998
1007
  constructor() {
999
1008
  super();
1000
1009
 
1001
- this._privateTypes = new DatatableTypes(this.constructor.customTypes);
1002
1010
  this._columnWidthManager = new ColumnWidthManager(this.widthsData);
1003
- this.updateRowsAndCellIndexes = updateRowsAndCellIndexes.bind(this);
1011
+ this._privateTypes = new DatatableTypes(this.constructor.customTypes);
1004
1012
 
1005
1013
  this._renderManager = new RenderManager();
1006
- this.getWrapperHeight = getDTWrapperHeight.bind(this);
1014
+ this.getWrapperHeight = () =>
1015
+ getScrollerXFromScrollerY(getScrollerY(this.template)).offsetHeight;
1007
1016
  }
1008
1017
 
1009
1018
  /**
1010
1019
  * Attach event handlers for various events on `lightning-datatable`
1011
1020
  */
1012
1021
  connectedCallback() {
1013
- const {
1014
- handleResizeColumn,
1015
- handleUpdateColumnSort,
1016
- handleCellFocusByClick,
1017
- handleFalseCellBlur,
1018
- handleSelectionCellClick,
1019
- } = this;
1020
-
1021
- // Row Selection and De-selection
1022
- this.template.addEventListener(
1023
- 'selectallrows',
1024
- handleSelectionCellClick.bind(this)
1025
- );
1026
- this.template.addEventListener(
1027
- 'deselectallrows',
1028
- handleSelectionCellClick.bind(this)
1029
- );
1030
- this.template.addEventListener(
1031
- 'selectrow',
1032
- handleSelectionCellClick.bind(this)
1033
- );
1034
- this.template.addEventListener(
1035
- 'deselectrow',
1036
- handleSelectionCellClick.bind(this)
1037
- );
1038
-
1039
- this.addEventListener(
1040
- 'rowselection',
1041
- handleRowSelectionChange.bind(this)
1042
- );
1043
-
1044
- // Column Resizing
1045
- this.template.addEventListener(
1046
- 'resizecol',
1047
- handleResizeColumn.bind(this)
1048
- );
1049
-
1050
- // Column Sorting
1051
- this.template.addEventListener(
1052
- 'privateupdatecolsort',
1053
- handleUpdateColumnSort.bind(this)
1054
- );
1055
-
1056
- // Cell Interaction
1057
- this.template.addEventListener(
1058
- 'privatecellkeydown',
1059
- handleKeydownOnCell.bind(this)
1060
- );
1022
+ const { template } = this;
1061
1023
 
1062
- this.template.addEventListener(
1063
- 'privatecellfocusedbyclick',
1064
- handleCellFocusByClick.bind(this)
1065
- );
1066
- this.template.addEventListener(
1067
- 'privatecellfalseblurred',
1068
- handleFalseCellBlur.bind(this)
1069
- );
1070
-
1071
- // Row Level Actions
1072
- this.template.addEventListener(
1073
- 'privatecellactiontriggered',
1074
- handleRowActionTriggered.bind(this)
1075
- );
1076
- this.template.addEventListener(
1077
- 'privatecellactionmenuopening',
1078
- handleLoadDynamicActions.bind(this)
1079
- );
1080
- this.template.addEventListener(
1081
- 'privatecellbuttonclicked',
1082
- handleCellButtonClick.bind(this)
1083
- );
1024
+ // Row selection and de-selection
1025
+ this.addEventListener('rowselection', (event) => {
1026
+ this.handleRowSelectionChange(event);
1027
+ });
1028
+ template.addEventListener('selectallrows', (event) => {
1029
+ this.handleSelectionCellClick(event);
1030
+ });
1031
+ template.addEventListener('deselectallrows', (event) => {
1032
+ this.handleSelectionCellClick(event);
1033
+ });
1034
+ template.addEventListener('selectrow', (event) => {
1035
+ this.handleSelectionCellClick(event);
1036
+ });
1037
+ template.addEventListener('deselectrow', (event) => {
1038
+ this.handleSelectionCellClick(event);
1039
+ });
1040
+ // Column resizing
1041
+ template.addEventListener('resizecol', (event) => {
1042
+ this.handleResizeColumn(event);
1043
+ });
1044
+ // Column sorting
1045
+ template.addEventListener('privateupdatecolsort', (event) => {
1046
+ this.handleUpdateColumnSort(event);
1047
+ });
1048
+ // Cell interaction
1049
+ template.addEventListener('privatecellkeydown', (event) => {
1050
+ this.handleKeydownOnCell(event);
1051
+ });
1052
+ template.addEventListener('privatecellfocusedbyclick', (event) => {
1053
+ this.handleCellFocusByClick(event);
1054
+ });
1055
+ template.addEventListener('privatecellfalseblurred', (event) => {
1056
+ this.handleFalseCellBlur(event);
1057
+ });
1058
+ // Row level actions
1059
+ template.addEventListener('privatecellactiontriggered', (event) => {
1060
+ this.handleRowActionTriggered(event);
1061
+ });
1062
+ template.addEventListener('privatecellactionmenuopening', (event) => {
1063
+ this.handleLoadDynamicActions(event);
1064
+ });
1065
+ template.addEventListener('privatecellbuttonclicked', (event) => {
1066
+ this.handleCellButtonClick(event);
1067
+ });
1084
1068
 
1085
- // Header Actions
1086
- this.template.addEventListener(
1069
+ // Header actions
1070
+ template.addEventListener(
1087
1071
  'privatecellheaderactionmenuopening',
1088
- handleHeaderActionMenuOpening.bind(this)
1072
+ (event) => {
1073
+ this.handleHeaderActionMenuOpening(event);
1074
+ }
1089
1075
  );
1090
- this.template.addEventListener(
1076
+ template.addEventListener(
1091
1077
  'privatecellheaderactionmenuclosed',
1092
- handleHeaderActionMenuClosed.bind(this)
1078
+ (event) => {
1079
+ this.handleHeaderActionMenuClosed(event);
1080
+ }
1093
1081
  );
1094
- this.template.addEventListener(
1082
+ template.addEventListener(
1095
1083
  'privatecellheaderactiontriggered',
1096
- handleHeaderActionTriggered.bind(this)
1097
- );
1098
-
1099
- // Inline Edit
1100
- this.template.addEventListener(
1101
- 'privateeditcell',
1102
- handleEditCell.bind(this)
1084
+ (event) => {
1085
+ this.handleHeaderActionTriggered(event);
1086
+ }
1103
1087
  );
1088
+ // Inline edit
1089
+ template.addEventListener('privateeditcell', (event) => {
1090
+ this.handleEditCell(event);
1091
+ });
1104
1092
  }
1105
1093
 
1106
1094
  /**
@@ -1113,64 +1101,76 @@ export default class LightningDatatable extends LightningElement {
1113
1101
  }
1114
1102
 
1115
1103
  renderedCallback() {
1116
- const { state, template, widthsData } = this;
1104
+ const { _columnWidthManager, state, template, widthsData } = this;
1117
1105
 
1118
1106
  // This keeps underlying table element up to date if the aria-* properties on this element is dynamically changed.
1119
1107
  // It does the work of removing and adding the attribute if the value is empty(ish) or a normal string.
1120
1108
  synchronizeAttrs(this.gridContainer, {
1121
1109
  'aria-label': this.ariaLabel,
1122
1110
  'aria-labelledby': this.ariaLabelledBy,
1111
+ 'aria-describedby': this.ariaDescribedBy,
1123
1112
  });
1124
1113
 
1125
- if (!this._privateWidthObserver) {
1126
- this._privateWidthObserver = new LightningDatatableResizeObserver(
1127
- template,
1128
- state,
1114
+ if (_columnWidthManager.isResizingUpdateQueued) {
1115
+ const { columns } = state;
1116
+ const fireResizeEvent = _columnWidthManager.shouldFireResizeEvent(
1129
1117
  widthsData,
1130
- this._columnWidthManager
1118
+ columns
1131
1119
  );
1132
- } else if (!this._privateWidthObserver.isConnected()) {
1133
- this._privateWidthObserver.observe(template);
1134
- }
1135
-
1136
- if (this._columnWidthManager.isResizingUpdateQueued()) {
1137
- const fireResizeEvent =
1138
- this._columnWidthManager.shouldFireResizeEvent(
1139
- widthsData,
1140
- getColumns(state)
1141
- );
1142
-
1143
- this._columnWidthManager.adjustColumnsSize(
1120
+ // Tracked state changes.
1121
+ _columnWidthManager.adjustColumnsSize(
1144
1122
  template,
1145
- getColumns(state),
1123
+ columns,
1146
1124
  widthsData
1147
1125
  );
1148
-
1149
1126
  if (fireResizeEvent) {
1150
1127
  this.fireOnResize(false);
1151
1128
  }
1152
1129
  this.updateTableAndScrollerStyleOnRender();
1153
1130
  }
1154
1131
 
1132
+ let { _widthObserver } = this;
1133
+ if (!_widthObserver) {
1134
+ // Tracked state changes.
1135
+ _widthObserver = new LightningDatatableResizeObserver(
1136
+ template,
1137
+ () => {
1138
+ // Tracked state change.
1139
+ _columnWidthManager.adjustColumnsSizeAfterResize(
1140
+ template,
1141
+ state.columns,
1142
+ widthsData
1143
+ );
1144
+ }
1145
+ );
1146
+ this._widthObserver = _widthObserver;
1147
+ } else if (!_widthObserver.isConnected()) {
1148
+ _widthObserver.observe(template);
1149
+ }
1150
+
1155
1151
  // Managing the cell widths is only required for the role-based table
1156
1152
  if (state.renderModeRoleBased) {
1157
1153
  // TODO: Look to further optimize - Do this only when required
1158
1154
  recomputeCellStyles(this.privateTypes, state);
1159
1155
  }
1160
1156
 
1161
- handlePrefetch.call(this, template, state);
1162
- // customerSelectedRows is only valid till render, after it, the one used should be the one from the state.
1157
+ handlePrefetch.call(this);
1158
+
1159
+ // customerSelectedRows is only valid till render, after it, the one
1160
+ // used should be the one from the state.
1163
1161
  this._customerSelectedRows = null;
1164
- // set the previous focused cell to null after render is done
1165
- resetCellToFocusFromPrev(state);
1166
- // reset focus styles on re-render
1162
+ // Set the previous focused cell to null after render is done.
1163
+ state.cellToFocusNext = undefined;
1164
+
1165
+ // Reset focus styles on re-render.
1167
1166
  if (this._shouldResetFocus) {
1168
- // since focus is now getting reset, can change this back to false
1167
+ // Since focus is now getting reset, can change this back to false.
1169
1168
  this._shouldResetFocus = false;
1170
- // don't return focus to active cell when inline edit panel is open
1169
+ // Don't return focus to active cell when inline edit panel is open.
1170
+ const { activeCell } = state;
1171
1171
  if (
1172
- state.activeCell &&
1173
- state.activeCell.focused &&
1172
+ activeCell &&
1173
+ activeCell.focused &&
1174
1174
  !state.inlineEdit.isPanelVisible
1175
1175
  ) {
1176
1176
  const cellElement = getActiveCellElement(template, state);
@@ -1179,7 +1179,8 @@ export default class LightningDatatable extends LightningElement {
1179
1179
  cellElement.parentElement &&
1180
1180
  !cellElement.parentElement.classList.contains(FOCUS_CLASS)
1181
1181
  ) {
1182
- setFocusActiveCell(template, state, null, null, false);
1182
+ // Tracked state change.
1183
+ setFocusActiveCell(state, template, null, null, false);
1183
1184
  }
1184
1185
  }
1185
1186
  }
@@ -1209,20 +1210,20 @@ export default class LightningDatatable extends LightningElement {
1209
1210
  }
1210
1211
 
1211
1212
  updateTableAndScrollerStyleOnRender() {
1212
- const role = '[role="' + this.computedTableRole + '"]';
1213
- const tableElement = this.template.querySelector(role);
1214
- const scrollYEle = this.template.querySelector('.slds-scrollable_y');
1213
+ const scrollYEle = getScrollerY(this.template);
1214
+ const tableElement = getGridContainerFromScrollerY(scrollYEle);
1215
1215
  if (tableElement) {
1216
1216
  tableElement.style = this.computedTableStyle;
1217
1217
  }
1218
1218
  if (scrollYEle) {
1219
- scrollYEle.style = this.computedScrollerStyle;
1219
+ scrollYEle.style = this.computedScrollerYStyle;
1220
1220
  }
1221
1221
  }
1222
1222
 
1223
1223
  disconnectedCallback() {
1224
- if (this._privateWidthObserver) {
1225
- this._privateWidthObserver.disconnect();
1224
+ const { _widthObserver } = this;
1225
+ if (_widthObserver) {
1226
+ _widthObserver.disconnect();
1226
1227
  }
1227
1228
 
1228
1229
  this._renderManager.disconnectResizeObserver();
@@ -1230,6 +1231,24 @@ export default class LightningDatatable extends LightningElement {
1230
1231
 
1231
1232
  /************************** EVENT HANDLERS ***************************/
1232
1233
 
1234
+ handleCellButtonClick = handleCellButtonClick;
1235
+
1236
+ handleEditCell = handleEditCell;
1237
+
1238
+ handleHeaderActionMenuClosed = handleHeaderActionMenuClosed;
1239
+
1240
+ handleHeaderActionMenuOpening = handleHeaderActionMenuOpening;
1241
+
1242
+ handleHeaderActionTriggered = handleHeaderActionTriggered;
1243
+
1244
+ handleKeydownOnCell = handleKeydownOnCell;
1245
+
1246
+ handleLoadDynamicActions = handleLoadDynamicActions;
1247
+
1248
+ handleRowSelectionChange = handleRowSelectionChange;
1249
+
1250
+ handleRowActionTriggered = handleRowActionTriggered;
1251
+
1233
1252
  handleCustomTypesChange() {
1234
1253
  const assignedNodes = this.template
1235
1254
  .querySelector('slot[name="customdatatypes"]')
@@ -1240,85 +1259,74 @@ export default class LightningDatatable extends LightningElement {
1240
1259
  this._privateTypes = new DatatableTypes(
1241
1260
  provider.getDataTypes()
1242
1261
  );
1243
- this.updateColumns(this._columns);
1262
+ this.updateColumns(this._rawColumns);
1244
1263
  }
1245
1264
  }
1246
1265
  }
1247
1266
 
1248
1267
  /**
1249
- * Handles the `keydown` event on <table> and the
1268
+ * Handles the 'keydown' event on <table> and the
1250
1269
  * corresponding <div> on the role-based table
1251
1270
  *
1252
- * @param {KeyboardEvent} event - `keydown`
1271
+ * @param {KeyboardEvent} event - 'keydown'
1253
1272
  */
1254
- handleTableKeydown(event) {
1255
- handleKeydownOnTable.call(this, event);
1256
- }
1273
+ handleTableKeydown = handleKeydownOnTable;
1257
1274
 
1258
1275
  /**
1259
- * Handles the `keydown` event on data row <tr> (table-based) and div[role="row"] (role-based)
1276
+ * Handles the 'keydown' event on data row <tr> (table-based) and div[role="row"] (role-based)
1260
1277
  *
1261
- * @param {KeyboardEvent} event - `keydown`
1278
+ * @param {KeyboardEvent} event - 'keydown'
1262
1279
  */
1263
1280
  handleKeydownOnDataRow(event) {
1281
+ const { state } = this;
1264
1282
  // we probably should not be doing this unless we actually are interested in it
1265
- if (
1266
- this.state.keyboardMode === 'NAVIGATION' &&
1267
- this.state.rowMode === true
1268
- ) {
1283
+ if (state.keyboardMode === KEYBOARD_NAVIGATION_MODE && state.rowMode) {
1269
1284
  event.stopPropagation();
1270
-
1271
- const tr = event.currentTarget;
1272
- const rowKeyValue = tr.getAttribute('data-row-key-value');
1273
- const keyCode = event.keyCode;
1274
- const rowHasChildren = !!tr.getAttribute('aria-expanded');
1275
- const rowExpanded = tr.getAttribute('aria-expanded') === 'true';
1276
- const rowLevel = tr.getAttribute('aria-level');
1277
-
1278
- const evt = {
1285
+ const { currentTarget: tr } = event;
1286
+ reactToKeyboardOnRow(this, {
1279
1287
  target: tr,
1280
1288
  detail: {
1281
- rowKeyValue,
1282
- keyCode,
1283
- rowHasChildren,
1284
- rowExpanded,
1285
- rowLevel,
1289
+ keyCode: event.keyCode,
1286
1290
  keyEvent: event,
1291
+ rowExpanded: tr.getAttribute('aria-expanded') === 'true',
1292
+ rowHasChildren: !!tr.getAttribute('aria-expanded'),
1293
+ rowKeyValue: tr.getAttribute('data-row-key-value'),
1294
+ rowLevel: tr.getAttribute('aria-level'),
1287
1295
  },
1288
- };
1289
-
1290
- reactToKeyboardOnRow(this, this.state, evt);
1296
+ });
1291
1297
  }
1292
1298
  }
1293
1299
 
1294
1300
  /**
1295
- * Handles the `scroll` event on the table container
1301
+ * Handles the 'scroll' event on the table container
1296
1302
  *
1297
- * @param {Event} event - `scroll`
1303
+ * @param {Event} event - 'scroll'
1298
1304
  */
1299
1305
  handleHorizontalScroll(event) {
1300
1306
  handleInlineEditPanelScroll.call(this, event);
1301
1307
  }
1302
1308
 
1303
1309
  /**
1304
- * Handles the `scroll` event on the child of the
1305
- * table container at div.slds-scrollable_y
1310
+ * Handles the 'scroll' event on the child of the
1311
+ * table container at div.slds-scrollable_y.
1306
1312
  *
1307
- * @param {Event} event - `scroll`
1313
+ * @param {Event} event - 'scroll'
1308
1314
  */
1309
1315
  handleVerticalScroll(event) {
1310
- if (this.enableInfiniteLoading) {
1316
+ const { state } = this;
1317
+ if (state.enableInfiniteLoading) {
1311
1318
  handleLoadMoreCheck.call(this, event);
1312
1319
  }
1313
1320
 
1321
+ // Tracked state changes.
1314
1322
  handleInlineEditPanelScroll.call(this, event);
1315
- if (this.state.virtualize) {
1316
- this.state.firstVisibleIndex = findFirstVisibleIndex(
1323
+ if (state.virtualize) {
1324
+ state.firstVisibleIndex = findFirstVisibleIndex(
1317
1325
  this.state,
1318
1326
  event.target.scrollTop
1319
1327
  );
1320
1328
  } else if (this.viewportRendering) {
1321
- this._renderManager.handleScroll(this.state, event);
1329
+ this._renderManager.handleScroll(state, event);
1322
1330
  }
1323
1331
  }
1324
1332
 
@@ -1328,15 +1336,13 @@ export default class LightningDatatable extends LightningElement {
1328
1336
  *
1329
1337
  * @param {MouseEvent} event - `click`
1330
1338
  */
1331
- handleCellClick(event) {
1339
+ handleTableCellClick(event) {
1332
1340
  // handles the case when clicking on the margin/pading of the td/th
1333
- const targetTagName = event.target.tagName.toLowerCase();
1334
- const targetRole = event.target.getAttribute('role');
1335
-
1336
- if (isCellElement(targetTagName, targetRole)) {
1341
+ const { target } = event;
1342
+ if (isCellElement(target)) {
1337
1343
  // get the row/col key value from the primitive cell.
1338
1344
  const { rowKeyValue, colKeyValue } =
1339
- event.target.querySelector(':first-child');
1345
+ target.querySelector(':first-child');
1340
1346
 
1341
1347
  const { state, template } = this;
1342
1348
  if (
@@ -1346,7 +1352,7 @@ export default class LightningDatatable extends LightningElement {
1346
1352
  if (state.rowMode && state.activeCell) {
1347
1353
  unsetRowNavigationMode(state);
1348
1354
  const { rowIndex } = getIndexesActiveCell(state);
1349
- updateTabIndexRow(state, rowIndex, -1);
1355
+ updateRowTabIndex(state, rowIndex, -1);
1350
1356
  }
1351
1357
  this.setActiveCell(rowKeyValue, colKeyValue);
1352
1358
  }
@@ -1358,14 +1364,13 @@ export default class LightningDatatable extends LightningElement {
1358
1364
  }
1359
1365
 
1360
1366
  /**
1361
- * Handles the `privateupdatecolsort` event on lightning-datatable
1367
+ * Handles the 'privateupdatecolsort' event on lightning-datatable
1362
1368
  *
1363
- * @param {CustomEvent} event - `privateupdatecolsort`
1369
+ * @param {CustomEvent} event - 'privateupdatecolsort'
1364
1370
  */
1365
1371
  handleUpdateColumnSort(event) {
1366
1372
  event.stopPropagation();
1367
1373
  const { fieldName, columnKey, sortDirection } = event.detail;
1368
-
1369
1374
  this.fireSortedColumnChange(fieldName, columnKey, sortDirection);
1370
1375
  }
1371
1376
 
@@ -1374,31 +1379,31 @@ export default class LightningDatatable extends LightningElement {
1374
1379
  }
1375
1380
 
1376
1381
  /**
1377
- * Handles the `resizecol` event on lightning-datatable
1382
+ * Handles the 'resizecol' event on lightning-datatable
1378
1383
  *
1379
- * @param {CustomEvent} event - `resizecol`
1384
+ * @param {CustomEvent} event - 'resizecol'
1380
1385
  */
1381
1386
  handleResizeColumn(event) {
1382
1387
  event.stopPropagation();
1383
- const { state, widthsData } = this;
1384
- const { colIndex, widthDelta } = event.detail;
1385
- if (widthDelta !== 0) {
1388
+ const { state } = this;
1389
+ const { colIndex, widthDelta: delta } = event.detail;
1390
+ if (delta !== 0) {
1386
1391
  resizeColumnWithDelta(
1387
- getColumns(state),
1388
- widthsData,
1392
+ state.columns,
1393
+ this.widthsData,
1389
1394
  colIndex,
1390
- widthDelta
1395
+ delta
1391
1396
  );
1392
1397
  this.fireOnResize(true);
1393
- this.safariHeaderFix();
1398
+ this.fixHeaderForSafari();
1394
1399
  }
1395
1400
  }
1396
1401
 
1397
1402
  /**
1398
- * Handles the `privateresizestart` event on the <tr> and the corresponding
1403
+ * Handles the 'privateresizestart' event on the <tr> and the corresponding
1399
1404
  * <div> in the role-based table on the column header row
1400
1405
  *
1401
- * @param {CustomEvent} event - `privateresizestart`
1406
+ * @param {CustomEvent} event - 'privateresizestart'
1402
1407
  */
1403
1408
  handleResizeStart(event) {
1404
1409
  event.stopPropagation();
@@ -1406,10 +1411,10 @@ export default class LightningDatatable extends LightningElement {
1406
1411
  }
1407
1412
 
1408
1413
  /**
1409
- * Handles the `privateresizeend` event on the <tr> and the corresponding
1414
+ * Handles the 'privateresizeend' event on the <tr> and the corresponding
1410
1415
  * <div> in the role-based table on the column header row
1411
1416
  *
1412
- * @param {CustomEvent} event - `privateresizeend`
1417
+ * @param {CustomEvent} event - 'privateresizeend'
1413
1418
  */
1414
1419
  handleResizeEnd(event) {
1415
1420
  event.stopPropagation();
@@ -1425,66 +1430,65 @@ export default class LightningDatatable extends LightningElement {
1425
1430
  */
1426
1431
  handleSelectionCellClick(event) {
1427
1432
  this.handleCellFocusByClick(event);
1428
-
1429
- if (event.type === 'selectrow') {
1433
+ const { type } = event;
1434
+ if (type === 'selectrow') {
1430
1435
  handleSelectRow.call(this, event);
1431
- } else if (event.type === 'deselectrow') {
1436
+ } else if (type === 'deselectrow') {
1432
1437
  handleDeselectRow.call(this, event);
1433
- } else if (event.type === 'selectallrows') {
1438
+ } else if (type === 'selectallrows') {
1434
1439
  handleSelectAllRows.call(this, event);
1435
- } else if (event.type === 'deselectallrows') {
1440
+ } else if (type === 'deselectallrows') {
1436
1441
  handleDeselectAllRows.call(this, event);
1437
1442
  }
1438
1443
  }
1439
1444
 
1440
1445
  /**
1441
- * Handles the `privatecellfocusedbyclick` event on lightning-datatable
1446
+ * Handles the 'privatecellfocusedbyclick' event on lightning-datatable
1442
1447
  *
1443
- * @param {CustomEvent} event - `privatecellfocusedbyclick`
1448
+ * @param {CustomEvent} event - 'privatecellfocusedbyclick'
1444
1449
  */
1445
1450
  handleCellFocusByClick(event) {
1446
1451
  event.stopPropagation();
1452
+ const { state } = this;
1447
1453
  const { rowKeyValue, colKeyValue, needsRefocusOnCellElement } =
1448
1454
  event.detail;
1449
- const { state } = this;
1450
1455
  if (!isActiveCell(state, rowKeyValue, colKeyValue)) {
1451
1456
  if (state.rowMode && state.activeCell) {
1452
1457
  unsetRowNavigationMode(state);
1453
1458
  const { rowIndex } = getIndexesActiveCell(state);
1454
- updateTabIndexRow(state, rowIndex, -1);
1459
+ updateRowTabIndex(state, rowIndex, -1);
1455
1460
  }
1456
1461
  this.setActiveCell(rowKeyValue, colKeyValue);
1457
- refocusCellElement(this.template, state, needsRefocusOnCellElement);
1462
+ refocusCellElement(state, this.template, needsRefocusOnCellElement);
1458
1463
  }
1459
1464
  }
1460
1465
 
1461
1466
  /**
1462
- * Handles the `privatecellfalseblurred` event on lightning-datatable
1467
+ * Handles the 'privatecellfalseblurred' event on lightning-datatable
1463
1468
  *
1464
- * @param {CustomEvent} event - `privatecellfalseblurred`
1469
+ * @param {CustomEvent} event - 'privatecellfalseblurred'
1465
1470
  */
1466
1471
  handleFalseCellBlur(event) {
1467
1472
  event.stopPropagation();
1468
- const { template, state } = this;
1473
+ const { state } = this;
1469
1474
  const { rowKeyValue, colKeyValue } = event.detail;
1470
1475
  if (!isActiveCell(state, rowKeyValue, colKeyValue)) {
1471
1476
  this.setActiveCell(rowKeyValue, colKeyValue);
1472
1477
  }
1473
- setFocusActiveCell(template, state);
1478
+ // Tracked state change.
1479
+ setFocusActiveCell(state, this.template);
1474
1480
  }
1475
1481
 
1476
1482
  /**
1477
- * Handles the `focusin` event on <table> and the corresponding
1483
+ * Handles the 'focusin' event on <table> and the corresponding
1478
1484
  * <div> on the role-based table
1479
1485
  *
1480
- * @param {FocusEvent} event - `focusin`
1486
+ * @param {FocusEvent} event - 'focusin'
1481
1487
  */
1482
- handleTableFocusIn(event) {
1483
- handleDatatableFocusIn.call(this, event);
1484
- }
1488
+ handleTableFocusIn = handleDatatableFocusIn;
1485
1489
 
1486
1490
  /**
1487
- * Handles the `focusout` event on <table> and the corresponding
1491
+ * Handles the 'focusout' event on <table> and the corresponding
1488
1492
  * <div> on the role-based table
1489
1493
  *
1490
1494
  * This gets called both when we expect the table to lose focus
@@ -1495,49 +1499,44 @@ export default class LightningDatatable extends LightningElement {
1495
1499
  * _shouldResetFocus, which will be true if and only if focus was
1496
1500
  * lost due to a renderedRows change for a virtualized table.
1497
1501
  *
1498
- * @param {FocusEvent} event - `focusout`
1502
+ * @param {FocusEvent} event - 'focusout'
1499
1503
  */
1500
1504
  handleTableFocusOut(event) {
1501
1505
  handleDatatableFocusOut.call(this, event);
1502
- if (this.state.activeCell) {
1503
- this.state.activeCell.focused = this._shouldResetFocus;
1506
+ const { activeCell } = this.state;
1507
+ if (activeCell) {
1508
+ activeCell.focused = this._shouldResetFocus;
1504
1509
  }
1505
1510
  }
1506
1511
 
1507
1512
  /**
1508
- * Handles the `ieditfinished` event on the inline edit panel -
1513
+ * Handles the 'ieditfinished' event on the inline edit panel -
1509
1514
  * `lightning-primitive-datatable-iedit-panel`
1510
1515
  *
1511
- * @param {CustomEvent} event - `ieditfinished`
1516
+ * @param {CustomEvent} event - 'ieditfinished'
1512
1517
  */
1513
- handleInlineEditFinish(event) {
1514
- handleInlineEditFinish.call(this, event);
1515
- }
1518
+ handleInlineEditFinish = handleInlineEditFinish;
1516
1519
 
1517
1520
  /**
1518
- * Handles the `masscheckboxchange` event on the inline edit panel -
1521
+ * Handles the 'masscheckboxchange' event on the inline edit panel -
1519
1522
  * `lightning-primitive-datatable-iedit-panel`
1520
1523
  *
1521
- * @param {CustomEvent} event - `masscheckboxchange`
1524
+ * @param {CustomEvent} event - 'masscheckboxchange'
1522
1525
  */
1523
- handleMassCheckboxChange(event) {
1524
- handleMassCheckboxChange.call(this, event);
1525
- }
1526
+ handleMassCheckboxChange = handleMassCheckboxChange;
1526
1527
 
1527
1528
  /**
1528
- * Handles the `privatesave` event on the status bar -
1529
+ * Handles the 'privatesave' event on the status bar -
1529
1530
  * `lightning-primitive-datatable-status-bar` and
1530
1531
  * fires the `save` custom event
1531
1532
  *
1532
- * @param {CustomEvent} event - `privatesave`
1533
+ * @param {CustomEvent} event - 'privatesave'
1533
1534
  */
1534
1535
  handleInlineEditSave(event) {
1535
1536
  event.stopPropagation();
1536
1537
  event.preventDefault();
1537
-
1538
1538
  closeInlineEdit(this);
1539
- const draftValues = this.draftValues;
1540
-
1539
+ const { draftValues } = this;
1541
1540
  this.dispatchEvent(
1542
1541
  new CustomEvent('save', {
1543
1542
  detail: {
@@ -1548,11 +1547,11 @@ export default class LightningDatatable extends LightningElement {
1548
1547
  }
1549
1548
 
1550
1549
  /**
1551
- * Handles the `privatecancel` event on the status bar -
1550
+ * Handles the 'privatecancel' event on the status bar -
1552
1551
  * `lightning-primitive-datatable-status-bar` and
1553
1552
  * fires the `cancel` custom event
1554
1553
  *
1555
- * @param {CustomEvent} event - `privatecancel`
1554
+ * @param {CustomEvent} event - 'privatecancel'
1556
1555
  */
1557
1556
  handleInlineEditCancel(event) {
1558
1557
  event.stopPropagation();
@@ -1563,6 +1562,7 @@ export default class LightningDatatable extends LightningElement {
1563
1562
  const customerEvent = new CustomEvent('cancel', {
1564
1563
  cancelable: true,
1565
1564
  });
1565
+
1566
1566
  this.dispatchEvent(customerEvent);
1567
1567
 
1568
1568
  if (!customerEvent.defaultPrevented) {
@@ -1573,27 +1573,25 @@ export default class LightningDatatable extends LightningElement {
1573
1573
 
1574
1574
  /**
1575
1575
  * @event LightningDatatable#onprivatelookupitempicked We need to augment the original event LightningFormattedLookup#onprivatelookupitempicked
1576
- * @type {object}
1577
- * @property {string} recordId
1578
- * @property {number} rowIndex
1579
- * @property {string} rowKeyValue
1576
+ * @type {Object}
1577
+ * @property {String} recordId
1578
+ * @property {Number} rowIndex
1579
+ * @property {String} rowKeyValue
1580
1580
  */
1581
-
1582
1581
  /**
1583
- * Handles the `privatelookupitempicked` event from the lightning-formatted-lookup or force-lookup
1584
- * `lightning-primitive-datatable-status-bar` and fires the augmented `privatelookupitempicked` custom event
1582
+ * Handles the 'privatelookupitempicked' event from the lightning-formatted-lookup or force-lookup
1583
+ * `lightning-primitive-datatable-status-bar` and fires the augmented 'privatelookupitempicked' custom event
1585
1584
  *
1586
- * @param {CustomEvent} event - `privatelookupitempicked`
1585
+ * @param {CustomEvent} event - 'privatelookupitempicked'
1587
1586
  * @fires LightningDatatable#onprivatelookupitempicked
1588
1587
  */
1589
1588
  handlePrivateLookupItemPicked(event) {
1590
1589
  event.stopPropagation();
1591
1590
  event.preventDefault();
1592
1591
 
1593
- const { currentTarget } = event;
1594
1592
  const { recordId } = event.detail;
1595
1593
  const { rowIndex, rowKeyValue } =
1596
- this.computeRowLookupItemPickedInformation(currentTarget);
1594
+ this.computeRowLookupItemPickedInformation(event.currentTarget);
1597
1595
 
1598
1596
  this.dispatchEvent(
1599
1597
  // We will the below Eslint rule as we use a constant to apply the name of the event
@@ -1616,55 +1614,65 @@ export default class LightningDatatable extends LightningElement {
1616
1614
 
1617
1615
  /************************ EVENT DISPATCHERS **************************/
1618
1616
 
1619
- fireSelectedRowsChange(selectedRows, config) {
1620
- const event = new CustomEvent('rowselection', {
1621
- detail: { selectedRows, config: config || {} },
1622
- });
1623
-
1624
- this.dispatchEvent(event);
1617
+ fireSelectedRowsChange(selectedRows, config = {}) {
1618
+ this.dispatchEvent(
1619
+ new CustomEvent('rowselection', {
1620
+ detail: { selectedRows, config },
1621
+ })
1622
+ );
1625
1623
  }
1626
1624
 
1627
1625
  fireSortedColumnChange(fieldName, columnKey, sortDirection) {
1628
- const event = new CustomEvent('sort', {
1629
- detail: { fieldName, columnKey, sortDirection },
1630
- });
1631
- this.dispatchEvent(event);
1626
+ this.dispatchEvent(
1627
+ new CustomEvent('sort', {
1628
+ detail: { fieldName, columnKey, sortDirection },
1629
+ })
1630
+ );
1632
1631
  }
1633
1632
 
1634
1633
  fireOnResize(isUserTriggered) {
1635
- const { state, widthsData } = this;
1636
- const event = new CustomEvent('resize', {
1637
- detail: {
1638
- columnWidths: getCustomerColumnWidths(
1639
- getColumns(state),
1640
- widthsData
1641
- ),
1642
- isUserTriggered: !!isUserTriggered,
1643
- },
1644
- });
1645
- this.dispatchEvent(event);
1634
+ this.dispatchEvent(
1635
+ new CustomEvent('resize', {
1636
+ detail: {
1637
+ columnWidths: getCustomerColumnWidths(
1638
+ this.state.columns,
1639
+ this.widthsData
1640
+ ),
1641
+ isUserTriggered: !!isUserTriggered,
1642
+ },
1643
+ })
1644
+ );
1646
1645
  }
1647
1646
 
1648
1647
  /************************* HELPER FUNCTIONS **************************/
1649
1648
 
1650
1649
  updateRowsState() {
1651
- const { state, widthsData, template } = this;
1652
- // calculate cell to focus next before indexes are updated
1653
- setCellToFocusFromPrev(state, template);
1650
+ this.updateRowsBeforeIndexes();
1651
+ this.updateRowsAndCells();
1652
+ this.updateRowsAfterIndexes();
1653
+ }
1654
1654
 
1655
- this.updateRowsAndCellIndexes(state);
1655
+ updateRowsBeforeIndexes() {
1656
+ // Untracked state change.
1657
+ setCellToFocusFromPrev(this.state, this.template);
1658
+ }
1656
1659
 
1660
+ updateRowsAfterIndexes() {
1661
+ const { state, widthsData } = this;
1657
1662
  if (this.viewportRendering || state.virtualize) {
1658
1663
  this._renderManager.updateViewportRendering(
1659
- this.state,
1664
+ state,
1660
1665
  this.gridContainer,
1661
1666
  !!state.virtualize
1662
1667
  );
1663
1668
  }
1664
1669
 
1670
+ // Tracked state changes.
1665
1671
  this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
1666
- // update celltofocus next to null if the row still exists after indexes calculation
1672
+ // Untracked state change.
1673
+ // Unset the cellToFocusNext if the row still exists after indexes calculation.
1667
1674
  updateCellToFocusFromPrev(state);
1675
+ // A mix of tracked and untracked state changes.
1668
1676
  syncSelectedRowsKeys(state, this.getSelectedRows()).ifChanged(() => {
1669
1677
  // Only trigger row selection event once after all the setters have executed
1670
1678
  // Otherwise, event can be fired with stale data if not all setters have been triggered
@@ -1678,52 +1686,77 @@ export default class LightningDatatable extends LightningElement {
1678
1686
  });
1679
1687
  }
1680
1688
  });
1689
+ // Untracked state change.
1681
1690
  syncActiveCell(state);
1682
1691
 
1683
- if (state.keyboardMode === 'NAVIGATION') {
1692
+ if (state.keyboardMode === KEYBOARD_NAVIGATION_MODE) {
1693
+ // Tracked state changes.
1684
1694
  updateTabIndexActiveCell(state);
1685
1695
  updateTabIndexActiveRow(state);
1686
1696
  }
1687
- // if there is previously focused cell which was deleted set focus from celltofocus next
1688
- if (state.cellToFocusNext && state.activeCell) {
1689
- setFocusActiveCell(this.template, this.state);
1697
+ // if there is previously focused cell which was deleted set focus from cellToFocusNext
1698
+ if (state.activeCell && state.cellToFocusNext) {
1699
+ // Tracked state change.
1700
+ setFocusActiveCell(state, this.template);
1690
1701
  }
1691
1702
  }
1692
1703
 
1693
1704
  updateColumns(columns) {
1694
- const { state, widthsData, template } = this;
1705
+ const { state } = this;
1706
+ this.updateColumnsBeforeIndexes(columns);
1707
+ state.headerIndexes = generateHeaderIndexes(state.columns);
1708
+ this.updateRowsAndCells();
1709
+ this.updateColumnsAfterIndexes();
1710
+ }
1711
+
1712
+ updateColumnsBeforeIndexes(columns) {
1713
+ const { state } = this;
1695
1714
  const hadTreeDataTypePreviously = hasTreeDataType(state);
1696
- // calculate cell to focus next before indexes are updated
1697
- setCellToFocusFromPrev(state, template);
1715
+ // Untracked state changes.
1716
+ // Calculate cell to focus next before indexes are updated.
1717
+ setCellToFocusFromPrev(state, this.template);
1698
1718
  normalizeColumns(state, columns, this.privateTypes);
1699
- setDirtyValues(state, this._draftValues);
1700
1719
  updateRowNavigationMode(hadTreeDataTypePreviously, state);
1701
- state.headerIndexes = generateHeaderIndexes(getColumns(state));
1720
+ // Tracked state changes.
1721
+ setDirtyValues(state, this._draftValues);
1702
1722
  // Updates state.wrapText and when isWrappableType, sets internal header actions
1703
- updateHeaderActions(state);
1704
- this.updateRowsAndCellIndexes(state);
1723
+ updateHeaderInternalActions(state);
1724
+ }
1725
+
1726
+ updateColumnsAfterIndexes() {
1727
+ const { state, widthsData } = this;
1728
+
1729
+ // Tracked state changes.
1705
1730
  updateBulkSelectionState(state);
1706
1731
  this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
1707
- updateColumnWidthsMetadata(getColumns(state), widthsData);
1708
- // set the celltofocus next to null if the column still exists after indexes calculation
1732
+ updateColumnWidthsMetadata(state.columns, widthsData);
1733
+ // Unset the cellToFocusNext if the column still exists after indexes calculation.
1709
1734
  updateCellToFocusFromPrev(state);
1710
1735
 
1711
- if (getColumns(state).length !== getColumnsWidths(widthsData).length) {
1712
- if (getData(state).length > 0) {
1713
- // when there are column changes, update the active cell
1714
- syncActiveCell(state);
1715
- }
1736
+ if (
1737
+ state.data.length > 0 &&
1738
+ state.columns.length !== widthsData.columnWidths.length
1739
+ ) {
1740
+ // Untracked state change.
1741
+ // When there are column changes, update the active cell.
1742
+ syncActiveCell(state);
1716
1743
  }
1717
- if (state.keyboardMode === 'NAVIGATION') {
1744
+ if (state.keyboardMode === KEYBOARD_NAVIGATION_MODE) {
1745
+ // Tracked state changes.
1718
1746
  updateTabIndexActiveCell(state);
1719
1747
  updateTabIndexActiveRow(state);
1720
1748
  }
1721
- // if there is previously focused cell which was deleted set focus from celltofocus next
1722
- if (state.cellToFocusNext && state.activeCell) {
1723
- setFocusActiveCell(this.template, this.state);
1749
+ // If there is previously focused cell which was deleted set focus from cellToFocusNext.
1750
+ if (state.activeCell && state.cellToFocusNext) {
1751
+ // Tracked state change.
1752
+ setFocusActiveCell(state, this.template);
1724
1753
  }
1725
1754
  }
1726
1755
 
1756
+ updateRowsAndCells() {
1757
+ updateRowsAndCellIndexes(this.state, this._privateTypes);
1758
+ }
1759
+
1727
1760
  updateVirtualizedRowHeights() {
1728
1761
  const state = this.state;
1729
1762
  const virtualizedRows = state.virtualize && this.renderedRows.length;
@@ -1740,7 +1773,7 @@ export default class LightningDatatable extends LightningElement {
1740
1773
  } else if (virtualizedRows && state.fixedHeight) {
1741
1774
  // if heights are fixed, we only need to check height of first row
1742
1775
  const rowElement = this.template.querySelector(
1743
- getDataRow(this.renderedRows[0].key)
1776
+ getRowDataSelector(this.renderedRows[0].key)
1744
1777
  );
1745
1778
  // increase height by 1 since first rendered row is missing an extra 1px border
1746
1779
  if (rowElement) {
@@ -1749,10 +1782,9 @@ export default class LightningDatatable extends LightningElement {
1749
1782
  state.rowHeight = height;
1750
1783
  resetTableHeight(state);
1751
1784
  state.rows.forEach((row) => {
1752
- row.style = styleToString({
1753
- position: 'absolute',
1754
- top: `${row.rowIndex * height}px`,
1755
- });
1785
+ row.style = `position:absolute;top:${
1786
+ row.rowIndex * height
1787
+ }px;`;
1756
1788
  });
1757
1789
  }
1758
1790
  }
@@ -1761,50 +1793,50 @@ export default class LightningDatatable extends LightningElement {
1761
1793
 
1762
1794
  setSelectedRows(value) {
1763
1795
  setSelectedRowsKeys(this.state, value);
1764
- handleRowSelectionChange.call(this);
1796
+ this.handleRowSelectionChange();
1765
1797
  }
1766
1798
 
1767
1799
  setActiveCell(rowKeyValue, colKeyValue) {
1768
- const { template, state } = this;
1800
+ const { state, template } = this;
1769
1801
  const { rowIndex, colIndex } = getIndexesByKeys(
1770
1802
  state,
1771
1803
  rowKeyValue,
1772
1804
  colKeyValue
1773
1805
  );
1774
- setBlurActiveCell(template, state);
1775
- updateActiveCell(state, rowKeyValue, colKeyValue);
1776
- addFocusStylesToActiveCell(template, state);
1777
- updateTabIndex(state, rowIndex, colIndex, 0);
1806
+ // Tracked state change.
1807
+ setBlurActiveCell(state, template);
1808
+ // Untracked state change.
1809
+ state.activeCell = { rowKeyValue, colKeyValue };
1810
+ // Tracked state changes.
1811
+ addFocusStylesToActiveCell(state, template);
1812
+ updateCellTabIndex(state, rowIndex, colIndex, 0);
1778
1813
  }
1779
1814
 
1780
1815
  /**
1781
1816
  * @returns {Object} containing the visible dimensions of the table { left, right, top, bottom, }
1782
1817
  */
1783
1818
  getViewableRect() {
1784
- const scrollerX = this.template
1785
- .querySelector('.slds-scrollable_x')
1786
- .getBoundingClientRect();
1787
- const scrollerY = this.template
1788
- .querySelector('.slds-scrollable_y')
1789
- .getBoundingClientRect();
1819
+ const { template } = this;
1820
+ const scrollerY = getScrollerY(template);
1821
+ const scrollerYRect = scrollerY.getBoundingClientRect();
1822
+ const scrollerX = getScrollerXFromScrollerY(scrollerY);
1823
+ const scrollerXRect = scrollerX.getBoundingClientRect();
1790
1824
 
1791
1825
  return {
1792
- left: scrollerX.left,
1793
- right: scrollerX.right,
1794
- top: scrollerY.top,
1795
- bottom: scrollerY.bottom,
1826
+ left: scrollerXRect.left,
1827
+ right: scrollerXRect.right,
1828
+ top: scrollerYRect.top,
1829
+ bottom: scrollerYRect.bottom,
1796
1830
  };
1797
1831
  }
1798
1832
 
1799
1833
  // W-6363867, W-7143375 Safari Refresh Bug
1800
- safariHeaderFix() {
1834
+ fixHeaderForSafari() {
1801
1835
  if (isSafari) {
1802
1836
  const thead = this.template.querySelector('thead');
1803
-
1804
1837
  if (thead) {
1805
1838
  /* Safari hack: hide and show the table head to force a browser repaint */
1806
1839
  thead.style.display = 'none';
1807
-
1808
1840
  // eslint-disable-next-line @lwc/lwc/no-async-operation
1809
1841
  requestAnimationFrame(() => {
1810
1842
  thead.style.display = '';
@@ -1817,10 +1849,11 @@ export default class LightningDatatable extends LightningElement {
1817
1849
  * @returns { rowIndex: number, rowKeyValue: string } Compute the information to use to generate the lookupItemPicked event based on the row where the event comes from
1818
1850
  */
1819
1851
  computeRowLookupItemPickedInformation(currentTarget) {
1820
- const rowIndex =
1821
- Number.parseInt(currentTarget.dataset.rowNumber, 10) - 1; // Row number always start to 1, so we convert it to be able to use it for an array
1822
- const rowKeyValue = currentTarget.dataset.rowKeyValue;
1823
-
1852
+ const { dataset } = currentTarget;
1853
+ // Row number always start to 1, so we convert it to be able to use
1854
+ // it for an array
1855
+ const rowIndex = Number.parseInt(dataset.rowNumber, 10) - 1;
1856
+ const { rowKeyValue } = dataset;
1824
1857
  return { rowIndex, rowKeyValue };
1825
1858
  }
1826
1859
  }