lightning-base-components 1.21.3-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 (183) hide show
  1. package/metadata/raptor.json +49 -0
  2. package/package.json +88 -21
  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/src/lightning/avatar/avatar.html +1 -0
  17. package/src/lightning/badge/badge.html +3 -3
  18. package/src/lightning/baseCombobox/baseCombobox.html +4 -1
  19. package/src/lightning/baseCombobox/baseCombobox.js +3 -16
  20. package/src/lightning/button/__docs__/button.md +2 -1
  21. package/src/lightning/button/button.js +3 -4
  22. package/src/lightning/buttonIcon/__docs__/buttonIcon.md +1 -0
  23. package/src/lightning/buttonIcon/buttonIcon.html +1 -1
  24. package/src/lightning/buttonIcon/buttonIcon.js +18 -17
  25. package/src/lightning/buttonMenu/buttonMenu.css +5 -0
  26. package/src/lightning/buttonMenu/buttonMenu.js +2 -0
  27. package/src/lightning/colorPickerCustom/colorPickerCustom.js +12 -0
  28. package/src/lightning/colorPickerPanel/colorPickerPanel.js +11 -1
  29. package/src/lightning/combobox/combobox.html +1 -0
  30. package/src/lightning/datatable/__examples__disabled/customComponentWrapper/customComponentWrapper.html +11 -0
  31. package/src/lightning/datatable/__examples__disabled/customComponentWrapper/customComponentWrapper.js +25 -0
  32. package/src/lightning/datatable/__examples__disabled/customComponentWrapper/generateData.js +15 -0
  33. package/src/lightning/datatable/__examples__disabled/myCustomTypeDatatable/customInput.html +4 -0
  34. package/src/lightning/datatable/__examples__disabled/myCustomTypeDatatable/myCustomTypeDatatable.js +17 -0
  35. package/src/lightning/datatable/__examples__disabled/myCustomTypeDatatable/nestedSimpleComponentParent.html +7 -0
  36. package/src/lightning/datatable/__examples__disabled/simpleComponentNested/simpleComponentNested.html +9 -0
  37. package/src/lightning/datatable/__examples__disabled/simpleComponentNested/simpleComponentNested.js +6 -0
  38. package/src/lightning/datatable/autoWidthStrategy.js +8 -36
  39. package/src/lightning/datatable/columnResizer.js +51 -161
  40. package/src/lightning/datatable/columnWidthManager.js +25 -81
  41. package/src/lightning/datatable/columns.js +180 -302
  42. package/src/lightning/datatable/datatable.js +455 -441
  43. package/src/lightning/datatable/errors.js +17 -29
  44. package/src/lightning/datatable/fixedWidthStrategy.js +7 -22
  45. package/src/lightning/datatable/headerActions.js +8 -38
  46. package/src/lightning/datatable/indexes.js +42 -0
  47. package/src/lightning/datatable/infiniteLoading.js +16 -35
  48. package/src/lightning/datatable/inlineEdit.js +125 -156
  49. package/src/lightning/datatable/keyboard.js +226 -282
  50. package/src/lightning/datatable/renderManager.js +0 -4
  51. package/src/lightning/datatable/resizeObserver.js +4 -13
  52. package/src/lightning/datatable/rowLevelActions.js +2 -2
  53. package/src/lightning/datatable/rowNumber.js +21 -59
  54. package/src/lightning/datatable/rowSelection.js +95 -178
  55. package/src/lightning/datatable/rowSelectionShared.js +13 -27
  56. package/src/lightning/datatable/rows.js +171 -418
  57. package/src/lightning/datatable/sort.js +16 -75
  58. package/src/lightning/datatable/templates/div/div.html +12 -4
  59. package/src/lightning/datatable/templates/div/div.lbc.synthetic.css +10 -16
  60. package/src/lightning/datatable/templates/table/table.html +15 -5
  61. package/src/lightning/datatable/tree.js +17 -35
  62. package/src/lightning/datatable/types.js +10 -31
  63. package/src/lightning/datatable/utils.js +49 -24
  64. package/src/lightning/datatable/virtualization.js +2 -5
  65. package/src/lightning/datatable/widthManagerShared.js +0 -20
  66. package/src/lightning/datatable/wrapText.js +29 -60
  67. package/src/lightning/dualListbox/dualListbox.js +7 -8
  68. package/src/lightning/formattedName/formattedName.js +3 -2
  69. package/src/lightning/formattedName/formattedName.js-meta.xml +3 -0
  70. package/src/lightning/formattedNumber/formattedNumber.js +3 -2
  71. package/src/lightning/formattedNumber/formattedNumber.js-meta.xml +3 -0
  72. package/src/lightning/formattedRichText/richTextConfig.js +1 -0
  73. package/src/lightning/helptext/helptext.css +7 -0
  74. package/src/lightning/helptext/helptext.js +3 -4
  75. package/src/lightning/icon/icon.html +1 -1
  76. package/src/lightning/input/input.html +5 -0
  77. package/src/lightning/inputAddress/addressFormat.js +31 -4
  78. package/src/lightning/inputAddress/fieldsLayout.js +6 -0
  79. package/src/lightning/inputAddress/inputAddress.html +19 -1
  80. package/src/lightning/inputAddress/inputAddress.js +74 -3
  81. package/src/lightning/internationalizationLibrary/address/AddressFormat.js +553 -610
  82. package/src/lightning/lookupAddress/lookupAddress.html +6 -1
  83. package/src/lightning/lookupAddress/lookupAddress.js +25 -0
  84. package/src/lightning/modal/__docs__/modal.md +10 -1
  85. package/src/lightning/modal/__modalUtils__/modalContainerTestConstants.js +3 -7
  86. package/src/lightning/modal/__modalUtils__/modalContainerTestMethods.js +39 -133
  87. package/src/lightning/modal/__modalUtils__/modalContainerTestMockData.js +1 -1
  88. package/src/lightning/modal/modal.js +1 -1
  89. package/src/lightning/modalBase/modalBase.html +15 -10
  90. package/src/lightning/modalBase/modalBase.js +131 -146
  91. package/src/lightning/modalBody/modalBody.css +6 -0
  92. package/src/lightning/modalHeader/modalHeader.html +16 -4
  93. package/src/lightning/modalHeader/modalHeader.js +61 -14
  94. package/src/lightning/pill/link.html +1 -0
  95. package/src/lightning/pill/plain.html +1 -0
  96. package/src/lightning/pill/plainLink.html +1 -0
  97. package/src/lightning/primitiveBubble/primitiveBubble.js +42 -0
  98. package/src/lightning/primitiveDatatableCell/primitiveDatatableCell.js +1 -1
  99. package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.html +1 -1
  100. package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.js +13 -0
  101. package/src/lightning/primitiveHeaderFactory/nonsortableHeader.html +19 -6
  102. package/src/lightning/primitiveHeaderFactory/sortableHeader.html +3 -1
  103. package/src/lightning/primitiveResizeHandler/primitiveResizeHandler.css +11 -0
  104. package/src/lightning/primitiveResizeHandler/primitiveResizeHandler.html +2 -1
  105. package/src/lightning/primitiveResizeHandler/primitiveResizeHandler.js +1 -0
  106. package/src/lightning/progressStep/base.html +5 -6
  107. package/src/lightning/progressStep/progressStep.js +14 -9
  108. package/src/lightning/prompt/__docs__/prompt.md +1 -1
  109. package/src/lightning/shadowBaseClassPrivate/shadowBaseClassPrivate.js +0 -2
  110. package/src/lightning/sldsCommon/sldsCommon.css +134 -98
  111. package/src/lightning/sldsUtilsAlignment/sldsUtilsAlignment.css +1 -1
  112. package/src/lightning/sldsUtilsBox/sldsUtilsBox.css +14 -13
  113. package/src/lightning/sldsUtilsGrid/sldsUtilsGrid.css +95 -92
  114. package/src/lightning/sldsUtilsHyphenation/sldsUtilsHyphenation.css +1 -1
  115. package/src/lightning/sldsUtilsMargin/sldsUtilsMargin.css +77 -75
  116. package/src/lightning/sldsUtilsPadding/sldsUtilsPadding.css +73 -73
  117. package/src/lightning/sldsUtilsSizing/sldsUtilsSizing.css +552 -558
  118. package/src/lightning/sldsUtilsVisibility/sldsUtilsVisibility.css +2 -2
  119. package/src/lightning/staticMap/staticMap.js +3 -2
  120. package/src/lightning/tab/tab.js +6 -3
  121. package/src/lightning/tab/tab.js-meta.xml +3 -0
  122. package/src/lightning/tabBar/tabBar.js +10 -5
  123. package/src/lightning/tabset/tabset.html +2 -0
  124. package/src/lightning/tabset/tabset.js-meta.xml +3 -0
  125. package/src/lightning/textarea/textarea.js +6 -1
  126. package/src/lightning/toastContainer/__docs__/toastContainer.md +3 -2
  127. package/src/lightning/tooltipLibrary/tooltipLibrary.js +24 -15
  128. package/src/lightning/verticalNavigation/vertical-navigation.slds.css +14 -0
  129. package/src/lightning/verticalNavigation/verticalNavigation.css +1 -1
  130. package/src/lightning/verticalNavigation/verticalNavigation.html +1 -1
  131. package/src/lightning/verticalNavigation/verticalNavigation.js +66 -28
  132. package/src/lightning/verticalNavigation/verticalNavigation.js-meta.xml +3 -0
  133. package/src/lightning/verticalNavigationItem/vertical-navigation-item.slds.css +63 -0
  134. package/src/lightning/verticalNavigationItem/verticalNavigationItem.css +2 -3
  135. package/src/lightning/verticalNavigationItem/verticalNavigationItem.js +29 -15
  136. package/src/lightning/verticalNavigationItem/verticalNavigationItem.js-meta.xml +3 -0
  137. package/src/lightning/verticalNavigationItem/verticalNavigationItem.lbc.native.css +2 -0
  138. package/src/lightning/verticalNavigationItem/verticalNavigationItem.lbc.synthetic.css +3 -0
  139. package/src/lightning/verticalNavigationItemBadge/badge.slds.css +76 -0
  140. package/src/lightning/verticalNavigationItemBadge/vertical-navigation-item.slds.css +63 -0
  141. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.css +2 -3
  142. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.html +1 -1
  143. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.js +28 -15
  144. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.js-meta.xml +3 -0
  145. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.lbc.native.css +5 -0
  146. package/src/lightning/verticalNavigationItemBadge/verticalNavigationItemBadge.lbc.synthetic.css +3 -0
  147. package/src/lightning/verticalNavigationItemIcon/vertical-navigation-item.slds.css +63 -0
  148. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.css +2 -3
  149. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.js +29 -15
  150. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.js-meta.xml +3 -0
  151. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.lbc.native.css +3 -0
  152. package/src/lightning/verticalNavigationItemIcon/verticalNavigationItemIcon.lbc.synthetic.css +3 -0
  153. package/src/lightning/verticalNavigationOverflow/button.slds.css +503 -0
  154. package/src/lightning/verticalNavigationOverflow/vertical-navigation-item.slds.css +63 -0
  155. package/src/lightning/verticalNavigationOverflow/vertical-navigation-section.slds.css +17 -0
  156. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.css +2 -1
  157. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.html +2 -0
  158. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.js +18 -13
  159. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.js-meta.xml +3 -0
  160. package/src/lightning/verticalNavigationOverflow/verticalNavigationOverflow.lbc.native.css +5 -0
  161. package/src/lightning/verticalNavigationSection/vertical-navigation-section.slds.css +14 -14
  162. package/src/lightning/verticalNavigationSection/verticalNavigationSection.js-meta.xml +3 -0
  163. package/src/lightning/datatable/inlineEditShared.js +0 -26
  164. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatableWrapper/customDatatableWrapper.html +0 -0
  165. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatableWrapper/customDatatableWrapper.js +0 -0
  166. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeDeleteRowBtn/customDatatypeDeleteRowBtn.html +0 -0
  167. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeDeleteRowBtn/customDatatypeDeleteRowBtn.js +0 -0
  168. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeLink/customDatatypeLink.html +0 -0
  169. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeLink/customDatatypeLink.js +0 -0
  170. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeNumber/customDatatypeNumber.html +0 -0
  171. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeNumber/customDatatypeNumber.js +0 -0
  172. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeRowOrderingBtn/customDatatypeRowOrderingBtn.html +0 -0
  173. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeRowOrderingBtn/customDatatypeRowOrderingBtn.js +0 -0
  174. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customDatatypeTable.js +0 -0
  175. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customLink.html +0 -0
  176. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customName.html +0 -0
  177. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customNumber.html +0 -0
  178. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/customNumberEdit.html +0 -0
  179. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/deleteRow.html +0 -0
  180. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/iconPill.html +0 -0
  181. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customDatatypeTable/orderingButtons.html +0 -0
  182. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customNestedComponent/customNestedComponent.html +0 -0
  183. /package/src/lightning/datatable/{__examples__ → __examples__disabled}/customNestedComponent/customNestedComponent.js +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
- isSafari,
9
13
  synchronizeAttrs,
10
- classSetToString,
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
- updateCellTabIndex,
65
- getIndexesByKeys,
66
- updateTabIndexActiveCell,
67
- updateTabIndexActiveRow,
68
- unsetRowNavigationMode,
69
- updateRowNavigationMode,
70
- handleDatatableFocusOut,
71
- handleDatatableFocusIn,
72
- updateRowTabIndex,
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
- getRowDataSelector,
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,
65
+ handlePrefetch,
98
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,31 +181,33 @@ 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;
230
211
 
231
212
  /**
232
213
  * Public property for passing `aria-describedby` down to the child table element.
@@ -254,9 +235,7 @@ export default class LightningDatatable extends LightningElement {
254
235
  this._columnWidthManager.columnWidthMode = normalizedValue;
255
236
  if (widthsData.columnWidthsMode !== normalizedValue) {
256
237
  // Tracked state changes.
257
- this._columnWidthManager.handleWidthModeChange(
258
- getColumns(this.state)
259
- );
238
+ this._columnWidthManager.handleWidthModeChange(this.state.columns);
260
239
  }
261
240
  // Untracked state change.
262
241
  widthsData.columnWidthsMode = normalizedValue;
@@ -270,13 +249,14 @@ export default class LightningDatatable extends LightningElement {
270
249
  */
271
250
  @api
272
251
  get columns() {
273
- return this._columns;
252
+ return this._rawColumns;
274
253
  }
275
254
 
276
255
  set columns(value) {
277
- this._columns = Array.isArray(value) ? value : [];
278
- this.updateColumns(this._columns);
279
- 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);
280
260
  }
281
261
 
282
262
  /**
@@ -286,22 +266,24 @@ export default class LightningDatatable extends LightningElement {
286
266
  @api
287
267
  // eslint-disable-next-line @lwc/lwc/valid-api
288
268
  get data() {
289
- return getData(this.state);
269
+ return this.state.data;
290
270
  }
291
271
 
292
272
  set data(value) {
293
273
  const { state } = this;
294
- const previousData = getData(state);
274
+ const { data: previousData } = state;
295
275
  const data = Array.isArray(value) ? value : [];
296
276
 
297
- const columns = getColumns(state);
298
- this._columnWidthManager.handleDataChange(previousData, data, columns);
299
-
300
- // set data in state
301
- setData(state, value);
277
+ // Untracked state change.
278
+ state.data = data;
279
+ this._columnWidthManager.handleDataChange(
280
+ previousData,
281
+ data,
282
+ state.columns
283
+ );
302
284
 
303
285
  // do necessary updates since rows have changed
304
- if (hasValidKeyField(state)) {
286
+ if (this.hasValidKeyField) {
305
287
  this.updateRowsState();
306
288
  resetTableHeight(state);
307
289
  }
@@ -319,7 +301,7 @@ export default class LightningDatatable extends LightningElement {
319
301
  */
320
302
  @api
321
303
  get defaultSortDirection() {
322
- return getDefaultSortDirection(this.state);
304
+ return this.state.defaultSortDirection;
323
305
  }
324
306
 
325
307
  set defaultSortDirection(value) {
@@ -342,8 +324,8 @@ export default class LightningDatatable extends LightningElement {
342
324
  this._draftValues = value;
343
325
  setDirtyValues(state, value);
344
326
 
345
- if (hasValidKeyField(state)) {
346
- this.updateRowsAndCellIndexes(state);
327
+ if (this.hasValidKeyField) {
328
+ this.updateRowsAndCells();
347
329
  }
348
330
 
349
331
  updateActiveCellTabIndexAfterSync(state);
@@ -358,14 +340,14 @@ export default class LightningDatatable extends LightningElement {
358
340
  */
359
341
  @api
360
342
  get enableInfiniteLoading() {
361
- return isInfiniteLoadingEnabled(this.state);
343
+ return this.state.enableInfiniteLoading;
362
344
  }
363
345
 
364
346
  set enableInfiniteLoading(value) {
365
347
  const { state } = this;
366
348
  // Untracked state change.
367
349
  setEnableInfiniteLoading(state, value);
368
- handlePrefetch.call(this, this.template, state);
350
+ handlePrefetch.call(this);
369
351
  }
370
352
 
371
353
  /**
@@ -375,7 +357,7 @@ export default class LightningDatatable extends LightningElement {
375
357
  */
376
358
  @api
377
359
  get errors() {
378
- return getErrors(this.state);
360
+ return this.state.errors;
379
361
  }
380
362
 
381
363
  set errors(value) {
@@ -400,12 +382,12 @@ export default class LightningDatatable extends LightningElement {
400
382
  this._columnWidthManager.handleCheckboxColumnChange(
401
383
  state.hideCheckboxColumn,
402
384
  normalizedValue,
403
- getColumns(state)
385
+ state.columns
404
386
  );
405
387
  // Untracked state changes.
406
388
  state.hideCheckboxColumn = normalizedValue;
407
389
  // update the columns metadata again to update the status.
408
- this.updateColumns(this._columns);
390
+ this.updateColumns(this._rawColumns);
409
391
  }
410
392
 
411
393
  /**
@@ -445,7 +427,7 @@ export default class LightningDatatable extends LightningElement {
445
427
  */
446
428
  @api
447
429
  get isLoading() {
448
- return isLoading(this.state);
430
+ return this.state.isLoading;
449
431
  }
450
432
 
451
433
  set isLoading(value) {
@@ -461,7 +443,7 @@ export default class LightningDatatable extends LightningElement {
461
443
  */
462
444
  @api
463
445
  get keyField() {
464
- return getKeyField(this.state);
446
+ return this.state.keyField;
465
447
  }
466
448
 
467
449
  set keyField(value) {
@@ -497,15 +479,15 @@ export default class LightningDatatable extends LightningElement {
497
479
  */
498
480
  @api
499
481
  get maxColumnWidth() {
500
- return getMaxColumnWidth(this.widthsData);
482
+ return this.widthsData.maxColumnWidth;
501
483
  }
502
484
 
503
485
  set maxColumnWidth(value) {
504
- const { state, widthsData } = this;
505
- // Tracked state change.
506
- setMaxColumnWidth(getColumns(state), widthsData, value);
486
+ const { widthsData } = this;
487
+ // Tracked state changes.
488
+ setMaxColumnWidth(this.state.columns, widthsData, value);
507
489
  // Untracked state change.
508
- this._columnWidthManager.maxColumnWidth = this.maxColumnWidth;
490
+ this._columnWidthManager.maxColumnWidth = widthsData.maxColumnWidth;
509
491
  }
510
492
 
511
493
  /**
@@ -516,7 +498,7 @@ export default class LightningDatatable extends LightningElement {
516
498
  */
517
499
  @api
518
500
  get maxRowSelection() {
519
- return getMaxRowSelection(this.state);
501
+ return this.state.maxRowSelection;
520
502
  }
521
503
 
522
504
  set maxRowSelection(value) {
@@ -537,15 +519,15 @@ export default class LightningDatatable extends LightningElement {
537
519
  */
538
520
  @api
539
521
  get minColumnWidth() {
540
- return getMinColumnWidth(this.widthsData);
522
+ return this.widthsData.minColumnWidth;
541
523
  }
542
524
 
543
525
  set minColumnWidth(value) {
544
- const { state, widthsData } = this;
526
+ const { widthsData } = this;
545
527
  // Tracked state change.
546
- setMinColumnWidth(getColumns(state), widthsData, value);
528
+ setMinColumnWidth(this.state.columns, widthsData, value);
547
529
  // Untracked state change.
548
- this._columnWidthManager.minColumnWidth = this.minColumnWidth;
530
+ this._columnWidthManager.minColumnWidth = widthsData.minColumnWidth;
549
531
  }
550
532
 
551
533
  /**
@@ -609,7 +591,6 @@ export default class LightningDatatable extends LightningElement {
609
591
  validValues: ['default', 'role-based'],
610
592
  });
611
593
  state.renderModeRoleBased = this._renderMode === 'role-based';
612
- this._columnWidthManager.setRenderMode(this.renderMode);
613
594
  if (_renderConfig) {
614
595
  setVirtualize(state, _renderConfig.virtualize);
615
596
  }
@@ -623,7 +604,7 @@ export default class LightningDatatable extends LightningElement {
623
604
  */
624
605
  @api
625
606
  get resizeColumnDisabled() {
626
- return isResizeColumnDisabled(this.widthsData);
607
+ return this.widthsData.resizeColumnDisabled;
627
608
  }
628
609
 
629
610
  set resizeColumnDisabled(value) {
@@ -639,7 +620,7 @@ export default class LightningDatatable extends LightningElement {
639
620
  */
640
621
  @api
641
622
  get resizeStep() {
642
- return getResizeStep(this.widthsData);
623
+ return this.widthsData.resizeStep;
643
624
  }
644
625
 
645
626
  set resizeStep(value) {
@@ -655,15 +636,18 @@ export default class LightningDatatable extends LightningElement {
655
636
  */
656
637
  @api
657
638
  get rowNumberOffset() {
658
- return getRowNumberOffset(this.state);
639
+ return this.state.rowNumberOffset;
659
640
  }
660
641
 
661
642
  set rowNumberOffset(value) {
662
- const { state, widthsData } = this;
643
+ const { state } = this;
663
644
  // Untracked state change.
664
645
  setRowNumberOffset(state, value);
665
646
  // Tracked state changes.
666
- this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
647
+ this._columnWidthManager.handleRowNumberOffsetChange(
648
+ state,
649
+ this.widthsData
650
+ );
667
651
  }
668
652
 
669
653
  /**
@@ -687,20 +671,20 @@ export default class LightningDatatable extends LightningElement {
687
671
  */
688
672
  @api
689
673
  get showRowNumberColumn() {
690
- return hasRowNumberColumn(this.state);
674
+ return this.state.showRowNumberColumn;
691
675
  }
692
676
 
693
677
  set showRowNumberColumn(value) {
694
- const { state, _columns } = this;
678
+ const { state, _rawColumns } = this;
695
679
  // A mix of tracked and untracked state changes.
696
680
  this._columnWidthManager.handleRowNumberColumnChange(
697
- getRowNumberOffset(state),
681
+ state.rowNumberOffset,
698
682
  value,
699
- getColumns(state)
683
+ state.columns
700
684
  );
701
685
  // Untracked state change.
702
- setShowRowNumberColumn(state, value);
703
- this.updateColumns(_columns);
686
+ state.showRowNumberColumn = normalizeBoolean(value);
687
+ this.updateColumns(_rawColumns);
704
688
  }
705
689
 
706
690
  /**
@@ -710,7 +694,7 @@ export default class LightningDatatable extends LightningElement {
710
694
  */
711
695
  @api
712
696
  get sortedBy() {
713
- return getSortedBy(this.state);
697
+ return this.state.sortedBy;
714
698
  }
715
699
 
716
700
  set sortedBy(value) {
@@ -727,7 +711,7 @@ export default class LightningDatatable extends LightningElement {
727
711
  */
728
712
  @api
729
713
  get sortedDirection() {
730
- return getSortedDirection(this.state);
714
+ return this.state.sortedDirection;
731
715
  }
732
716
 
733
717
  set sortedDirection(value) {
@@ -766,19 +750,19 @@ export default class LightningDatatable extends LightningElement {
766
750
  // Untracked state changes.
767
751
  setWrapTextMaxLines(state, value);
768
752
  this._columnWidthManager.wrapTextMaxLines = state.wrapTextMaxLines;
769
- this.updateRowsAndCellIndexes(state);
753
+ this.updateRowsAndCells();
770
754
  }
771
755
 
772
756
  /************************** PUBLIC METHODS ***************************/
773
757
 
774
758
  /**
775
759
  * Returns data in each selected row.
776
- * @returns {array} An array of data in each selected row.
760
+ * @returns {Array} An array of data in each selected row.
777
761
  */
778
762
  @api
779
763
  getSelectedRows() {
780
764
  const { state } = this;
781
- const data = unwrap(getData(state));
765
+ const data = unwrap(state.data);
782
766
  const { rows } = state;
783
767
  const selectedRows = [];
784
768
  for (let i = 0, { length: rowCount } = rows; i < rowCount; i += 1) {
@@ -824,20 +808,21 @@ export default class LightningDatatable extends LightningElement {
824
808
 
825
809
  get computedTableContainerClass() {
826
810
  return classSetToString({
827
- 'slds-table_header-fixed_container': !this.hideTableHeader,
811
+ 'slds-table_header-fixed_container': !this.state.hideTableHeader,
828
812
  'slds-scrollable_x': !this._isResizing,
829
813
  });
830
814
  }
831
815
 
832
816
  get computedTableClass() {
833
- const headerType = this.hideTableHeader ? 'hidden' : 'fixed';
817
+ const { state } = this;
818
+ const headerType = state.hideTableHeader ? 'hidden' : 'fixed';
834
819
  return classSetToString({
835
820
  'slds-table': true,
836
821
  [`slds-table_header-${headerType}`]: true,
837
822
  'slds-table_bordered': true,
838
823
  'slds-table_edit': true,
839
- 'slds-table_resizable-cols': this.hasResizebleColumns,
840
- 'slds-tree slds-table_tree': hasTreeDataType(this.state),
824
+ 'slds-table_resizable-cols': !this.widthsData.resizeColumnDisabled,
825
+ 'slds-tree slds-table_tree': hasTreeDataType(state),
841
826
  });
842
827
  }
843
828
 
@@ -849,8 +834,11 @@ export default class LightningDatatable extends LightningElement {
849
834
  const tableLayout = this._columnWidthManager.isAutoResizingUpdateQueued
850
835
  ? 'auto'
851
836
  : 'fixed';
852
- let style = `table-layout:${tableLayout}`;
853
- style += getCSSWidthStyleOfTable(this.widthsData);
837
+ let style = `table-layout: ${tableLayout};`;
838
+ const { tableWidth } = this.widthsData;
839
+ if (tableWidth) {
840
+ style += `width: ${tableWidth}px;`;
841
+ }
854
842
  return style;
855
843
  }
856
844
 
@@ -862,9 +850,9 @@ export default class LightningDatatable extends LightningElement {
862
850
  */
863
851
  get computedTbodyStyle() {
864
852
  const { state } = this;
865
- const rowNumberOffset = getRowNumberOffset(state);
853
+ const { rowNumberOffset } = state;
866
854
  let style = '';
867
- if (hasRowNumberColumn(state) && rowNumberOffset >= 0) {
855
+ if (state.showRowNumberColumn && rowNumberOffset >= 0) {
868
856
  const { firstVisibleIndex, bufferSize } = state;
869
857
  const firstRenderedRow = Math.max(
870
858
  firstVisibleIndex - bufferSize,
@@ -890,35 +878,30 @@ export default class LightningDatatable extends LightningElement {
890
878
  * is overflowing horizontally, we need to set the width in order
891
879
  * to be able to view the remaining columns on scroll.
892
880
  */
893
- get computedScrollerStyle() {
881
+ get computedScrollerYStyle() {
894
882
  const minHeight = this._actionsMinHeightStyle
895
883
  ? `${this._actionsMinHeightStyle};`
896
884
  : '';
897
885
  if (this._columnWidthManager.isAutoResizingUpdateQueued) {
898
886
  return `${minHeight}overflow-x:auto`;
899
887
  }
900
- return `${minHeight}${getCSSWidthStyleOfTable(this.widthsData)}`;
888
+ const { tableWidth } = this.widthsData;
889
+ return tableWidth ? `width: ${tableWidth}px;` : '';
901
890
  }
902
891
 
903
- get scrollerXStyles() {
904
- const styles = {
905
- height: '100%',
906
- };
907
-
892
+ get computedScrollerXStyle() {
893
+ let style = 'height: 100%;';
908
894
  if (this.showStatusBar) {
909
- styles['padding-bottom'] = '3rem';
895
+ style += 'padding-bottom: 3rem;';
910
896
  }
911
-
912
897
  if (this._columnWidthManager.isAutoResizingUpdateQueued) {
913
- styles['overflow-x'] = 'auto';
898
+ style += 'overflow-x: auto;';
914
899
  }
915
-
916
- if (this.wrapTableHeader) {
900
+ if (this.state.wrapTableHeader) {
917
901
  // increase padding from 2rem to 3rem on the top when header wraps
918
- styles['padding-top'] = '3rem';
902
+ style += 'padding-top: 3rem;';
919
903
  }
920
-
921
- return styleToString(styles);
904
+ return style;
922
905
  }
923
906
 
924
907
  /**
@@ -931,17 +914,15 @@ export default class LightningDatatable extends LightningElement {
931
914
  }
932
915
 
933
916
  get computedAriaLiveClassForNavMode() {
934
- const keyboardMode = this.state.keyboardMode;
935
- return classSet()
936
- .add({
937
- 'slds-hide': keyboardMode !== 'NAVIGATION',
938
- 'slds-assistive-text': keyboardMode === 'NAVIGATION',
939
- })
940
- .toString();
917
+ const isNavMode = this.state.keyboardMode === KEYBOARD_NAVIGATION_MODE;
918
+ return classSetToString({
919
+ 'slds-hide': !isNavMode,
920
+ 'slds-assistive-text': isNavMode,
921
+ });
941
922
  }
942
923
 
943
924
  get computedAriaLiveClassForActionMode() {
944
- const isActionMode = this.state.keyboardMode === 'ACTION';
925
+ const isActionMode = this.state.keyboardMode === KEYBOARD_ACTION_MODE;
945
926
  return classSetToString({
946
927
  'slds-hide': !isActionMode,
947
928
  'slds-assistive-text': isActionMode,
@@ -958,7 +939,7 @@ export default class LightningDatatable extends LightningElement {
958
939
  }
959
940
 
960
941
  get hasValidKeyField() {
961
- if (hasValidKeyField(this.state)) {
942
+ if (typeof this.state.keyField === 'string') {
962
943
  return true;
963
944
  }
964
945
  // eslint-disable-next-line no-console
@@ -968,12 +949,8 @@ export default class LightningDatatable extends LightningElement {
968
949
  return false;
969
950
  }
970
951
 
971
- get numberOfColumns() {
972
- return getColumns(this.state).length;
973
- }
974
-
975
952
  get hasResizebleColumns() {
976
- return !isResizeColumnDisabled(this.widthsData);
953
+ return !this.widthsData.resizeColumnDisabled;
977
954
  }
978
955
 
979
956
  get privateTypes() {
@@ -1004,15 +981,15 @@ export default class LightningDatatable extends LightningElement {
1004
981
  }
1005
982
 
1006
983
  get showSelectAllCheckbox() {
1007
- return !getHideSelectAllCheckbox(this.state);
984
+ return this.state.maxRowSelection !== 1;
1008
985
  }
1009
986
 
1010
987
  get showStatusBar() {
1011
- return isInlineEditTriggered(this.state) && !this.suppressBottomBar;
988
+ return !this._suppressBottomBar && isInlineEditTriggered(this.state);
1012
989
  }
1013
990
 
1014
991
  get tableError() {
1015
- return getTableError(this.state);
992
+ return this.state.errors.table;
1016
993
  }
1017
994
 
1018
995
  get i18n() {
@@ -1030,12 +1007,12 @@ export default class LightningDatatable extends LightningElement {
1030
1007
  constructor() {
1031
1008
  super();
1032
1009
 
1033
- this._privateTypes = new DatatableTypes(this.constructor.customTypes);
1034
1010
  this._columnWidthManager = new ColumnWidthManager(this.widthsData);
1035
- this.updateRowsAndCellIndexes = updateRowsAndCellIndexes.bind(this);
1011
+ this._privateTypes = new DatatableTypes(this.constructor.customTypes);
1036
1012
 
1037
1013
  this._renderManager = new RenderManager();
1038
- this.getWrapperHeight = getDTWrapperHeight.bind(this);
1014
+ this.getWrapperHeight = () =>
1015
+ getScrollerXFromScrollerY(getScrollerY(this.template)).offsetHeight;
1039
1016
  }
1040
1017
 
1041
1018
  /**
@@ -1043,84 +1020,75 @@ export default class LightningDatatable extends LightningElement {
1043
1020
  */
1044
1021
  connectedCallback() {
1045
1022
  const { template } = this;
1046
- const {
1047
- handleResizeColumn,
1048
- handleUpdateColumnSort,
1049
- handleCellFocusByClick,
1050
- handleFalseCellBlur,
1051
- handleSelectionCellClick,
1052
- } = this;
1053
1023
 
1054
1024
  // Row selection and de-selection
1055
- this.addEventListener(
1056
- 'rowselection',
1057
- handleRowSelectionChange.bind(this)
1058
- );
1059
- template.addEventListener(
1060
- 'selectallrows',
1061
- handleSelectionCellClick.bind(this)
1062
- );
1063
- template.addEventListener(
1064
- 'deselectallrows',
1065
- handleSelectionCellClick.bind(this)
1066
- );
1067
- template.addEventListener(
1068
- 'selectrow',
1069
- handleSelectionCellClick.bind(this)
1070
- );
1071
- template.addEventListener(
1072
- 'deselectrow',
1073
- handleSelectionCellClick.bind(this)
1074
- );
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
+ });
1075
1040
  // Column resizing
1076
- template.addEventListener('resizecol', handleResizeColumn.bind(this));
1041
+ template.addEventListener('resizecol', (event) => {
1042
+ this.handleResizeColumn(event);
1043
+ });
1077
1044
  // Column sorting
1078
- template.addEventListener(
1079
- 'privateupdatecolsort',
1080
- handleUpdateColumnSort.bind(this)
1081
- );
1045
+ template.addEventListener('privateupdatecolsort', (event) => {
1046
+ this.handleUpdateColumnSort(event);
1047
+ });
1082
1048
  // Cell interaction
1083
- template.addEventListener(
1084
- 'privatecellkeydown',
1085
- handleKeydownOnCell.bind(this)
1086
- );
1087
- template.addEventListener(
1088
- 'privatecellfocusedbyclick',
1089
- handleCellFocusByClick.bind(this)
1090
- );
1091
- template.addEventListener(
1092
- 'privatecellfalseblurred',
1093
- handleFalseCellBlur.bind(this)
1094
- );
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
+ });
1095
1058
  // Row level actions
1096
- template.addEventListener(
1097
- 'privatecellactiontriggered',
1098
- handleRowActionTriggered.bind(this)
1099
- );
1100
- template.addEventListener(
1101
- 'privatecellactionmenuopening',
1102
- handleLoadDynamicActions.bind(this)
1103
- );
1104
- template.addEventListener(
1105
- 'privatecellbuttonclicked',
1106
- handleCellButtonClick.bind(this)
1107
- );
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
+ });
1108
1068
 
1109
- // Header Actions
1069
+ // Header actions
1110
1070
  template.addEventListener(
1111
1071
  'privatecellheaderactionmenuopening',
1112
- handleHeaderActionMenuOpening.bind(this)
1072
+ (event) => {
1073
+ this.handleHeaderActionMenuOpening(event);
1074
+ }
1113
1075
  );
1114
1076
  template.addEventListener(
1115
1077
  'privatecellheaderactionmenuclosed',
1116
- handleHeaderActionMenuClosed.bind(this)
1078
+ (event) => {
1079
+ this.handleHeaderActionMenuClosed(event);
1080
+ }
1117
1081
  );
1118
1082
  template.addEventListener(
1119
1083
  'privatecellheaderactiontriggered',
1120
- handleHeaderActionTriggered.bind(this)
1084
+ (event) => {
1085
+ this.handleHeaderActionTriggered(event);
1086
+ }
1121
1087
  );
1122
1088
  // Inline edit
1123
- template.addEventListener('privateeditcell', handleEditCell.bind(this));
1089
+ template.addEventListener('privateeditcell', (event) => {
1090
+ this.handleEditCell(event);
1091
+ });
1124
1092
  }
1125
1093
 
1126
1094
  /**
@@ -1143,21 +1111,8 @@ export default class LightningDatatable extends LightningElement {
1143
1111
  'aria-describedby': this.ariaDescribedBy,
1144
1112
  });
1145
1113
 
1146
- let { _privateWidthObserver } = this;
1147
- if (!_privateWidthObserver) {
1148
- _privateWidthObserver = new LightningDatatableResizeObserver(
1149
- template,
1150
- state,
1151
- widthsData,
1152
- _columnWidthManager
1153
- );
1154
- this._privateWidthObserver = _privateWidthObserver;
1155
- } else if (!_privateWidthObserver.isConnected()) {
1156
- _privateWidthObserver.observe(template);
1157
- }
1158
-
1159
1114
  if (_columnWidthManager.isResizingUpdateQueued) {
1160
- const columns = getColumns(state);
1115
+ const { columns } = state;
1161
1116
  const fireResizeEvent = _columnWidthManager.shouldFireResizeEvent(
1162
1117
  widthsData,
1163
1118
  columns
@@ -1168,26 +1123,44 @@ export default class LightningDatatable extends LightningElement {
1168
1123
  columns,
1169
1124
  widthsData
1170
1125
  );
1171
-
1172
1126
  if (fireResizeEvent) {
1173
1127
  this.fireOnResize(false);
1174
1128
  }
1175
1129
  this.updateTableAndScrollerStyleOnRender();
1176
1130
  }
1177
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
+
1178
1151
  // Managing the cell widths is only required for the role-based table
1179
1152
  if (state.renderModeRoleBased) {
1180
1153
  // TODO: Look to further optimize - Do this only when required
1181
1154
  recomputeCellStyles(this.privateTypes, state);
1182
1155
  }
1183
1156
 
1184
- handlePrefetch.call(this, template, state);
1157
+ handlePrefetch.call(this);
1185
1158
 
1186
1159
  // customerSelectedRows is only valid till render, after it, the one
1187
1160
  // used should be the one from the state.
1188
1161
  this._customerSelectedRows = null;
1189
1162
  // Set the previous focused cell to null after render is done.
1190
- resetCellToFocusFromPrev(state);
1163
+ state.cellToFocusNext = undefined;
1191
1164
 
1192
1165
  // Reset focus styles on re-render.
1193
1166
  if (this._shouldResetFocus) {
@@ -1207,7 +1180,7 @@ export default class LightningDatatable extends LightningElement {
1207
1180
  !cellElement.parentElement.classList.contains(FOCUS_CLASS)
1208
1181
  ) {
1209
1182
  // Tracked state change.
1210
- setFocusActiveCell(template, state, null, null, false);
1183
+ setFocusActiveCell(state, template, null, null, false);
1211
1184
  }
1212
1185
  }
1213
1186
  }
@@ -1237,21 +1210,20 @@ export default class LightningDatatable extends LightningElement {
1237
1210
  }
1238
1211
 
1239
1212
  updateTableAndScrollerStyleOnRender() {
1240
- const role = '[role="' + this.computedTableRole + '"]';
1241
- const tableElement = this.template.querySelector(role);
1242
- const scrollYEle = this.template.querySelector('.slds-scrollable_y');
1213
+ const scrollYEle = getScrollerY(this.template);
1214
+ const tableElement = getGridContainerFromScrollerY(scrollYEle);
1243
1215
  if (tableElement) {
1244
1216
  tableElement.style = this.computedTableStyle;
1245
1217
  }
1246
1218
  if (scrollYEle) {
1247
- scrollYEle.style = this.computedScrollerStyle;
1219
+ scrollYEle.style = this.computedScrollerYStyle;
1248
1220
  }
1249
1221
  }
1250
1222
 
1251
1223
  disconnectedCallback() {
1252
- const { _privateWidthObserver } = this;
1253
- if (_privateWidthObserver) {
1254
- _privateWidthObserver.disconnect();
1224
+ const { _widthObserver } = this;
1225
+ if (_widthObserver) {
1226
+ _widthObserver.disconnect();
1255
1227
  }
1256
1228
 
1257
1229
  this._renderManager.disconnectResizeObserver();
@@ -1259,6 +1231,24 @@ export default class LightningDatatable extends LightningElement {
1259
1231
 
1260
1232
  /************************** EVENT HANDLERS ***************************/
1261
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
+
1262
1252
  handleCustomTypesChange() {
1263
1253
  const assignedNodes = this.template
1264
1254
  .querySelector('slot[name="customdatatypes"]')
@@ -1269,33 +1259,31 @@ export default class LightningDatatable extends LightningElement {
1269
1259
  this._privateTypes = new DatatableTypes(
1270
1260
  provider.getDataTypes()
1271
1261
  );
1272
- this.updateColumns(this._columns);
1262
+ this.updateColumns(this._rawColumns);
1273
1263
  }
1274
1264
  }
1275
1265
  }
1276
1266
 
1277
1267
  /**
1278
- * Handles the `keydown` event on <table> and the
1268
+ * Handles the 'keydown' event on <table> and the
1279
1269
  * corresponding <div> on the role-based table
1280
1270
  *
1281
- * @param {KeyboardEvent} event - `keydown`
1271
+ * @param {KeyboardEvent} event - 'keydown'
1282
1272
  */
1283
- handleTableKeydown(event) {
1284
- handleKeydownOnTable.call(this, event);
1285
- }
1273
+ handleTableKeydown = handleKeydownOnTable;
1286
1274
 
1287
1275
  /**
1288
- * 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)
1289
1277
  *
1290
- * @param {KeyboardEvent} event - `keydown`
1278
+ * @param {KeyboardEvent} event - 'keydown'
1291
1279
  */
1292
1280
  handleKeydownOnDataRow(event) {
1293
1281
  const { state } = this;
1294
1282
  // we probably should not be doing this unless we actually are interested in it
1295
- if (state.keyboardMode === 'NAVIGATION' && state.rowMode === true) {
1283
+ if (state.keyboardMode === KEYBOARD_NAVIGATION_MODE && state.rowMode) {
1296
1284
  event.stopPropagation();
1297
1285
  const { currentTarget: tr } = event;
1298
- reactToKeyboardOnRow(this, state, {
1286
+ reactToKeyboardOnRow(this, {
1299
1287
  target: tr,
1300
1288
  detail: {
1301
1289
  keyCode: event.keyCode,
@@ -1310,23 +1298,23 @@ export default class LightningDatatable extends LightningElement {
1310
1298
  }
1311
1299
 
1312
1300
  /**
1313
- * Handles the `scroll` event on the table container
1301
+ * Handles the 'scroll' event on the table container
1314
1302
  *
1315
- * @param {Event} event - `scroll`
1303
+ * @param {Event} event - 'scroll'
1316
1304
  */
1317
1305
  handleHorizontalScroll(event) {
1318
1306
  handleInlineEditPanelScroll.call(this, event);
1319
1307
  }
1320
1308
 
1321
1309
  /**
1322
- * Handles the `scroll` event on the child of the
1323
- * 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.
1324
1312
  *
1325
- * @param {Event} event - `scroll`
1313
+ * @param {Event} event - 'scroll'
1326
1314
  */
1327
1315
  handleVerticalScroll(event) {
1328
1316
  const { state } = this;
1329
- if (this.enableInfiniteLoading) {
1317
+ if (state.enableInfiniteLoading) {
1330
1318
  handleLoadMoreCheck.call(this, event);
1331
1319
  }
1332
1320
 
@@ -1348,15 +1336,13 @@ export default class LightningDatatable extends LightningElement {
1348
1336
  *
1349
1337
  * @param {MouseEvent} event - `click`
1350
1338
  */
1351
- handleCellClick(event) {
1339
+ handleTableCellClick(event) {
1352
1340
  // handles the case when clicking on the margin/pading of the td/th
1353
- const targetTagName = event.target.tagName.toLowerCase();
1354
- const targetRole = event.target.getAttribute('role');
1355
-
1356
- if (isCellElement(targetTagName, targetRole)) {
1341
+ const { target } = event;
1342
+ if (isCellElement(target)) {
1357
1343
  // get the row/col key value from the primitive cell.
1358
1344
  const { rowKeyValue, colKeyValue } =
1359
- event.target.querySelector(':first-child');
1345
+ target.querySelector(':first-child');
1360
1346
 
1361
1347
  const { state, template } = this;
1362
1348
  if (
@@ -1378,9 +1364,9 @@ export default class LightningDatatable extends LightningElement {
1378
1364
  }
1379
1365
 
1380
1366
  /**
1381
- * Handles the `privateupdatecolsort` event on lightning-datatable
1367
+ * Handles the 'privateupdatecolsort' event on lightning-datatable
1382
1368
  *
1383
- * @param {CustomEvent} event - `privateupdatecolsort`
1369
+ * @param {CustomEvent} event - 'privateupdatecolsort'
1384
1370
  */
1385
1371
  handleUpdateColumnSort(event) {
1386
1372
  event.stopPropagation();
@@ -1393,9 +1379,9 @@ export default class LightningDatatable extends LightningElement {
1393
1379
  }
1394
1380
 
1395
1381
  /**
1396
- * Handles the `resizecol` event on lightning-datatable
1382
+ * Handles the 'resizecol' event on lightning-datatable
1397
1383
  *
1398
- * @param {CustomEvent} event - `resizecol`
1384
+ * @param {CustomEvent} event - 'resizecol'
1399
1385
  */
1400
1386
  handleResizeColumn(event) {
1401
1387
  event.stopPropagation();
@@ -1403,21 +1389,21 @@ export default class LightningDatatable extends LightningElement {
1403
1389
  const { colIndex, widthDelta: delta } = event.detail;
1404
1390
  if (delta !== 0) {
1405
1391
  resizeColumnWithDelta(
1406
- getColumns(state),
1392
+ state.columns,
1407
1393
  this.widthsData,
1408
1394
  colIndex,
1409
1395
  delta
1410
1396
  );
1411
1397
  this.fireOnResize(true);
1412
- this.safariHeaderFix();
1398
+ this.fixHeaderForSafari();
1413
1399
  }
1414
1400
  }
1415
1401
 
1416
1402
  /**
1417
- * Handles the `privateresizestart` event on the <tr> and the corresponding
1403
+ * Handles the 'privateresizestart' event on the <tr> and the corresponding
1418
1404
  * <div> in the role-based table on the column header row
1419
1405
  *
1420
- * @param {CustomEvent} event - `privateresizestart`
1406
+ * @param {CustomEvent} event - 'privateresizestart'
1421
1407
  */
1422
1408
  handleResizeStart(event) {
1423
1409
  event.stopPropagation();
@@ -1425,10 +1411,10 @@ export default class LightningDatatable extends LightningElement {
1425
1411
  }
1426
1412
 
1427
1413
  /**
1428
- * Handles the `privateresizeend` event on the <tr> and the corresponding
1414
+ * Handles the 'privateresizeend' event on the <tr> and the corresponding
1429
1415
  * <div> in the role-based table on the column header row
1430
1416
  *
1431
- * @param {CustomEvent} event - `privateresizeend`
1417
+ * @param {CustomEvent} event - 'privateresizeend'
1432
1418
  */
1433
1419
  handleResizeEnd(event) {
1434
1420
  event.stopPropagation();
@@ -1457,9 +1443,9 @@ export default class LightningDatatable extends LightningElement {
1457
1443
  }
1458
1444
 
1459
1445
  /**
1460
- * Handles the `privatecellfocusedbyclick` event on lightning-datatable
1446
+ * Handles the 'privatecellfocusedbyclick' event on lightning-datatable
1461
1447
  *
1462
- * @param {CustomEvent} event - `privatecellfocusedbyclick`
1448
+ * @param {CustomEvent} event - 'privatecellfocusedbyclick'
1463
1449
  */
1464
1450
  handleCellFocusByClick(event) {
1465
1451
  event.stopPropagation();
@@ -1473,14 +1459,14 @@ export default class LightningDatatable extends LightningElement {
1473
1459
  updateRowTabIndex(state, rowIndex, -1);
1474
1460
  }
1475
1461
  this.setActiveCell(rowKeyValue, colKeyValue);
1476
- refocusCellElement(this.template, state, needsRefocusOnCellElement);
1462
+ refocusCellElement(state, this.template, needsRefocusOnCellElement);
1477
1463
  }
1478
1464
  }
1479
1465
 
1480
1466
  /**
1481
- * Handles the `privatecellfalseblurred` event on lightning-datatable
1467
+ * Handles the 'privatecellfalseblurred' event on lightning-datatable
1482
1468
  *
1483
- * @param {CustomEvent} event - `privatecellfalseblurred`
1469
+ * @param {CustomEvent} event - 'privatecellfalseblurred'
1484
1470
  */
1485
1471
  handleFalseCellBlur(event) {
1486
1472
  event.stopPropagation();
@@ -1490,21 +1476,19 @@ export default class LightningDatatable extends LightningElement {
1490
1476
  this.setActiveCell(rowKeyValue, colKeyValue);
1491
1477
  }
1492
1478
  // Tracked state change.
1493
- setFocusActiveCell(this.template, state);
1479
+ setFocusActiveCell(state, this.template);
1494
1480
  }
1495
1481
 
1496
1482
  /**
1497
- * Handles the `focusin` event on <table> and the corresponding
1483
+ * Handles the 'focusin' event on <table> and the corresponding
1498
1484
  * <div> on the role-based table
1499
1485
  *
1500
- * @param {FocusEvent} event - `focusin`
1486
+ * @param {FocusEvent} event - 'focusin'
1501
1487
  */
1502
- handleTableFocusIn(event) {
1503
- handleDatatableFocusIn.call(this, event);
1504
- }
1488
+ handleTableFocusIn = handleDatatableFocusIn;
1505
1489
 
1506
1490
  /**
1507
- * Handles the `focusout` event on <table> and the corresponding
1491
+ * Handles the 'focusout' event on <table> and the corresponding
1508
1492
  * <div> on the role-based table
1509
1493
  *
1510
1494
  * This gets called both when we expect the table to lose focus
@@ -1515,7 +1499,7 @@ export default class LightningDatatable extends LightningElement {
1515
1499
  * _shouldResetFocus, which will be true if and only if focus was
1516
1500
  * lost due to a renderedRows change for a virtualized table.
1517
1501
  *
1518
- * @param {FocusEvent} event - `focusout`
1502
+ * @param {FocusEvent} event - 'focusout'
1519
1503
  */
1520
1504
  handleTableFocusOut(event) {
1521
1505
  handleDatatableFocusOut.call(this, event);
@@ -1526,31 +1510,27 @@ export default class LightningDatatable extends LightningElement {
1526
1510
  }
1527
1511
 
1528
1512
  /**
1529
- * Handles the `ieditfinished` event on the inline edit panel -
1513
+ * Handles the 'ieditfinished' event on the inline edit panel -
1530
1514
  * `lightning-primitive-datatable-iedit-panel`
1531
1515
  *
1532
- * @param {CustomEvent} event - `ieditfinished`
1516
+ * @param {CustomEvent} event - 'ieditfinished'
1533
1517
  */
1534
- handleInlineEditFinish(event) {
1535
- handleInlineEditFinish.call(this, event);
1536
- }
1518
+ handleInlineEditFinish = handleInlineEditFinish;
1537
1519
 
1538
1520
  /**
1539
- * Handles the `masscheckboxchange` event on the inline edit panel -
1521
+ * Handles the 'masscheckboxchange' event on the inline edit panel -
1540
1522
  * `lightning-primitive-datatable-iedit-panel`
1541
1523
  *
1542
- * @param {CustomEvent} event - `masscheckboxchange`
1524
+ * @param {CustomEvent} event - 'masscheckboxchange'
1543
1525
  */
1544
- handleMassCheckboxChange(event) {
1545
- handleMassCheckboxChange.call(this, event);
1546
- }
1526
+ handleMassCheckboxChange = handleMassCheckboxChange;
1547
1527
 
1548
1528
  /**
1549
- * Handles the `privatesave` event on the status bar -
1529
+ * Handles the 'privatesave' event on the status bar -
1550
1530
  * `lightning-primitive-datatable-status-bar` and
1551
1531
  * fires the `save` custom event
1552
1532
  *
1553
- * @param {CustomEvent} event - `privatesave`
1533
+ * @param {CustomEvent} event - 'privatesave'
1554
1534
  */
1555
1535
  handleInlineEditSave(event) {
1556
1536
  event.stopPropagation();
@@ -1567,11 +1547,11 @@ export default class LightningDatatable extends LightningElement {
1567
1547
  }
1568
1548
 
1569
1549
  /**
1570
- * Handles the `privatecancel` event on the status bar -
1550
+ * Handles the 'privatecancel' event on the status bar -
1571
1551
  * `lightning-primitive-datatable-status-bar` and
1572
1552
  * fires the `cancel` custom event
1573
1553
  *
1574
- * @param {CustomEvent} event - `privatecancel`
1554
+ * @param {CustomEvent} event - 'privatecancel'
1575
1555
  */
1576
1556
  handleInlineEditCancel(event) {
1577
1557
  event.stopPropagation();
@@ -1593,17 +1573,16 @@ export default class LightningDatatable extends LightningElement {
1593
1573
 
1594
1574
  /**
1595
1575
  * @event LightningDatatable#onprivatelookupitempicked We need to augment the original event LightningFormattedLookup#onprivatelookupitempicked
1596
- * @type {object}
1597
- * @property {string} recordId
1598
- * @property {number} rowIndex
1599
- * @property {string} rowKeyValue
1576
+ * @type {Object}
1577
+ * @property {String} recordId
1578
+ * @property {Number} rowIndex
1579
+ * @property {String} rowKeyValue
1600
1580
  */
1601
-
1602
1581
  /**
1603
- * Handles the `privatelookupitempicked` event from the lightning-formatted-lookup or force-lookup
1604
- * `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
1605
1584
  *
1606
- * @param {CustomEvent} event - `privatelookupitempicked`
1585
+ * @param {CustomEvent} event - 'privatelookupitempicked'
1607
1586
  * @fires LightningDatatable#onprivatelookupitempicked
1608
1587
  */
1609
1588
  handlePrivateLookupItemPicked(event) {
@@ -1635,55 +1614,65 @@ export default class LightningDatatable extends LightningElement {
1635
1614
 
1636
1615
  /************************ EVENT DISPATCHERS **************************/
1637
1616
 
1638
- fireSelectedRowsChange(selectedRows, config) {
1639
- const event = new CustomEvent('rowselection', {
1640
- detail: { selectedRows, config: config || {} },
1641
- });
1642
-
1643
- this.dispatchEvent(event);
1617
+ fireSelectedRowsChange(selectedRows, config = {}) {
1618
+ this.dispatchEvent(
1619
+ new CustomEvent('rowselection', {
1620
+ detail: { selectedRows, config },
1621
+ })
1622
+ );
1644
1623
  }
1645
1624
 
1646
1625
  fireSortedColumnChange(fieldName, columnKey, sortDirection) {
1647
- const event = new CustomEvent('sort', {
1648
- detail: { fieldName, columnKey, sortDirection },
1649
- });
1650
- this.dispatchEvent(event);
1626
+ this.dispatchEvent(
1627
+ new CustomEvent('sort', {
1628
+ detail: { fieldName, columnKey, sortDirection },
1629
+ })
1630
+ );
1651
1631
  }
1652
1632
 
1653
1633
  fireOnResize(isUserTriggered) {
1654
- const { state, widthsData } = this;
1655
- const event = new CustomEvent('resize', {
1656
- detail: {
1657
- columnWidths: getCustomerColumnWidths(
1658
- getColumns(state),
1659
- widthsData
1660
- ),
1661
- isUserTriggered: !!isUserTriggered,
1662
- },
1663
- });
1664
- 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
+ );
1665
1645
  }
1666
1646
 
1667
1647
  /************************* HELPER FUNCTIONS **************************/
1668
1648
 
1669
1649
  updateRowsState() {
1670
- const { state, widthsData, template } = this;
1671
- // calculate cell to focus next before indexes are updated
1672
- setCellToFocusFromPrev(state, template);
1650
+ this.updateRowsBeforeIndexes();
1651
+ this.updateRowsAndCells();
1652
+ this.updateRowsAfterIndexes();
1653
+ }
1673
1654
 
1674
- this.updateRowsAndCellIndexes(state);
1655
+ updateRowsBeforeIndexes() {
1656
+ // Untracked state change.
1657
+ setCellToFocusFromPrev(this.state, this.template);
1658
+ }
1675
1659
 
1660
+ updateRowsAfterIndexes() {
1661
+ const { state, widthsData } = this;
1676
1662
  if (this.viewportRendering || state.virtualize) {
1677
1663
  this._renderManager.updateViewportRendering(
1678
- this.state,
1664
+ state,
1679
1665
  this.gridContainer,
1680
1666
  !!state.virtualize
1681
1667
  );
1682
1668
  }
1683
1669
 
1670
+ // Tracked state changes.
1684
1671
  this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
1685
- // 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.
1686
1674
  updateCellToFocusFromPrev(state);
1675
+ // A mix of tracked and untracked state changes.
1687
1676
  syncSelectedRowsKeys(state, this.getSelectedRows()).ifChanged(() => {
1688
1677
  // Only trigger row selection event once after all the setters have executed
1689
1678
  // Otherwise, event can be fired with stale data if not all setters have been triggered
@@ -1697,52 +1686,77 @@ export default class LightningDatatable extends LightningElement {
1697
1686
  });
1698
1687
  }
1699
1688
  });
1689
+ // Untracked state change.
1700
1690
  syncActiveCell(state);
1701
1691
 
1702
- if (state.keyboardMode === 'NAVIGATION') {
1692
+ if (state.keyboardMode === KEYBOARD_NAVIGATION_MODE) {
1693
+ // Tracked state changes.
1703
1694
  updateTabIndexActiveCell(state);
1704
1695
  updateTabIndexActiveRow(state);
1705
1696
  }
1706
- // if there is previously focused cell which was deleted set focus from celltofocus next
1707
- if (state.cellToFocusNext && state.activeCell) {
1708
- 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);
1709
1701
  }
1710
1702
  }
1711
1703
 
1712
1704
  updateColumns(columns) {
1713
- 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;
1714
1714
  const hadTreeDataTypePreviously = hasTreeDataType(state);
1715
- // calculate cell to focus next before indexes are updated
1716
- setCellToFocusFromPrev(state, template);
1715
+ // Untracked state changes.
1716
+ // Calculate cell to focus next before indexes are updated.
1717
+ setCellToFocusFromPrev(state, this.template);
1717
1718
  normalizeColumns(state, columns, this.privateTypes);
1718
- setDirtyValues(state, this._draftValues);
1719
1719
  updateRowNavigationMode(hadTreeDataTypePreviously, state);
1720
- state.headerIndexes = generateHeaderIndexes(getColumns(state));
1720
+ // Tracked state changes.
1721
+ setDirtyValues(state, this._draftValues);
1721
1722
  // Updates state.wrapText and when isWrappableType, sets internal header actions
1722
- updateHeaderActions(state);
1723
- this.updateRowsAndCellIndexes(state);
1723
+ updateHeaderInternalActions(state);
1724
+ }
1725
+
1726
+ updateColumnsAfterIndexes() {
1727
+ const { state, widthsData } = this;
1728
+
1729
+ // Tracked state changes.
1724
1730
  updateBulkSelectionState(state);
1725
1731
  this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
1726
- updateColumnWidthsMetadata(getColumns(state), widthsData);
1727
- // 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.
1728
1734
  updateCellToFocusFromPrev(state);
1729
1735
 
1730
- if (getColumns(state).length !== getColumnsWidths(widthsData).length) {
1731
- if (getData(state).length > 0) {
1732
- // when there are column changes, update the active cell
1733
- syncActiveCell(state);
1734
- }
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);
1735
1743
  }
1736
- if (state.keyboardMode === 'NAVIGATION') {
1744
+ if (state.keyboardMode === KEYBOARD_NAVIGATION_MODE) {
1745
+ // Tracked state changes.
1737
1746
  updateTabIndexActiveCell(state);
1738
1747
  updateTabIndexActiveRow(state);
1739
1748
  }
1740
- // if there is previously focused cell which was deleted set focus from celltofocus next
1741
- if (state.cellToFocusNext && state.activeCell) {
1742
- 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);
1743
1753
  }
1744
1754
  }
1745
1755
 
1756
+ updateRowsAndCells() {
1757
+ updateRowsAndCellIndexes(this.state, this._privateTypes);
1758
+ }
1759
+
1746
1760
  updateVirtualizedRowHeights() {
1747
1761
  const state = this.state;
1748
1762
  const virtualizedRows = state.virtualize && this.renderedRows.length;
@@ -1768,10 +1782,9 @@ export default class LightningDatatable extends LightningElement {
1768
1782
  state.rowHeight = height;
1769
1783
  resetTableHeight(state);
1770
1784
  state.rows.forEach((row) => {
1771
- row.style = styleToString({
1772
- position: 'absolute',
1773
- top: `${row.rowIndex * height}px`,
1774
- });
1785
+ row.style = `position:absolute;top:${
1786
+ row.rowIndex * height
1787
+ }px;`;
1775
1788
  });
1776
1789
  }
1777
1790
  }
@@ -1780,19 +1793,22 @@ export default class LightningDatatable extends LightningElement {
1780
1793
 
1781
1794
  setSelectedRows(value) {
1782
1795
  setSelectedRowsKeys(this.state, value);
1783
- handleRowSelectionChange.call(this);
1796
+ this.handleRowSelectionChange();
1784
1797
  }
1785
1798
 
1786
1799
  setActiveCell(rowKeyValue, colKeyValue) {
1787
- const { template, state } = this;
1800
+ const { state, template } = this;
1788
1801
  const { rowIndex, colIndex } = getIndexesByKeys(
1789
1802
  state,
1790
1803
  rowKeyValue,
1791
1804
  colKeyValue
1792
1805
  );
1793
- setBlurActiveCell(template, state);
1794
- updateActiveCell(state, rowKeyValue, colKeyValue);
1795
- addFocusStylesToActiveCell(template, state);
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);
1796
1812
  updateCellTabIndex(state, rowIndex, colIndex, 0);
1797
1813
  }
1798
1814
 
@@ -1800,30 +1816,27 @@ export default class LightningDatatable extends LightningElement {
1800
1816
  * @returns {Object} containing the visible dimensions of the table { left, right, top, bottom, }
1801
1817
  */
1802
1818
  getViewableRect() {
1803
- const scrollerX = this.template
1804
- .querySelector('.slds-scrollable_x')
1805
- .getBoundingClientRect();
1806
- const scrollerY = this.template
1807
- .querySelector('.slds-scrollable_y')
1808
- .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();
1809
1824
 
1810
1825
  return {
1811
- left: scrollerX.left,
1812
- right: scrollerX.right,
1813
- top: scrollerY.top,
1814
- bottom: scrollerY.bottom,
1826
+ left: scrollerXRect.left,
1827
+ right: scrollerXRect.right,
1828
+ top: scrollerYRect.top,
1829
+ bottom: scrollerYRect.bottom,
1815
1830
  };
1816
1831
  }
1817
1832
 
1818
1833
  // W-6363867, W-7143375 Safari Refresh Bug
1819
- safariHeaderFix() {
1834
+ fixHeaderForSafari() {
1820
1835
  if (isSafari) {
1821
1836
  const thead = this.template.querySelector('thead');
1822
-
1823
1837
  if (thead) {
1824
1838
  /* Safari hack: hide and show the table head to force a browser repaint */
1825
1839
  thead.style.display = 'none';
1826
-
1827
1840
  // eslint-disable-next-line @lwc/lwc/no-async-operation
1828
1841
  requestAnimationFrame(() => {
1829
1842
  thead.style.display = '';
@@ -1836,10 +1849,11 @@ export default class LightningDatatable extends LightningElement {
1836
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
1837
1850
  */
1838
1851
  computeRowLookupItemPickedInformation(currentTarget) {
1839
- const rowIndex =
1840
- 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
1841
- const rowKeyValue = currentTarget.dataset.rowKeyValue;
1842
-
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;
1843
1857
  return { rowIndex, rowKeyValue };
1844
1858
  }
1845
1859
  }