lightning-base-components 1.21.4-alpha → 1.21.6-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 (104) hide show
  1. package/metadata/raptor.json +2 -1
  2. package/package.json +9 -1
  3. package/scopedImports/@salesforce-label-LightningLookup.messageWhenSearchTermTooShort.js +1 -0
  4. package/src/lightning/accordion/__docs__/accordion.md +0 -4
  5. package/src/lightning/accordionSection/__docs__/accordionSection.md +0 -4
  6. package/src/lightning/avatar/__docs__/avatar.md +0 -4
  7. package/src/lightning/badge/__docs__/badge.md +0 -4
  8. package/src/lightning/badge/badge.slds.css +1 -1
  9. package/src/lightning/barcodeScanner/__docs__/barcodeScanner.md +0 -4
  10. package/src/lightning/baseCombobox/baseCombobox.js +2 -2
  11. package/src/lightning/baseComboboxItem/baseComboboxItem.js +6 -10
  12. package/src/lightning/button/__docs__/button.md +3 -7
  13. package/src/lightning/buttonGroup/__docs__/buttonGroup.md +0 -4
  14. package/src/lightning/buttonIcon/__docs__/buttonIcon.md +0 -4
  15. package/src/lightning/buttonIconStateful/__docs__/buttonIconStateful.md +0 -4
  16. package/src/lightning/buttonMenu/__docs__/buttonMenu.md +0 -4
  17. package/src/lightning/buttonStateful/__docs__/buttonStateful.md +0 -4
  18. package/src/lightning/buttonStateful/buttonStateful.html +5 -3
  19. package/src/lightning/buttonStateful/buttonStateful.js +4 -0
  20. package/src/lightning/card/__docs__/card.md +0 -4
  21. package/src/lightning/card/card.js-meta.xml +3 -0
  22. package/src/lightning/carousel/__docs__/carousel.md +0 -4
  23. package/src/lightning/checkboxGroup/__docs__/checkboxGroup.md +0 -4
  24. package/src/lightning/combobox/__docs__/combobox.md +0 -4
  25. package/src/lightning/combobox/form-element.slds.css +4 -1
  26. package/src/lightning/datatable/columnWidthManager.js +3 -3
  27. package/src/lightning/datatable/columns.js +17 -18
  28. package/src/lightning/datatable/datatable.js +146 -84
  29. package/src/lightning/datatable/indexes.js +1 -3
  30. package/src/lightning/datatable/infiniteLoading.js +1 -1
  31. package/src/lightning/datatable/inlineEdit.js +10 -7
  32. package/src/lightning/datatable/keyboard.js +21 -44
  33. package/src/lightning/datatable/renderManager.js +9 -18
  34. package/src/lightning/datatable/rows.js +112 -128
  35. package/src/lightning/datatable/sort.js +35 -14
  36. package/src/lightning/datatable/state.js +5 -0
  37. package/src/lightning/datatable/tree.js +0 -33
  38. package/src/lightning/datatable/utils.js +15 -5
  39. package/src/lightning/datepicker/datepicker.js +12 -3
  40. package/src/lightning/datepicker/form-element.slds.css +4 -1
  41. package/src/lightning/datetimepicker/form-element.slds.css +4 -1
  42. package/src/lightning/dualListbox/__docs__/dualListbox.md +0 -4
  43. package/src/lightning/dualListbox/form-element.slds.css +4 -1
  44. package/src/lightning/dynamicIcon/__docs__/dynamicIcon.md +0 -4
  45. package/src/lightning/formattedDateTime/__docs__/formattedDateTime.md +0 -4
  46. package/src/lightning/formattedLocation/__docs__/formattedLocation.md +0 -4
  47. package/src/lightning/formattedName/__docs__/formattedName.md +0 -4
  48. package/src/lightning/formattedNumber/__docs__/formattedNumber.md +0 -4
  49. package/src/lightning/formattedPhone/__docs__/formattedPhone.md +0 -4
  50. package/src/lightning/formattedText/__docs__/formattedText.md +0 -4
  51. package/src/lightning/formattedTime/__docs__/formattedTime.md +0 -4
  52. package/src/lightning/formattedUrl/__docs__/formattedUrl.md +0 -4
  53. package/src/lightning/groupedCombobox/form-element.slds.css +4 -1
  54. package/src/lightning/helptext/form-element.slds.css +4 -1
  55. package/src/lightning/icon/__docs__/icon.md +0 -4
  56. package/src/lightning/input/form-element.slds.css +4 -1
  57. package/src/lightning/inputAddress/form-element.slds.css +4 -1
  58. package/src/lightning/inputAddress/inputAddress.js +13 -7
  59. package/src/lightning/inputLocation/__docs__/inputLocation.md +0 -4
  60. package/src/lightning/inputLocation/form-element.slds.css +4 -1
  61. package/src/lightning/inputName/form-element.slds.css +4 -1
  62. package/src/lightning/layout/__docs__/layout.md +0 -4
  63. package/src/lightning/layoutItem/__docs__/layoutItem.md +0 -4
  64. package/src/lightning/lookupAddress/form-element.slds.css +4 -1
  65. package/src/lightning/menuItem/__docs__/menuItem.md +0 -4
  66. package/src/lightning/menuSubheader/menu-subheader.slds.css +1 -1
  67. package/src/lightning/modalBase/modalBase.js +14 -31
  68. package/src/lightning/pill/__docs__/pill.md +0 -4
  69. package/src/lightning/pillContainer/__docs__/pillContainer.md +0 -4
  70. package/src/lightning/primitiveBubble/primitiveBubble.js +26 -11
  71. package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +1 -1
  72. package/src/lightning/primitiveInputCheckbox/form-element.slds.css +4 -1
  73. package/src/lightning/primitiveInputCheckboxButton/form-element.slds.css +4 -1
  74. package/src/lightning/primitiveInputColor/form-element.slds.css +4 -1
  75. package/src/lightning/primitiveInputFile/form-element.slds.css +4 -1
  76. package/src/lightning/primitiveInputSimple/form-element.slds.css +4 -1
  77. package/src/lightning/primitiveInputToggle/form-element.slds.css +4 -1
  78. package/src/lightning/progressBar/progress-bar.slds.css +1 -1
  79. package/src/lightning/radioGroup/__docs__/radioGroup.md +0 -4
  80. package/src/lightning/radioGroup/form-element.slds.css +4 -1
  81. package/src/lightning/relativeDateTime/__docs__/relativeDateTime.md +0 -4
  82. package/src/lightning/select/form-element.slds.css +4 -1
  83. package/src/lightning/slider/__docs__/slider.md +0 -4
  84. package/src/lightning/spinner/__docs__/spinner.md +0 -4
  85. package/src/lightning/tab/__docs__/tab.md +0 -4
  86. package/src/lightning/tabset/__docs__/tabset.md +0 -4
  87. package/src/lightning/textarea/__docs__/textarea.md +0 -4
  88. package/src/lightning/textarea/__examples__/various/various.html +18 -1
  89. package/src/lightning/textarea/form-element.slds.css +4 -1
  90. package/src/lightning/textarea/textarea.js +25 -0
  91. package/src/lightning/tile/__docs__/tile.md +0 -4
  92. package/src/lightning/timepicker/form-element.slds.css +4 -1
  93. package/src/lightning/tree/__docs__/tree.md +0 -4
  94. package/src/lightning/tree/tree.js +5 -1
  95. package/src/lightning/verticalNavigation/__docs__/verticalNavigation.md +0 -4
  96. package/src/lightning/verticalNavigationItem/__docs__/verticalNavigationItem.md +0 -4
  97. package/src/lightning/verticalNavigationItem/vertical-navigation-item.slds.css +1 -1
  98. package/src/lightning/verticalNavigationItemBadge/__docs__/verticalNavigationItemBadge.md +0 -4
  99. package/src/lightning/verticalNavigationItemBadge/badge.slds.css +1 -1
  100. package/src/lightning/verticalNavigationItemBadge/vertical-navigation-item.slds.css +1 -1
  101. package/src/lightning/verticalNavigationItemIcon/__docs__/verticalNavigationItemIcon.md +0 -4
  102. package/src/lightning/verticalNavigationItemIcon/vertical-navigation-item.slds.css +1 -1
  103. package/src/lightning/verticalNavigationOverflow/vertical-navigation-item.slds.css +1 -1
  104. package/src/lightning/datatable/columns-shared.js +0 -12
@@ -1,12 +1,7 @@
1
1
  import { getShadowActiveElements, isRTL } from 'lightning/utilsPrivate';
2
2
  import { getCellFromIndexes, HEADER_ROW_KEY, getRowByKey } from './indexes';
3
- import {
4
- hasTreeDataType,
5
- getStateTreeColumn,
6
- fireRowToggleEvent,
7
- } from './tree';
8
- import { generateColKeyValue, getStateColumnIndex } from './columns';
9
- import { isCellEditable } from './rows';
3
+ import { fireRowToggleEvent } from './tree';
4
+ import { getStateColumnIndex } from './columns';
10
5
  import { findFirstVisibleIndex } from './virtualization';
11
6
  import { getColDataSelector, getRowDataSelector, getScrollerY } from './utils';
12
7
 
@@ -211,10 +206,7 @@ function reactToArrowLeft(state, template, event) {
211
206
  // Update activeCell.
212
207
  state.activeCell = {
213
208
  rowKeyValue,
214
- colKeyValue: generateColKeyValue(
215
- state.columns[nextColIndex],
216
- nextColIndex
217
- ),
209
+ colKeyValue: state.columns[nextColIndex].colKeyValue,
218
210
  };
219
211
  // Tracked state change.
220
212
  setFocusActiveCell(state, template, NAVIGATION_DIR.LEFT);
@@ -233,10 +225,7 @@ function reactToArrowRight(state, template, event) {
233
225
  // Update activeCell.
234
226
  state.activeCell = {
235
227
  rowKeyValue,
236
- colKeyValue: generateColKeyValue(
237
- state.columns[nextColIndex],
238
- nextColIndex
239
- ),
228
+ colKeyValue: state.columns[nextColIndex].colKeyValue,
240
229
  };
241
230
  setFocusActiveCell(state, template, NAVIGATION_DIR.RIGHT);
242
231
  }
@@ -375,10 +364,7 @@ export function reactToTabForward(state, template) {
375
364
  state.activeCell = {
376
365
  rowKeyValue:
377
366
  nextRowIndex === -1 ? HEADER_ROW_KEY : state.rows[nextRowIndex].key,
378
- colKeyValue: generateColKeyValue(
379
- state.columns[nextColIndex],
380
- nextColIndex
381
- ),
367
+ colKeyValue: state.columns[nextColIndex].colKeyValue,
382
368
  };
383
369
  // Tracked state change.
384
370
  setFocusActiveCell(state, template, NAVIGATION_DIR.TAB_FORWARD, {
@@ -395,10 +381,7 @@ export function reactToTabBackward(state, template) {
395
381
  state.activeCell = {
396
382
  rowKeyValue:
397
383
  nextRowIndex === -1 ? HEADER_ROW_KEY : state.rows[nextRowIndex].key,
398
- colKeyValue: generateColKeyValue(
399
- state.columns[nextColIndex],
400
- nextColIndex
401
- ),
384
+ colKeyValue: state.columns[nextColIndex].colKeyValue,
402
385
  };
403
386
  // Tracked state change.
404
387
  setFocusActiveCell(state, template, NAVIGATION_DIR.TAB_BACKWARD, {
@@ -505,7 +488,7 @@ function reactToArrowLeftOnRow(dt, state, template, event) {
505
488
  if (rowHasChildren && rowExpanded) {
506
489
  fireRowToggleEvent(dt, rowKeyValue, rowExpanded);
507
490
  } else if (rowLevel > 1) {
508
- const treeColumn = getStateTreeColumn(state);
491
+ const { treeColumn } = state;
509
492
  if (treeColumn) {
510
493
  const { colKeyValue } = treeColumn;
511
494
  const { rowIndex } = getIndexesByKeys(
@@ -552,7 +535,7 @@ function reactToArrowRightOnRow(dt, state, template, event) {
552
535
  function reactToArrowUpOnRow(state, template, event) {
553
536
  // Move tabIndex 0 one row down.
554
537
  const { rowKeyValue, keyEvent } = event.detail;
555
- const treeColumn = getStateTreeColumn(state);
538
+ const { treeColumn } = state;
556
539
 
557
540
  keyEvent.stopPropagation();
558
541
  keyEvent.preventDefault();
@@ -579,7 +562,7 @@ function reactToArrowUpOnRow(state, template, event) {
579
562
  function reactToArrowDownOnRow(state, template, event) {
580
563
  // Move tabIndex 0 one row down.
581
564
  const { rowKeyValue, keyEvent } = event.detail;
582
- const treeColumn = getStateTreeColumn(state);
565
+ const { treeColumn } = state;
583
566
 
584
567
  keyEvent.stopPropagation();
585
568
  keyEvent.preventDefault();
@@ -624,7 +607,7 @@ function getDefaultActiveCell(state) {
624
607
  const { rows } = state;
625
608
  return {
626
609
  rowKeyValue: rows.length > 0 ? rows[0].key : HEADER_ROW_KEY,
627
- colKeyValue: generateColKeyValue(columns[colIndex], colIndex),
610
+ colKeyValue: columns[colIndex].colKeyValue,
628
611
  };
629
612
  }
630
613
 
@@ -822,7 +805,7 @@ export function setFocusActiveCell(
822
805
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
823
806
  let cellElement = getActiveCellElement(template, state);
824
807
 
825
- state.activeCell.focused = !(info && isActiveCellValid(state));
808
+ state.activeCell.hasFocus = !(info && isActiveCellValid(state));
826
809
 
827
810
  updateCellTabIndex(state, rowIndex, colIndex);
828
811
 
@@ -874,7 +857,7 @@ export function setFocusActiveCell(
874
857
  export function setBlurActiveCell(state, template) {
875
858
  if (state.activeCell) {
876
859
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
877
- state.activeCell.focused = false;
860
+ state.activeCell.hasFocus = false;
878
861
  let cellElement = getActiveCellElement(template, state);
879
862
  // eslint-disable-next-line @lwc/lwc/no-async-operation
880
863
  setTimeout(() => {
@@ -957,7 +940,7 @@ export function updateCellToFocusFromPrev(state) {
957
940
  * @param {Node} template - The custom element template `this.template`
958
941
  */
959
942
  export function addFocusStylesToActiveCell(state, template) {
960
- state.activeCell.focused = true;
943
+ state.activeCell.hasFocus = true;
961
944
  const cellElement = getActiveCellElement(template, state);
962
945
  if (cellElement) {
963
946
  cellElement.parentElement.classList.add(FOCUS_CLASS);
@@ -1053,7 +1036,7 @@ export function handleDatatableFocusIn(event) {
1053
1036
  // workaround for delegatesFocus issue that focusin is called when not supposed to W-6220418
1054
1037
  if (isFocusInside(event.currentTarget)) {
1055
1038
  if (state.activeCell && !state.rowMode) {
1056
- state.activeCell.focused = true;
1039
+ state.activeCell.hasFocus = true;
1057
1040
  const cellElement = getActiveCellElement(this.template, state);
1058
1041
  // we need to check because of the tree,
1059
1042
  // at this point it may remove/change the rows/keys because opening or closing a row.
@@ -1243,10 +1226,7 @@ function getNextIndexDownWrapped(state, rowIndex) {
1243
1226
  /***************************** ROW NAVIGATION MODE *****************************/
1244
1227
 
1245
1228
  function canBeRowNavigationMode(state) {
1246
- return (
1247
- state.keyboardMode === KEYBOARD_NAVIGATION_MODE &&
1248
- hasTreeDataType(state)
1249
- );
1229
+ return state.keyboardMode === KEYBOARD_NAVIGATION_MODE && state.treeColumn;
1250
1230
  }
1251
1231
 
1252
1232
  function isRowNavigationMode(state) {
@@ -1257,10 +1237,7 @@ function isRowNavigationMode(state) {
1257
1237
  }
1258
1238
 
1259
1239
  function setRowNavigationMode(state) {
1260
- if (
1261
- hasTreeDataType(state) &&
1262
- state.keyboardMode === KEYBOARD_NAVIGATION_MODE
1263
- ) {
1240
+ if (state.treeColumn && state.keyboardMode === KEYBOARD_NAVIGATION_MODE) {
1264
1241
  state.rowMode = true;
1265
1242
  }
1266
1243
  }
@@ -1276,13 +1253,12 @@ export function unsetRowNavigationMode(state) {
1276
1253
  * Earlier it didn't have tree data, set rowMode to true to start
1277
1254
  * if rowMode is false and earlier it has tree data, keep it false
1278
1255
  * if rowMode is true and it has tree data, keep it true
1279
- * @param {Boolean} hadTreeDataTypePreviously - state object
1280
1256
  * @param {Object} state - The state object
1281
1257
  */
1282
- export function updateRowNavigationMode(hadTreeDataTypePreviously, state) {
1283
- if (!hasTreeDataType(state)) {
1258
+ export function updateRowNavigationMode(state) {
1259
+ if (!state.treeColumn) {
1284
1260
  state.rowMode = false;
1285
- } else if (state.rowMode === false && !hadTreeDataTypePreviously) {
1261
+ } else if (state.rowMode === false && !state.hadTreeDataTypePreviously) {
1286
1262
  state.rowMode = true;
1287
1263
  }
1288
1264
  }
@@ -1360,7 +1336,8 @@ function scrollToCell(state, template, rowIndex) {
1360
1336
  export function isActiveCellEditable(state) {
1361
1337
  if (state.activeCell) {
1362
1338
  const { rowIndex, colIndex } = getIndexesActiveCell(state);
1363
- return isCellEditable(state.rows[rowIndex], state.columns[colIndex]);
1339
+ const activeCell = state.rows[rowIndex].cells[colIndex];
1340
+ return activeCell ? activeCell.editable : false;
1364
1341
  }
1365
1342
  return false;
1366
1343
  }
@@ -13,10 +13,6 @@ export function setViewportRendering(state, value) {
13
13
  state.enableViewportRendering = normalizeBoolean(value);
14
14
  }
15
15
 
16
- export function isViewportRenderingEnabled(state) {
17
- return state.enableViewportRendering;
18
- }
19
-
20
16
  export function setVirtualize(state, value) {
21
17
  if (state.renderModeRoleBased) {
22
18
  state.virtualize = normalizeString(value, {
@@ -68,16 +64,11 @@ export class RenderManager {
68
64
  * @param {RenderManagerConfig} config - The render management config
69
65
  */
70
66
  configure(state, getWrapperHeight, config) {
71
- const {
72
- viewportRendering,
73
- rowHeight,
74
- virtualize,
75
- bufferSize,
76
- fixedHeight,
77
- } = config;
78
- setVirtualize(state, virtualize);
79
-
80
- if (normalizeBoolean(viewportRendering) || state.virtualize) {
67
+ const { rowHeight, bufferSize } = config;
68
+ // Untracked state changes.
69
+ setVirtualize(state, config.virtualize);
70
+ setViewportRendering(state, config.viewportRendering);
71
+ if (state.virtualize || state.enableViewportRendering) {
81
72
  this.initializeResizeObserver(state, getWrapperHeight);
82
73
  }
83
74
  let computedBufferSize =
@@ -88,10 +79,10 @@ export class RenderManager {
88
79
  'non-negative',
89
80
  DEFAULT_BUFFER_SIZE
90
81
  );
91
- state.fixedHeight = normalizeBoolean(fixedHeight);
82
+ state.fixedHeight = normalizeBoolean(config.fixedHeight);
92
83
  if (typeof rowHeight === 'number') {
93
84
  state.rowHeight = rowHeight;
94
- this.threshold = ROW_THRESHOLD * state.rowHeight;
85
+ this.threshold = ROW_THRESHOLD * rowHeight;
95
86
  }
96
87
  }
97
88
 
@@ -212,7 +203,7 @@ export class RenderManager {
212
203
  const normalizedRowCount = rowCount
213
204
  ? Math.min(rowCount, totalRows)
214
205
  : totalRows;
215
- if (isViewportRenderingEnabled(state)) {
206
+ if (state.enableViewportRendering) {
216
207
  if (state.renderedRowCount < normalizedRowCount) {
217
208
  state.renderedRowCount = normalizedRowCount;
218
209
  // Update our internal cache
@@ -247,7 +238,7 @@ export class RenderManager {
247
238
  * when the datatable component's height changes
248
239
  *
249
240
  * @param {Object} state - datatable state
250
- * @param {Function} getWrapperHeight - function to get height of datatable wrapper
241
+ * @param {Function} getWrapperHeight - A function to get the height of datatable wrapper
251
242
  */
252
243
  initializeResizeObserver(state, getWrapperHeight) {
253
244
  if (!this._heightResizeObserver) {
@@ -9,7 +9,6 @@ import {
9
9
  getTypeAttributesValues,
10
10
  getSubTypeAttributesValues,
11
11
  getCellAttributesValues,
12
- generateColKeyValue,
13
12
  } from './columns';
14
13
  import { getRowNumberError } from './rowNumber';
15
14
 
@@ -19,6 +18,16 @@ const IS_EDITED_CLASS = 'slds-is-edited';
19
18
  const ROLE_BASED_CELL_CLASS = 'cell';
20
19
  const TREE__ITEM_CLASS = 'slds-tree__item';
21
20
 
21
+ function resolveAttributeValue(attrValue, rowData) {
22
+ if (isObjectLike(attrValue)) {
23
+ const { fieldName } = attrValue;
24
+ if (fieldName) {
25
+ return rowData[fieldName];
26
+ }
27
+ }
28
+ return attrValue;
29
+ }
30
+
22
31
  export function setKeyField(state, value) {
23
32
  if (typeof value === 'string') {
24
33
  state.keyField = value;
@@ -32,8 +41,7 @@ export function setKeyField(state, value) {
32
41
  }
33
42
 
34
43
  /**
35
- * It compute the state.rows collection based on the current normalized (data, columns)
36
- * and generate cells indexes map(state.indexes)
44
+ * Compute state.rows and state.indexes based on the current normalized (data, columns).
37
45
  *
38
46
  * TODO: Reduce redundant calls to this function. This is indirectly called by the
39
47
  * setters of 'data' and 'columns'. Additionally, for the role-based table, if we are
@@ -43,18 +51,11 @@ export function setKeyField(state, value) {
43
51
  * @param {Object} state - The datatable state
44
52
  * @param {Object} types - The type handling factory
45
53
  */
46
- export function updateRowsAndCellIndexes(state, types) {
47
- const {
48
- columns,
49
- data,
50
- keyField,
51
- maxRowSelection,
52
- renderModeRoleBased,
53
- virtualize,
54
- rowHeight,
55
- } = state;
54
+ export function updateRowsAndCells(state, types) {
55
+ const { columns, data, keyField, maxRowSelection, virtualize, rowHeight } =
56
+ state;
57
+ const { privateCustomTypes } = types;
56
58
  const { length: rowCount } = data;
57
- const { dirtyValues } = state.inlineEdit;
58
59
  const { length: colCount } = columns;
59
60
  const currentSelectionLength =
60
61
  maxRowSelection === 1 ? 1 : getCurrentSelectionLength(state);
@@ -76,7 +77,6 @@ export function updateRowsAndCellIndexes(state, types) {
76
77
  // initializing indexes
77
78
  state.indexes = {};
78
79
 
79
- const { rows: errorsRows } = state.errors;
80
80
  const rows = Array(rowCount);
81
81
  // Tracked state changes.
82
82
  state.rows = rows;
@@ -87,37 +87,36 @@ export function updateRowsAndCellIndexes(state, types) {
87
87
  const rowKeyValue = rowDataKeyField
88
88
  ? `${rowDataKeyField}`
89
89
  : `row-${rowIndex}`;
90
- const dirtyRowData = dirtyValues[rowKeyValue];
91
- const rowErrors = errorsRows && errorsRows[rowKeyValue];
92
- const cellErrors = rowErrors && rowErrors.cells;
93
- const errorFieldNames = rowErrors && rowErrors.fieldNames;
94
90
 
95
91
  state.indexes[rowKeyValue] = { rowIndex };
96
92
 
97
93
  const isRowSelected = !!state.selectedRowsKeys[rowKeyValue];
98
94
  const rowNumber = rowIndex + 1;
95
+ const scopeColValue = scopeCol
96
+ ? rowData[scopeCol.fieldName]
97
+ : undefined;
99
98
  const cells = Array(colCount);
100
99
 
101
100
  const row = {
102
- key: rowKeyValue,
103
- cells,
104
- rowIndex,
105
- rowNumber, // for UTAM since methods are base-1
106
101
  ariaRowIndex: rowIndex + 2, // aria attrs are base-1 and also count header as a row
102
+ ariaSelected: isRowSelected ? 'true' : false,
103
+ cells,
104
+ classnames: `slds-hint-parent${
105
+ isRowSelected ? ' slds-is-selected' : ''
106
+ }`,
107
107
  inputType,
108
108
  isSelected: isRowSelected,
109
- ariaSelected: isRowSelected ? 'true' : false,
110
109
  isDisabled:
111
110
  !isRowSelected &&
112
111
  maxRowSelection !== 1 &&
113
112
  currentSelectionLength === maxRowSelection,
114
- classnames: `slds-hint-parent${
115
- isRowSelected ? ' slds-is-selected' : ''
116
- }`,
117
- tabIndex: -1,
113
+ key: rowKeyValue,
114
+ rowIndex,
115
+ rowNumber, // for UTAM since methods are base-1
118
116
  style: virtualize
119
117
  ? `position:absolute;top:${rowIndex * rowHeight}px;`
120
118
  : '',
119
+ tabIndex: -1,
121
120
  level: undefined,
122
121
  posInSet: undefined,
123
122
  setSize: undefined,
@@ -152,29 +151,27 @@ export function updateRowsAndCellIndexes(state, types) {
152
151
  for (let colIndex = 0; colIndex < colCount; colIndex += 1) {
153
152
  const col = columns[colIndex];
154
153
  const {
155
- columnKey,
156
- fieldName,
154
+ colKeyValue,
157
155
  isScopeCol,
158
156
  label: dataLabel,
159
157
  type: columnType,
160
158
  typeAttributes,
161
159
  } = col;
162
- const colKeyValue = generateColKeyValue(col, colIndex);
163
160
  const columnSubType = typeAttributes
164
161
  ? typeAttributes.subType
165
162
  : undefined;
166
- const dirtyValue = dirtyRowData && dirtyRowData[colKeyValue];
167
- const hasError = columnKey
168
- ? !!(cellErrors && cellErrors[columnKey])
169
- : !!(errorFieldNames && errorFieldNames.includes(fieldName));
170
163
  const hasTreeData = columnType === 'tree';
171
- // value based on the fieldName
172
- const value =
173
- dirtyValue === undefined ? rowData[fieldName] : dirtyValue;
164
+ const privateType =
165
+ privateCustomTypes && privateCustomTypes.get(columnType);
166
+ const standardCellLayout = privateType
167
+ ? privateType.standardCellLayout
168
+ : false;
174
169
  const displayReadOnlyIcon = !!col.displayReadOnlyIcon;
175
- const editable = isCellEditable(rowData, col);
170
+ const editable = !!resolveAttributeValue(col.editable, rowData);
176
171
  const isValidType = types.isValidType(columnType);
177
172
  const isCheckbox = columnType === SELECTABLE_HEADER_TYPE;
173
+ const isCustom = privateType !== undefined;
174
+ const isCustomBareLayout = isCustom && !standardCellLayout;
178
175
  const isDataType = isValidType && !isScopeCol;
179
176
  const isDataTypeScope = isValidType && isScopeCol;
180
177
 
@@ -186,31 +183,23 @@ export function updateRowsAndCellIndexes(state, types) {
186
183
  columnSubType,
187
184
  columnType,
188
185
  dataLabel,
189
- describedBy: dirtyValue ? 'unsaved-cell-notification' : null,
190
186
  displayReadOnlyIcon,
191
187
  displayValue: rowData.displayValue || '',
192
188
  editable,
193
- hasError,
189
+ hasError: undefined,
194
190
  isCheckbox,
191
+ isCustomBareLayout,
195
192
  isDataType,
196
193
  isDataTypeScope,
197
- rowKeyValue: row.key, // unique row key value
198
- style: computeCellStyles(types, col, renderModeRoleBased),
194
+ rowKeyValue, // unique row key value
195
+ scopeColValue,
196
+ style: '',
199
197
  tabIndex: -1,
200
- value,
201
- wrapText: state.wrapText[colKeyValue], // wrapText state
202
- wrapTextMaxLines: state.wrapText[colKeyValue]
203
- ? state.wrapTextMaxLines
204
- : undefined,
198
+ value: undefined,
199
+ wrapText: undefined, // wrapText state
200
+ wrapTextMaxLines: 0,
205
201
  };
206
202
 
207
- cell.class = computeCellClassNames(
208
- cell,
209
- hasTreeData,
210
- dirtyValue,
211
- renderModeRoleBased
212
- );
213
-
214
203
  if (!col.internal) {
215
204
  // Assign cell type or cell subType attributes.
216
205
  let attributeNames;
@@ -260,40 +249,79 @@ export function updateRowsAndCellIndexes(state, types) {
260
249
  cell.typeAttribute22 = row.isExpanded === 'true';
261
250
  }
262
251
  }
263
- // Populate row number attributes.
264
- else if (columnType === 'rowNumber') {
265
- const scopeColValue = rowData[scopeCol.fieldName];
266
- // computes and sets the resolved typeAttribute for the row
267
- // number column error state
268
- cell.typeAttribute0 = getRowNumberError(
269
- rowErrors,
270
- scopeColValue
271
- );
272
- }
273
252
 
274
253
  // adding cell indexes to state.indexes
275
254
  // Keeping the hash for backward compatibility, but we need to have 2 indexes, 1 for columns and one for rows,
276
255
  // because of memory usage and also at certain point we might have the data but not the columns
277
256
  state.indexes[row.key][colKeyValue] = [rowIndex, colIndex];
278
257
  cells[colIndex] = cell;
258
+
259
+ // Update cell properties including class, style, and value properties.
260
+ updateCell(state, rowIndex, colIndex);
279
261
  }
280
262
  }
281
263
  }
282
264
 
283
265
  /**
284
- * Returns true in the following three cases:
266
+ * Performs a smaller update on the cell at the given rowIndex and colIndex.
267
+ * Used by updateCells() and updateCellsByColIndex().
285
268
  *
286
- * (1) typeof column.editable !== 'object' && column.editable
287
- * (2) typeof column.editable === 'object' && !column.editable.fieldName
288
- * (3) typeof column.editable === 'object' && column.editable.fieldName && row[column.editable.fieldName]
289
- *
290
- * Returns false in all other cases.
291
- *
292
- * @param {object} rowData - a row data object stored in datatable state. Must be truthy.
293
- * @param {object} col - a column data object stored in datatable state. Must be truthy.
269
+ * @param {Object} state - The tracked datatable state
270
+ * @param {Object} rowIndex - The cell row index
271
+ * @param {Object} colIndex - The cell column index
272
+ * @param {Object} [_state = state] - The untracked datatable state
294
273
  */
295
- export function isCellEditable(rowData, col) {
296
- return !!resolveAttributeValue(col.editable, rowData);
274
+ export function updateCell(state, rowIndex, colIndex) {
275
+ const { renderModeRoleBased } = state;
276
+ const { rows: errorsRows } = state.errors;
277
+ const row = state.rows[rowIndex];
278
+ const rowData = state.data[rowIndex];
279
+ const { key: rowKeyValue } = row;
280
+ const dirtyRowData = state.inlineEdit.dirtyValues[rowKeyValue];
281
+ const rowErrors = errorsRows && errorsRows[rowKeyValue];
282
+ const cellErrors = rowErrors && rowErrors.cells;
283
+ const errorFieldNames = rowErrors && rowErrors.fieldNames;
284
+ const col = state.columns[colIndex];
285
+ const cell = row.cells[colIndex];
286
+ const { colKeyValue, columnKey, fieldName, type: columnType } = col;
287
+ const dirtyValue = dirtyRowData && dirtyRowData[colKeyValue];
288
+ const hasError = columnKey
289
+ ? !!(cellErrors && cellErrors[columnKey])
290
+ : !!(errorFieldNames && errorFieldNames.includes(fieldName));
291
+ const hasTreeData = columnType === 'tree';
292
+ // value based on the fieldName
293
+ const value = dirtyValue === undefined ? rowData[fieldName] : dirtyValue;
294
+ const wrapText = state.wrapText[colKeyValue];
295
+ const wrapTextMaxLines = wrapText ? state.wrapTextMaxLines : undefined;
296
+
297
+ cell.hasError = hasError;
298
+ cell.wrapText = wrapText;
299
+ cell.wrapTextMaxLines = wrapTextMaxLines;
300
+ cell.value = value;
301
+
302
+ if (col.internal && col.type === 'rowNumber') {
303
+ cell.typeAttribute0 = getRowNumberError(rowErrors, cell.scopeColValue);
304
+ }
305
+
306
+ let cellClass = '';
307
+ if (cell.displayReadOnlyIcon || cell.editable) {
308
+ cellClass += CELL_EDIT_CLASS;
309
+ }
310
+ if (hasTreeData) {
311
+ cellClass += (cellClass.length ? ' ' : '') + TREE__ITEM_CLASS;
312
+ }
313
+ if (hasError) {
314
+ cellClass += (cellClass.length ? ' ' : '') + HAS_ERROR_CLASS;
315
+ }
316
+ if (dirtyValue !== undefined) {
317
+ cellClass += (cellClass.length ? ' ' : '') + IS_EDITED_CLASS;
318
+ }
319
+ if (renderModeRoleBased) {
320
+ cellClass += (cellClass.length ? ' ' : '') + ROLE_BASED_CELL_CLASS;
321
+ }
322
+
323
+ cell.class = cellClass;
324
+ cell.style = computeCellStyles(cell, col, renderModeRoleBased);
297
325
  }
298
326
 
299
327
  /**
@@ -308,14 +336,9 @@ export function isCellEditable(rowData, col) {
308
336
  * @param {Boolean} renderModeRoleBased - render mode of datatable (div || table)
309
337
  * @returns {String} - styles to be set on the cell
310
338
  */
311
- function computeCellStyles(types, col, renderModeRoleBased) {
312
- const columnType = col.type;
313
-
339
+ function computeCellStyles(cell, col, renderModeRoleBased) {
314
340
  let cellStyle = '';
315
- if (
316
- types.isCustomType(columnType) &&
317
- !types.isStandardCellLayoutForCustomType(columnType)
318
- ) {
341
+ if (cell.isCustomBareLayout) {
319
342
  // When a custom type is not using the standard layout,
320
343
  // remove the padding that comes with the standard layout
321
344
  cellStyle = 'padding: 0;';
@@ -332,45 +355,6 @@ function computeCellStyles(types, col, renderModeRoleBased) {
332
355
  return cellStyle;
333
356
  }
334
357
 
335
- function computeCellClassNames(
336
- cell,
337
- hasTreeData,
338
- dirtyValue,
339
- renderModeRoleBased
340
- ) {
341
- // TODO: With the current SLDS design, the 'slds-cell-edit' class is required on a cell in cases
342
- // where the read only icon is to be displayed. This is an issue with their design that will need to
343
- // be addressed on their end, so once they do that we can modify this code accordingly.
344
- let cellClass = '';
345
- if (cell.displayReadOnlyIcon || cell.editable) {
346
- cellClass += CELL_EDIT_CLASS;
347
- }
348
- if (hasTreeData) {
349
- cellClass += (cellClass.length ? ' ' : '') + TREE__ITEM_CLASS;
350
- }
351
- if (cell.hasError) {
352
- cellClass += (cellClass.length ? ' ' : '') + HAS_ERROR_CLASS;
353
- }
354
- if (dirtyValue !== undefined) {
355
- cellClass += (cellClass.length ? ' ' : '') + IS_EDITED_CLASS;
356
- }
357
- if (renderModeRoleBased) {
358
- cellClass += (cellClass.length ? ' ' : '') + ROLE_BASED_CELL_CLASS;
359
- }
360
- return cellClass;
361
- }
362
-
363
- function resolveAttributeValue(attrValue, rowData) {
364
- if (isObjectLike(attrValue)) {
365
- const { fieldName } = attrValue;
366
- if (fieldName) {
367
- return rowData[fieldName];
368
- }
369
- }
370
-
371
- return attrValue;
372
- }
373
-
374
358
  /**
375
359
  * For the role-based table, we need to manage the width of each cell separately.
376
360
  * Re-compute the cell styles so that the width of the cell is set
@@ -378,27 +362,27 @@ function resolveAttributeValue(attrValue, rowData) {
378
362
  *
379
363
  * @param {Object} state - Datatable's state object
380
364
  */
381
- export function recomputeCellStyles(types, state) {
365
+ export function recomputeCellStyles(state) {
382
366
  const { columns } = state;
383
367
  state.rows.forEach((row) => {
384
368
  row.cells.forEach((cell, colIndex) => {
385
369
  const colData = columns[colIndex];
386
- cell.style = computeCellStyles(types, colData, true);
370
+ cell.style = computeCellStyles(cell, colData, true);
387
371
  });
388
372
  });
389
373
  }
390
374
 
391
375
  /**
392
- * The cells' classes are normally updated via `updateRowsAndCellIndexes()`. This ideally
393
- * happens after renderMode is set since `updateRowsAndCellIndexes` requires the final
376
+ * The cells' classes are normally updated via `updateRowsAndCells()`. This ideally
377
+ * happens after renderMode is set since `updateRowsAndCells` requires the final
394
378
  * renderMode value in order to set the 'cell' class on each cell.
395
379
  *
396
- * However, in some cases, it's possible that updateRowsAndCellIndexes is called
380
+ * However, in some cases, it's possible that updateRowsAndCells is called
397
381
  * before the renderMode is set (to 'role-based'). This will cause the 'cell' class to NOT be set
398
382
  * in the individual cells because state.renderModeRoleBased will be `false` at that point.
399
383
  * As a result, positioning of the cell content will be off.
400
384
  *
401
- * In such a case where the renderMode is 'role-based' and when the updateRowsAndCellIndexes
385
+ * In such a case where the renderMode is 'role-based' and when the updateRowsAndCells
402
386
  * has already been called (indicated by the presence of 'state.rows'), retroactively
403
387
  * add the 'cell' class to each cell.
404
388
  *