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.
- package/metadata/raptor.json +1 -0
- package/package.json +1 -1
- package/src/lightning/badge/badge.slds.css +1 -1
- package/src/lightning/combobox/form-element.slds.css +4 -1
- package/src/lightning/datatable/columns.js +17 -18
- package/src/lightning/datatable/datatable.js +143 -80
- package/src/lightning/datatable/indexes.js +1 -3
- package/src/lightning/datatable/infiniteLoading.js +1 -1
- package/src/lightning/datatable/inlineEdit.js +9 -7
- package/src/lightning/datatable/keyboard.js +21 -44
- package/src/lightning/datatable/renderManager.js +9 -18
- package/src/lightning/datatable/rows.js +112 -128
- package/src/lightning/datatable/sort.js +35 -14
- package/src/lightning/datatable/state.js +5 -0
- package/src/lightning/datatable/tree.js +0 -33
- package/src/lightning/datatable/utils.js +11 -0
- package/src/lightning/datepicker/datepicker.js +12 -3
- package/src/lightning/datepicker/form-element.slds.css +4 -1
- package/src/lightning/datetimepicker/form-element.slds.css +4 -1
- package/src/lightning/dualListbox/form-element.slds.css +4 -1
- package/src/lightning/groupedCombobox/form-element.slds.css +4 -1
- package/src/lightning/helptext/form-element.slds.css +4 -1
- package/src/lightning/input/form-element.slds.css +4 -1
- package/src/lightning/inputAddress/form-element.slds.css +4 -1
- package/src/lightning/inputLocation/form-element.slds.css +4 -1
- package/src/lightning/inputName/form-element.slds.css +4 -1
- package/src/lightning/lookupAddress/form-element.slds.css +4 -1
- package/src/lightning/modalBase/modalBase.js +12 -29
- package/src/lightning/primitiveBubble/primitiveBubble.js +26 -11
- package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +1 -1
- package/src/lightning/primitiveInputCheckbox/form-element.slds.css +4 -1
- package/src/lightning/primitiveInputCheckboxButton/form-element.slds.css +4 -1
- package/src/lightning/primitiveInputColor/form-element.slds.css +4 -1
- package/src/lightning/primitiveInputFile/form-element.slds.css +4 -1
- package/src/lightning/primitiveInputSimple/form-element.slds.css +4 -1
- package/src/lightning/primitiveInputToggle/form-element.slds.css +4 -1
- package/src/lightning/progressBar/progress-bar.slds.css +1 -1
- package/src/lightning/radioGroup/form-element.slds.css +4 -1
- package/src/lightning/select/form-element.slds.css +4 -1
- package/src/lightning/textarea/__examples__/various/various.html +18 -1
- package/src/lightning/textarea/form-element.slds.css +4 -1
- package/src/lightning/textarea/textarea.js +25 -0
- package/src/lightning/timepicker/form-element.slds.css +4 -1
- package/src/lightning/verticalNavigationItem/vertical-navigation-item.slds.css +1 -1
- package/src/lightning/verticalNavigationItemBadge/badge.slds.css +1 -1
- package/src/lightning/verticalNavigationItemBadge/vertical-navigation-item.slds.css +1 -1
- package/src/lightning/verticalNavigationItemIcon/vertical-navigation-item.slds.css +1 -1
- package/src/lightning/verticalNavigationOverflow/vertical-navigation-item.slds.css +1 -1
- 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
|
-
*
|
|
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
|
|
47
|
-
const {
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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 =
|
|
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
|
|
198
|
-
|
|
194
|
+
rowKeyValue, // unique row key value
|
|
195
|
+
scopeColValue,
|
|
196
|
+
style: '',
|
|
199
197
|
tabIndex: -1,
|
|
200
|
-
value,
|
|
201
|
-
wrapText:
|
|
202
|
-
wrapTextMaxLines:
|
|
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
|
-
*
|
|
266
|
+
* Performs a smaller update on the cell at the given rowIndex and colIndex.
|
|
267
|
+
* Used by updateCells() and updateCellsByColIndex().
|
|
285
268
|
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
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
|
|
296
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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 `
|
|
393
|
-
* happens after renderMode is set since `
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|