lightning-base-components 1.13.10-alpha → 1.14.4-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 (69) hide show
  1. package/metadata/raptor.json +24 -0
  2. package/package.json +20 -4
  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-LightningMap.titleWithAddress.js +1 -0
  8. package/scopedImports/@salesforce-label-LightningModalBase.cancelandclose.js +1 -0
  9. package/src/lightning/ariaObserver/__component__/ariaObserver.spec.js +112 -0
  10. package/src/lightning/ariaObserver/__docs__/ariaObserver.md +142 -0
  11. package/src/lightning/{utilsPrivate/contentMutation.js → ariaObserver/ariaObserver.js} +60 -98
  12. package/src/lightning/buttonMenu/keyboard.js +0 -10
  13. package/src/lightning/card/card.html +6 -0
  14. package/src/lightning/checkboxGroup/checkboxGroup.html +2 -2
  15. package/src/lightning/checkboxGroup/checkboxGroup.js +6 -1
  16. package/src/lightning/colorPickerCustom/colorPickerCustom.js +20 -1
  17. package/src/lightning/datatable/__docs__/datatable.md +55 -0
  18. package/src/lightning/datatable/__examples__/basic/basic.html +1 -1
  19. package/src/lightning/datatable/columns-shared.js +1 -1
  20. package/src/lightning/datatable/datatable.js +98 -30
  21. package/src/lightning/datatable/errors.js +20 -9
  22. package/src/lightning/datatable/headerActions.js +77 -49
  23. package/src/lightning/datatable/infiniteLoading.js +100 -28
  24. package/src/lightning/datatable/inlineEdit.js +505 -379
  25. package/src/lightning/datatable/inlineEditShared.js +24 -0
  26. package/src/lightning/datatable/keyboard.js +162 -127
  27. package/src/lightning/datatable/renderManager.js +201 -133
  28. package/src/lightning/datatable/rowLevelActions.js +17 -13
  29. package/src/lightning/datatable/rowNumber.js +54 -20
  30. package/src/lightning/datatable/rowSelection.js +760 -0
  31. package/src/lightning/datatable/rowSelectionShared.js +79 -0
  32. package/src/lightning/datatable/rows.js +17 -6
  33. package/src/lightning/datatable/state.js +16 -2
  34. package/src/lightning/datatable/templates/div/div.css +4 -0
  35. package/src/lightning/datatable/templates/div/div.html +6 -0
  36. package/src/lightning/datatable/templates/table/table.html +5 -0
  37. package/src/lightning/datatable/utils.js +14 -0
  38. package/src/lightning/datatable/wrapText.js +77 -47
  39. package/src/lightning/dualListbox/dualListbox.html +1 -1
  40. package/src/lightning/dualListbox/dualListbox.js +42 -0
  41. package/src/lightning/formattedDateTime/__docs__/formattedDateTime.md +36 -3
  42. package/src/lightning/formattedDateTime/__examples__/datetime/datetime.html +2 -2
  43. package/src/lightning/formattedDateTime/__examples__/datetime/datetime.js +3 -1
  44. package/src/lightning/formattedDateTime/__examples__/time/time.html +1 -1
  45. package/src/lightning/formattedDateTime/__examples__/time/time.js +3 -1
  46. package/src/lightning/formattedDateTime/formattedDateTime.js +1 -0
  47. package/src/lightning/input/input.html +1 -5
  48. package/src/lightning/input/input.js +69 -48
  49. package/src/lightning/inputUtils/validity.js +12 -1
  50. package/src/lightning/pillContainer/__docs__/pillContainer.md +45 -1
  51. package/src/lightning/primitiveCellActions/primitiveCellActions.js +69 -12
  52. package/src/lightning/primitiveCellFactory/cellWithStandardLayout.html +13 -11
  53. package/src/lightning/primitiveCellFactory/primitiveCellFactory.js +13 -8
  54. package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.html +17 -14
  55. package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.js +167 -98
  56. package/src/lightning/primitiveDatatableIeditTypeFactory/primitiveDatatableIeditTypeFactory.js +94 -69
  57. package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.html +4 -4
  58. package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.js +4 -4
  59. package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.js +99 -37
  60. package/src/lightning/progressIndicator/progressIndicator.js +1 -1
  61. package/src/lightning/progressStep/progressStep.js +30 -22
  62. package/src/lightning/staticMap/staticMap.html +1 -0
  63. package/src/lightning/staticMap/staticMap.js +39 -2
  64. package/src/lightning/utils/classSet.js +4 -1
  65. package/src/lightning/utilsPrivate/utilsPrivate.js +12 -1
  66. package/scopedImports/@salesforce-label-LightningModalBase.close.js +0 -1
  67. package/src/lightning/datatable/inlineEdit-shared.js +0 -14
  68. package/src/lightning/datatable/selector-shared.js +0 -38
  69. package/src/lightning/datatable/selector.js +0 -527
@@ -8,6 +8,7 @@ import labelHexLabel from '@salesforce/label/LightningColorPicker.hexLabel';
8
8
  import labelHueInput from '@salesforce/label/LightningColorPicker.hueInput';
9
9
  import labelRInput from '@salesforce/label/LightningColorPicker.rInput';
10
10
  import labelRedAbbr from '@salesforce/label/LightningColorPicker.redAbbr';
11
+ import formFactorPropertyName from '@salesforce/client/formFactor';
11
12
  import { LightningElement, api, track } from 'lwc';
12
13
  import { keyCodes } from 'lightning/utilsPrivate';
13
14
  import { generateUniqueId, getErrorMessage } from 'lightning/inputUtils';
@@ -58,7 +59,25 @@ export default class LightningColorPickerCustom extends LightningElement {
58
59
  if (!this._initialized) {
59
60
  // eslint-disable-next-line @lwc/lwc/no-async-operation
60
61
  requestAnimationFrame(() => {
61
- this.focus();
62
+ // (*1*)
63
+ if (formFactorPropertyName !== 'Large') {
64
+ /**
65
+ * We need to wait for one more animation frame and invoke .focus()
66
+ * in iOS. This is because the positionLibray.js initially sets the position
67
+ * of this color-picker element to "top: 0px" and then later repositions it asynchronously
68
+ * it the next animation frames. The first (*1*) rAF callback is fired between
69
+ * setting "top: 0px" and then later repositioning it. Calling .focus() in this callback
70
+ * triggers a re-paint step and the page is scrolled to the top due to "top: 0px" being
71
+ * present in the styles. To avoid this, we can delay the next re-paint after color-picker
72
+ * is repositioned correctly by positionLibrary.js. Hence we wait for next animation frame
73
+ * and then call .focus() to trigger the next re-paint after the color-picker is repositioned correctly
74
+ * which was initially positioned with "top: 0px" by positionLibrary.js
75
+ */
76
+ // eslint-disable-next-line @lwc/lwc/no-async-operation
77
+ requestAnimationFrame(() => this.focus());
78
+ } else {
79
+ this.focus();
80
+ }
62
81
  });
63
82
  this.gradient();
64
83
  this.handleUpdateAnchor();
@@ -244,6 +244,28 @@ Valid data types and their supported attributes include:
244
244
  | text | Displays text using [lightning-formatted-text](bundle/lightning-formatted-text/). This is the default data type. | linkify |
245
245
  | url | Displays a URL using [lightning-formatted-url](bundle/lightning-formatted-url/) | label, target, tooltip |
246
246
 
247
+ In some situations, multiple columns reference the same `fieldName` but have different `fieldApiNames` and different ways of working with the field information. To give a column a unique ID when using the same field name for two columns, use the attribute `columnKey` instead of `fieldName` on one of the column definitions.
248
+
249
+ ```javascript
250
+ get columns() {
251
+ return [
252
+ // Column using 'fieldName' as identifier
253
+ {
254
+ label: 'Lead',
255
+ fieldName: 'leadId',
256
+ ...
257
+ },
258
+ // Column using 'columnKey' as identifier
259
+ {
260
+ label: 'Company',
261
+ columnKey: 'leadCompany',
262
+ fieldName: 'leadId',
263
+ ...
264
+ }
265
+ ]
266
+ }
267
+ ```
268
+
247
269
  #### Custom Formatting Examples
248
270
 
249
271
  To customize the formatting based on the data type, pass in the attributes for
@@ -494,6 +516,21 @@ const columns = [
494
516
 
495
517
  Custom classes are currently not supported. To apply custom styling on your datatable cells, create a custom data type and then apply your custom CSS classes. See [Custom Data Type Layout and Styles](docs/component-library/documentation/lwc/lwc.data_table_custom_types_styling).
496
518
 
519
+ #### Displaying Indicators for Read-Only Fields
520
+
521
+ You can display a lock icon on read-only fields to specify they're not editable. To specify that a column's field as read-only, set the column attribute `editable` to `false` and the column attribute `displayReadOnlyIcon` to `true` in the associated column definition. This example displays a lock icon on each field in a column called "Website."
522
+
523
+ ```javascript
524
+ const columns = [
525
+ {
526
+ label: 'Website',
527
+ fieldName: 'website',
528
+ type: 'url',
529
+ editable: false,
530
+ displayReadOnlyIcon: true,
531
+ }
532
+ ```
533
+
497
534
  #### Using Infinite Scrolling to Load More Rows
498
535
 
499
536
  Infinite scrolling enables you to load a subset of data and then display more
@@ -1031,6 +1068,24 @@ handleSave(event) {
1031
1068
  }
1032
1069
  ```
1033
1070
 
1071
+ You can also program an external element, such as a button, to open an inline edit panel on the currently active cell or next editable cell in the datatable. Invoke the `openInlineEdit()` method in the external element that should direct a user to the first editable cell in your datatable component.
1072
+
1073
+ This example opens a datatable cell for inline edit when the user clicks an "Edit" button.
1074
+
1075
+ ```javascript
1076
+ import { LightningElement } from 'lwc';
1077
+ export default class DatatableWithInlineEdit extends LightningElement {
1078
+ data = [];
1079
+ columns = columns;
1080
+ rowOffset = 0;
1081
+
1082
+ handleClick() {
1083
+ const dt = this.template.querySelector('lightning-datatable');
1084
+ dt.openInlineEdit();
1085
+ }
1086
+ }
1087
+ ```
1088
+
1034
1089
  For more information, see [Display Data in a Table with Inline Editing](docs/component-library/documentation/lwc/lwc.data_table_inline_edit).
1035
1090
 
1036
1091
  #### Displaying Errors
@@ -5,5 +5,5 @@
5
5
  data={data}
6
6
  columns={columns}>
7
7
  </lightning-datatable>
8
- </div>
8
+ </div>
9
9
  </template>
@@ -4,7 +4,7 @@
4
4
  * which also has a dependency on `columns.js` for `getColumnName()`.
5
5
  *
6
6
  * We split out some of the functions that could cause circular dependencies with
7
- * `column.js` into the `*-shared.js` files. `inlineEdit-shared.js` is another.
7
+ * `column.js` into the `*-shared.js` files. `inlineEditShared.js` is another.
8
8
  */
9
9
 
10
10
  export function getColumnName(column) {
@@ -42,7 +42,7 @@ import {
42
42
  import {
43
43
  syncSelectedRowsKeys,
44
44
  handleRowSelectionChange,
45
- updateSelectionState,
45
+ updateBulkSelectionState,
46
46
  getMaxRowSelection,
47
47
  setMaxRowSelection,
48
48
  getSelectedRowsKeys,
@@ -53,7 +53,7 @@ import {
53
53
  handleDeselectRow,
54
54
  getHideSelectAllCheckbox,
55
55
  getCurrentSelectionLength,
56
- } from './selector';
56
+ } from './rowSelection';
57
57
  import {
58
58
  syncActiveCell,
59
59
  handleKeydownOnCell,
@@ -80,6 +80,9 @@ import {
80
80
  handleKeydownOnTable,
81
81
  addFocusStylesToActiveCell,
82
82
  refocusCellElement,
83
+ isCellElement,
84
+ getActiveCellElement,
85
+ FOCUS_CLASS,
83
86
  } from './keyboard';
84
87
  import {
85
88
  getRowNumberOffset,
@@ -134,7 +137,11 @@ import {
134
137
  import {
135
138
  isViewportRenderingEnabled,
136
139
  setViewportRendering,
140
+ getDTWrapperHeight,
141
+ setFirstVisibleIndex,
142
+ setVirtualize,
137
143
  RenderManager,
144
+ DEFAULT_ROW_HEIGHT,
138
145
  } from './renderManager';
139
146
 
140
147
  import { hasTreeDataType } from './tree';
@@ -144,6 +151,7 @@ import { generateUniqueId } from 'lightning/inputUtils';
144
151
  import DatatableTypes from './types';
145
152
  import labelAriaLiveNavigationMode from '@salesforce/label/LightningDatatable.ariaLiveNavigationMode';
146
153
  import labelAriaLiveActionMode from '@salesforce/label/LightningDatatable.ariaLiveActionMode';
154
+ import { styleToString } from './utils';
147
155
 
148
156
  const i18n = {
149
157
  ariaLiveNavigationMode: labelAriaLiveNavigationMode,
@@ -196,7 +204,6 @@ export default class LightningDatatable extends LightningElement {
196
204
  _privateTypes = {};
197
205
  _privateWidthObserver = null; // Instance of LightningDatatableResizeObserver
198
206
  _renderMode = 'table';
199
- _renderedRowCount = 0;
200
207
  _suppressBottomBar = false;
201
208
 
202
209
  /************************* PUBLIC PROPERTIES *************************/
@@ -493,6 +500,7 @@ export default class LightningDatatable extends LightningElement {
493
500
  * @type {object}
494
501
  * @property {boolean} viewportRendering - Specifies whether to defer rendering of rows outside the viewport until the user begins scrolling. To use this feature, create a fixed-height container element for lightning-datatable.
495
502
  * @property {number} rowHeight - Specifies the height of a row, in px
503
+ * @property {string} virtualize - specifies whether to enable virtualization. This requires the "role-based" render mode and a fixed-height container for lightning-datatable
496
504
  */
497
505
 
498
506
  /**
@@ -508,10 +516,21 @@ export default class LightningDatatable extends LightningElement {
508
516
 
509
517
  set renderConfig(value) {
510
518
  if (typeof value === 'object' && !isIE11) {
511
- const enableViewportRendering = value.viewportRendering;
512
- setViewportRendering(this.state, enableViewportRendering);
519
+ setViewportRendering(this.state, value.viewportRendering);
513
520
 
514
- this._renderManager.configure(this, value);
521
+ this._renderManager.configure(
522
+ this.state,
523
+ this.getWrapperHeight,
524
+ value
525
+ );
526
+ // if renderConfig already exists, update rendering
527
+ if (this._renderConfig) {
528
+ this._renderManager.updateViewportRendering(
529
+ this.state,
530
+ this.gridContainer,
531
+ true
532
+ );
533
+ }
515
534
  this._renderConfig = value;
516
535
  }
517
536
  }
@@ -536,6 +555,9 @@ export default class LightningDatatable extends LightningElement {
536
555
  validValues: ['default', 'role-based'],
537
556
  });
538
557
  this.state.renderModeRoleBased = this._renderMode === 'role-based';
558
+ if (this._renderConfig) {
559
+ setVirtualize(this.state, this._renderConfig.virtualize);
560
+ }
539
561
  updateCellClassForRoleBasedMode(this.state);
540
562
  }
541
563
 
@@ -759,24 +781,42 @@ export default class LightningDatatable extends LightningElement {
759
781
 
760
782
  get computedTableStyle() {
761
783
  if (this._columnWidthManager.isAutoResizingUpdateQueued()) {
762
- return ['table-layout:auto'].join(';');
784
+ return styleToString(['table-layout:auto']);
763
785
  }
764
- return [
786
+ return styleToString([
765
787
  'table-layout:fixed',
766
788
  getCSSWidthStyleOfTable(this.widthsData),
767
- ].join(';');
789
+ ]);
768
790
  }
769
791
 
792
+ /**
793
+ * Resets row-number counter to offset to show
794
+ * correct value when row number column is present
795
+ * and adds necessary position and height styles when
796
+ * virtualization is enabled
797
+ */
770
798
  get computedTbodyStyle() {
799
+ const style = [];
800
+ const { firstVisibleIndex, bufferSize, virtualize, rows } = this.state;
771
801
  if (
772
802
  hasRowNumberColumn(this.state) &&
773
803
  getRowNumberOffset(this.state) >= 0
774
804
  ) {
775
- return (
776
- 'counter-reset: row-number ' + getRowNumberOffset(this.state)
805
+ const firstRenderedRow = Math.max(
806
+ firstVisibleIndex - bufferSize,
807
+ 0
808
+ );
809
+ const rowNumber = firstRenderedRow + getRowNumberOffset(this.state);
810
+ style.push(`counter-reset: row-number ${rowNumber}`);
811
+ }
812
+ if (virtualize) {
813
+ const length = rows.length;
814
+ style.push(
815
+ 'position: relative',
816
+ `height:${length * DEFAULT_ROW_HEIGHT}px`
777
817
  );
778
818
  }
779
- return '';
819
+ return styleToString(style);
780
820
  }
781
821
 
782
822
  /**
@@ -812,9 +852,7 @@ export default class LightningDatatable extends LightningElement {
812
852
  styles['overflow-x'] = 'auto';
813
853
  }
814
854
 
815
- return Object.entries(styles)
816
- .map(([key, value]) => key + ':' + value)
817
- .join(';');
855
+ return styleToString(styles);
818
856
  }
819
857
 
820
858
  /**
@@ -897,10 +935,16 @@ export default class LightningDatatable extends LightningElement {
897
935
  }
898
936
 
899
937
  get renderedRows() {
938
+ const { virtualize, rows, renderedRowCount } = this.state;
939
+ if (virtualize) {
940
+ const { firstIndex, lastIndex } =
941
+ this._renderManager.getRenderedRange(this.state);
942
+ return rows.slice(firstIndex, lastIndex);
943
+ }
900
944
  if (this.viewportRendering && !isIE11) {
901
- return this.state.rows.slice(0, this._renderedRowCount);
945
+ return rows.slice(0, renderedRowCount);
902
946
  }
903
- return this.state.rows;
947
+ return rows;
904
948
  }
905
949
 
906
950
  get showSelectAllCheckbox() {
@@ -936,6 +980,7 @@ export default class LightningDatatable extends LightningElement {
936
980
  this.updateRowsAndCellIndexes = updateRowsAndCellIndexes.bind(this);
937
981
 
938
982
  this._renderManager = new RenderManager();
983
+ this.getWrapperHeight = getDTWrapperHeight.bind(this);
939
984
  }
940
985
 
941
986
  /**
@@ -1094,17 +1139,35 @@ export default class LightningDatatable extends LightningElement {
1094
1139
  this._customerSelectedRows = null;
1095
1140
  // set the previous focused cell to null after render is done
1096
1141
  resetCellToFocusFromPrev(state);
1142
+ // reset focus styles on re-render
1143
+ if (state.activeCell && state.activeCell.focused) {
1144
+ const cellElement = getActiveCellElement(template, state);
1145
+ if (
1146
+ cellElement &&
1147
+ cellElement.parentElement &&
1148
+ !cellElement.parentElement.classList.contains(FOCUS_CLASS)
1149
+ ) {
1150
+ setFocusActiveCell(template, state, null, null, false);
1151
+ }
1152
+ }
1097
1153
 
1098
- if (this.viewportRendering) {
1099
- this._renderManager.connectResizeObserver(this);
1154
+ if (this.viewportRendering || state.virtualize) {
1155
+ const resizeTarget = this.template.querySelector(
1156
+ 'div.dt-outer-container'
1157
+ );
1158
+ this._renderManager.connectResizeObserver(resizeTarget);
1100
1159
  if (!this._renderManager.hasWrapperHeight()) {
1101
- this._renderManager.updateWrapperHeight(this);
1160
+ this._renderManager.updateWrapperHeight(this.getWrapperHeight);
1102
1161
 
1103
1162
  // Reset the row count if we already had one before updating the wrapper height.
1104
1163
  // This can happen if the number of rows was calculated before the datatable
1105
1164
  // was rendered.
1106
- if (this._renderedRowCount) {
1107
- this._renderManager.updateViewportRendering(this, true);
1165
+ if (this.state.renderedRowCount) {
1166
+ this._renderManager.updateViewportRendering(
1167
+ this.state,
1168
+ this.gridContainer,
1169
+ true
1170
+ );
1108
1171
  }
1109
1172
  }
1110
1173
  }
@@ -1187,9 +1250,10 @@ export default class LightningDatatable extends LightningElement {
1187
1250
  }
1188
1251
 
1189
1252
  handleInlineEditPanelScroll.call(this, event);
1190
-
1191
- if (this.viewportRendering) {
1192
- this._renderManager.handleScroll(this, event);
1253
+ if (this.state.virtualize) {
1254
+ setFirstVisibleIndex(this.state, event.target.scrollTop);
1255
+ } else if (this.viewportRendering) {
1256
+ this._renderManager.handleScroll(this.state, event);
1193
1257
  }
1194
1258
  }
1195
1259
 
@@ -1202,8 +1266,9 @@ export default class LightningDatatable extends LightningElement {
1202
1266
  handleCellClick(event) {
1203
1267
  // handles the case when clicking on the margin/pading of the td/th
1204
1268
  const targetTagName = event.target.tagName.toLowerCase();
1269
+ const targetRole = event.target.getAttribute('role');
1205
1270
 
1206
- if (targetTagName === 'td' || targetTagName === 'th') {
1271
+ if (isCellElement(targetTagName, targetRole)) {
1207
1272
  // get the row/col key value from the primitive cell.
1208
1273
  const { rowKeyValue, colKeyValue } =
1209
1274
  event.target.querySelector(':first-child');
@@ -1464,8 +1529,11 @@ export default class LightningDatatable extends LightningElement {
1464
1529
 
1465
1530
  this.updateRowsAndCellIndexes(state);
1466
1531
 
1467
- if (this.viewportRendering) {
1468
- this._renderManager.updateViewportRendering(this);
1532
+ if (this.viewportRendering || state.virtualize) {
1533
+ this._renderManager.updateViewportRendering(
1534
+ this.state,
1535
+ this.gridContainer
1536
+ );
1469
1537
  }
1470
1538
 
1471
1539
  this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
@@ -1505,10 +1573,10 @@ export default class LightningDatatable extends LightningElement {
1505
1573
  setDirtyValues(state, this._draftValues);
1506
1574
  updateRowNavigationMode(hadTreeDataTypePreviously, state);
1507
1575
  state.headerIndexes = generateHeaderIndexes(getColumns(state));
1508
- // Updates state.wrapText and when isWrapableType, sets internal header actions
1576
+ // Updates state.wrapText and when isWrappableType, sets internal header actions
1509
1577
  updateHeaderActions(state);
1510
1578
  this.updateRowsAndCellIndexes(state);
1511
- updateSelectionState(state);
1579
+ updateBulkSelectionState(state);
1512
1580
  this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
1513
1581
  updateColumnWidthsMetadata(getColumns(state), widthsData);
1514
1582
  // set the celltofocus next to null if the column still exists after indexes calculation
@@ -1,25 +1,36 @@
1
- export function getErrorsState() {
2
- return {
3
- errors: {
4
- rows: {},
5
- table: {},
6
- },
7
- };
8
- }
1
+ // Default empty error state
2
+ const DEFAULT_ERROR_STATE = {
3
+ rows: {},
4
+ table: {},
5
+ };
9
6
 
7
+ /**
8
+ * Retrieves the errors object from datatable's state object
9
+ * Returns the set of row-level errors and table-level errors
10
+ */
10
11
  export function getErrors(state) {
11
12
  return state.errors;
12
13
  }
13
14
 
15
+ /**
16
+ * Sets the row-level errors and table-level errors in datatable's state object
17
+ * Errors being set here overwrite the previous error object in the state
18
+ */
14
19
  export function setErrors(state, errors) {
15
- return (state.errors = Object.assign({}, getErrorsState(), errors));
20
+ return (state.errors = Object.assign({}, DEFAULT_ERROR_STATE, errors));
16
21
  }
17
22
 
23
+ /**
24
+ * Retrieves the row-level errors of a particular row from datatable's state object
25
+ */
18
26
  export function getRowError(state, rowKey) {
19
27
  const rows = getErrors(state).rows;
20
28
  return (rows && rows[rowKey]) || {};
21
29
  }
22
30
 
31
+ /**
32
+ * Retrieves the table-level errors from the datatable's state object
33
+ */
23
34
  export function getTableError(state) {
24
35
  return getErrors(state).table || {};
25
36
  }
@@ -1,49 +1,31 @@
1
1
  import { unwrap } from 'lwc';
2
2
  import { getUserColumnIndex, getColumns } from './columns';
3
- import * as wraptext from './wrapText';
3
+ import { getActions, handleTriggeredAction } from './wrapText';
4
4
 
5
- function handleTriggeredInternalAction(dt, action, colKeyValue) {
6
- wraptext.handleTriggeredAction(dt.state, action, colKeyValue);
7
- dispatchHeaderActionEvent(dt, action, colKeyValue);
8
- }
9
-
10
- function handleTriggeredCustomerAction(dt, action, colKeyValue) {
11
- dispatchHeaderActionEvent(dt, action, colKeyValue);
12
- }
5
+ // Height of a clickable menu item
6
+ const ACTION_REM_HEIGHT = 2.125;
13
7
 
14
- function dispatchHeaderActionEvent(dt, action, colKeyValue) {
15
- const userColumnIndex = getUserColumnIndex(dt.state, colKeyValue);
16
- const customerColumnDefinition = dt.columns[userColumnIndex];
17
-
18
- dt.dispatchEvent(
19
- new CustomEvent('headeraction', {
20
- detail: {
21
- action: unwrap(action),
22
- columnDefinition: unwrap(customerColumnDefinition),
23
- },
24
- })
25
- );
26
- }
8
+ // Height of the menu divider, 1 rem + 1px (1/16px)
9
+ const DIVIDER_REM_HEIGHT = 1.0625;
27
10
 
28
- function getMenuAlignment(columns, index) {
29
- const isLastColumn = index === columns.length - 1;
30
-
31
- return isLastColumn || columns[index + 1].type === 'action'
32
- ? 'auto-right'
33
- : 'auto-left';
34
- }
11
+ /************************** PUBLIC METHODS ***************************/
35
12
 
13
+ /**
14
+ * Merges wrapText internal actions.
15
+ * If there are new internal actions in the future, they may be added here.
16
+ *
17
+ * @param {Object} state The state of the datatable
18
+ * @param {Object} columnDefinition The column definition to extract internal actions from
19
+ * @return {Array} All wrapText internal actions
20
+ */
36
21
  export function getInternalActions(state, columnDefinition) {
37
- // merge all internal actions here
38
- // currently, only wrapText internal actions
39
- // there may be new internal actions in the future
40
- return [...wraptext.getActions(state, columnDefinition)];
22
+ return [...getActions(state, columnDefinition)];
41
23
  }
42
24
 
43
25
  /**
44
26
  * Overrides the actions with the internal ones, plus the customer ones.
45
27
  *
46
- * @param {Object} state The state of the datatable.
28
+ * @param {Object} state The state of the datatable
47
29
  */
48
30
  export function updateHeaderActions(state) {
49
31
  const columns = getColumns(state);
@@ -59,31 +41,36 @@ export function updateHeaderActions(state) {
59
41
  });
60
42
  }
61
43
 
44
+ /**
45
+ * For internal actions, handles triggering the action.
46
+ * Then dispatches the header action event.
47
+ *
48
+ * @param {Event} event
49
+ */
62
50
  export function handleHeaderActionTriggered(event) {
51
+ event.stopPropagation();
52
+
63
53
  const { action, actionType, colKeyValue } = event.detail;
64
54
 
65
- event.stopPropagation();
66
- if (actionType === 'customer') {
67
- handleTriggeredCustomerAction(this, action, colKeyValue);
68
- } else {
69
- handleTriggeredInternalAction(this, action, colKeyValue);
55
+ if (actionType !== 'customer') {
56
+ handleTriggeredAction(this.state, action, colKeyValue);
70
57
  }
71
- }
72
58
 
73
- export function getColumnActionsDefaultState() {
74
- return Object.assign({}, wraptext.getDefaultState());
59
+ dispatchHeaderActionEvent(this, action, colKeyValue);
75
60
  }
76
61
 
77
- // in rem, the height of a clickable menu item
78
- const ACTION_HEIGHT = 2.125;
79
- // 1 rem + 1px (1/16px), height of the menu divider
80
- const DIVIDER_HEIGHT = 1.0625;
81
-
62
+ /**
63
+ * Calculates the size and positioning of the header action
64
+ * menu when it is opened.
65
+ *
66
+ * @param {Event} event
67
+ */
82
68
  export function handleHeaderActionMenuOpening(event) {
83
69
  event.stopPropagation();
84
70
  event.preventDefault();
85
- const actionsHeight = event.detail.actionsCount * ACTION_HEIGHT;
86
- const dividersHeight = event.detail.dividersCount * DIVIDER_HEIGHT;
71
+
72
+ const actionsHeight = event.detail.actionsCount * ACTION_REM_HEIGHT;
73
+ const dividersHeight = event.detail.dividersCount * DIVIDER_REM_HEIGHT;
87
74
  const wrapperHeight = 1;
88
75
  this._actionsMinHeightStyle = `min-height:${
89
76
  actionsHeight + dividersHeight + wrapperHeight
@@ -91,6 +78,47 @@ export function handleHeaderActionMenuOpening(event) {
91
78
  event.detail.saveContainerPosition(this.getViewableRect());
92
79
  }
93
80
 
81
+ /**
82
+ * Resets header action menu height when closed.
83
+ */
94
84
  export function handleHeaderActionMenuClosed() {
95
85
  this._actionsMinHeightStyle = '';
96
86
  }
87
+
88
+ /************************** PRIVATE METHODS ***************************/
89
+
90
+ /**
91
+ * Dispatches the `headeraction` event.
92
+ *
93
+ * @param {Object} dt The datatable
94
+ * @param {Object} action The action to dispatch
95
+ * @param {String} colKeyValue The column to dispatch the action on
96
+ */
97
+ function dispatchHeaderActionEvent(dt, action, colKeyValue) {
98
+ const userColumnIndex = getUserColumnIndex(dt.state, colKeyValue);
99
+ const customerColumnDefinition = dt.columns[userColumnIndex];
100
+
101
+ dt.dispatchEvent(
102
+ new CustomEvent('headeraction', {
103
+ detail: {
104
+ action: unwrap(action),
105
+ columnDefinition: unwrap(customerColumnDefinition),
106
+ },
107
+ })
108
+ );
109
+ }
110
+
111
+ /**
112
+ * Determines the menu alignment based on column placement.
113
+ *
114
+ * @param {Array} columns Array of all the columns
115
+ * @param {Integer} index The current column index to check
116
+ * @return {String} The computed alignment
117
+ */
118
+ function getMenuAlignment(columns, index) {
119
+ const isLastColumn = index === columns.length - 1;
120
+
121
+ return isLastColumn || columns[index + 1].type === 'action'
122
+ ? 'auto-right'
123
+ : 'auto-left';
124
+ }