lightning-base-components 1.13.9-alpha → 1.14.3-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 (83) hide show
  1. package/metadata/raptor.json +1 -0
  2. package/package.json +21 -1
  3. package/scopedImports/@salesforce-internal-core.appVersion.js +1 -1
  4. package/scopedImports/@salesforce-label-LightningDualListbox.movedOptionsPlural.js +1 -0
  5. package/scopedImports/@salesforce-label-LightningDualListbox.movedOptionsSingular.js +1 -0
  6. package/scopedImports/@salesforce-label-LightningErrorMessage.validitySelectAtleastOne.js +1 -0
  7. package/scopedImports/@salesforce-label-LightningLookup.recentItems.js +1 -0
  8. package/scopedImports/@salesforce-label-LightningMap.titleWithAddress.js +1 -0
  9. package/src/lightning/ariaObserver/__component__/ariaObserver.spec.js +103 -0
  10. package/src/lightning/ariaObserver/__docs__/ariaObserver.md +142 -0
  11. package/src/lightning/{utilsPrivate/contentMutation.js → ariaObserver/ariaObserver.js} +51 -78
  12. package/src/lightning/baseCombobox/baseCombobox.html +1 -0
  13. package/src/lightning/baseCombobox/baseCombobox.js +14 -1
  14. package/src/lightning/buttonMenu/keyboard.js +0 -10
  15. package/src/lightning/card/card.html +6 -0
  16. package/src/lightning/checkboxGroup/checkboxGroup.html +2 -2
  17. package/src/lightning/checkboxGroup/checkboxGroup.js +6 -1
  18. package/src/lightning/colorPickerCustom/colorPickerCustom.js +20 -1
  19. package/src/lightning/combobox/combobox.css +12 -0
  20. package/src/lightning/combobox/combobox.html +1 -0
  21. package/src/lightning/datatable/__docs__/datatable.md +55 -0
  22. package/src/lightning/datatable/__examples__/basic/basic.html +1 -1
  23. package/src/lightning/datatable/columnWidthManager.js +7 -3
  24. package/src/lightning/datatable/columns-shared.js +1 -1
  25. package/src/lightning/datatable/datatable.js +122 -40
  26. package/src/lightning/datatable/errors.js +20 -9
  27. package/src/lightning/datatable/headerActions.js +77 -49
  28. package/src/lightning/datatable/inlineEdit.js +520 -373
  29. package/src/lightning/datatable/inlineEditShared.js +24 -0
  30. package/src/lightning/datatable/keyboard.js +1077 -933
  31. package/src/lightning/datatable/renderManager.js +241 -129
  32. package/src/lightning/datatable/resizer.js +91 -108
  33. package/src/lightning/datatable/rowLevelActions.js +17 -13
  34. package/src/lightning/datatable/rowNumber.js +54 -20
  35. package/src/lightning/datatable/rowSelection.js +760 -0
  36. package/src/lightning/datatable/rowSelectionShared.js +79 -0
  37. package/src/lightning/datatable/rows.js +16 -5
  38. package/src/lightning/datatable/state.js +10 -10
  39. package/src/lightning/datatable/templates/div/div.css +23 -0
  40. package/src/lightning/datatable/templates/div/div.html +6 -5
  41. package/src/lightning/datatable/templates/table/table.html +4 -4
  42. package/src/lightning/datatable/utils.js +14 -0
  43. package/src/lightning/datatable/widthManagerShared.js +1 -1
  44. package/src/lightning/dualListbox/dualListbox.html +1 -1
  45. package/src/lightning/dualListbox/dualListbox.js +42 -0
  46. package/src/lightning/iconSvgTemplates/buildTemplates/templates.js +2 -1
  47. package/src/lightning/iconSvgTemplates/buildTemplates/utility/contract_alt.html +1 -2
  48. package/src/lightning/iconSvgTemplates/buildTemplates/utility/contract_doc.html +8 -0
  49. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/templates.js +2 -1
  50. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/contract_alt.html +1 -2
  51. package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/contract_doc.html +8 -0
  52. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/templates.js +2 -1
  53. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/contract_alt.html +1 -2
  54. package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/contract_doc.html +8 -0
  55. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/templates.js +2 -1
  56. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/contract_alt.html +1 -2
  57. package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/contract_doc.html +8 -0
  58. package/src/lightning/input/input.html +0 -1
  59. package/src/lightning/input/input.js +69 -48
  60. package/src/lightning/inputUtils/validity.js +12 -1
  61. package/src/lightning/pillContainer/__docs__/pillContainer.md +45 -1
  62. package/src/lightning/primitiveCellActions/primitiveCellActions.js +69 -12
  63. package/src/lightning/primitiveCellFactory/cellWithStandardLayout.html +13 -11
  64. package/src/lightning/primitiveCellFactory/primitiveCellFactory.js +13 -8
  65. package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.html +17 -14
  66. package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.js +169 -80
  67. package/src/lightning/primitiveDatatableIeditTypeFactory/primitiveDatatableIeditTypeFactory.js +97 -62
  68. package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.html +4 -4
  69. package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.js +4 -4
  70. package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.js +99 -37
  71. package/src/lightning/primitiveHeaderFactory/nonsortableHeader.html +5 -4
  72. package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +46 -46
  73. package/src/lightning/primitiveHeaderFactory/selectableHeader.html +25 -23
  74. package/src/lightning/primitiveHeaderFactory/sortableHeader.html +13 -9
  75. package/src/lightning/progressIndicator/progressIndicator.js +4 -6
  76. package/src/lightning/progressStep/progressStep.js +31 -22
  77. package/src/lightning/staticMap/staticMap.html +1 -0
  78. package/src/lightning/staticMap/staticMap.js +39 -2
  79. package/src/lightning/utils/classSet.js +4 -1
  80. package/src/lightning/utilsPrivate/utilsPrivate.js +12 -1
  81. package/src/lightning/datatable/inlineEdit-shared.js +0 -14
  82. package/src/lightning/datatable/selector-shared.js +0 -38
  83. package/src/lightning/datatable/selector.js +0 -527
@@ -1,5 +1,7 @@
1
1
  import lang from '@salesforce/i18n/lang';
2
2
  import formFactor from '@salesforce/client/formFactor';
3
+ import labelTitleWithAddress from '@salesforce/label/LightningMap.titleWithAddress';
4
+ import labelTitleWithoutAddress from '@salesforce/label/LightningMap.iframeTitle';
3
5
  import { LightningElement, api, track } from 'lwc';
4
6
  import { ratioToScale, calculateSize } from './util';
5
7
  import {
@@ -9,12 +11,19 @@ import {
9
11
  postMessage,
10
12
  } from 'lightning/messageDispatcher';
11
13
  import { buildMapSourceUrl } from 'lightning/mapUtils';
14
+ import { isEmptyString } from 'lightning/inputUtils';
15
+ import { formatLabel } from 'lightning/utils';
12
16
 
13
17
  const EVENT_NAME = {
14
18
  LOADING_MAP: 'loadingMap',
15
19
  STATIC_MAP_LOADED: 'lightning:staticMapLoaded',
16
20
  };
17
21
 
22
+ const i18n = {
23
+ titleWithAddress: labelTitleWithAddress,
24
+ titleWithoutAddress: labelTitleWithoutAddress,
25
+ };
26
+
18
27
  export default class LightningStaticMap extends LightningElement {
19
28
  @api width;
20
29
  @api height;
@@ -23,6 +32,7 @@ export default class LightningStaticMap extends LightningElement {
23
32
  @api province;
24
33
  @api postalCode;
25
34
  @api country;
35
+ @api title;
26
36
 
27
37
  _zoom = 14;
28
38
  _scale = 1;
@@ -109,8 +119,7 @@ export default class LightningStaticMap extends LightningElement {
109
119
  return '';
110
120
  }
111
121
 
112
- get address() {
113
- // if latitude/longitude specified use that to avoid expensive Google geo-coding processing
122
+ get latLongString() {
114
123
  if (
115
124
  this.latitude != null &&
116
125
  this.latitude >= -90.0 &&
@@ -121,12 +130,40 @@ export default class LightningStaticMap extends LightningElement {
121
130
  ) {
122
131
  return `${this.latitude},${this.longitude}`;
123
132
  }
133
+ return null;
134
+ }
124
135
 
136
+ get addressString() {
125
137
  return `${this.street || ''} ${this.city || ''} ${
126
138
  this.province || ''
127
139
  } ${this.postalCode || ''} ${this.country || ''}`;
128
140
  }
129
141
 
142
+ get address() {
143
+ // if latitude/longitude specified use that to avoid expensive Google geo-coding processing
144
+ return this.latLongString || this.addressString;
145
+ }
146
+
147
+ /**
148
+ * getter for the i18 constant containing the localized strings
149
+ */
150
+ get i18n() {
151
+ return i18n;
152
+ }
153
+
154
+ get mapTitle() {
155
+ if (isEmptyString(this.title)) {
156
+ let titleAddress =
157
+ (this.addressString && this.addressString.trim()) ||
158
+ (this.latLongString && this.latLongString.trim());
159
+ if (isEmptyString(titleAddress)) {
160
+ return this.i18n.titleWithoutAddress;
161
+ }
162
+ return formatLabel(this.i18n.titleWithAddress, titleAddress);
163
+ }
164
+ return this.title;
165
+ }
166
+
130
167
  handleMessage(data) {
131
168
  if (data.event === EVENT_NAME.STATIC_MAP_LOADED) {
132
169
  this._mapLoaded = true;
@@ -3,7 +3,10 @@ const classNamesHash = (classes) => {
3
3
  ? classes
4
4
  .trim()
5
5
  .split(/\s+/)
6
- .reduce((acc, cn) => ({ ...acc, [cn]: true }), {})
6
+ .reduce((acc, cn) => {
7
+ acc[cn] = true;
8
+ return acc;
9
+ }, {})
7
10
  : classes;
8
11
  };
9
12
 
@@ -23,7 +23,6 @@ export {
23
23
  } from './keyboard';
24
24
  export { raf } from './scroll';
25
25
  export { isChrome, isIE11, isSafari } from './browser';
26
- export { ContentMutation } from './contentMutation';
27
26
  export { observePosition } from './observers';
28
27
  export { hasOnlyAllowedVideoIframes } from './videoUtils';
29
28
  export {
@@ -212,3 +211,15 @@ export function buttonGroupOrderClass(groupOrder) {
212
211
  [BUTTON_GROUP_ORDER.ONLY]: 'single-button',
213
212
  }[groupOrder];
214
213
  }
214
+
215
+ /**
216
+ * Checks if the given component is native
217
+ * @param {Object} cmp Component instance
218
+ * @returns {Boolean} Whether the component is native
219
+ */
220
+ export function isNativeComponent(cmp) {
221
+ if (cmp && cmp.template && cmp.template.constructor) {
222
+ return !!String(cmp.template.constructor).match(/\[native code\]/);
223
+ }
224
+ return false;
225
+ }
@@ -1,14 +0,0 @@
1
- export function getDirtyValue(state, rowKeyValue, colKeyValue) {
2
- const dirtyValues = state.inlineEdit.dirtyValues;
3
-
4
- if (
5
- // eslint-disable-next-line no-prototype-builtins
6
- dirtyValues.hasOwnProperty(rowKeyValue) &&
7
- // eslint-disable-next-line no-prototype-builtins
8
- dirtyValues[rowKeyValue].hasOwnProperty(colKeyValue)
9
- ) {
10
- return dirtyValues[rowKeyValue][colKeyValue];
11
- }
12
-
13
- return undefined;
14
- }
@@ -1,38 +0,0 @@
1
- export function isSelectedRow(state, rowKeyValue) {
2
- return !!state.selectedRowsKeys[rowKeyValue];
3
- }
4
-
5
- export function isDisabledRow(state, rowKeyValue) {
6
- if (!isSelectedRow(state, rowKeyValue)) {
7
- const maxRowSelection = getMaxRowSelection(state);
8
-
9
- // W-4819182 when selection is 1, we should not disable selection.
10
- return (
11
- maxRowSelection !== 1 &&
12
- getCurrentSelectionLength(state) === maxRowSelection
13
- );
14
- }
15
-
16
- return false;
17
- }
18
-
19
- export function getRowSelectionInputType(state) {
20
- if (getMaxRowSelection(state) === 1) {
21
- return 'radio';
22
- }
23
- return 'checkbox';
24
- }
25
-
26
- export function getMaxRowSelection(state) {
27
- return state.maxRowSelection;
28
- }
29
-
30
- export function getCurrentSelectionLength(state) {
31
- return getSelectedRowsKeys(state).length;
32
- }
33
-
34
- export function getSelectedRowsKeys(state) {
35
- return Object.keys(state.selectedRowsKeys).filter(
36
- (key) => state.selectedRowsKeys[key]
37
- );
38
- }
@@ -1,527 +0,0 @@
1
- import {
2
- resolveRowClassNames,
3
- getRows,
4
- getRowByKey,
5
- getRowsTotal,
6
- getRowIndexByKey,
7
- rowKeyExists,
8
- } from './rows';
9
- import {
10
- getColumns,
11
- getStateColumnIndex,
12
- SELECTABLE_ROW_CHECKBOX,
13
- } from './columns';
14
- import { isNonNegativeInteger } from './utils';
15
-
16
- export {
17
- getCurrentSelectionLength,
18
- isSelectedRow,
19
- isDisabledRow,
20
- getRowSelectionInputType,
21
- getMaxRowSelection,
22
- } from './selector-shared';
23
-
24
- import {
25
- getCurrentSelectionLength,
26
- isSelectedRow,
27
- isDisabledRow,
28
- getRowSelectionInputType,
29
- getMaxRowSelection,
30
- getSelectedRowsKeys as sharedGetSelectedRowsKeys,
31
- } from './selector-shared';
32
-
33
- // Looks like mocks are failing if this is exported via a direct export from selector-shared, so we need to
34
- // implement this as a direct function
35
- export function getSelectedRowsKeys(state) {
36
- return sharedGetSelectedRowsKeys(state);
37
- }
38
-
39
- const MAX_ROW_SELECTION_DEFAULT = undefined;
40
-
41
- export function getSelectorDefaultState() {
42
- return {
43
- selectedRowsKeys: {},
44
- maxRowSelection: MAX_ROW_SELECTION_DEFAULT,
45
- };
46
- }
47
-
48
- export function handleSelectAllRows(event) {
49
- event.stopPropagation();
50
- markAllRowsSelected(this.state);
51
- this.fireSelectedRowsChange(this.getSelectedRows());
52
- }
53
-
54
- export function handleDeselectAllRows(event) {
55
- event.stopPropagation();
56
- markAllRowsDeselected(this.state);
57
- this.fireSelectedRowsChange(this.getSelectedRows());
58
- }
59
-
60
- /**
61
- * Will select the cell identified by rowKeyValue, colKeyValue.
62
- * This will reflect as aria-selected="true" attribute in the cell td or th.
63
- *
64
- * Note: This change is volatile, and will be reset (lost) in the next index regeneration.
65
- *
66
- * @param {Object} state - the state of the datatable
67
- * @param {String} rowKeyValue - the row key of the cell to select
68
- * @param {String} colKeyValue - the col key of the cell to select
69
- */
70
- export function markSelectedCell(state, rowKeyValue, colKeyValue) {
71
- const row = getRowByKey(state, rowKeyValue);
72
- const colIndex = getStateColumnIndex(state, colKeyValue);
73
-
74
- if (row && colIndex) {
75
- row.cells[colIndex].ariaSelected = 'true';
76
- }
77
- }
78
-
79
- /**
80
- * Will deselect the cell identified by rowKeyValue, colKeyValue.
81
- * This will reflect in removing aria-selected attribute in the cell td or th (if it was previously added).
82
- *
83
- * Note: This change is volatile, and will be reset (lost) in the next index regeneration.
84
- *
85
- * @param {Object} state - the state of the datatable
86
- * @param {String} rowKeyValue - the row key of the cell to select
87
- * @param {String} colKeyValue - the col key of the cell to select
88
- */
89
- export function markDeselectedCell(state, rowKeyValue, colKeyValue) {
90
- const row = getRowByKey(state, rowKeyValue);
91
- const colIndex = getStateColumnIndex(state, colKeyValue);
92
-
93
- if (row && colIndex) {
94
- row.cells[colIndex].ariaSelected = false;
95
- }
96
- }
97
-
98
- /**
99
- * Returns the last rowKey that was clicked, false otherwise.
100
- * @param {Object} state - the datatable state.
101
- * @return {String | undefined } the row key or false.
102
- */
103
- function getLastRowSelection(state) {
104
- const lastSelectedRowKey = state.selectionLastSelectedRow;
105
- const keyIsValid =
106
- lastSelectedRowKey !== undefined &&
107
- getRowIndexByKey(state, lastSelectedRowKey) !== undefined;
108
-
109
- return keyIsValid ? lastSelectedRowKey : undefined;
110
- }
111
-
112
- function setLastRowSelection(state, rowKeyValue) {
113
- state.selectionLastSelectedRow = rowKeyValue;
114
- }
115
-
116
- export function handleSelectRow(event) {
117
- event.stopPropagation();
118
- const { rowKeyValue, isMultiple } = event.detail;
119
- let fromRowKey = rowKeyValue;
120
-
121
- if (isMultiple) {
122
- fromRowKey = getLastRowSelection(this.state) || rowKeyValue;
123
- }
124
-
125
- markSelectedRowsInterval(this.state, fromRowKey, rowKeyValue);
126
- setLastRowSelection(this.state, rowKeyValue);
127
- this.fireSelectedRowsChange(this.getSelectedRows());
128
- }
129
-
130
- function markSelectedRowsInterval(state, startRowKey, endRowKey) {
131
- const rows = getRows(state);
132
- const { start, end } = getRowIntervalIndexes(state, startRowKey, endRowKey);
133
- const maxRowSelection = getMaxRowSelection(state) || getRowsTotal(state);
134
- let i = start,
135
- maxSelectionReached;
136
-
137
- do {
138
- markRowSelected(state, rows[i].key);
139
- maxSelectionReached =
140
- getCurrentSelectionLength(state) >= maxRowSelection;
141
- i++;
142
- } while (i <= end && !maxSelectionReached);
143
- }
144
-
145
- export function handleDeselectRow(event) {
146
- event.stopPropagation();
147
- const { rowKeyValue, isMultiple } = event.detail;
148
- let fromRowKey = rowKeyValue;
149
-
150
- if (isMultiple) {
151
- fromRowKey = getLastRowSelection(this.state) || rowKeyValue;
152
- }
153
-
154
- markDeselectedRowsInterval(this.state, fromRowKey, rowKeyValue);
155
- setLastRowSelection(this.state, rowKeyValue);
156
- this.fireSelectedRowsChange(this.getSelectedRows());
157
- }
158
-
159
- function getRowIntervalIndexes(state, startRowKey, endRowKey) {
160
- const start =
161
- startRowKey === 'HEADER' ? 0 : getRowIndexByKey(state, startRowKey);
162
- const end = getRowIndexByKey(state, endRowKey);
163
-
164
- return {
165
- start: Math.min(start, end),
166
- end: Math.max(start, end),
167
- };
168
- }
169
-
170
- function markDeselectedRowsInterval(state, startRowKey, endRowKey) {
171
- const rows = getRows(state);
172
- const { start, end } = getRowIntervalIndexes(state, startRowKey, endRowKey);
173
-
174
- for (let i = start; i <= end; i++) {
175
- markRowDeselected(state, rows[i].key);
176
- }
177
- }
178
-
179
- function getSelectedDiff(state, value) {
180
- const selectedRowsKeys = state.selectedRowsKeys;
181
- return value.filter((key) => !selectedRowsKeys[key]);
182
- }
183
-
184
- function getDeselectedDiff(state, value) {
185
- const currentSelectedRowsKeys = state.selectedRowsKeys;
186
- return Object.keys(currentSelectedRowsKeys).filter(
187
- (key) => currentSelectedRowsKeys[key] && !value[key]
188
- );
189
- }
190
-
191
- function normalizeSelectedRowsKey(value) {
192
- return value.reduce((map, key) => {
193
- map[key] = true;
194
- return map;
195
- }, {});
196
- }
197
-
198
- function markRowsSelectedByKeys(state, keys) {
199
- keys.forEach((rowKeyValue) => {
200
- const row = getRowByKey(state, rowKeyValue);
201
- row.isSelected = true;
202
- row.ariaSelected = 'true';
203
- row.classnames = resolveRowClassNames(row);
204
- });
205
- }
206
-
207
- function markRowsDeselectedByKeys(state, keys) {
208
- keys.forEach((rowKeyValue) => {
209
- const row = getRowByKey(state, rowKeyValue);
210
- row.isSelected = false;
211
- row.ariaSelected = false;
212
- row.classnames = resolveRowClassNames(row);
213
- });
214
- }
215
-
216
- function filterValidKeys(state, keys) {
217
- return keys.filter((key) => rowKeyExists(state, key));
218
- }
219
-
220
- export function setSelectedRowsKeys(state, value) {
221
- if (Array.isArray(value)) {
222
- const maxRowSelection = getMaxRowSelection(state);
223
- const previousSelectionLength = getCurrentSelectionLength(state);
224
- let selectedRows = filterValidKeys(state, value);
225
- if (selectedRows.length > maxRowSelection) {
226
- // eslint-disable-next-line no-console
227
- console.warn(`The number of keys in selectedRows for lightning:datatable
228
- exceeds the limit defined by maxRowSelection.`);
229
- selectedRows = selectedRows.slice(0, maxRowSelection);
230
- }
231
- const normalizedSelectedRowsKeys =
232
- normalizeSelectedRowsKey(selectedRows);
233
- const selectionOperations = getSelectedDiff(state, selectedRows);
234
- const deselectionOperations = getDeselectedDiff(
235
- state,
236
- normalizedSelectedRowsKeys
237
- );
238
- markRowsSelectedByKeys(state, selectionOperations);
239
- markRowsDeselectedByKeys(state, deselectionOperations);
240
- state.selectedRowsKeys = normalizedSelectedRowsKeys;
241
-
242
- if (selectedRows.length === maxRowSelection && maxRowSelection > 1) {
243
- markDeselectedRowDisabled(state);
244
- } else if (
245
- selectedRows.length < maxRowSelection &&
246
- previousSelectionLength === maxRowSelection
247
- ) {
248
- markDeselectedRowEnabled(state);
249
- }
250
- } else {
251
- // eslint-disable-next-line no-console
252
- console.error(`The "selectedRows" passed into "lightning:datatable"
253
- must be an Array with the keys of the selected rows. We receive instead ${value}`);
254
- markAllRowsDeselected(state);
255
- }
256
- }
257
-
258
- export function getHideSelectAllCheckbox(state) {
259
- return getMaxRowSelection(state) === 1;
260
- }
261
-
262
- /**
263
- * sets maxRowSelection to provided value,
264
- * only keeping up to maxRowSelection values selected
265
- * Use input type checkbox if maxRowSelection > 1
266
- * and input type is radio if maxRowSelection = 1.
267
- * Invalid values are set to default and log an error
268
- * @param {Object} state - the datatable state.
269
- * @param {Number | String} - value to set for maxRowSelection
270
- */
271
- export function setMaxRowSelection(state, value) {
272
- const previousSelectedRowsKeys = getSelectedRowsKeys(state);
273
- markAllRowsDeselected(state);
274
- if (isNonNegativeInteger(value)) {
275
- const previousMaxRowSelection = getMaxRowSelection(state);
276
- state.maxRowSelection = Number(value);
277
- const newMaxRowSelection = getMaxRowSelection(state);
278
- // reselect up to maxRowSelection rows
279
- const numberOfRows = Math.min(
280
- previousSelectedRowsKeys.length,
281
- newMaxRowSelection
282
- );
283
- for (let i = 0; i < numberOfRows; i++) {
284
- markRowSelected(state, previousSelectedRowsKeys[i]);
285
- }
286
- if (
287
- inputTypeNeedsToChange(
288
- previousMaxRowSelection,
289
- getMaxRowSelection(state)
290
- )
291
- ) {
292
- updateRowSelectionInputType(state);
293
- updateSelectionState(state);
294
- }
295
- } else {
296
- state.maxRowSelection = MAX_ROW_SELECTION_DEFAULT;
297
- // eslint-disable-next-line no-console
298
- console.error(
299
- `The maxRowSelection value passed into lightning:datatable
300
- should be a positive integer. We receive instead (${value}).`
301
- );
302
- }
303
- }
304
-
305
- export function inputTypeNeedsToChange(
306
- previousMaxRowSelection,
307
- newMaxRowSelection
308
- ) {
309
- return (
310
- (previousMaxRowSelection === 1 &&
311
- isMultiSelection(newMaxRowSelection)) ||
312
- (isMultiSelection(previousMaxRowSelection) &&
313
- newMaxRowSelection === 1) ||
314
- previousMaxRowSelection === 0 ||
315
- newMaxRowSelection === 0
316
- );
317
- }
318
-
319
- export function isMultiSelection(value) {
320
- return value > 1 || value === undefined;
321
- }
322
-
323
- export function updateRowSelectionInputType(state) {
324
- const type = getRowSelectionInputType(state);
325
- const rows = getRows(state);
326
-
327
- rows.forEach((row) => {
328
- row.inputType = type;
329
- row.isDisabled = isDisabledRow(state, row.key);
330
- });
331
- }
332
-
333
- export function markDeselectedRowDisabled(state) {
334
- const rows = getRows(state);
335
- rows.forEach((row) => {
336
- if (!isSelectedRow(state, row.key)) {
337
- row.isDisabled = true;
338
- }
339
- });
340
- }
341
-
342
- export function markDeselectedRowEnabled(state) {
343
- const rows = getRows(state);
344
- rows.forEach((row) => {
345
- if (!isSelectedRow(state, row.key)) {
346
- row.isDisabled = false;
347
- }
348
- });
349
- }
350
-
351
- export function markRowSelected(state, rowKeyValue) {
352
- const row = getRowByKey(state, rowKeyValue);
353
- const maxRowSelection = getMaxRowSelection(state) || getRowsTotal(state);
354
- const previousSelectionLength = getCurrentSelectionLength(state);
355
-
356
- row.isSelected = true;
357
- row.ariaSelected = 'true';
358
- row.classnames = resolveRowClassNames(row);
359
-
360
- if (maxRowSelection > 1) {
361
- addKeyToSelectedRowKeys(state, row.key);
362
- if (previousSelectionLength + 1 === maxRowSelection) {
363
- markDeselectedRowDisabled(state);
364
- }
365
- } else {
366
- if (previousSelectionLength === 1) {
367
- const previousSelectedRow = getRowByKey(
368
- state,
369
- Object.keys(state.selectedRowsKeys)[0]
370
- );
371
- previousSelectedRow.isSelected = false;
372
- previousSelectedRow.ariaSelected = false;
373
- previousSelectedRow.classnames =
374
- resolveRowClassNames(previousSelectedRow);
375
- resetSelectedRowsKeys(state);
376
- }
377
- addKeyToSelectedRowKeys(state, row.key);
378
- }
379
- }
380
-
381
- export function markRowDeselected(state, rowKeyValue) {
382
- const row = getRowByKey(state, rowKeyValue);
383
- const maxRowSelection = getMaxRowSelection(state);
384
-
385
- row.isSelected = false;
386
- row.ariaSelected = false;
387
- row.classnames = resolveRowClassNames(row);
388
- removeKeyFromSelectedRowKeys(state, row.key);
389
-
390
- if (getCurrentSelectionLength(state) === maxRowSelection - 1) {
391
- markDeselectedRowEnabled(state);
392
- }
393
- }
394
-
395
- export function resetSelectedRowsKeys(state) {
396
- state.selectedRowsKeys = {};
397
- }
398
-
399
- export function markAllRowsSelected(state) {
400
- const rows = getRows(state);
401
- const maxRowSelection = getMaxRowSelection(state);
402
-
403
- resetSelectedRowsKeys(state);
404
- rows.forEach((row, index) => {
405
- if (index < maxRowSelection || maxRowSelection === undefined) {
406
- row.isSelected = true;
407
- row.ariaSelected = 'true';
408
- row.classnames = resolveRowClassNames(row);
409
- addKeyToSelectedRowKeys(state, row.key);
410
- } else {
411
- row.isDisabled = true;
412
- row.isSelected = false;
413
- row.ariaSelected = false;
414
- row.classnames = resolveRowClassNames(row);
415
- }
416
- });
417
- }
418
-
419
- export function markAllRowsDeselected(state) {
420
- const rows = getRows(state);
421
-
422
- resetSelectedRowsKeys(state);
423
- rows.forEach((row) => {
424
- row.isDisabled = false;
425
- row.isSelected = false;
426
- row.ariaSelected = false;
427
- row.classnames = resolveRowClassNames(row);
428
- });
429
- return state;
430
- }
431
-
432
- export function syncSelectedRowsKeys(state, selectedRows) {
433
- let changed = false;
434
- const { selectedRowsKeys, keyField } = state;
435
-
436
- if (Object.keys(selectedRowsKeys).length !== selectedRows.length) {
437
- changed = true;
438
- state.selectedRowsKeys = updateSelectedRowsKeysFromSelectedRows(
439
- selectedRows,
440
- keyField
441
- );
442
- } else {
443
- changed = selectedRows.some((row) => !selectedRowsKeys[row[keyField]]);
444
- if (changed) {
445
- state.selectedRowsKeys = updateSelectedRowsKeysFromSelectedRows(
446
- selectedRows,
447
- keyField
448
- );
449
- }
450
- }
451
-
452
- updateSelectionState(state);
453
-
454
- return {
455
- ifChanged: (callback) => {
456
- if (changed && typeof callback === 'function') {
457
- callback(selectedRows);
458
- }
459
- },
460
- };
461
- }
462
-
463
- export function handleRowSelectionChange() {
464
- updateSelectionState(this.state);
465
- }
466
-
467
- function updateSelectedRowsKeysFromSelectedRows(selectedRows, keyField) {
468
- return selectedRows.reduce((selectedRowsKeys, row) => {
469
- selectedRowsKeys[row[keyField]] = true;
470
- return selectedRowsKeys;
471
- }, {});
472
- }
473
-
474
- function addKeyToSelectedRowKeys(state, key) {
475
- state.selectedRowsKeys[key] = true;
476
- }
477
-
478
- function removeKeyFromSelectedRowKeys(state, key) {
479
- // not using delete this.state.selectedRowsKeys[key]
480
- // because that cause perf issues
481
- state.selectedRowsKeys[key] = false;
482
- }
483
-
484
- export function updateSelectionState(state) {
485
- const selectBoxesColumnIndex = getSelectBoxesColumnIndex(state);
486
- if (selectBoxesColumnIndex >= 0) {
487
- state.columns[selectBoxesColumnIndex] = Object.assign(
488
- {},
489
- state.columns[selectBoxesColumnIndex],
490
- {
491
- bulkSelection: getBulkSelectionState(state),
492
- isBulkSelectionDisabled: isBulkSelectionDisabled(state),
493
- }
494
- );
495
- }
496
- }
497
-
498
- export function getBulkSelectionState(state) {
499
- const selected = getCurrentSelectionLength(state);
500
- const total = getMaxRowSelection(state) || getRowsTotal(state);
501
- if (selected === 0) {
502
- return 'none';
503
- } else if (selected === total) {
504
- return 'all';
505
- }
506
- return 'some';
507
- }
508
-
509
- export function isBulkSelectionDisabled(state) {
510
- return getRowsTotal(state) === 0 || getMaxRowSelection(state) === 0;
511
- }
512
-
513
- function getSelectBoxesColumnIndex(state) {
514
- const columns = getColumns(state) || [];
515
- let selectBoxColumnIndex = -1;
516
-
517
- columns.some((column, index) => {
518
- if (column.type === SELECTABLE_ROW_CHECKBOX) {
519
- selectBoxColumnIndex = index;
520
- return true;
521
- }
522
-
523
- return false;
524
- });
525
-
526
- return selectBoxColumnIndex;
527
- }