lightning-base-components 1.14.3-alpha → 1.14.7-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 (144) hide show
  1. package/metadata/raptor.json +37 -4
  2. package/package.json +11 -4
  3. package/scopedImports/@salesforce-label-LightningModalBase.cancelandclose.js +1 -0
  4. package/scopedImports/@salesforce-label-LightningProgressBar.progressBar.js +1 -0
  5. package/src/lightning/alert/__docs__/alert.md +101 -0
  6. package/src/lightning/alert/__examples__disabled/basic/basic.css +7 -0
  7. package/src/lightning/alert/__examples__disabled/basic/basic.html +8 -0
  8. package/src/lightning/alert/__examples__disabled/basic/basic.js +14 -0
  9. package/src/lightning/alert/alert.html +3 -0
  10. package/src/lightning/alert/alert.js +78 -0
  11. package/src/lightning/alert/alert.js-meta.xml +6 -0
  12. package/src/lightning/ariaObserver/__component__/ariaObserver.spec.js +9 -0
  13. package/src/lightning/ariaObserver/ariaObserver.js +24 -35
  14. package/src/lightning/baseFormattedText/baseFormattedText.html +6 -1
  15. package/src/lightning/baseFormattedText/baseFormattedText.js +5 -0
  16. package/src/lightning/buttonMenu/buttonMenu.js +12 -0
  17. package/src/lightning/confirm/__docs__/confirm.md +100 -0
  18. package/src/lightning/confirm/__examples__disabled/basic/basic.css +7 -0
  19. package/src/lightning/confirm/__examples__disabled/basic/basic.html +8 -0
  20. package/src/lightning/confirm/__examples__disabled/basic/basic.js +14 -0
  21. package/src/lightning/confirm/confirm.html +3 -0
  22. package/src/lightning/confirm/confirm.js +80 -0
  23. package/src/lightning/confirm/confirm.js-meta.xml +6 -0
  24. package/src/lightning/datatable/__examples__/withInfiniteLoading/fetchDataHelper.js +21 -0
  25. package/src/lightning/datatable/__examples__/withInfiniteLoading/withInfiniteLoading.html +13 -0
  26. package/src/lightning/datatable/__examples__/withInfiniteLoading/withInfiniteLoading.js +42 -0
  27. package/src/lightning/datatable/autoWidthStrategy.js +170 -61
  28. package/src/lightning/datatable/{resizer.js → columnResizer.js} +0 -0
  29. package/src/lightning/datatable/columnWidthManager.js +226 -44
  30. package/src/lightning/datatable/columns.js +166 -71
  31. package/src/lightning/datatable/datatable.js +132 -60
  32. package/src/lightning/datatable/fixedWidthStrategy.js +43 -8
  33. package/src/lightning/datatable/headerActions.js +2 -2
  34. package/src/lightning/datatable/infiniteLoading.js +100 -28
  35. package/src/lightning/datatable/inlineEdit.js +21 -30
  36. package/src/lightning/datatable/keyboard.js +166 -131
  37. package/src/lightning/datatable/renderManager.js +117 -122
  38. package/src/lightning/datatable/{datatableResizeObserver.js → resizeObserver.js} +46 -29
  39. package/src/lightning/datatable/resizeSensor.js +19 -3
  40. package/src/lightning/datatable/rowSelection.js +1 -1
  41. package/src/lightning/datatable/rowSelectionShared.js +33 -20
  42. package/src/lightning/datatable/rows.js +7 -8
  43. package/src/lightning/datatable/sort.js +8 -8
  44. package/src/lightning/datatable/state.js +14 -2
  45. package/src/lightning/datatable/templates/div/div.html +127 -117
  46. package/src/lightning/datatable/templates/table/table.html +5 -0
  47. package/src/lightning/datatable/tree.js +25 -0
  48. package/src/lightning/datatable/types.js +77 -9
  49. package/src/lightning/datatable/utils.js +51 -24
  50. package/src/lightning/datatable/virtualization.js +319 -0
  51. package/src/lightning/datatable/widthManagerShared.js +27 -3
  52. package/src/lightning/datatable/wrapText.js +115 -48
  53. package/src/lightning/formattedDateTime/__docs__/formattedDateTime.md +36 -3
  54. package/src/lightning/formattedDateTime/__examples__/datetime/datetime.html +2 -2
  55. package/src/lightning/formattedDateTime/__examples__/datetime/datetime.js +3 -1
  56. package/src/lightning/formattedDateTime/__examples__/time/time.html +1 -1
  57. package/src/lightning/formattedDateTime/__examples__/time/time.js +3 -1
  58. package/src/lightning/formattedDateTime/formattedDateTime.js +1 -0
  59. package/src/lightning/iconSvgTemplates/buildTemplates/standard/dashboard_component.html +7 -0
  60. package/src/lightning/iconSvgTemplates/buildTemplates/standard/slack.html +7 -0
  61. package/src/lightning/iconSvgTemplates/buildTemplates/standard/tableau.html +7 -0
  62. package/src/lightning/iconSvgTemplates/buildTemplates/standard/travel_mode.html +2 -2
  63. package/src/lightning/iconSvgTemplates/buildTemplates/templates.js +8 -1
  64. package/src/lightning/iconSvgTemplates/buildTemplates/utility/data_model.html +7 -0
  65. package/src/lightning/iconSvgTemplates/buildTemplates/utility/serialized_product.html +1 -1
  66. package/src/lightning/iconSvgTemplates/buildTemplates/utility/serialized_product_transaction.html +2 -1
  67. package/src/lightning/iconSvgTemplates/buildTemplates/utility/slack.html +7 -0
  68. package/src/lightning/iconSvgTemplates/buildTemplates/utility/tableau.html +7 -0
  69. package/src/lightning/iconSvgTemplates/buildTemplates/utility/video_off.html +7 -0
  70. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/standard/dashboard_component.html +7 -0
  71. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/standard/slack.html +7 -0
  72. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/standard/tableau.html +7 -0
  73. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/standard/travel_mode.html +2 -2
  74. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/templates.js +8 -1
  75. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/data_model.html +7 -0
  76. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/serialized_product.html +1 -1
  77. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/serialized_product_transaction.html +2 -1
  78. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/slack.html +7 -0
  79. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/tableau.html +7 -0
  80. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/video_off.html +7 -0
  81. package/src/lightning/iconSvgTemplatesStandard/buildTemplates/standard/dashboard_component.html +7 -0
  82. package/src/lightning/iconSvgTemplatesStandard/buildTemplates/standard/slack.html +7 -0
  83. package/src/lightning/iconSvgTemplatesStandard/buildTemplates/standard/tableau.html +7 -0
  84. package/src/lightning/iconSvgTemplatesStandard/buildTemplates/standard/travel_mode.html +2 -2
  85. package/src/lightning/iconSvgTemplatesStandard/buildTemplates/templates.js +4 -1
  86. package/src/lightning/iconSvgTemplatesStandardRtl/buildTemplates/standard/dashboard_component.html +7 -0
  87. package/src/lightning/iconSvgTemplatesStandardRtl/buildTemplates/standard/slack.html +7 -0
  88. package/src/lightning/iconSvgTemplatesStandardRtl/buildTemplates/standard/tableau.html +7 -0
  89. package/src/lightning/iconSvgTemplatesStandardRtl/buildTemplates/standard/travel_mode.html +2 -2
  90. package/src/lightning/iconSvgTemplatesStandardRtl/buildTemplates/templates.js +4 -1
  91. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/templates.js +5 -1
  92. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/data_model.html +7 -0
  93. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/serialized_product.html +1 -1
  94. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/serialized_product_transaction.html +2 -1
  95. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/slack.html +7 -0
  96. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/tableau.html +7 -0
  97. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/video_off.html +7 -0
  98. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/templates.js +5 -1
  99. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/data_model.html +7 -0
  100. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/serialized_product.html +1 -1
  101. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/serialized_product_transaction.html +2 -1
  102. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/slack.html +7 -0
  103. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/tableau.html +7 -0
  104. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/video_off.html +7 -0
  105. package/src/lightning/input/__docs__/input.md +2 -0
  106. package/src/lightning/input/input.html +2 -5
  107. package/src/lightning/interactiveDialogBase/interactiveDialogBase.css +494 -0
  108. package/src/lightning/interactiveDialogBase/interactiveDialogBase.html +63 -0
  109. package/src/lightning/interactiveDialogBase/interactiveDialogBase.js +200 -0
  110. package/src/lightning/menuItem/menuItem.js +4 -1
  111. package/src/lightning/modalBase/modalBase.css +20 -0
  112. package/src/lightning/modalBase/modalBase.html +54 -0
  113. package/src/lightning/modalBase/modalBase.js +1039 -0
  114. package/src/lightning/overlay/__docs__/overlay.md +90 -0
  115. package/src/lightning/overlay/__examples__/alert/alert.html +27 -0
  116. package/src/lightning/overlay/__examples__/alert/alert.js +33 -0
  117. package/src/lightning/overlay/__examples__/basic/basic.css +7 -0
  118. package/src/lightning/overlay/__examples__/basic/basic.html +18 -0
  119. package/src/lightning/overlay/__examples__/basic/basic.js +61 -0
  120. package/src/lightning/overlay/__examples__/demo/demo.html +29 -0
  121. package/src/lightning/overlay/__examples__/demo/demo.js +40 -0
  122. package/src/lightning/overlay/__examples__/panel/panel.html +17 -0
  123. package/src/lightning/overlay/__examples__/panel/panel.js +21 -0
  124. package/src/lightning/overlay/overlay.html +3 -0
  125. package/src/lightning/overlay/overlay.js +45 -0
  126. package/src/lightning/overlayContainer/__docs__/overlayContainer.md +0 -0
  127. package/src/lightning/overlayContainer/overlayContainer.html +3 -0
  128. package/src/lightning/overlayContainer/overlayContainer.js +138 -0
  129. package/src/lightning/overlayManager/overlayManager.js +54 -0
  130. package/src/lightning/overlayUtils/overlayUtils.js +17 -0
  131. package/src/lightning/progressBar/progressBar.html +2 -1
  132. package/src/lightning/progressBar/progressBar.js +18 -1
  133. package/src/lightning/prompt/__docs__/prompt.md +102 -0
  134. package/src/lightning/prompt/__examples__disabled/basic/basic.css +7 -0
  135. package/src/lightning/prompt/__examples__disabled/basic/basic.html +8 -0
  136. package/src/lightning/prompt/__examples__disabled/basic/basic.js +15 -0
  137. package/src/lightning/prompt/prompt.css +81 -0
  138. package/src/lightning/prompt/prompt.html +8 -0
  139. package/src/lightning/prompt/prompt.js +92 -0
  140. package/src/lightning/prompt/prompt.js-meta.xml +6 -0
  141. package/src/lightning/spinner/spinner.html +1 -1
  142. package/src/lightning/spinner/spinner.js +12 -0
  143. package/src/lightning/utilsPrivate/phonify.js +1 -1
  144. package/scopedImports/@salesforce-label-LightningModalBase.close.js +0 -1
@@ -9,7 +9,7 @@ import {
9
9
  isSafari,
10
10
  synchronizeAttrs,
11
11
  } from 'lightning/utilsPrivate';
12
- import { LightningDatatableResizeObserver } from './datatableResizeObserver';
12
+ import { LightningDatatableResizeObserver } from './resizeObserver';
13
13
  import { ColumnWidthManager } from './columnWidthManager';
14
14
  import { getDefaultState } from './state';
15
15
  import { getColumns, normalizeColumns, generateHeaderIndexes } from './columns';
@@ -38,7 +38,7 @@ import {
38
38
  getCSSWidthStyleOfTable,
39
39
  updateColumnWidthsMetadata,
40
40
  getResizerDefaultState,
41
- } from './resizer';
41
+ } from './columnResizer';
42
42
  import {
43
43
  syncSelectedRowsKeys,
44
44
  handleRowSelectionChange,
@@ -81,6 +81,9 @@ import {
81
81
  addFocusStylesToActiveCell,
82
82
  refocusCellElement,
83
83
  isCellElement,
84
+ getActiveCellElement,
85
+ getDataRow,
86
+ FOCUS_CLASS,
84
87
  } from './keyboard';
85
88
  import {
86
89
  getRowNumberOffset,
@@ -135,14 +138,16 @@ import {
135
138
  import {
136
139
  isViewportRenderingEnabled,
137
140
  setViewportRendering,
138
- getDTRows,
139
- getDTRenderedRowCount,
140
- setDTRenderedRowCount,
141
141
  getDTWrapperHeight,
142
- normalizeVirtualization,
142
+ setVirtualize,
143
143
  RenderManager,
144
- DEFAULT_ROW_HEIGHT,
145
144
  } from './renderManager';
145
+ import {
146
+ handleVariableRowHeights,
147
+ resetRowHeights,
148
+ resetTableHeight,
149
+ findFirstVisibleIndex,
150
+ } from './virtualization';
146
151
 
147
152
  import { hasTreeDataType } from './tree';
148
153
  import { setErrors, getTableError, getErrors } from './errors';
@@ -200,14 +205,13 @@ export default class LightningDatatable extends LightningElement {
200
205
  _customerSelectedRows = null;
201
206
  _datatableId = generateUniqueId('lgt-datatable');
202
207
  _draftValues = [];
203
- _firstVisibleIndex = 0; // first row that should be visible in viewport, used for virtualization
204
208
  _isResizing = false; // Whether resizing is in progress
205
209
  _privateTypes = {};
206
210
  _privateWidthObserver = null; // Instance of LightningDatatableResizeObserver
207
211
  _renderMode = 'table';
208
- _renderedRowCount = 0;
212
+ _shouldResetHeights = false;
209
213
  _suppressBottomBar = false;
210
- _virtualize = '';
214
+ _shouldResetFocus = false; // used to ensure focus isn't lost from changes in renderedRows
211
215
 
212
216
  /************************* PUBLIC PROPERTIES *************************/
213
217
 
@@ -287,6 +291,7 @@ export default class LightningDatatable extends LightningElement {
287
291
  // do necessary updates since rows have changed
288
292
  if (hasValidKeyField(this.state)) {
289
293
  this.updateRowsState();
294
+ resetTableHeight(this.state);
290
295
  }
291
296
  if (this._customerSelectedRows) {
292
297
  this.setSelectedRows(this._customerSelectedRows);
@@ -342,6 +347,7 @@ export default class LightningDatatable extends LightningElement {
342
347
 
343
348
  set enableInfiniteLoading(value) {
344
349
  setInfiniteLoading(this.state, value);
350
+ handlePrefetch.call(this, this.template, this.state);
345
351
  }
346
352
 
347
353
  /**
@@ -519,24 +525,17 @@ export default class LightningDatatable extends LightningElement {
519
525
 
520
526
  set renderConfig(value) {
521
527
  if (typeof value === 'object' && !isIE11) {
522
- const { viewportRendering, virtualize } = value;
523
- setViewportRendering(this.state, viewportRendering);
524
- if (this.state.renderModeRoleBased) {
525
- this._virtualize = normalizeVirtualization(virtualize);
526
- }
528
+ setViewportRendering(this.state, value.viewportRendering);
527
529
 
528
530
  this._renderManager.configure(
529
- this.getRows,
531
+ this.state,
530
532
  this.getWrapperHeight,
531
- this.getRenderedRowCount,
532
- this.setRenderedRowCount,
533
533
  value
534
534
  );
535
535
  // if renderConfig already exists, update rendering
536
536
  if (this._renderConfig) {
537
537
  this._renderManager.updateViewportRendering(
538
- this.state.rows,
539
- this.setRenderedRowCount,
538
+ this.state,
540
539
  this.gridContainer,
541
540
  true
542
541
  );
@@ -565,6 +564,10 @@ export default class LightningDatatable extends LightningElement {
565
564
  validValues: ['default', 'role-based'],
566
565
  });
567
566
  this.state.renderModeRoleBased = this._renderMode === 'role-based';
567
+ this._columnWidthManager.setRenderMode(this.renderMode);
568
+ if (this._renderConfig) {
569
+ setVirtualize(this.state, this._renderConfig.virtualize);
570
+ }
568
571
  updateCellClassForRoleBasedMode(this.state);
569
572
  }
570
573
 
@@ -803,21 +806,23 @@ export default class LightningDatatable extends LightningElement {
803
806
  * virtualization is enabled
804
807
  */
805
808
  get computedTbodyStyle() {
806
- const style = [];
809
+ const style = {};
810
+ const { firstVisibleIndex, bufferSize, virtualize, tableHeight } =
811
+ this.state;
807
812
  if (
808
813
  hasRowNumberColumn(this.state) &&
809
814
  getRowNumberOffset(this.state) >= 0
810
815
  ) {
811
- style.push(
812
- 'counter-reset: row-number ' + getRowNumberOffset(this.state)
816
+ const firstRenderedRow = Math.max(
817
+ firstVisibleIndex - bufferSize,
818
+ 0
813
819
  );
820
+ const rowNumber = firstRenderedRow + getRowNumberOffset(this.state);
821
+ style['counter-reset'] = `row-number ${rowNumber}`;
814
822
  }
815
- if (this._virtualize) {
816
- const length = this.state.rows.length;
817
- style.push(
818
- 'position: relative',
819
- `height:${length * DEFAULT_ROW_HEIGHT}px`
820
- );
823
+ if (virtualize) {
824
+ style.position = 'relative';
825
+ style.height = `${tableHeight}px`;
821
826
  }
822
827
  return styleToString(style);
823
828
  }
@@ -938,18 +943,18 @@ export default class LightningDatatable extends LightningElement {
938
943
  }
939
944
 
940
945
  get renderedRows() {
941
- if (this._virtualize) {
946
+ const { virtualize, rows, renderedRowCount } = this.state;
947
+ if (virtualize) {
942
948
  const { firstIndex, lastIndex } =
943
- this._renderManager.getRenderedRange(
944
- this._firstVisibleIndex,
945
- this._renderedRowCount
946
- );
947
- return this.state.rows.slice(firstIndex, lastIndex);
949
+ this._renderManager.getRenderedRange(this.state);
950
+ // we shouldn't lose focus from re-renders caused by a change in renderedRows
951
+ this._shouldResetFocus = true;
952
+ return rows.slice(firstIndex, lastIndex);
948
953
  }
949
954
  if (this.viewportRendering && !isIE11) {
950
- return this.state.rows.slice(0, this._renderedRowCount);
955
+ return rows.slice(0, renderedRowCount);
951
956
  }
952
- return this.state.rows;
957
+ return rows;
953
958
  }
954
959
 
955
960
  get showSelectAllCheckbox() {
@@ -980,14 +985,10 @@ export default class LightningDatatable extends LightningElement {
980
985
  super();
981
986
 
982
987
  this._privateTypes = new DatatableTypes(this.constructor.customTypes);
983
-
984
988
  this._columnWidthManager = new ColumnWidthManager(this.widthsData);
985
989
  this.updateRowsAndCellIndexes = updateRowsAndCellIndexes.bind(this);
986
990
 
987
991
  this._renderManager = new RenderManager();
988
- this.getRenderedRowCount = getDTRenderedRowCount.bind(this);
989
- this.setRenderedRowCount = setDTRenderedRowCount.bind(this);
990
- this.getRows = getDTRows.bind(this);
991
992
  this.getWrapperHeight = getDTWrapperHeight.bind(this);
992
993
  }
993
994
 
@@ -1134,6 +1135,7 @@ export default class LightningDatatable extends LightningElement {
1134
1135
  if (fireResizeEvent) {
1135
1136
  this.fireOnResize(false);
1136
1137
  }
1138
+ this.updateTableAndScrollerStyleOnRender();
1137
1139
  }
1138
1140
 
1139
1141
  // Managing the cell widths is only required for the role-based table
@@ -1147,8 +1149,25 @@ export default class LightningDatatable extends LightningElement {
1147
1149
  this._customerSelectedRows = null;
1148
1150
  // set the previous focused cell to null after render is done
1149
1151
  resetCellToFocusFromPrev(state);
1152
+ // reset focus styles on re-render
1153
+ if (this._shouldResetFocus) {
1154
+ // since focus is now getting reset, can change this back to false
1155
+ this._shouldResetFocus = false;
1156
+ if (state.activeCell && state.activeCell.focused) {
1157
+ const cellElement = getActiveCellElement(template, state);
1158
+ if (
1159
+ cellElement &&
1160
+ cellElement.parentElement &&
1161
+ !cellElement.parentElement.classList.contains(FOCUS_CLASS)
1162
+ ) {
1163
+ setFocusActiveCell(template, state, null, null, false);
1164
+ }
1165
+ }
1166
+ }
1150
1167
 
1151
- if (this.viewportRendering || this._virtualize) {
1168
+ this.updateVirtualizedRowHeights();
1169
+
1170
+ if (this.viewportRendering || state.virtualize) {
1152
1171
  const resizeTarget = this.template.querySelector(
1153
1172
  'div.dt-outer-container'
1154
1173
  );
@@ -1159,10 +1178,9 @@ export default class LightningDatatable extends LightningElement {
1159
1178
  // Reset the row count if we already had one before updating the wrapper height.
1160
1179
  // This can happen if the number of rows was calculated before the datatable
1161
1180
  // was rendered.
1162
- if (this._renderedRowCount) {
1181
+ if (this.state.renderedRowCount) {
1163
1182
  this._renderManager.updateViewportRendering(
1164
- this.state.rows,
1165
- this.setRenderedRowCount,
1183
+ this.state,
1166
1184
  this.gridContainer,
1167
1185
  true
1168
1186
  );
@@ -1171,6 +1189,18 @@ export default class LightningDatatable extends LightningElement {
1171
1189
  }
1172
1190
  }
1173
1191
 
1192
+ updateTableAndScrollerStyleOnRender() {
1193
+ const role = '[role="' + this.computedTableRole + '"]';
1194
+ const tableElement = this.template.querySelector(role);
1195
+ const scrollYEle = this.template.querySelector('.slds-scrollable_y');
1196
+ if (tableElement) {
1197
+ tableElement.style = this.computedTableStyle;
1198
+ }
1199
+ if (scrollYEle) {
1200
+ scrollYEle.style = this.computedScrollerStyle;
1201
+ }
1202
+ }
1203
+
1174
1204
  disconnectedCallback() {
1175
1205
  if (this._privateWidthObserver) {
1176
1206
  this._privateWidthObserver.disconnect();
@@ -1248,16 +1278,13 @@ export default class LightningDatatable extends LightningElement {
1248
1278
  }
1249
1279
 
1250
1280
  handleInlineEditPanelScroll.call(this, event);
1251
- if (this._virtualize) {
1252
- this._firstVisibleIndex =
1253
- this._renderManager.getFirstVisibleIndex(event);
1254
- } else if (this.viewportRendering) {
1255
- this._renderManager.handleScroll(
1256
- this.state.rows,
1257
- this._renderedRowCount,
1258
- this.setRenderedRowCount,
1259
- event
1281
+ if (this.state.virtualize) {
1282
+ this.state.firstVisibleIndex = findFirstVisibleIndex(
1283
+ this.state,
1284
+ event.target.scrollTop
1260
1285
  );
1286
+ } else if (this.viewportRendering) {
1287
+ this._renderManager.handleScroll(this.state, event);
1261
1288
  }
1262
1289
  }
1263
1290
 
@@ -1349,6 +1376,7 @@ export default class LightningDatatable extends LightningElement {
1349
1376
  handleResizeEnd(event) {
1350
1377
  event.stopPropagation();
1351
1378
  this._isResizing = false;
1379
+ this._shouldResetHeights = true;
1352
1380
  }
1353
1381
 
1354
1382
  /**
@@ -1421,10 +1449,19 @@ export default class LightningDatatable extends LightningElement {
1421
1449
  * Handles the `focusout` event on <table> and the corresponding
1422
1450
  * <div> on the role-based table
1423
1451
  *
1452
+ * This gets called both when we expect the table to lose focus
1453
+ * and when the active cell loses focus after renderedRows changes
1454
+ * on a virtualized table, in which case we don't want to lose focus.
1455
+ *
1456
+ * We account for this by setting activeCell.focused to the value of
1457
+ * _shouldResetFocus, which will be true if and only if focus was
1458
+ * lost due to a renderedRows change for a virtualized table.
1459
+ *
1424
1460
  * @param {FocusEvent} event - `focusout`
1425
1461
  */
1426
1462
  handleTableFocusOut(event) {
1427
1463
  handleDatatableFocusOut.call(this, event);
1464
+ this.state.activeCell.focused = this._shouldResetFocus;
1428
1465
  }
1429
1466
 
1430
1467
  /**
@@ -1533,11 +1570,11 @@ export default class LightningDatatable extends LightningElement {
1533
1570
 
1534
1571
  this.updateRowsAndCellIndexes(state);
1535
1572
 
1536
- if (this.viewportRendering || this._virtualize) {
1573
+ if (this.viewportRendering || state.virtualize) {
1537
1574
  this._renderManager.updateViewportRendering(
1538
- this.state.rows,
1539
- this.setRenderedRowCount,
1540
- this.gridContainer
1575
+ this.state,
1576
+ this.gridContainer,
1577
+ !!state.virtualize
1541
1578
  );
1542
1579
  }
1543
1580
 
@@ -1578,7 +1615,7 @@ export default class LightningDatatable extends LightningElement {
1578
1615
  setDirtyValues(state, this._draftValues);
1579
1616
  updateRowNavigationMode(hadTreeDataTypePreviously, state);
1580
1617
  state.headerIndexes = generateHeaderIndexes(getColumns(state));
1581
- // Updates state.wrapText and when isWrapableType, sets internal header actions
1618
+ // Updates state.wrapText and when isWrappableType, sets internal header actions
1582
1619
  updateHeaderActions(state);
1583
1620
  this.updateRowsAndCellIndexes(state);
1584
1621
  updateBulkSelectionState(state);
@@ -1603,6 +1640,41 @@ export default class LightningDatatable extends LightningElement {
1603
1640
  }
1604
1641
  }
1605
1642
 
1643
+ updateVirtualizedRowHeights() {
1644
+ const state = this.state;
1645
+ const virtualizedRows = state.virtualize && this.renderedRows.length;
1646
+
1647
+ // no need to handle other virtualization/row height logic
1648
+ // if heights need to be reset
1649
+ if (this._shouldResetHeights) {
1650
+ resetRowHeights(state);
1651
+ this._shouldResetHeights = false;
1652
+ } else if (virtualizedRows && !state.fixedHeight) {
1653
+ // if row heights aren't fixed, we need to update items
1654
+ // in state to know where rows should be positioned
1655
+ handleVariableRowHeights(this.template, state, this.renderedRows);
1656
+ } else if (virtualizedRows && state.fixedHeight) {
1657
+ // if heights are fixed, we only need to check height of first row
1658
+ const rowElement = this.template.querySelector(
1659
+ getDataRow(this.renderedRows[0].key)
1660
+ );
1661
+ // increase height by 1 since first rendered row is missing an extra 1px border
1662
+ if (rowElement) {
1663
+ const height = rowElement.getBoundingClientRect().height + 1;
1664
+ if (state.rowHeight !== height) {
1665
+ state.rowHeight = height;
1666
+ resetTableHeight(state);
1667
+ state.rows.forEach((row) => {
1668
+ row.style = styleToString({
1669
+ position: 'absolute',
1670
+ top: `${row.rowIndex * height}px`,
1671
+ });
1672
+ });
1673
+ }
1674
+ }
1675
+ }
1676
+ }
1677
+
1606
1678
  setSelectedRows(value) {
1607
1679
  setSelectedRowsKeys(this.state, value);
1608
1680
  handleRowSelectionChange.call(this);
@@ -1622,7 +1694,7 @@ export default class LightningDatatable extends LightningElement {
1622
1694
  }
1623
1695
 
1624
1696
  /**
1625
- * @return {Object} containing the visible dimensions of the table { left, right, top, bottom, }
1697
+ * @returns {Object} containing the visible dimensions of the table { left, right, top, bottom, }
1626
1698
  */
1627
1699
  getViewableRect() {
1628
1700
  const scrollerX = this.template
@@ -3,13 +3,26 @@ import {
3
3
  getColumnWidthFromDef,
4
4
  } from './widthManagerShared';
5
5
 
6
+ /**
7
+ * Determines the expected table width
8
+ *
9
+ * @param {Number} availableWidth The available width for the entire table
10
+ * @param {Object} widthsMetadata The widths metadata object
11
+ * @returns {Number} The expected width of the table
12
+ */
6
13
  function getExpectedTableWidth(availableWidth, widthsMetadata) {
7
14
  const minExpectedTableWidth = getMinExpectedTableWidth(widthsMetadata);
8
- return hasNoFlexibleColumns(widthsMetadata)
15
+ return widthsMetadata.totalFlexibleColumns === 0
9
16
  ? minExpectedTableWidth
10
17
  : Math.max(minExpectedTableWidth, availableWidth);
11
18
  }
12
19
 
20
+ /**
21
+ * Determines the minimum expected table width
22
+ *
23
+ * @param {Object} widthsMetadata The widths metadata object
24
+ * @returns {Number} The minimum expected table width
25
+ */
13
26
  function getMinExpectedTableWidth(widthsMetadata) {
14
27
  const {
15
28
  totalFixedWidth,
@@ -21,21 +34,35 @@ function getMinExpectedTableWidth(widthsMetadata) {
21
34
  return minTotalFlexibleWidth + totalFixedWidth + totalResizedWidth;
22
35
  }
23
36
 
24
- function hasNoFlexibleColumns(widthsMetadata) {
25
- return widthsMetadata.totalFlexibleColumns === 0;
26
- }
27
-
37
+ /**
38
+ * Strategy for columns with defined fixed widths.
39
+ */
28
40
  export class FixedWidthStrategy {
41
+ // Private variables
29
42
  _columnWidthMetaData = {};
30
43
 
44
+ /************************** LIFECYCLE HOOKS **************************/
45
+
31
46
  constructor(minColumnWidth, maxColumnWidth) {
32
47
  this._columnWidthMetaData = { minColumnWidth, maxColumnWidth };
33
48
  }
34
49
 
50
+ /************************** PRIVATE SETTERS **************************/
51
+
52
+ /**
53
+ * Sets the minimum column width
54
+ *
55
+ * @param {Number} value The minimum width
56
+ */
35
57
  set minColumnWidth(value) {
36
58
  this._columnWidthMetaData.minColumnWidth = value;
37
59
  }
38
60
 
61
+ /**
62
+ * Sets the maximum column width
63
+ *
64
+ * @param {Number} value The maximum width
65
+ */
39
66
  set maxColumnWidth(value) {
40
67
  this._columnWidthMetaData.maxColumnWidth = value;
41
68
  }
@@ -43,9 +70,10 @@ export class FixedWidthStrategy {
43
70
  /**
44
71
  * Get adjusted column widths either from defined widths in columnDefs or by dividing total width
45
72
  * equally amongst the possible columns
46
- * @param datatableInterface - interface to datatable with callbacks giving width information
47
- * @param columnDefs - column definitions array with defined widths and other attributes
48
- * @returns {object} with columnWidths: [], expectedTableWidth: (number)
73
+ *
74
+ * @param {Object} datatableInterface Interface to datatable with callbacks giving width information
75
+ * @param {Array} columnDefs Ccolumn definitions array with defined widths and other attributes
76
+ * @returns {Object} columnWidths: [], expectedTableWidth: (number)
49
77
  */
50
78
  getAdjustedColumnWidths(datatableInterface, columnDefs) {
51
79
  const widthsMetadata = getTotalWidthsMetadata(
@@ -73,6 +101,13 @@ export class FixedWidthStrategy {
73
101
  return { columnWidths, expectedTableWidth };
74
102
  }
75
103
 
104
+ /**
105
+ * Determines the expected flexible column width
106
+ *
107
+ * @param {Object} widthsMetadata The widths metadata object
108
+ * @param {Number} totalTableWidth The total available width for the table
109
+ * @returns {Number} The column width
110
+ */
76
111
  _getFlexibleColumnWidth(widthsMetadata, totalTableWidth) {
77
112
  const {
78
113
  totalFixedWidth,
@@ -16,7 +16,7 @@ const DIVIDER_REM_HEIGHT = 1.0625;
16
16
  *
17
17
  * @param {Object} state The state of the datatable
18
18
  * @param {Object} columnDefinition The column definition to extract internal actions from
19
- * @return {Array} All wrapText internal actions
19
+ * @returns {Array} All wrapText internal actions
20
20
  */
21
21
  export function getInternalActions(state, columnDefinition) {
22
22
  return [...getActions(state, columnDefinition)];
@@ -113,7 +113,7 @@ function dispatchHeaderActionEvent(dt, action, colKeyValue) {
113
113
  *
114
114
  * @param {Array} columns Array of all the columns
115
115
  * @param {Integer} index The current column index to check
116
- * @return {String} The computed alignment
116
+ * @returns {String} The computed alignment
117
117
  */
118
118
  function getMenuAlignment(columns, index) {
119
119
  const isLastColumn = index === columns.length - 1;
@@ -1,34 +1,67 @@
1
1
  import { normalizeBoolean } from 'lightning/utilsPrivate';
2
2
  import { getScrollOffsetFromTableEnd, isNonNegativeInteger } from './utils';
3
3
 
4
- const SCROLLABLE_CONTAINER_SEL = '.slds-scrollable_y';
5
4
  const SCROLL_ALLOWANCE = 2;
5
+ export const DEFAULT_LOAD_MORE_OFFSET = 20;
6
6
 
7
- export function getInfiniteLoadingDefaultState() {
8
- return {
9
- enableInfiniteLoading: false,
10
- loadMoreOffset: 20,
11
- isLoading: false,
12
- };
13
- }
7
+ /*********************** STATE MANAGEMENT ************************/
14
8
 
9
+ /**
10
+ * Returns whether the datatable is in a loading state
11
+ *
12
+ * @param {Object} state The datatable state object
13
+ * @returns {Boolean} The loading state
14
+ */
15
15
  export function isLoading(state) {
16
16
  return state.isLoading;
17
17
  }
18
+
19
+ /**
20
+ * Sets the loading state of the datatable
21
+ *
22
+ * @param {Object} state The datatable state object
23
+ * @param {Boolean} value The loading state to set
24
+ */
18
25
  export function setLoading(state, value) {
19
26
  state.isLoading = normalizeBoolean(value);
20
27
  }
21
28
 
29
+ /**
30
+ * Returns whether infinite loading is enabled on the datatable
31
+ *
32
+ * @param {Object} state The datatable state object
33
+ * @returns {Boolean} The infinite loading state
34
+ */
22
35
  export function isInfiniteLoadingEnabled(state) {
23
36
  return state.enableInfiniteLoading;
24
37
  }
38
+
39
+ /**
40
+ * Sets the infinite loading option on the datatable
41
+ *
42
+ * @param {Object} state The datatable state object
43
+ * @param {Boolean} value The infinite loading state to set
44
+ */
25
45
  export function setInfiniteLoading(state, value) {
26
46
  state.enableInfiniteLoading = normalizeBoolean(value);
27
47
  }
28
48
 
49
+ /**
50
+ * Returns the load more offset
51
+ *
52
+ * @param {Object} state The datatable state object
53
+ * @returns {Number} The currently configured load more offset value
54
+ */
29
55
  export function getLoadMoreOffset(state) {
30
56
  return state.loadMoreOffset;
31
57
  }
58
+
59
+ /**
60
+ * Sets the load more offset value. Must be a number >= 0.
61
+ *
62
+ * @param {Object} state The datatable state object
63
+ * @param {Boolean} value The load more offset value to set
64
+ */
32
65
  export function setLoadMoreOffset(state, value) {
33
66
  if (!isNonNegativeInteger(value)) {
34
67
  // eslint-disable-next-line no-console
@@ -40,9 +73,17 @@ export function setLoadMoreOffset(state, value) {
40
73
 
41
74
  state.loadMoreOffset = isNonNegativeInteger(value)
42
75
  ? parseInt(value, 10)
43
- : getInfiniteLoadingDefaultState().loadMoreOffset;
76
+ : DEFAULT_LOAD_MORE_OFFSET;
44
77
  }
45
78
 
79
+ /************************** PUBLIC METHODS ***************************/
80
+
81
+ /**
82
+ * Checks whether the datatable should begin loading more content
83
+ * and then dispatches the `loadmore` event indicating that directive.
84
+ *
85
+ * @param {Event} event
86
+ */
46
87
  export function handleLoadMoreCheck(event) {
47
88
  if (isLoading(this.state)) {
48
89
  return;
@@ -60,24 +101,13 @@ export function handleLoadMoreCheck(event) {
60
101
  }
61
102
  }
62
103
 
63
- function isScrollable(element) {
64
- // scrollHeight should be greater than clientHeight by some allowance
65
- return (
66
- element &&
67
- element.scrollHeight > element.clientHeight + SCROLL_ALLOWANCE
68
- );
69
- }
70
-
71
- function isScrollerVisible(elem) {
72
- return (
73
- elem && !!(elem.offsetParent || elem.offsetHeight || elem.offsetWidth)
74
- );
75
- }
76
-
77
- function hasData(root) {
78
- return root.querySelectorAll('tbody > tr').length > 0;
79
- }
80
-
104
+ /**
105
+ * Determines whether or not to prefetch data. If so,
106
+ * dispatches the `loadmore` event.
107
+ *
108
+ * @param {Object} root The datatable
109
+ * @param {Object} state The datatable state object
110
+ */
81
111
  export function handlePrefetch(root, state) {
82
112
  if (
83
113
  !isInfiniteLoadingEnabled(state) ||
@@ -91,9 +121,51 @@ export function handlePrefetch(root, state) {
91
121
  return;
92
122
  }
93
123
 
94
- const elem = root.querySelector(SCROLLABLE_CONTAINER_SEL);
124
+ const elem = root.querySelector('.slds-scrollable_y');
95
125
 
96
126
  if (isScrollerVisible(elem) && !isScrollable(elem)) {
97
127
  this.dispatchEvent(new CustomEvent('loadmore'));
98
128
  }
99
129
  }
130
+
131
+ /************************** PRIVATE METHODS ***************************/
132
+
133
+ /**
134
+ * Determines if a DOM element is scrollable
135
+ *
136
+ * @param {Element} element The DOM element to check
137
+ * @returns {Boolean} Whether or not the element is scrollable
138
+ */
139
+ function isScrollable(element) {
140
+ // scrollHeight should be greater than clientHeight by some allowance
141
+ return (
142
+ element &&
143
+ element.scrollHeight > element.clientHeight + SCROLL_ALLOWANCE
144
+ );
145
+ }
146
+
147
+ /**
148
+ * Determines if a DOM element's scroll bars are visible
149
+ *
150
+ * @param {Element} element The DOM element to check
151
+ * @returns {Boolean} Whether or not the element's scroll bars are visible
152
+ */
153
+ function isScrollerVisible(element) {
154
+ return (
155
+ element &&
156
+ !!(element.offsetParent || element.offsetHeight || element.offsetWidth)
157
+ );
158
+ }
159
+
160
+ /**
161
+ * Determines if a root element has data
162
+ *
163
+ * @param {Element} root The parent element to check
164
+ * @returns {Boolean} Whether or not the element contains any data
165
+ */
166
+ function hasData(root) {
167
+ return (
168
+ root.querySelectorAll('tbody > tr, [role="rowgroup"] > [role="row"]')
169
+ .length > 0
170
+ );
171
+ }