lightning-base-components 1.14.3-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.
- package/metadata/raptor.json +23 -0
- package/package.json +4 -4
- package/scopedImports/@salesforce-label-LightningModalBase.cancelandclose.js +1 -0
- package/src/lightning/ariaObserver/__component__/ariaObserver.spec.js +9 -0
- package/src/lightning/ariaObserver/ariaObserver.js +24 -35
- package/src/lightning/datatable/datatable.js +44 -49
- package/src/lightning/datatable/infiniteLoading.js +100 -28
- package/src/lightning/datatable/inlineEdit.js +21 -30
- package/src/lightning/datatable/keyboard.js +161 -126
- package/src/lightning/datatable/renderManager.js +76 -120
- package/src/lightning/datatable/rows.js +4 -4
- package/src/lightning/datatable/state.js +6 -1
- package/src/lightning/datatable/templates/div/div.html +5 -0
- package/src/lightning/datatable/templates/table/table.html +5 -0
- package/src/lightning/datatable/wrapText.js +77 -47
- package/src/lightning/formattedDateTime/__docs__/formattedDateTime.md +36 -3
- package/src/lightning/formattedDateTime/__examples__/datetime/datetime.html +2 -2
- package/src/lightning/formattedDateTime/__examples__/datetime/datetime.js +3 -1
- package/src/lightning/formattedDateTime/__examples__/time/time.html +1 -1
- package/src/lightning/formattedDateTime/__examples__/time/time.js +3 -1
- package/src/lightning/formattedDateTime/formattedDateTime.js +1 -0
- package/src/lightning/input/input.html +1 -4
- package/scopedImports/@salesforce-label-LightningModalBase.close.js +0 -1
package/metadata/raptor.json
CHANGED
|
@@ -1356,6 +1356,7 @@
|
|
|
1356
1356
|
"industriesIdentityVerificationApi": {},
|
|
1357
1357
|
"industriesInterestTaggingApi": {},
|
|
1358
1358
|
"industriesLoyaltyEngineApi": {},
|
|
1359
|
+
"industriesPublicSectorApi": {},
|
|
1359
1360
|
"industriesRcgTenantmanagementApi": {},
|
|
1360
1361
|
"industriesRuleBuilderApi": {},
|
|
1361
1362
|
"industriesSustainabilityRecalculateApi": {},
|
|
@@ -3413,6 +3414,28 @@
|
|
|
3413
3414
|
"uiRelatedListApi": {
|
|
3414
3415
|
"minVersion": "53.0"
|
|
3415
3416
|
},
|
|
3417
|
+
"unstable_analyticsDataServiceApi": {},
|
|
3418
|
+
"unstable_analyticsWaveApi": {},
|
|
3419
|
+
"unstable_cmsAuthoringApi": {},
|
|
3420
|
+
"unstable_cmsDeliveryApi": {},
|
|
3421
|
+
"unstable_cmsTypeApi": {},
|
|
3422
|
+
"unstable_commerceApi": {},
|
|
3423
|
+
"unstable_communityNavigationMenuApi": {},
|
|
3424
|
+
"unstable_communityRecordSeoPropertiesApi": {},
|
|
3425
|
+
"unstable_communitySitesSearchApi": {},
|
|
3426
|
+
"unstable_experienceMarketingIntegrationApi": {},
|
|
3427
|
+
"unstable_industriesCibApi": {},
|
|
3428
|
+
"unstable_industriesDecisionMatrixDesignerApi": {},
|
|
3429
|
+
"unstable_industriesExplainabilityApi": {},
|
|
3430
|
+
"unstable_industriesHealthcloudHpiApi": {},
|
|
3431
|
+
"unstable_industriesInterestTaggingApi": {},
|
|
3432
|
+
"unstable_industriesLoyaltyEngineApi": {},
|
|
3433
|
+
"unstable_industriesPublicSectorApi": {},
|
|
3434
|
+
"unstable_industriesRcgTenantmanagementApi": {},
|
|
3435
|
+
"unstable_industriesRuleBuilderApi": {},
|
|
3436
|
+
"unstable_platformAdminSuccessGuidanceApi": {},
|
|
3437
|
+
"unstable_platformInteractionOrchestratorApi": {},
|
|
3438
|
+
"unstable_platformScaleCenterApi": {},
|
|
3416
3439
|
"unstable_uiActionsApi": {},
|
|
3417
3440
|
"unstable_uiAppsApi": {},
|
|
3418
3441
|
"unstable_uiDuplicatesApi": {},
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightning-base-components",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.4-alpha",
|
|
4
4
|
"engines": {
|
|
5
|
-
"node": ">=
|
|
5
|
+
"node": ">=14.16.0"
|
|
6
6
|
},
|
|
7
7
|
"files": [
|
|
8
8
|
"external",
|
|
@@ -958,8 +958,8 @@
|
|
|
958
958
|
"path": "scopedImports/@salesforce-label-LightningRating.nStars.js"
|
|
959
959
|
},
|
|
960
960
|
{
|
|
961
|
-
"name": "@salesforce/label/LightningModalBase.
|
|
962
|
-
"path": "scopedImports/@salesforce-label-LightningModalBase.
|
|
961
|
+
"name": "@salesforce/label/LightningModalBase.cancelandclose",
|
|
962
|
+
"path": "scopedImports/@salesforce-label-LightningModalBase.cancelandclose.js"
|
|
963
963
|
},
|
|
964
964
|
{
|
|
965
965
|
"name": "@salesforce/label/LightningModalBase.waitstate",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'Cancel and close';
|
|
@@ -47,6 +47,15 @@ describe('AriaObserver', () => {
|
|
|
47
47
|
expect(testElement.labelContent).toEqual('Foo\nBar');
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
+
it('should work with label ids appearing in the opposite of document order', async () => {
|
|
51
|
+
const container = createTestElement();
|
|
52
|
+
container.updateAriaLabelledby('alt-label-id id-label');
|
|
53
|
+
await Promise.resolve();
|
|
54
|
+
|
|
55
|
+
const testElement = container.testElement;
|
|
56
|
+
expect(testElement.labelContent).toEqual('Bar\nFoo');
|
|
57
|
+
});
|
|
58
|
+
|
|
50
59
|
it('should update the internal label content when external content changes', async () => {
|
|
51
60
|
const container = createTestElement();
|
|
52
61
|
container.updateLabelContent();
|
|
@@ -13,11 +13,13 @@ function getAttr(elm, attr) {
|
|
|
13
13
|
return elm.getAttribute(attr);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
function extractElements(root,
|
|
17
|
-
if (typeof
|
|
16
|
+
function extractElements(root, ids) {
|
|
17
|
+
if (typeof ids !== 'string' || ids === '') {
|
|
18
18
|
return [];
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
// We must query the elements in the order of ids, so that
|
|
21
|
+
// the content will be extracted in the correct order.
|
|
22
|
+
return splitIds(ids).map((id) => root.querySelector(`#${id}`));
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
function extractContent(elements) {
|
|
@@ -113,38 +115,28 @@ export default class AriaObserver {
|
|
|
113
115
|
connect({ targetSelector, attribute, id, ids }) {
|
|
114
116
|
ids = ids || id;
|
|
115
117
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
attrState.ids = ids;
|
|
118
|
+
this.state[attribute] = this.state[attribute] || {};
|
|
119
|
+
const attrState = this.state[attribute];
|
|
120
|
+
|
|
121
|
+
// note: we don't support linking to a different targetSelector
|
|
122
|
+
attrState.innerSelector = attrState.innerSelector || targetSelector;
|
|
123
|
+
|
|
124
|
+
// removing the old ids if possible before setting the new ones
|
|
125
|
+
if (!this.isNative && attrState.ids) {
|
|
126
|
+
const elm = this.template.querySelector(attrState.innerSelector);
|
|
127
|
+
if (elm) {
|
|
128
|
+
removeAriaRefWhenPossible(elm, attribute, attrState.ids);
|
|
128
129
|
}
|
|
129
|
-
} else {
|
|
130
|
-
attrState = this.state[attribute] = {
|
|
131
|
-
ids,
|
|
132
|
-
innerSelector: targetSelector,
|
|
133
|
-
};
|
|
134
130
|
}
|
|
135
|
-
if (this.isNative) {
|
|
136
|
-
attrState.outerSelector = (ids + '')
|
|
137
|
-
.trim()
|
|
138
|
-
.split(/\s+/)
|
|
139
|
-
.map((ref) => `#${ref}`)
|
|
140
|
-
.join(',');
|
|
141
131
|
|
|
132
|
+
attrState.ids = ids;
|
|
133
|
+
|
|
134
|
+
if (this.isNative && !attrState.placeholder) {
|
|
142
135
|
// create placeholder element for copied content
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
attrState.placeholder.id = `auto-link-${attribute}-${this.guid}`;
|
|
146
|
-
}
|
|
136
|
+
attrState.placeholder = document.createElement('span');
|
|
137
|
+
attrState.placeholder.id = `auto-link-${attribute}-${this.guid}`;
|
|
147
138
|
}
|
|
139
|
+
|
|
148
140
|
if (this.component.isConnected) {
|
|
149
141
|
this.privateUpdate(attribute);
|
|
150
142
|
}
|
|
@@ -213,12 +205,9 @@ export default class AriaObserver {
|
|
|
213
205
|
}
|
|
214
206
|
let computedIds;
|
|
215
207
|
if (this.isNative) {
|
|
216
|
-
const {
|
|
217
|
-
this.state[attrName];
|
|
208
|
+
const { ids, content, placeholder } = this.state[attrName];
|
|
218
209
|
|
|
219
|
-
const newContent = extractContent(
|
|
220
|
-
extractElements(this.root, outerSelector)
|
|
221
|
-
);
|
|
210
|
+
const newContent = extractContent(extractElements(this.root, ids));
|
|
222
211
|
if (content !== newContent) {
|
|
223
212
|
this.state[attrName].content = placeholder.textContent =
|
|
224
213
|
newContent;
|
|
@@ -81,6 +81,8 @@ import {
|
|
|
81
81
|
addFocusStylesToActiveCell,
|
|
82
82
|
refocusCellElement,
|
|
83
83
|
isCellElement,
|
|
84
|
+
getActiveCellElement,
|
|
85
|
+
FOCUS_CLASS,
|
|
84
86
|
} from './keyboard';
|
|
85
87
|
import {
|
|
86
88
|
getRowNumberOffset,
|
|
@@ -135,11 +137,9 @@ import {
|
|
|
135
137
|
import {
|
|
136
138
|
isViewportRenderingEnabled,
|
|
137
139
|
setViewportRendering,
|
|
138
|
-
getDTRows,
|
|
139
|
-
getDTRenderedRowCount,
|
|
140
|
-
setDTRenderedRowCount,
|
|
141
140
|
getDTWrapperHeight,
|
|
142
|
-
|
|
141
|
+
setFirstVisibleIndex,
|
|
142
|
+
setVirtualize,
|
|
143
143
|
RenderManager,
|
|
144
144
|
DEFAULT_ROW_HEIGHT,
|
|
145
145
|
} from './renderManager';
|
|
@@ -200,14 +200,11 @@ export default class LightningDatatable extends LightningElement {
|
|
|
200
200
|
_customerSelectedRows = null;
|
|
201
201
|
_datatableId = generateUniqueId('lgt-datatable');
|
|
202
202
|
_draftValues = [];
|
|
203
|
-
_firstVisibleIndex = 0; // first row that should be visible in viewport, used for virtualization
|
|
204
203
|
_isResizing = false; // Whether resizing is in progress
|
|
205
204
|
_privateTypes = {};
|
|
206
205
|
_privateWidthObserver = null; // Instance of LightningDatatableResizeObserver
|
|
207
206
|
_renderMode = 'table';
|
|
208
|
-
_renderedRowCount = 0;
|
|
209
207
|
_suppressBottomBar = false;
|
|
210
|
-
_virtualize = '';
|
|
211
208
|
|
|
212
209
|
/************************* PUBLIC PROPERTIES *************************/
|
|
213
210
|
|
|
@@ -519,24 +516,17 @@ export default class LightningDatatable extends LightningElement {
|
|
|
519
516
|
|
|
520
517
|
set renderConfig(value) {
|
|
521
518
|
if (typeof value === 'object' && !isIE11) {
|
|
522
|
-
|
|
523
|
-
setViewportRendering(this.state, viewportRendering);
|
|
524
|
-
if (this.state.renderModeRoleBased) {
|
|
525
|
-
this._virtualize = normalizeVirtualization(virtualize);
|
|
526
|
-
}
|
|
519
|
+
setViewportRendering(this.state, value.viewportRendering);
|
|
527
520
|
|
|
528
521
|
this._renderManager.configure(
|
|
529
|
-
this.
|
|
522
|
+
this.state,
|
|
530
523
|
this.getWrapperHeight,
|
|
531
|
-
this.getRenderedRowCount,
|
|
532
|
-
this.setRenderedRowCount,
|
|
533
524
|
value
|
|
534
525
|
);
|
|
535
526
|
// if renderConfig already exists, update rendering
|
|
536
527
|
if (this._renderConfig) {
|
|
537
528
|
this._renderManager.updateViewportRendering(
|
|
538
|
-
this.state
|
|
539
|
-
this.setRenderedRowCount,
|
|
529
|
+
this.state,
|
|
540
530
|
this.gridContainer,
|
|
541
531
|
true
|
|
542
532
|
);
|
|
@@ -565,6 +555,9 @@ export default class LightningDatatable extends LightningElement {
|
|
|
565
555
|
validValues: ['default', 'role-based'],
|
|
566
556
|
});
|
|
567
557
|
this.state.renderModeRoleBased = this._renderMode === 'role-based';
|
|
558
|
+
if (this._renderConfig) {
|
|
559
|
+
setVirtualize(this.state, this._renderConfig.virtualize);
|
|
560
|
+
}
|
|
568
561
|
updateCellClassForRoleBasedMode(this.state);
|
|
569
562
|
}
|
|
570
563
|
|
|
@@ -804,16 +797,20 @@ export default class LightningDatatable extends LightningElement {
|
|
|
804
797
|
*/
|
|
805
798
|
get computedTbodyStyle() {
|
|
806
799
|
const style = [];
|
|
800
|
+
const { firstVisibleIndex, bufferSize, virtualize, rows } = this.state;
|
|
807
801
|
if (
|
|
808
802
|
hasRowNumberColumn(this.state) &&
|
|
809
803
|
getRowNumberOffset(this.state) >= 0
|
|
810
804
|
) {
|
|
811
|
-
|
|
812
|
-
|
|
805
|
+
const firstRenderedRow = Math.max(
|
|
806
|
+
firstVisibleIndex - bufferSize,
|
|
807
|
+
0
|
|
813
808
|
);
|
|
809
|
+
const rowNumber = firstRenderedRow + getRowNumberOffset(this.state);
|
|
810
|
+
style.push(`counter-reset: row-number ${rowNumber}`);
|
|
814
811
|
}
|
|
815
|
-
if (
|
|
816
|
-
const length =
|
|
812
|
+
if (virtualize) {
|
|
813
|
+
const length = rows.length;
|
|
817
814
|
style.push(
|
|
818
815
|
'position: relative',
|
|
819
816
|
`height:${length * DEFAULT_ROW_HEIGHT}px`
|
|
@@ -938,18 +935,16 @@ export default class LightningDatatable extends LightningElement {
|
|
|
938
935
|
}
|
|
939
936
|
|
|
940
937
|
get renderedRows() {
|
|
941
|
-
|
|
938
|
+
const { virtualize, rows, renderedRowCount } = this.state;
|
|
939
|
+
if (virtualize) {
|
|
942
940
|
const { firstIndex, lastIndex } =
|
|
943
|
-
this._renderManager.getRenderedRange(
|
|
944
|
-
|
|
945
|
-
this._renderedRowCount
|
|
946
|
-
);
|
|
947
|
-
return this.state.rows.slice(firstIndex, lastIndex);
|
|
941
|
+
this._renderManager.getRenderedRange(this.state);
|
|
942
|
+
return rows.slice(firstIndex, lastIndex);
|
|
948
943
|
}
|
|
949
944
|
if (this.viewportRendering && !isIE11) {
|
|
950
|
-
return
|
|
945
|
+
return rows.slice(0, renderedRowCount);
|
|
951
946
|
}
|
|
952
|
-
return
|
|
947
|
+
return rows;
|
|
953
948
|
}
|
|
954
949
|
|
|
955
950
|
get showSelectAllCheckbox() {
|
|
@@ -985,9 +980,6 @@ export default class LightningDatatable extends LightningElement {
|
|
|
985
980
|
this.updateRowsAndCellIndexes = updateRowsAndCellIndexes.bind(this);
|
|
986
981
|
|
|
987
982
|
this._renderManager = new RenderManager();
|
|
988
|
-
this.getRenderedRowCount = getDTRenderedRowCount.bind(this);
|
|
989
|
-
this.setRenderedRowCount = setDTRenderedRowCount.bind(this);
|
|
990
|
-
this.getRows = getDTRows.bind(this);
|
|
991
983
|
this.getWrapperHeight = getDTWrapperHeight.bind(this);
|
|
992
984
|
}
|
|
993
985
|
|
|
@@ -1147,8 +1139,19 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1147
1139
|
this._customerSelectedRows = null;
|
|
1148
1140
|
// set the previous focused cell to null after render is done
|
|
1149
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
|
+
}
|
|
1150
1153
|
|
|
1151
|
-
if (this.viewportRendering ||
|
|
1154
|
+
if (this.viewportRendering || state.virtualize) {
|
|
1152
1155
|
const resizeTarget = this.template.querySelector(
|
|
1153
1156
|
'div.dt-outer-container'
|
|
1154
1157
|
);
|
|
@@ -1159,10 +1162,9 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1159
1162
|
// Reset the row count if we already had one before updating the wrapper height.
|
|
1160
1163
|
// This can happen if the number of rows was calculated before the datatable
|
|
1161
1164
|
// was rendered.
|
|
1162
|
-
if (this.
|
|
1165
|
+
if (this.state.renderedRowCount) {
|
|
1163
1166
|
this._renderManager.updateViewportRendering(
|
|
1164
|
-
this.state
|
|
1165
|
-
this.setRenderedRowCount,
|
|
1167
|
+
this.state,
|
|
1166
1168
|
this.gridContainer,
|
|
1167
1169
|
true
|
|
1168
1170
|
);
|
|
@@ -1248,16 +1250,10 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1248
1250
|
}
|
|
1249
1251
|
|
|
1250
1252
|
handleInlineEditPanelScroll.call(this, event);
|
|
1251
|
-
if (this.
|
|
1252
|
-
this.
|
|
1253
|
-
this._renderManager.getFirstVisibleIndex(event);
|
|
1253
|
+
if (this.state.virtualize) {
|
|
1254
|
+
setFirstVisibleIndex(this.state, event.target.scrollTop);
|
|
1254
1255
|
} else if (this.viewportRendering) {
|
|
1255
|
-
this._renderManager.handleScroll(
|
|
1256
|
-
this.state.rows,
|
|
1257
|
-
this._renderedRowCount,
|
|
1258
|
-
this.setRenderedRowCount,
|
|
1259
|
-
event
|
|
1260
|
-
);
|
|
1256
|
+
this._renderManager.handleScroll(this.state, event);
|
|
1261
1257
|
}
|
|
1262
1258
|
}
|
|
1263
1259
|
|
|
@@ -1533,10 +1529,9 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1533
1529
|
|
|
1534
1530
|
this.updateRowsAndCellIndexes(state);
|
|
1535
1531
|
|
|
1536
|
-
if (this.viewportRendering ||
|
|
1532
|
+
if (this.viewportRendering || state.virtualize) {
|
|
1537
1533
|
this._renderManager.updateViewportRendering(
|
|
1538
|
-
this.state
|
|
1539
|
-
this.setRenderedRowCount,
|
|
1534
|
+
this.state,
|
|
1540
1535
|
this.gridContainer
|
|
1541
1536
|
);
|
|
1542
1537
|
}
|
|
@@ -1578,7 +1573,7 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1578
1573
|
setDirtyValues(state, this._draftValues);
|
|
1579
1574
|
updateRowNavigationMode(hadTreeDataTypePreviously, state);
|
|
1580
1575
|
state.headerIndexes = generateHeaderIndexes(getColumns(state));
|
|
1581
|
-
// Updates state.wrapText and when
|
|
1576
|
+
// Updates state.wrapText and when isWrappableType, sets internal header actions
|
|
1582
1577
|
updateHeaderActions(state);
|
|
1583
1578
|
this.updateRowsAndCellIndexes(state);
|
|
1584
1579
|
updateBulkSelectionState(state);
|
|
@@ -1,34 +1,67 @@
|
|
|
1
1
|
import { normalizeBoolean } from 'lightning/utilsPrivate';
|
|
2
2
|
import { getScrollOffsetFromTableEnd, isNonNegativeInteger } from './utils';
|
|
3
3
|
|
|
4
|
-
const SCROLLABLE_CONTAINER_SEL = '.slds-scrollable_y';
|
|
5
4
|
const SCROLL_ALLOWANCE = 2;
|
|
5
|
+
export const DEFAULT_LOAD_MORE_OFFSET = 20;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
enableInfiniteLoading: false,
|
|
10
|
-
loadMoreOffset: 20,
|
|
11
|
-
isLoading: false,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
7
|
+
/*********************** STATE MANAGEMENT ************************/
|
|
14
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Returns whether the datatable is in a loading state
|
|
11
|
+
*
|
|
12
|
+
* @param {Object} state The datatable state object
|
|
13
|
+
* @returns {Boolean} The loading state
|
|
14
|
+
*/
|
|
15
15
|
export function isLoading(state) {
|
|
16
16
|
return state.isLoading;
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Sets the loading state of the datatable
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} state The datatable state object
|
|
23
|
+
* @param {Boolean} value The loading state to set
|
|
24
|
+
*/
|
|
18
25
|
export function setLoading(state, value) {
|
|
19
26
|
state.isLoading = normalizeBoolean(value);
|
|
20
27
|
}
|
|
21
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Returns whether infinite loading is enabled on the datatable
|
|
31
|
+
*
|
|
32
|
+
* @param {Object} state The datatable state object
|
|
33
|
+
* @returns {Boolean} The infinite loading state
|
|
34
|
+
*/
|
|
22
35
|
export function isInfiniteLoadingEnabled(state) {
|
|
23
36
|
return state.enableInfiniteLoading;
|
|
24
37
|
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Sets the infinite loading option on the datatable
|
|
41
|
+
*
|
|
42
|
+
* @param {Object} state The datatable state object
|
|
43
|
+
* @param {Boolean} value The infinite loading state to set
|
|
44
|
+
*/
|
|
25
45
|
export function setInfiniteLoading(state, value) {
|
|
26
46
|
state.enableInfiniteLoading = normalizeBoolean(value);
|
|
27
47
|
}
|
|
28
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Returns the load more offset
|
|
51
|
+
*
|
|
52
|
+
* @param {Object} state The datatable state object
|
|
53
|
+
* @returns {Number} The currently configured load more offset value
|
|
54
|
+
*/
|
|
29
55
|
export function getLoadMoreOffset(state) {
|
|
30
56
|
return state.loadMoreOffset;
|
|
31
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Sets the load more offset value. Must be a number >= 0.
|
|
61
|
+
*
|
|
62
|
+
* @param {Object} state The datatable state object
|
|
63
|
+
* @param {Boolean} value The load more offset value to set
|
|
64
|
+
*/
|
|
32
65
|
export function setLoadMoreOffset(state, value) {
|
|
33
66
|
if (!isNonNegativeInteger(value)) {
|
|
34
67
|
// eslint-disable-next-line no-console
|
|
@@ -40,9 +73,17 @@ export function setLoadMoreOffset(state, value) {
|
|
|
40
73
|
|
|
41
74
|
state.loadMoreOffset = isNonNegativeInteger(value)
|
|
42
75
|
? parseInt(value, 10)
|
|
43
|
-
:
|
|
76
|
+
: DEFAULT_LOAD_MORE_OFFSET;
|
|
44
77
|
}
|
|
45
78
|
|
|
79
|
+
/************************** PUBLIC METHODS ***************************/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Checks whether the datatable should begin loading more content
|
|
83
|
+
* and then dispatches the `loadmore` event indicating that directive.
|
|
84
|
+
*
|
|
85
|
+
* @param {Event} event
|
|
86
|
+
*/
|
|
46
87
|
export function handleLoadMoreCheck(event) {
|
|
47
88
|
if (isLoading(this.state)) {
|
|
48
89
|
return;
|
|
@@ -60,24 +101,13 @@ export function handleLoadMoreCheck(event) {
|
|
|
60
101
|
}
|
|
61
102
|
}
|
|
62
103
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
function isScrollerVisible(elem) {
|
|
72
|
-
return (
|
|
73
|
-
elem && !!(elem.offsetParent || elem.offsetHeight || elem.offsetWidth)
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function hasData(root) {
|
|
78
|
-
return root.querySelectorAll('tbody > tr').length > 0;
|
|
79
|
-
}
|
|
80
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Determines whether or not to prefetch data. If so,
|
|
106
|
+
* dispatches the `loadmore` event.
|
|
107
|
+
*
|
|
108
|
+
* @param {Object} root The datatable
|
|
109
|
+
* @param {Object} state The datatable state object
|
|
110
|
+
*/
|
|
81
111
|
export function handlePrefetch(root, state) {
|
|
82
112
|
if (
|
|
83
113
|
!isInfiniteLoadingEnabled(state) ||
|
|
@@ -91,9 +121,51 @@ export function handlePrefetch(root, state) {
|
|
|
91
121
|
return;
|
|
92
122
|
}
|
|
93
123
|
|
|
94
|
-
const elem = root.querySelector(
|
|
124
|
+
const elem = root.querySelector('.slds-scrollable_y');
|
|
95
125
|
|
|
96
126
|
if (isScrollerVisible(elem) && !isScrollable(elem)) {
|
|
97
127
|
this.dispatchEvent(new CustomEvent('loadmore'));
|
|
98
128
|
}
|
|
99
129
|
}
|
|
130
|
+
|
|
131
|
+
/************************** PRIVATE METHODS ***************************/
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Determines if a DOM element is scrollable
|
|
135
|
+
*
|
|
136
|
+
* @param {Element} element The DOM element to check
|
|
137
|
+
* @returns {Boolean} Whether or not the element is scrollable
|
|
138
|
+
*/
|
|
139
|
+
function isScrollable(element) {
|
|
140
|
+
// scrollHeight should be greater than clientHeight by some allowance
|
|
141
|
+
return (
|
|
142
|
+
element &&
|
|
143
|
+
element.scrollHeight > element.clientHeight + SCROLL_ALLOWANCE
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Determines if a DOM element's scroll bars are visible
|
|
149
|
+
*
|
|
150
|
+
* @param {Element} element The DOM element to check
|
|
151
|
+
* @returns {Boolean} Whether or not the element's scroll bars are visible
|
|
152
|
+
*/
|
|
153
|
+
function isScrollerVisible(element) {
|
|
154
|
+
return (
|
|
155
|
+
element &&
|
|
156
|
+
!!(element.offsetParent || element.offsetHeight || element.offsetWidth)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Determines if a root element has data
|
|
162
|
+
*
|
|
163
|
+
* @param {Element} root The parent element to check
|
|
164
|
+
* @returns {Boolean} Whether or not the element contains any data
|
|
165
|
+
*/
|
|
166
|
+
function hasData(root) {
|
|
167
|
+
return (
|
|
168
|
+
root.querySelectorAll('tbody > tr, [role="rowgroup"] > [role="row"]')
|
|
169
|
+
.length > 0
|
|
170
|
+
);
|
|
171
|
+
}
|
|
@@ -8,14 +8,16 @@ import {
|
|
|
8
8
|
reactToTabBackward,
|
|
9
9
|
reactToTabForward,
|
|
10
10
|
getActiveCellElement,
|
|
11
|
-
getCellElementByIndexes,
|
|
12
11
|
updateActiveCell,
|
|
12
|
+
isActiveCellEditable,
|
|
13
|
+
isValidCell,
|
|
13
14
|
} from './keyboard';
|
|
14
15
|
import {
|
|
15
16
|
updateRowsAndCellIndexes,
|
|
16
17
|
getRowByKey,
|
|
17
18
|
getKeyField,
|
|
18
19
|
getUserRowByCellKeys,
|
|
20
|
+
isCellEditable,
|
|
19
21
|
} from './rows';
|
|
20
22
|
import {
|
|
21
23
|
getColumnIndexByColumnKey,
|
|
@@ -315,6 +317,11 @@ function openInlineEdit(dt, target) {
|
|
|
315
317
|
|
|
316
318
|
const { rowKeyValue, colKeyValue } = target;
|
|
317
319
|
|
|
320
|
+
// ensure that focus remains on inline edit panel instead of active cell
|
|
321
|
+
if (state.activeCell) {
|
|
322
|
+
state.activeCell.focused = false;
|
|
323
|
+
}
|
|
324
|
+
|
|
318
325
|
inlineEdit.isPanelVisible = true;
|
|
319
326
|
inlineEdit.rowKeyValue = rowKeyValue;
|
|
320
327
|
inlineEdit.colKeyValue = colKeyValue;
|
|
@@ -378,11 +385,7 @@ function openInlineEdit(dt, target) {
|
|
|
378
385
|
export function openInlineEditOnActiveCell(dt) {
|
|
379
386
|
const hasData = dt.state.data && dt.state.data.length > 0;
|
|
380
387
|
if (hasData) {
|
|
381
|
-
|
|
382
|
-
const isEditable = activeCellElement.editable;
|
|
383
|
-
if (isEditable) {
|
|
384
|
-
setFocusAndOpenInlineEdit(dt, activeCellElement);
|
|
385
|
-
} else {
|
|
388
|
+
if (!isActiveCellEditable(dt.state)) {
|
|
386
389
|
const firstEditableCell = getFirstEditableCell(dt);
|
|
387
390
|
if (firstEditableCell) {
|
|
388
391
|
updateActiveCell(
|
|
@@ -390,8 +393,10 @@ export function openInlineEditOnActiveCell(dt) {
|
|
|
390
393
|
firstEditableCell.rowKeyValue,
|
|
391
394
|
firstEditableCell.colKeyValue
|
|
392
395
|
);
|
|
393
|
-
setFocusAndOpenInlineEdit(dt,
|
|
396
|
+
setFocusAndOpenInlineEdit(dt, dt.state.activeCell);
|
|
394
397
|
}
|
|
398
|
+
} else {
|
|
399
|
+
setFocusAndOpenInlineEdit(dt, dt.state.activeCell);
|
|
395
400
|
}
|
|
396
401
|
}
|
|
397
402
|
}
|
|
@@ -400,11 +405,11 @@ export function openInlineEditOnActiveCell(dt) {
|
|
|
400
405
|
* Async function to await setting focus on an editable cell before opening inline-edit panel
|
|
401
406
|
*
|
|
402
407
|
* @param {Object} dt - The datatable instance
|
|
403
|
-
* @param {Object} cell - editable cell to be focused before open inline-edit panel
|
|
404
408
|
*/
|
|
405
409
|
// eslint-disable-next-line @lwc/lwc/no-async-await
|
|
406
|
-
async function setFocusAndOpenInlineEdit(dt
|
|
410
|
+
async function setFocusAndOpenInlineEdit(dt) {
|
|
407
411
|
await setFocusActiveCell(dt.template, dt.state, 0);
|
|
412
|
+
const cell = getActiveCellElement(dt.template, dt.state);
|
|
408
413
|
openInlineEdit(dt, cell);
|
|
409
414
|
}
|
|
410
415
|
|
|
@@ -716,8 +721,8 @@ function resolveNestedTypeAttributesHelper(rowData, typeAttributesValue) {
|
|
|
716
721
|
/************************** HELPER FUNCTIONS **************************/
|
|
717
722
|
|
|
718
723
|
/**
|
|
719
|
-
* Returns
|
|
720
|
-
* then undefined is returned.
|
|
724
|
+
* Returns the row and column keys of the first editable cell in the table.
|
|
725
|
+
* If no editable cells exist in the table then undefined is returned.
|
|
721
726
|
*
|
|
722
727
|
* @param {Object} dt - The datatable instance. Must be a truthy and valid datatable reference.
|
|
723
728
|
*/
|
|
@@ -732,18 +737,11 @@ function getFirstEditableCell(dt) {
|
|
|
732
737
|
// Loop through the editable columns in order and examine the corresponding cells
|
|
733
738
|
// in the current row for editability, returning the first such cell that is editable
|
|
734
739
|
const editableColumn = editableColumns[i];
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
dt.template,
|
|
741
|
-
rowIndex,
|
|
742
|
-
editableColumnIndex,
|
|
743
|
-
dt.state
|
|
744
|
-
);
|
|
745
|
-
if (cell.editable) {
|
|
746
|
-
return cell;
|
|
740
|
+
if (isCellEditable(rows[rowIndex], editableColumn)) {
|
|
741
|
+
return {
|
|
742
|
+
rowKeyValue: rows[rowIndex].key,
|
|
743
|
+
colKeyValue: editableColumn.colKeyValue,
|
|
744
|
+
};
|
|
747
745
|
}
|
|
748
746
|
}
|
|
749
747
|
}
|
|
@@ -768,13 +766,6 @@ function getCellValue(state, rowKeyValue, colKeyValue) {
|
|
|
768
766
|
return row.cells[colIndex].value;
|
|
769
767
|
}
|
|
770
768
|
|
|
771
|
-
function isValidCell(state, rowKeyValue, colKeyValue) {
|
|
772
|
-
const row = getRowByKey(state, rowKeyValue);
|
|
773
|
-
const colIndex = getStateColumnIndex(state, colKeyValue);
|
|
774
|
-
|
|
775
|
-
return row && row.cells[colIndex];
|
|
776
|
-
}
|
|
777
|
-
|
|
778
769
|
/**
|
|
779
770
|
* Sets `aria-selected` to true on cells whose rows are selected
|
|
780
771
|
* and are in the same column as the cell being currently edited
|