lightning-base-components 1.21.5-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 (49) hide show
  1. package/metadata/raptor.json +1 -0
  2. package/package.json +1 -1
  3. package/src/lightning/badge/badge.slds.css +1 -1
  4. package/src/lightning/combobox/form-element.slds.css +4 -1
  5. package/src/lightning/datatable/columns.js +17 -18
  6. package/src/lightning/datatable/datatable.js +143 -80
  7. package/src/lightning/datatable/indexes.js +1 -3
  8. package/src/lightning/datatable/infiniteLoading.js +1 -1
  9. package/src/lightning/datatable/inlineEdit.js +9 -7
  10. package/src/lightning/datatable/keyboard.js +21 -44
  11. package/src/lightning/datatable/renderManager.js +9 -18
  12. package/src/lightning/datatable/rows.js +112 -128
  13. package/src/lightning/datatable/sort.js +35 -14
  14. package/src/lightning/datatable/state.js +5 -0
  15. package/src/lightning/datatable/tree.js +0 -33
  16. package/src/lightning/datatable/utils.js +11 -0
  17. package/src/lightning/datepicker/datepicker.js +12 -3
  18. package/src/lightning/datepicker/form-element.slds.css +4 -1
  19. package/src/lightning/datetimepicker/form-element.slds.css +4 -1
  20. package/src/lightning/dualListbox/form-element.slds.css +4 -1
  21. package/src/lightning/groupedCombobox/form-element.slds.css +4 -1
  22. package/src/lightning/helptext/form-element.slds.css +4 -1
  23. package/src/lightning/input/form-element.slds.css +4 -1
  24. package/src/lightning/inputAddress/form-element.slds.css +4 -1
  25. package/src/lightning/inputLocation/form-element.slds.css +4 -1
  26. package/src/lightning/inputName/form-element.slds.css +4 -1
  27. package/src/lightning/lookupAddress/form-element.slds.css +4 -1
  28. package/src/lightning/modalBase/modalBase.js +12 -29
  29. package/src/lightning/primitiveBubble/primitiveBubble.js +26 -11
  30. package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +1 -1
  31. package/src/lightning/primitiveInputCheckbox/form-element.slds.css +4 -1
  32. package/src/lightning/primitiveInputCheckboxButton/form-element.slds.css +4 -1
  33. package/src/lightning/primitiveInputColor/form-element.slds.css +4 -1
  34. package/src/lightning/primitiveInputFile/form-element.slds.css +4 -1
  35. package/src/lightning/primitiveInputSimple/form-element.slds.css +4 -1
  36. package/src/lightning/primitiveInputToggle/form-element.slds.css +4 -1
  37. package/src/lightning/progressBar/progress-bar.slds.css +1 -1
  38. package/src/lightning/radioGroup/form-element.slds.css +4 -1
  39. package/src/lightning/select/form-element.slds.css +4 -1
  40. package/src/lightning/textarea/__examples__/various/various.html +18 -1
  41. package/src/lightning/textarea/form-element.slds.css +4 -1
  42. package/src/lightning/textarea/textarea.js +25 -0
  43. package/src/lightning/timepicker/form-element.slds.css +4 -1
  44. package/src/lightning/verticalNavigationItem/vertical-navigation-item.slds.css +1 -1
  45. package/src/lightning/verticalNavigationItemBadge/badge.slds.css +1 -1
  46. package/src/lightning/verticalNavigationItemBadge/vertical-navigation-item.slds.css +1 -1
  47. package/src/lightning/verticalNavigationItemIcon/vertical-navigation-item.slds.css +1 -1
  48. package/src/lightning/verticalNavigationOverflow/vertical-navigation-item.slds.css +1 -1
  49. package/src/lightning/datatable/columns-shared.js +0 -12
@@ -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
  *
@@ -1,5 +1,4 @@
1
1
  import { assert } from 'lightning/utilsPrivate';
2
- import { getColumnName } from './columns-shared';
3
2
 
4
3
  /**
5
4
  * Sets the default sort direction. When clicking on a header to sort,
@@ -28,20 +27,29 @@ export function setDefaultSortDirection(state, value) {
28
27
  * `sortedDirection` will be `undefined`
29
28
  *
30
29
  * @param {Object} state The datatable state
31
- * @param {String} value The value to update the sort direction to
30
+ * @param {String|String[]} value The value or values to update the sort direction to
32
31
  */
33
32
  export function setSortedDirection(state, value) {
34
- if (value === 'asc' || value === 'desc') {
33
+ if (typeof value === 'string' && (value === 'asc' || value === 'desc')) {
35
34
  state.sortedDirection = value;
36
- return;
35
+ } else if (Array.isArray(value)) {
36
+ // If value is an array, validate each item
37
+ value.forEach((item) => {
38
+ assert(
39
+ item === 'asc' || item === 'desc',
40
+ `The "sortedDirection" value passed into lightning:datatable
41
+ is incorrect. All values should be one of 'asc' or 'desc'.`
42
+ );
43
+ });
44
+ state.sortedDirection = value;
45
+ } else {
46
+ assert(
47
+ false,
48
+ `The "sortedDirection" value passed into lightning:datatable
49
+ is incorrect. It should be either a single value of 'asc' or 'desc'
50
+ or an array of such values.`
51
+ );
37
52
  }
38
- assert(
39
- false,
40
- `The "sortedDirection" value passed into lightning:datatable
41
- is incorrect, "sortedDirection" value should be one of
42
- 'asc' or 'desc'.`
43
- );
44
- state.sortedDirection = undefined;
45
53
  }
46
54
 
47
55
  /**
@@ -51,10 +59,10 @@ export function setSortedDirection(state, value) {
51
59
  * to `undefined`
52
60
  *
53
61
  * @param {Object} state The datatable state
54
- * @param {String} value The value to update the sort state to
62
+ * @param {String|String[]} value The value or values to update the sort state to
55
63
  */
56
64
  export function setSortedBy(state, value) {
57
- if (typeof value === 'string') {
65
+ if (typeof value === 'string' || Array.isArray(value)) {
58
66
  state.sortedBy = value;
59
67
  } else {
60
68
  state.sortedBy = undefined;
@@ -68,13 +76,26 @@ export function setSortedBy(state, value) {
68
76
  */
69
77
  export function updateSorting(state) {
70
78
  const { columns, defaultSortDirection, sortedBy, sortedDirection } = state;
79
+
80
+ // Determine if sortedBy is an array
81
+ const isSortedByArray = Array.isArray(sortedBy);
82
+
71
83
  for (let i = 0, { length } = columns; i < length; i += 1) {
72
84
  const col = columns[i];
73
- if (col.sortable && getColumnName(col) === sortedBy) {
85
+ if (
86
+ col.sortable &&
87
+ (isSortedByArray
88
+ ? sortedBy.includes(col.name)
89
+ : sortedBy === col.name)
90
+ ) {
74
91
  col.sorted = true;
75
92
  col.sortAriaLabel =
76
93
  sortedDirection === 'desc' ? 'descending' : 'ascending';
77
94
  col.sortedDirection = sortedDirection;
95
+
96
+ // If sortedBy is an array, set col.sorted to the index in the array
97
+ // Otherwise, set it to true
98
+ col.sorted = isSortedByArray ? sortedBy.indexOf(col.name) : true;
78
99
  } else {
79
100
  col.sorted = false;
80
101
  col.sortAriaLabel = col.sortable ? 'other' : null;
@@ -10,7 +10,9 @@ export const getDefaultState = function () {
10
10
  return {
11
11
  // columns
12
12
  columns: [],
13
+ hadTreeDataTypePreviously: false,
13
14
  hideCheckboxColumn: false,
15
+ treeColumn: undefined,
14
16
 
15
17
  // rows
16
18
  data: [],
@@ -90,5 +92,8 @@ export const getDefaultState = function () {
90
92
  rows: {},
91
93
  table: {},
92
94
  },
95
+
96
+ // table rendered flag
97
+ hasRenderedFirstTime: false,
93
98
  };
94
99
  };
@@ -1,36 +1,3 @@
1
- /**
2
- * Determines if any of the columns in the datatable are of a tree-type.
3
- *
4
- * @param {Object} state The datatable state
5
- * @returns {Boolean} Whether any of the columns are of a tree-type
6
- */
7
- export function hasTreeDataType(state) {
8
- const { columns } = state;
9
- for (let i = 0, { length } = columns; i < length; i += 1) {
10
- if (columns[i].type === 'tree') {
11
- return true;
12
- }
13
- }
14
- return false;
15
- }
16
-
17
- /**
18
- * Retrieves the first tree-type column from the state.
19
- *
20
- * @param {Object} state The datatable state
21
- * @returns {Object} The first tree-type column, else `null`
22
- */
23
- export function getStateTreeColumn(state) {
24
- const { columns } = state;
25
- for (let i = 0, { length } = columns; i < length; i += 1) {
26
- const col = columns[i];
27
- if (col.type === 'tree') {
28
- return col;
29
- }
30
- }
31
- return null;
32
- }
33
-
34
1
  /**
35
2
  * Dispatches an event when a row is toggled to be expanded or collapsed.
36
3
  *
@@ -24,6 +24,7 @@ const CLASS_SET_PROTOTYPE = {
24
24
 
25
25
  const NON_NEGATIVE_INTEGER_REGEXP = /^\d+$/;
26
26
  const POSITIVE_INTEGER_REGEXP = /^[0-9]*[1-9][0-9]*$/;
27
+ const RENDER_MODE_ROLE_BASED_REGEXP = /\brole-based\b/;
27
28
 
28
29
  /**
29
30
  * Escapes double quotes. Later can be
@@ -130,6 +131,16 @@ export function isNonNegativeInteger(value) {
130
131
  return NON_NEGATIVE_INTEGER_REGEXP.test(value);
131
132
  }
132
133
 
134
+ /**
135
+ * Tests if render mode is role-based.
136
+ *
137
+ * @param {String} renderMode The render mode to test
138
+ * @returns {Boolean} Whether the render mode is role-based
139
+ */
140
+ export function isRenderModeRoleBased(renderMode) {
141
+ return RENDER_MODE_ROLE_BASED_REGEXP.test(renderMode);
142
+ }
143
+
133
144
  /**
134
145
  * Accepts a value which may be an Integer or String and tests that value
135
146
  * with respect to the numberType:
@@ -681,9 +681,14 @@ export default class LightningDatePicker extends LightningShadowBaseClass {
681
681
  hideCalendarAndFocusTrigger() {
682
682
  this.hideCalendar();
683
683
 
684
- if (this.calendarTrigger) {
685
- this.calendarTrigger.focus();
686
- }
684
+ if (this.calendarTrigger)
685
+ if (this.calendarTrigger === this.calendarButtonElement) {
686
+ // Fix for W-14258862, focus is transferred to the input element
687
+ // instead of the button element when trigger is button
688
+ this.inputElement.focus();
689
+ } else {
690
+ this.calendarTrigger.focus();
691
+ }
687
692
  }
688
693
 
689
694
  focusCalendar() {
@@ -752,6 +757,10 @@ export default class LightningDatePicker extends LightningShadowBaseClass {
752
757
  return this.template.querySelector('input');
753
758
  }
754
759
 
760
+ get calendarButtonElement() {
761
+ return this.template.querySelector('lightning-button-icon');
762
+ }
763
+
755
764
  dispatchChangeEvent() {
756
765
  this.dispatchEvent(
757
766
  new CustomEvent('change', {
@@ -187,7 +187,10 @@
187
187
  }
188
188
 
189
189
  :host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__label,:host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__control {
190
- border-bottom: 0; /* Remove border when using legacy version of slds-form-element */
190
+ /* @W-14518344 The following line still exists in SLDS-internal
191
+ but it was removed here because it was causing the input
192
+ component to not display it's bottom border
193
+ border-bottom: 0; Remove border when using legacy version of slds-form-element */
191
194
  padding-inline-start: 0;
192
195
  }
193
196
 
@@ -187,7 +187,10 @@
187
187
  }
188
188
 
189
189
  :host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__label,:host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__control {
190
- border-bottom: 0; /* Remove border when using legacy version of slds-form-element */
190
+ /* @W-14518344 The following line still exists in SLDS-internal
191
+ but it was removed here because it was causing the input
192
+ component to not display it's bottom border
193
+ border-bottom: 0; Remove border when using legacy version of slds-form-element */
191
194
  padding-inline-start: 0;
192
195
  }
193
196
 
@@ -187,7 +187,10 @@
187
187
  }
188
188
 
189
189
  :host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__label,:host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__control {
190
- border-bottom: 0; /* Remove border when using legacy version of slds-form-element */
190
+ /* @W-14518344 The following line still exists in SLDS-internal
191
+ but it was removed here because it was causing the input
192
+ component to not display it's bottom border
193
+ border-bottom: 0; Remove border when using legacy version of slds-form-element */
191
194
  padding-inline-start: 0;
192
195
  }
193
196
 
@@ -187,7 +187,10 @@
187
187
  }
188
188
 
189
189
  :host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__label,:host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__control {
190
- border-bottom: 0; /* Remove border when using legacy version of slds-form-element */
190
+ /* @W-14518344 The following line still exists in SLDS-internal
191
+ but it was removed here because it was causing the input
192
+ component to not display it's bottom border
193
+ border-bottom: 0; Remove border when using legacy version of slds-form-element */
191
194
  padding-inline-start: 0;
192
195
  }
193
196
 
@@ -187,7 +187,10 @@
187
187
  }
188
188
 
189
189
  :host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__label,:host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__control {
190
- border-bottom: 0; /* Remove border when using legacy version of slds-form-element */
190
+ /* @W-14518344 The following line still exists in SLDS-internal
191
+ but it was removed here because it was causing the input
192
+ component to not display it's bottom border
193
+ border-bottom: 0; Remove border when using legacy version of slds-form-element */
191
194
  padding-inline-start: 0;
192
195
  }
193
196
 
@@ -187,7 +187,10 @@
187
187
  }
188
188
 
189
189
  :host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__label,:host([data-render-mode="shadow"][variant='label-stacked']) .slds-form-element__control {
190
- border-bottom: 0; /* Remove border when using legacy version of slds-form-element */
190
+ /* @W-14518344 The following line still exists in SLDS-internal
191
+ but it was removed here because it was causing the input
192
+ component to not display it's bottom border
193
+ border-bottom: 0; Remove border when using legacy version of slds-form-element */
191
194
  padding-inline-start: 0;
192
195
  }
193
196