lightning-base-components 1.15.1-alpha → 1.15.2-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 +27 -2
- package/package.json +6 -2
- package/scopedImports/@salesforce-label-LightningMap.defaultTitle.js +1 -0
- package/src/lightning/alert/__docs__/alert.md +0 -2
- package/src/lightning/baseCombobox/baseCombobox.html +2 -1
- package/src/lightning/baseCombobox/baseCombobox.js +41 -6
- package/src/lightning/button/button.js +22 -1
- package/src/lightning/checkboxGroup/checkboxGroup.html +2 -2
- package/src/lightning/checkboxGroup/checkboxGroup.js +9 -5
- package/src/lightning/combobox/__docs__/combobox.md +3 -1
- package/src/lightning/combobox/combobox.js +0 -1
- package/src/lightning/confirm/__docs__/confirm.md +0 -2
- package/src/lightning/datatable/__docs__/datatable.md +45 -0
- package/src/lightning/datatable/__wdio__/utam/utam.html +15 -0
- package/src/lightning/datatable/__wdio__/utam/utam.spec.js +208 -183
- package/src/lightning/datatable/datatable.js +12 -7
- package/src/lightning/datatable/inlineEdit.js +0 -5
- package/src/lightning/datatable/inlineEditShared.js +4 -2
- package/src/lightning/datatable/keyboard.js +7 -3
- package/src/lightning/datatable/rowSelection.js +8 -2
- package/src/lightning/datatable/state.js +1 -0
- package/src/lightning/datatable/templates/table/table.html +2 -2
- package/src/lightning/datatable/wrapText.js +1 -0
- package/src/lightning/datepicker/datepicker.html +1 -0
- package/src/lightning/datepicker/datepicker.js +10 -0
- package/src/lightning/datetimepicker/datetimepicker.html +2 -0
- package/src/lightning/datetimepicker/datetimepicker.js +8 -0
- package/src/lightning/dualListbox/dualListbox.js +2 -1
- package/src/lightning/formattedAddress/__docs__/formattedAddress.md +3 -0
- package/src/lightning/formattedAddress/__examples__/customLocale/customLocale.html +22 -0
- package/src/lightning/formattedAddress/__examples__/customLocale/customLocale.js +3 -0
- package/src/lightning/formattedAddress/formattedAddress.js +7 -1
- package/src/lightning/groupedCombobox/groupedCombobox.html +2 -1
- package/src/lightning/groupedCombobox/groupedCombobox.js +16 -2
- package/src/lightning/input/input.html +6 -0
- package/src/lightning/input/input.js +2 -1
- package/src/lightning/inputAddress/__docs__/inputAddress.md +5 -0
- package/src/lightning/inputAddress/__examples__/customLocale/customLocale.html +12 -0
- package/src/lightning/inputAddress/__examples__/customLocale/customLocale.js +3 -0
- package/src/lightning/inputAddress/inputAddress.html +2 -0
- package/src/lightning/inputAddress/inputAddress.js +26 -3
- package/src/lightning/inputName/__docs__/inputName.md +2 -0
- package/src/lightning/inputName/inputName.html +4 -1
- package/src/lightning/inputUtils/inputUtils.js +11 -0
- package/src/lightning/picklist/picklist.js +6 -1
- package/src/lightning/prompt/__docs__/prompt.md +0 -2
- package/src/lightning/radioGroup/radioGroup.js +9 -0
- package/src/lightning/select/select.html +3 -1
- package/src/lightning/select/select.js +5 -1
- package/src/lightning/textarea/textarea.html +1 -0
- package/src/lightning/textarea/textarea.js +5 -0
- package/src/lightning/timepicker/timepicker.html +3 -1
- package/src/lightning/timepicker/timepicker.js +8 -0
- package/src/lightning/utilsPrivate/aria.js +26 -0
- package/src/lightning/utilsPrivate/linkify.js +1 -1
- package/src/lightning/utilsPrivate/utilsPrivate.js +7 -1
- package/src/lightning/icon/__component__/icon-spirite.spec.js +0 -59
|
@@ -1,189 +1,214 @@
|
|
|
1
1
|
const Datatable = require('pageobjects/datatable');
|
|
2
2
|
const Button = require('pageobjects/button');
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
4
|
+
const tableTypes = {
|
|
5
|
+
default: '[data-render-mode="default"]',
|
|
6
|
+
roleBased: '[data-render-mode="role-based"]',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
describe('Datatable UTAM Page Object Tests', () => {
|
|
10
|
+
Object.keys(tableTypes).forEach((type) => {
|
|
11
|
+
describe(`${type} table`, () => {
|
|
12
|
+
const TABLE_SELECTOR = tableTypes[type];
|
|
13
|
+
|
|
14
|
+
let root;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
await browser.url('/datatable/utam');
|
|
18
|
+
root = await $('datatable-utam');
|
|
19
|
+
await root.waitForDisplayed();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should get the cell value by row and column index', async () => {
|
|
23
|
+
const datatable = await utam.load(Datatable, {
|
|
24
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const cellValue = await datatable.getCellValueByIndex(1, 2);
|
|
28
|
+
expect(cellValue).toBe('Billy Simmons');
|
|
29
|
+
});
|
|
30
|
+
it('should get the cell value by row index and column label', async () => {
|
|
31
|
+
const datatable = await utam.load(Datatable, {
|
|
32
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const cellValue = await datatable.getCellValueByLabel(2, 'Age');
|
|
36
|
+
expect(cellValue).toBe('35');
|
|
37
|
+
});
|
|
38
|
+
it('should get the number of rows in the table', async () => {
|
|
39
|
+
const datatable = await utam.load(Datatable, {
|
|
40
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const cellValue = await datatable.getNumRows();
|
|
44
|
+
expect(cellValue).toBe(4);
|
|
45
|
+
});
|
|
46
|
+
it('should tell if the table has any rows', async () => {
|
|
47
|
+
const datatable = await utam.load(Datatable, {
|
|
48
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const cellValue = await datatable.hasRows();
|
|
52
|
+
expect(cellValue).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
it('should toggle selection of row - comprehensive', async () => {
|
|
55
|
+
const datatable = await utam.load(Datatable, {
|
|
56
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
for (let i = 1; i <= 4; i++) {
|
|
60
|
+
expect(await datatable.isRowSelected(i)).toBe('false');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await datatable.toggleRowSelection(1);
|
|
64
|
+
expect(await datatable.isRowSelected(1)).toBe('true');
|
|
65
|
+
[2, 3, 4].forEach(async (i) => {
|
|
66
|
+
expect(await datatable.isRowSelected(i)).toBe('false');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
await datatable.toggleRowSelection(2);
|
|
70
|
+
expect(await datatable.isRowSelected(2)).toBe('true');
|
|
71
|
+
[3, 4].forEach(async (i) => {
|
|
72
|
+
expect(await datatable.isRowSelected(i)).toBe('false');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await datatable.toggleRowSelection(3);
|
|
76
|
+
expect(await datatable.isRowSelected(3)).toBe('true');
|
|
77
|
+
expect(await datatable.isRowSelected(4)).toBe('false');
|
|
78
|
+
|
|
79
|
+
await datatable.toggleRowSelection(4);
|
|
80
|
+
expect(await datatable.isRowSelected(4)).toBe('true');
|
|
81
|
+
});
|
|
82
|
+
it('should toggle selection of row', async () => {
|
|
83
|
+
const datatable = await utam.load(Datatable, {
|
|
84
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await datatable.toggleRowSelection(3);
|
|
88
|
+
expect(await datatable.isRowSelected(3)).toBe('true');
|
|
89
|
+
|
|
90
|
+
await datatable.toggleRowSelection(3);
|
|
91
|
+
expect(await datatable.isRowSelected(3)).toBe('false');
|
|
92
|
+
});
|
|
93
|
+
it('should get the number of selected rows when not all rows are selected', async () => {
|
|
94
|
+
const datatable = await utam.load(Datatable, {
|
|
95
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await datatable.toggleRowSelection(3);
|
|
99
|
+
expect(await datatable.getNumSelectedRows()).toBe(1);
|
|
100
|
+
|
|
101
|
+
await datatable.toggleRowSelection(2);
|
|
102
|
+
expect(await datatable.getNumSelectedRows()).toBe(2);
|
|
103
|
+
});
|
|
104
|
+
it('should get the number of selected rows when all rows are selected', async () => {
|
|
105
|
+
const datatable = await utam.load(Datatable, {
|
|
106
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
await datatable.clickSelectAllCheckbox();
|
|
110
|
+
expect(await datatable.getNumSelectedRows()).toBe(4);
|
|
111
|
+
});
|
|
112
|
+
it('should get the number of columns in the table', async () => {
|
|
113
|
+
const datatable = await utam.load(Datatable, {
|
|
114
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
expect(await datatable.getNumColumns()).toBe(5);
|
|
118
|
+
});
|
|
119
|
+
it('should tell whether or not a column is sortable', async () => {
|
|
120
|
+
const datatable = await utam.load(Datatable, {
|
|
121
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
expect(await datatable.isSortableColumn('Age')).toBe(true);
|
|
125
|
+
|
|
126
|
+
// Need to speak to UTAM (about isPresent) or find a better way to write this method
|
|
127
|
+
// If column is not sortable, the test fails with the error:
|
|
128
|
+
// "Can't find elements with locator 'lightning-primitive-header-factory.slds-is-sortable' inside its scope element."
|
|
129
|
+
// expect(await datatable.isSortableColumn('Name')).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
it('should tell whether or not the row is selectable', async () => {
|
|
132
|
+
const datatable = await utam.load(Datatable, {
|
|
133
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
expect(await datatable.isSelectableRow(1)).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
it('should get the width of a column', async () => {
|
|
139
|
+
const datatable = await utam.load(Datatable, {
|
|
140
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const datatableElement = await root.shadow$(
|
|
144
|
+
'lightning-datatable'
|
|
145
|
+
);
|
|
146
|
+
const columnHeader = await datatableElement.shadow$(
|
|
147
|
+
'[aria-label="Name"]'
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// Remove intermediate white spaces
|
|
151
|
+
let expectedWidth = await columnHeader.getAttribute('style');
|
|
152
|
+
expectedWidth = expectedWidth.replace(/\s/g, '');
|
|
153
|
+
let actualWidth = await datatable.getWidth('Name');
|
|
154
|
+
actualWidth = actualWidth.replace(/\s/g, '');
|
|
155
|
+
|
|
156
|
+
// Using indexOf in case of presence of ';'
|
|
157
|
+
expect(actualWidth.indexOf(expectedWidth) >= 0).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
it('should tell whether or not a column has header actions', async () => {
|
|
160
|
+
const datatable = await utam.load(Datatable, {
|
|
161
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
expect(await datatable.hasHeaderActions('Name')).toBe(true);
|
|
165
|
+
expect(await datatable.hasHeaderActions('Age')).toBe(true);
|
|
166
|
+
// false fails; need to check for true or null; check with UTAM if expected
|
|
167
|
+
expect(await datatable.hasHeaderActions('Email')).toBe(null);
|
|
168
|
+
});
|
|
169
|
+
it('should get the text of the rowheader cell of the specified row', async () => {
|
|
170
|
+
const datatable = await utam.load(Datatable, {
|
|
171
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
expect(await datatable.getRowHeaderText(2)).toBe(
|
|
175
|
+
'Kelsey Denesik'
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
it('should click column header of the sortable column', async () => {
|
|
179
|
+
const datatable = await utam.load(Datatable, {
|
|
180
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
let cellValue = await datatable.getCellValueByLabel(1, 'Age');
|
|
184
|
+
expect(cellValue).toBe('40');
|
|
185
|
+
|
|
186
|
+
await datatable.clickSortHeaderButton('Age');
|
|
187
|
+
|
|
188
|
+
cellValue = await datatable.getCellValueByLabel(1, 'Age');
|
|
189
|
+
expect(cellValue).toBe('35');
|
|
190
|
+
});
|
|
191
|
+
it('should tell whether the specified row has row actions or not', async () => {
|
|
192
|
+
const datatable = await utam.load(Datatable, {
|
|
193
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(await datatable.hasRowActionInRow(2)).toBe(true);
|
|
197
|
+
});
|
|
198
|
+
it('should tell whether or not the datatable has the loading indicator visible', async () => {
|
|
199
|
+
const datatable = await utam.load(Datatable, {
|
|
200
|
+
element: await root.shadow$(TABLE_SELECTOR),
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
expect(await datatable.isLoading()).toBe(false);
|
|
204
|
+
|
|
205
|
+
const button = await utam.load(Button, {
|
|
206
|
+
element: await root.shadow$('lightning-button'),
|
|
207
|
+
});
|
|
208
|
+
await button.click();
|
|
209
|
+
|
|
210
|
+
expect(await datatable.isLoading()).toBe(true);
|
|
211
|
+
});
|
|
57
212
|
});
|
|
58
|
-
|
|
59
|
-
await datatable.toggleRowSelection(2);
|
|
60
|
-
expect(await datatable.isRowSelected(2)).toBe('true');
|
|
61
|
-
[3, 4].forEach(async (i) => {
|
|
62
|
-
expect(await datatable.isRowSelected(i)).toBe('false');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
await datatable.toggleRowSelection(3);
|
|
66
|
-
expect(await datatable.isRowSelected(3)).toBe('true');
|
|
67
|
-
expect(await datatable.isRowSelected(4)).toBe('false');
|
|
68
|
-
|
|
69
|
-
await datatable.toggleRowSelection(4);
|
|
70
|
-
expect(await datatable.isRowSelected(4)).toBe('true');
|
|
71
|
-
});
|
|
72
|
-
it('should toggle selection of row', async () => {
|
|
73
|
-
const datatable = await utam.load(Datatable, {
|
|
74
|
-
element: await root.shadow$('lightning-datatable'),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
await datatable.toggleRowSelection(3);
|
|
78
|
-
expect(await datatable.isRowSelected(3)).toBe('true');
|
|
79
|
-
|
|
80
|
-
await datatable.toggleRowSelection(3);
|
|
81
|
-
expect(await datatable.isRowSelected(3)).toBe('false');
|
|
82
|
-
});
|
|
83
|
-
it('should get the number of selected rows when not all rows are selected', async () => {
|
|
84
|
-
const datatable = await utam.load(Datatable, {
|
|
85
|
-
element: await root.shadow$('lightning-datatable'),
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
await datatable.toggleRowSelection(3);
|
|
89
|
-
expect(await datatable.getNumSelectedRows()).toBe(1);
|
|
90
|
-
|
|
91
|
-
await datatable.toggleRowSelection(2);
|
|
92
|
-
expect(await datatable.getNumSelectedRows()).toBe(2);
|
|
93
|
-
});
|
|
94
|
-
it('should get the number of selected rows when all rows are selected', async () => {
|
|
95
|
-
const datatable = await utam.load(Datatable, {
|
|
96
|
-
element: await root.shadow$('lightning-datatable'),
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
await datatable.clickSelectAllCheckbox();
|
|
100
|
-
expect(await datatable.getNumSelectedRows()).toBe(4);
|
|
101
|
-
});
|
|
102
|
-
it('should get the number of columns in the table', async () => {
|
|
103
|
-
const datatable = await utam.load(Datatable, {
|
|
104
|
-
element: await root.shadow$('lightning-datatable'),
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
expect(await datatable.getNumColumns()).toBe(5);
|
|
108
|
-
});
|
|
109
|
-
it('should tell whether or not a column is sortable', async () => {
|
|
110
|
-
const datatable = await utam.load(Datatable, {
|
|
111
|
-
element: await root.shadow$('lightning-datatable'),
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
expect(await datatable.isSortableColumn('Age')).toBe(true);
|
|
115
|
-
|
|
116
|
-
// Need to speak to UTAM (about isPresent) or find a better way to write this method
|
|
117
|
-
// If column is not sortable, the test fails with the error:
|
|
118
|
-
// "Can't find elements with locator 'lightning-primitive-header-factory.slds-is-sortable' inside its scope element."
|
|
119
|
-
// expect(await datatable.isSortableColumn('Name')).toBe(false);
|
|
120
|
-
});
|
|
121
|
-
it('should tell whether or not the row is selectable', async () => {
|
|
122
|
-
const datatable = await utam.load(Datatable, {
|
|
123
|
-
element: await root.shadow$('lightning-datatable'),
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
expect(await datatable.isSelectableRow(1)).toBe(true);
|
|
127
|
-
});
|
|
128
|
-
it('should get the width of a column', async () => {
|
|
129
|
-
const datatable = await utam.load(Datatable, {
|
|
130
|
-
element: await root.shadow$('lightning-datatable'),
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const dt = await root.shadow$('lightning-datatable');
|
|
134
|
-
const columnHeader = await dt.shadow$('thead > tr > th:nth-child(2)');
|
|
135
|
-
const expectedWidth = await columnHeader.getAttribute('style');
|
|
136
|
-
expect(await datatable.getWidth('Name')).toBe(expectedWidth);
|
|
137
|
-
});
|
|
138
|
-
it('should tell whether or not a column has header actions', async () => {
|
|
139
|
-
const datatable = await utam.load(Datatable, {
|
|
140
|
-
element: await root.shadow$('lightning-datatable'),
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
expect(await datatable.hasHeaderActions('Name')).toBe(true);
|
|
144
|
-
expect(await datatable.hasHeaderActions('Age')).toBe(true);
|
|
145
|
-
// false fails; need to check for true or null; check with UTAM if expected
|
|
146
|
-
expect(await datatable.hasHeaderActions('Email')).toBe(null);
|
|
147
|
-
});
|
|
148
|
-
it('should get the text of the rowheader cell of the specified row', async () => {
|
|
149
|
-
const datatable = await utam.load(Datatable, {
|
|
150
|
-
element: await root.shadow$('lightning-datatable'),
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
expect(await datatable.getRowHeaderText(2)).toBe('Kelsey Denesik');
|
|
154
|
-
});
|
|
155
|
-
it('should click column header of the sortable column', async () => {
|
|
156
|
-
const datatable = await utam.load(Datatable, {
|
|
157
|
-
element: await root.shadow$('lightning-datatable'),
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
let cellValue = await datatable.getCellValueByLabel(1, 'Age');
|
|
161
|
-
expect(cellValue).toBe('40');
|
|
162
|
-
|
|
163
|
-
await datatable.clickSortHeaderButton('Age');
|
|
164
|
-
|
|
165
|
-
cellValue = await datatable.getCellValueByLabel(1, 'Age');
|
|
166
|
-
expect(cellValue).toBe('35');
|
|
167
|
-
});
|
|
168
|
-
it('should tell whether the specified row has row actions or not', async () => {
|
|
169
|
-
const datatable = await utam.load(Datatable, {
|
|
170
|
-
element: await root.shadow$('lightning-datatable'),
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
expect(await datatable.hasRowActionInRow(2)).toBe(true);
|
|
174
|
-
});
|
|
175
|
-
it('should tell whether or not the datatable has the loading indicator visible', async () => {
|
|
176
|
-
const datatable = await utam.load(Datatable, {
|
|
177
|
-
element: await root.shadow$('lightning-datatable'),
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
expect(await datatable.isLoading()).toBe(false);
|
|
181
|
-
|
|
182
|
-
const button = await utam.load(Button, {
|
|
183
|
-
element: await root.shadow$('lightning-button'),
|
|
184
|
-
});
|
|
185
|
-
await button.click();
|
|
186
|
-
|
|
187
|
-
expect(await datatable.isLoading()).toBe(true);
|
|
188
213
|
});
|
|
189
214
|
});
|
|
@@ -211,7 +211,6 @@ export default class LightningDatatable extends LightningElement {
|
|
|
211
211
|
_privateWidthObserver = null; // Instance of LightningDatatableResizeObserver
|
|
212
212
|
_renderMode = 'table';
|
|
213
213
|
_shouldResetFocus = false; // used to ensure focus isn't lost from changes in renderedRows
|
|
214
|
-
_shouldResetHeights = false;
|
|
215
214
|
_suppressBottomBar = false;
|
|
216
215
|
|
|
217
216
|
/************************* PUBLIC PROPERTIES *************************/
|
|
@@ -514,8 +513,8 @@ export default class LightningDatatable extends LightningElement {
|
|
|
514
513
|
*/
|
|
515
514
|
|
|
516
515
|
/**
|
|
517
|
-
* Reserved for internal use.
|
|
518
516
|
* Enables and configures advanced rendering modes.
|
|
517
|
+
* It supports properties 'bufferSize', 'fixedHeight', 'rowHeight', and 'virtualize'.
|
|
519
518
|
*
|
|
520
519
|
* @type {RenderManagerConfig} value - config object for datatable rendering
|
|
521
520
|
*/
|
|
@@ -552,7 +551,8 @@ export default class LightningDatatable extends LightningElement {
|
|
|
552
551
|
* `default` -> Renders <table>
|
|
553
552
|
*/
|
|
554
553
|
/**
|
|
555
|
-
*
|
|
554
|
+
* Enables virtual rendering when set to 'role-based'.
|
|
555
|
+
* Default value is 'default'.
|
|
556
556
|
*/
|
|
557
557
|
@api
|
|
558
558
|
get renderMode() {
|
|
@@ -1157,7 +1157,12 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1157
1157
|
if (this._shouldResetFocus) {
|
|
1158
1158
|
// since focus is now getting reset, can change this back to false
|
|
1159
1159
|
this._shouldResetFocus = false;
|
|
1160
|
-
|
|
1160
|
+
// don't return focus to active cell when inline edit panel is open
|
|
1161
|
+
if (
|
|
1162
|
+
state.activeCell &&
|
|
1163
|
+
state.activeCell.focused &&
|
|
1164
|
+
!state.inlineEdit.isPanelVisible
|
|
1165
|
+
) {
|
|
1161
1166
|
const cellElement = getActiveCellElement(template, state);
|
|
1162
1167
|
if (
|
|
1163
1168
|
cellElement &&
|
|
@@ -1380,7 +1385,7 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1380
1385
|
handleResizeEnd(event) {
|
|
1381
1386
|
event.stopPropagation();
|
|
1382
1387
|
this._isResizing = false;
|
|
1383
|
-
this.
|
|
1388
|
+
this.state.shouldResetHeights = true;
|
|
1384
1389
|
}
|
|
1385
1390
|
|
|
1386
1391
|
/**
|
|
@@ -1650,9 +1655,9 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1650
1655
|
|
|
1651
1656
|
// no need to handle other virtualization/row height logic
|
|
1652
1657
|
// if heights need to be reset
|
|
1653
|
-
if (this.
|
|
1658
|
+
if (this.state.shouldResetHeights) {
|
|
1654
1659
|
resetRowHeights(state);
|
|
1655
|
-
this.
|
|
1660
|
+
this.state.shouldResetHeights = false;
|
|
1656
1661
|
} else if (virtualizedRows && !state.fixedHeight) {
|
|
1657
1662
|
// if row heights aren't fixed, we need to update items
|
|
1658
1663
|
// in state to know where rows should be positioned
|
|
@@ -317,11 +317,6 @@ function openInlineEdit(dt, target) {
|
|
|
317
317
|
|
|
318
318
|
const { rowKeyValue, colKeyValue } = target;
|
|
319
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
|
-
|
|
325
320
|
inlineEdit.isPanelVisible = true;
|
|
326
321
|
inlineEdit.rowKeyValue = rowKeyValue;
|
|
327
322
|
inlineEdit.colKeyValue = colKeyValue;
|
|
@@ -14,8 +14,10 @@ export function getDirtyValueFromCell(state, rowKeyValue, colKeyValue) {
|
|
|
14
14
|
|
|
15
15
|
if (
|
|
16
16
|
dirtyValues &&
|
|
17
|
-
|
|
18
|
-
dirtyValues
|
|
17
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
18
|
+
dirtyValues.hasOwnProperty(rowKeyValue) &&
|
|
19
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
20
|
+
dirtyValues[rowKeyValue].hasOwnProperty(colKeyValue)
|
|
19
21
|
) {
|
|
20
22
|
return dirtyValues[rowKeyValue][colKeyValue];
|
|
21
23
|
}
|
|
@@ -799,7 +799,13 @@ function stillValidActiveCell(state) {
|
|
|
799
799
|
const {
|
|
800
800
|
activeCell: { rowKeyValue, colKeyValue },
|
|
801
801
|
} = state;
|
|
802
|
+
|
|
803
|
+
let sortableColumns = state.columns.filter((column) => column.sortable);
|
|
804
|
+
|
|
802
805
|
if (rowKeyValue === HEADER_ROW) {
|
|
806
|
+
if (state.rows.length && sortableColumns.length === 0) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
803
809
|
return state.headerIndexes[colKeyValue] !== undefined;
|
|
804
810
|
}
|
|
805
811
|
return !!(
|
|
@@ -830,9 +836,7 @@ export function setFocusActiveCell(
|
|
|
830
836
|
const { keyboardMode } = state;
|
|
831
837
|
const { rowIndex, colIndex } = getIndexesActiveCell(state);
|
|
832
838
|
|
|
833
|
-
|
|
834
|
-
state.activeCell.focused =
|
|
835
|
-
!(info && isActiveCellEditable(state)) && isActiveCellValid(state);
|
|
839
|
+
state.activeCell.focused = !(info && isActiveCellValid(state));
|
|
836
840
|
updateTabIndex(state, rowIndex, colIndex);
|
|
837
841
|
|
|
838
842
|
let cellElement = getActiveCellElement(template, state);
|
|
@@ -430,7 +430,7 @@ export function setSelectedRowsKeys(state, value) {
|
|
|
430
430
|
export function syncSelectedRowsKeys(state, selectedRows) {
|
|
431
431
|
let changed = false;
|
|
432
432
|
const { selectedRowsKeys, keyField } = state;
|
|
433
|
-
|
|
433
|
+
const maxRowSelection = getMaxRowSelection(state) || getRowsTotal(state);
|
|
434
434
|
if (Object.keys(selectedRowsKeys).length !== selectedRows.length) {
|
|
435
435
|
changed = true;
|
|
436
436
|
state.selectedRowsKeys = updateSelectedRowsKeysFromSelectedRows(
|
|
@@ -446,7 +446,13 @@ export function syncSelectedRowsKeys(state, selectedRows) {
|
|
|
446
446
|
);
|
|
447
447
|
}
|
|
448
448
|
}
|
|
449
|
-
|
|
449
|
+
if (maxRowSelection > 1 && changed) {
|
|
450
|
+
if (selectedRows.length < maxRowSelection) {
|
|
451
|
+
markDeselectedRowEnabled(state);
|
|
452
|
+
} else {
|
|
453
|
+
markDeselectedRowDisabled(state);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
450
456
|
updateBulkSelectionState(state);
|
|
451
457
|
|
|
452
458
|
return {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
<!-- empty since keyField wasn't provided TODO: Why is this here? Test and remove! -->
|
|
41
41
|
</template>
|
|
42
42
|
<template if:true={hasValidKeyField}>
|
|
43
|
-
<thead>
|
|
43
|
+
<thead data-rowgroup-header>
|
|
44
44
|
<!-- Column Header Row -->
|
|
45
45
|
<tr class="slds-line-height_reset"
|
|
46
46
|
data-row-key-value="HEADER"
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
</template>
|
|
102
102
|
</tr>
|
|
103
103
|
</thead>
|
|
104
|
-
<tbody style={computedTbodyStyle}>
|
|
104
|
+
<tbody data-rowgroup-body style={computedTbodyStyle}>
|
|
105
105
|
<template for:each={renderedRows} for:item="row" for:index="rowIndex">
|
|
106
106
|
<!-- Data Rows -->
|
|
107
107
|
<tr class={row.classnames}
|
|
@@ -143,6 +143,7 @@ export function handleTriggeredAction(state, action, colKeyValue) {
|
|
|
143
143
|
if (actionName === 'wrapText' || actionName === 'clipText') {
|
|
144
144
|
// If state should be changed
|
|
145
145
|
if (state.wrapText[colKeyValue] !== (actionName === 'wrapText')) {
|
|
146
|
+
state.shouldResetHeights = true;
|
|
146
147
|
state.wrapText[colKeyValue] = actionName === 'wrapText';
|
|
147
148
|
|
|
148
149
|
updateSelectedOptionInHeaderActions(state, colKeyValue);
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
synchronizeAttrs,
|
|
30
30
|
getRealDOMId,
|
|
31
31
|
isIE11,
|
|
32
|
+
computeAriaInvalid,
|
|
32
33
|
} from 'lightning/utilsPrivate';
|
|
33
34
|
import {
|
|
34
35
|
generateUniqueId,
|
|
@@ -55,6 +56,7 @@ const ARIA_CONTROLS = 'aria-controls';
|
|
|
55
56
|
const ARIA_LABEL = 'aria-label';
|
|
56
57
|
const ARIA_LABELLEDBY = 'aria-labelledby';
|
|
57
58
|
const ARIA_DESCRIBEDBY = 'aria-describedby';
|
|
59
|
+
const ARIA_INVALID = 'aria-invalid';
|
|
58
60
|
const DATE_STYLE = {
|
|
59
61
|
SHORT: 'short',
|
|
60
62
|
MEDIUM: 'medium',
|
|
@@ -228,6 +230,7 @@ export default class LightningDatePicker extends LightningElement {
|
|
|
228
230
|
[ARIA_DESCRIBEDBY]: this.computedAriaDescribedby,
|
|
229
231
|
[ARIA_CONTROLS]: this.ariaControlsId,
|
|
230
232
|
[ARIA_LABEL]: this._ariaLabel,
|
|
233
|
+
[ARIA_INVALID]: this.computedAriaInvalid,
|
|
231
234
|
});
|
|
232
235
|
|
|
233
236
|
// Set aria-describedby on the calendar button that opens the calendar dialog
|
|
@@ -744,4 +747,11 @@ export default class LightningDatePicker extends LightningElement {
|
|
|
744
747
|
this.ariaLabelledByElement.length
|
|
745
748
|
);
|
|
746
749
|
}
|
|
750
|
+
|
|
751
|
+
get computedAriaInvalid() {
|
|
752
|
+
const isAriaInvalid =
|
|
753
|
+
this.template.host.getAttribute('data-aria-invalid') ||
|
|
754
|
+
this._errorMessage;
|
|
755
|
+
return computeAriaInvalid(isAriaInvalid, this.value);
|
|
756
|
+
}
|
|
747
757
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
<div class="slds-form-element__group">
|
|
12
12
|
<div class="slds-form-element__row">
|
|
13
13
|
<lightning-datepicker
|
|
14
|
+
data-aria-invalid={computedDateAriaInvalid}
|
|
14
15
|
class="slds-form-element"
|
|
15
16
|
autocomplete={autocomplete}
|
|
16
17
|
min={dateMin}
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
</lightning-datepicker>
|
|
30
31
|
|
|
31
32
|
<lightning-timepicker
|
|
33
|
+
data-aria-invalid={computedTimeAriaInvalid}
|
|
32
34
|
class="slds-form-element"
|
|
33
35
|
autocomplete={autocomplete}
|
|
34
36
|
label={i18n.time}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
normalizeAriaAttribute,
|
|
10
10
|
synchronizeAttrs,
|
|
11
11
|
getRealDOMId,
|
|
12
|
+
computeAriaInvalid,
|
|
12
13
|
} from 'lightning/utilsPrivate';
|
|
13
14
|
import {
|
|
14
15
|
getCurrentTime,
|
|
@@ -579,4 +580,11 @@ export default class LightningDateTimePicker extends LightningElement {
|
|
|
579
580
|
? isoString.split(TIME_SEPARATOR)
|
|
580
581
|
: null;
|
|
581
582
|
}
|
|
583
|
+
|
|
584
|
+
get computedDateAriaInvalid() {
|
|
585
|
+
return computeAriaInvalid(this._customErrorMessage, this._dateValue);
|
|
586
|
+
}
|
|
587
|
+
get computedTimeAriaInvalid() {
|
|
588
|
+
return computeAriaInvalid(this._customErrorMessage, this._timeValue);
|
|
589
|
+
}
|
|
582
590
|
}
|
|
@@ -498,7 +498,8 @@ export default class LightningDualListbox extends LightningElement {
|
|
|
498
498
|
|
|
499
499
|
return {
|
|
500
500
|
...option,
|
|
501
|
-
tabIndex:
|
|
501
|
+
tabIndex:
|
|
502
|
+
!this.disabled && option.value === focusableValue ? '0' : '-1',
|
|
502
503
|
selected: isSelected ? 'true' : 'false',
|
|
503
504
|
classList,
|
|
504
505
|
};
|