lightning-base-components 1.14.2-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.
- package/metadata/raptor.json +1 -0
- package/package.json +17 -1
- package/scopedImports/@salesforce-label-LightningDualListbox.movedOptionsPlural.js +1 -0
- package/scopedImports/@salesforce-label-LightningDualListbox.movedOptionsSingular.js +1 -0
- package/scopedImports/@salesforce-label-LightningErrorMessage.validitySelectAtleastOne.js +1 -0
- package/scopedImports/@salesforce-label-LightningMap.titleWithAddress.js +1 -0
- package/src/lightning/ariaObserver/__docs__/ariaObserver.md +142 -0
- package/src/lightning/buttonMenu/keyboard.js +0 -10
- package/src/lightning/card/card.html +6 -0
- package/src/lightning/checkboxGroup/checkboxGroup.html +2 -2
- package/src/lightning/checkboxGroup/checkboxGroup.js +6 -1
- package/src/lightning/colorPickerCustom/colorPickerCustom.js +20 -1
- package/src/lightning/datatable/__docs__/datatable.md +55 -0
- package/src/lightning/datatable/__examples__/basic/basic.html +1 -1
- package/src/lightning/datatable/columns-shared.js +1 -1
- package/src/lightning/datatable/datatable.js +97 -24
- package/src/lightning/datatable/errors.js +20 -9
- package/src/lightning/datatable/headerActions.js +77 -49
- package/src/lightning/datatable/inlineEdit.js +505 -370
- package/src/lightning/datatable/inlineEditShared.js +24 -0
- package/src/lightning/datatable/keyboard.js +1 -1
- package/src/lightning/datatable/renderManager.js +241 -129
- package/src/lightning/datatable/rowLevelActions.js +17 -13
- package/src/lightning/datatable/rowNumber.js +54 -20
- package/src/lightning/datatable/rowSelection.js +760 -0
- package/src/lightning/datatable/rowSelectionShared.js +79 -0
- package/src/lightning/datatable/rows.js +16 -5
- package/src/lightning/datatable/state.js +10 -1
- package/src/lightning/datatable/templates/div/div.css +4 -0
- package/src/lightning/datatable/templates/div/div.html +1 -0
- package/src/lightning/datatable/utils.js +14 -0
- package/src/lightning/dualListbox/dualListbox.html +1 -1
- package/src/lightning/dualListbox/dualListbox.js +42 -0
- package/src/lightning/inputUtils/validity.js +12 -1
- package/src/lightning/pillContainer/__docs__/pillContainer.md +45 -1
- package/src/lightning/positionLibrary/positionLibrary.js +31 -43
- package/src/lightning/primitiveCellActions/primitiveCellActions.js +69 -12
- package/src/lightning/primitiveCellFactory/cellWithStandardLayout.html +13 -11
- package/src/lightning/primitiveCellFactory/primitiveCellFactory.js +13 -8
- package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.html +17 -14
- package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.js +167 -98
- package/src/lightning/primitiveDatatableIeditTypeFactory/primitiveDatatableIeditTypeFactory.js +94 -69
- package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.html +4 -4
- package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.js +4 -4
- package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.js +99 -37
- package/src/lightning/progressIndicator/progressIndicator.js +1 -1
- package/src/lightning/progressStep/progressStep.js +1 -1
- package/src/lightning/staticMap/staticMap.html +1 -0
- package/src/lightning/staticMap/staticMap.js +39 -2
- package/src/lightning/utils/classSet.js +4 -1
- package/src/lightning/datatable/inlineEdit-shared.js +0 -14
- package/src/lightning/datatable/selector-shared.js +0 -38
- package/src/lightning/datatable/selector.js +0 -527
package/metadata/raptor.json
CHANGED
|
@@ -1352,6 +1352,7 @@
|
|
|
1352
1352
|
"industriesCibApi": {},
|
|
1353
1353
|
"industriesDecisionMatrixDesignerApi": {},
|
|
1354
1354
|
"industriesExplainabilityApi": {},
|
|
1355
|
+
"industriesHealthcloudHpiApi": {},
|
|
1355
1356
|
"industriesIdentityVerificationApi": {},
|
|
1356
1357
|
"industriesInterestTaggingApi": {},
|
|
1357
1358
|
"industriesLoyaltyEngineApi": {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightning-base-components",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.3-alpha",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=12.18.3"
|
|
6
6
|
},
|
|
@@ -57,6 +57,10 @@
|
|
|
57
57
|
"name": "@salesforce/label/LightningErrorMessage.validityTooShort",
|
|
58
58
|
"path": "scopedImports/@salesforce-label-LightningErrorMessage.validityTooShort.js"
|
|
59
59
|
},
|
|
60
|
+
{
|
|
61
|
+
"name": "@salesforce/label/LightningErrorMessage.validitySelectAtleastOne",
|
|
62
|
+
"path": "scopedImports/@salesforce-label-LightningErrorMessage.validitySelectAtleastOne.js"
|
|
63
|
+
},
|
|
60
64
|
{
|
|
61
65
|
"name": "@salesforce/label/LightningCarousel.tabString",
|
|
62
66
|
"path": "scopedImports/@salesforce-label-LightningCarousel.tabString.js"
|
|
@@ -369,6 +373,14 @@
|
|
|
369
373
|
"name": "@salesforce/label/LightningDualListbox.requiredOptionError",
|
|
370
374
|
"path": "scopedImports/@salesforce-label-LightningDualListbox.requiredOptionError.js"
|
|
371
375
|
},
|
|
376
|
+
{
|
|
377
|
+
"name": "@salesforce/label/LightningDualListbox.movedOptionsSingular",
|
|
378
|
+
"path": "scopedImports/@salesforce-label-LightningDualListbox.movedOptionsSingular.js"
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"name": "@salesforce/label/LightningDualListbox.movedOptionsPlural",
|
|
382
|
+
"path": "scopedImports/@salesforce-label-LightningDualListbox.movedOptionsPlural.js"
|
|
383
|
+
},
|
|
372
384
|
{
|
|
373
385
|
"name": "@salesforce/label/LightningProgressIndicator.stageComplete",
|
|
374
386
|
"path": "scopedImports/@salesforce-label-LightningProgressIndicator.stageComplete.js"
|
|
@@ -861,6 +873,10 @@
|
|
|
861
873
|
"name": "@salesforce/label/LightningMap.iframeTitle",
|
|
862
874
|
"path": "scopedImports/@salesforce-label-LightningMap.iframeTitle.js"
|
|
863
875
|
},
|
|
876
|
+
{
|
|
877
|
+
"name": "@salesforce/label/LightningMap.titleWithAddress",
|
|
878
|
+
"path": "scopedImports/@salesforce-label-LightningMap.titleWithAddress.js"
|
|
879
|
+
},
|
|
864
880
|
{
|
|
865
881
|
"name": "@salesforce/label/LightningPrimitiveCoordinate.selected",
|
|
866
882
|
"path": "scopedImports/@salesforce-label-LightningPrimitiveCoordinate.selected.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'Items {0} moved to the list {1}';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'Item {0} moved to the list {1}';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'You must select at least one choice from this set.';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'Map of {0}';
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
The `lightning/ariaObserver` module provides an easy way for users to write accessible component that works in both synthetic and native shadow.
|
|
2
|
+
|
|
3
|
+
## Aria ID referencing in native shadow
|
|
4
|
+
Use the` AriaObserver` library to write accessible component that works where `ariaLabelledBy` would break native shadow.
|
|
5
|
+
|
|
6
|
+
Here's an example that won't work with native shadow. In the following code, we support attribute `ariaLabelledBy` in our component `c-foo`, so the `input` element is labelled by external elements.
|
|
7
|
+
|
|
8
|
+
``` html
|
|
9
|
+
<template>
|
|
10
|
+
<input aria-labelledby={ariaLabelledBy}>
|
|
11
|
+
</template>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
class Foo extends LightningElement {
|
|
16
|
+
@api ariaLabelledBy;
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This example uses the `aria-labelledby` attribute to use the internal input as an external label in `c-foo`.
|
|
21
|
+
|
|
22
|
+
``` html
|
|
23
|
+
<span id="my-label">Input field</span>
|
|
24
|
+
<c-foo aria-labelledby="my-label"></c-foo>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The above example works fine in synthetic shadow, but in native shadow mode, the `aria-labelledby` ID reference is broken. The `input` element is isolated in its own shadow DOM, so the label with id `my-label` isn't in the same shadow boundary.
|
|
28
|
+
|
|
29
|
+
## Creating AriaObserver
|
|
30
|
+
|
|
31
|
+
To use `AriaObserver` in your component, first import it from `lightning/ariaObserver`. Then, instantiate the `AriaObserver` within your component.
|
|
32
|
+
|
|
33
|
+
The `AriaObserver` constructor takes one parameter:
|
|
34
|
+
- `cmpReference` The reference of the current component (`this`).
|
|
35
|
+
|
|
36
|
+
``` js
|
|
37
|
+
import AriaObserver from 'lightning/ariaObserver';
|
|
38
|
+
|
|
39
|
+
class Foo extends LightningElement {
|
|
40
|
+
constructor() {
|
|
41
|
+
super();
|
|
42
|
+
this.ariaObserver = new AriaObserver(this);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Next, use the `connect(options)` method to connect between the internal element and the external reference. It takes an options object with the following keys:
|
|
48
|
+
- `targetSelector` The selector to the internal element where the aria attribute should be attached.
|
|
49
|
+
- `attribute` The name of the aria attribute. Two supported options: `aria-labelledby`and `aria-describedby`.
|
|
50
|
+
- `id` The ID of the external element. Alternatively, you can use `ids` for multiple IDs.
|
|
51
|
+
|
|
52
|
+
This example uses `connect(options)` to display an aria label for the internal `input` element.
|
|
53
|
+
``` js
|
|
54
|
+
@api
|
|
55
|
+
get ariaLabelledBy() {
|
|
56
|
+
return this._ariaLabelledBy;
|
|
57
|
+
}
|
|
58
|
+
set ariaLabelledBy(refs) {
|
|
59
|
+
this._ariaLabelledBy = refs;
|
|
60
|
+
|
|
61
|
+
this.ariaObserver.connect({
|
|
62
|
+
targetSelector: 'input',
|
|
63
|
+
attribute: 'aria-labelledby',
|
|
64
|
+
id: refs
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then use the `sync()` method to synchronize the ID references when the template is re-rendered.
|
|
70
|
+
|
|
71
|
+
``` js
|
|
72
|
+
renderedCallback() {
|
|
73
|
+
this.ariaObserver.sync();
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Finally, disconnect the aria observer and free the resources at the end of the component lifecycle.
|
|
78
|
+
|
|
79
|
+
``` js
|
|
80
|
+
disconnectedCallback() {
|
|
81
|
+
if (this.ariaObserver) {
|
|
82
|
+
this.ariaObserver.disconnect();
|
|
83
|
+
this.ariaObserver = undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Here is all these steps combined into a complete example of a component using `AriaObserver`.
|
|
89
|
+
|
|
90
|
+
``` html
|
|
91
|
+
<template>
|
|
92
|
+
<!-- element where the aria attribute is attached -->
|
|
93
|
+
<input>
|
|
94
|
+
</template>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
``` js
|
|
98
|
+
import {api, LightningElement} from 'lwc';
|
|
99
|
+
import AriaObserver from 'lightning/ariaObserver';
|
|
100
|
+
|
|
101
|
+
export default class Foo extends LightningElement {
|
|
102
|
+
constructor() {
|
|
103
|
+
super();
|
|
104
|
+
this.ariaObserver = new AriaObserver(this);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_ariaLabelledBy = '';
|
|
108
|
+
|
|
109
|
+
@api
|
|
110
|
+
get ariaLabelledBy() {
|
|
111
|
+
return this._ariaLabelledBy;
|
|
112
|
+
}
|
|
113
|
+
set ariaLabelledBy(refs) {
|
|
114
|
+
this._ariaLabelledBy = refs;
|
|
115
|
+
|
|
116
|
+
/* Establish the connection between input and the external label */
|
|
117
|
+
this.ariaObserver.connect({
|
|
118
|
+
targetSelector: 'input',
|
|
119
|
+
attribute: 'aria-labelledby',
|
|
120
|
+
id: refs
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
renderedCallback() {
|
|
125
|
+
this.ariaObserver.sync();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
disconnectedCallback() {
|
|
129
|
+
if (this.ariaObserver) {
|
|
130
|
+
this.ariaObserver.disconnect();
|
|
131
|
+
this.ariaObserver = undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Limitations
|
|
138
|
+
`AriaObserver` only works with text-only aria ID references.
|
|
139
|
+
|
|
140
|
+
Supported attributes:
|
|
141
|
+
- `aria-labelledby`
|
|
142
|
+
- `aria-describedby`
|
|
@@ -113,16 +113,6 @@ export function handleKeyDownOnMenuTrigger(event, menuInterface) {
|
|
|
113
113
|
menuInterface.toggleMenuVisibility();
|
|
114
114
|
}
|
|
115
115
|
break;
|
|
116
|
-
// W3: Home and End: If arrow key wrapping is not supported, move focus to first and last item
|
|
117
|
-
// Note: We do support wrapping, but it doesn't hurt to support these keys anyway.
|
|
118
|
-
case keyCodes.home:
|
|
119
|
-
preventDefaultAndStopPropagation(event);
|
|
120
|
-
menuInterface.focusOnIndex(0);
|
|
121
|
-
break;
|
|
122
|
-
case keyCodes.end:
|
|
123
|
-
preventDefaultAndStopPropagation(event);
|
|
124
|
-
menuInterface.focusOnIndex(menuInterface.getTotalMenuItems() - 1);
|
|
125
|
-
break;
|
|
126
116
|
// W3: Escape: Close the menu and return focus to the element or context, e.g., menu button or
|
|
127
117
|
// parent menu item, from which the menu was opened
|
|
128
118
|
case keyCodes.escape:
|
|
@@ -40,5 +40,11 @@
|
|
|
40
40
|
<slot name="footer"></slot>
|
|
41
41
|
</div>
|
|
42
42
|
</template>
|
|
43
|
+
<!-- This dummy placeholder slot is required because
|
|
44
|
+
a slot's presence is verified by assignedElements count
|
|
45
|
+
and not whether the slot itself is present or not -->
|
|
46
|
+
<template if:false={showFooter}>
|
|
47
|
+
<slot name="footer" class="slds-hide"></slot>
|
|
48
|
+
</template>
|
|
43
49
|
</article>
|
|
44
50
|
</template>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<fieldset aria-
|
|
2
|
+
<fieldset aria-describedby={computearaiDescriedBy}>
|
|
3
3
|
|
|
4
4
|
<legend class={computedLegendClass}>
|
|
5
5
|
<template if:true={required}>
|
|
@@ -32,6 +32,6 @@
|
|
|
32
32
|
<template if:true={_helpMessage}>
|
|
33
33
|
<div id="helptext" data-helptext class="slds-form-element__help">{_helpMessage}</div>
|
|
34
34
|
</template>
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
</fieldset>
|
|
37
37
|
</template>
|
|
@@ -295,7 +295,7 @@ export default class LightningCheckboxGroup extends LightningElement {
|
|
|
295
295
|
get _constraint() {
|
|
296
296
|
if (!this._constraintApi) {
|
|
297
297
|
this._constraintApi = new FieldConstraintApi(() => this, {
|
|
298
|
-
|
|
298
|
+
validitySelectAtleastOneValue: () =>
|
|
299
299
|
!this.disabled && this.required && this.value.length === 0,
|
|
300
300
|
});
|
|
301
301
|
}
|
|
@@ -313,4 +313,9 @@ export default class LightningCheckboxGroup extends LightningElement {
|
|
|
313
313
|
})
|
|
314
314
|
.toString();
|
|
315
315
|
}
|
|
316
|
+
|
|
317
|
+
computearaiDescriedBy() {
|
|
318
|
+
const helpMessage = this.template.querySelector('[data-helptext]');
|
|
319
|
+
return getRealDOMId(helpMessage);
|
|
320
|
+
}
|
|
316
321
|
}
|
|
@@ -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
|
-
|
|
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
|
|
@@ -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. `
|
|
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
|
-
|
|
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 './
|
|
56
|
+
} from './rowSelection';
|
|
57
57
|
import {
|
|
58
58
|
syncActiveCell,
|
|
59
59
|
handleKeydownOnCell,
|
|
@@ -80,6 +80,7 @@ import {
|
|
|
80
80
|
handleKeydownOnTable,
|
|
81
81
|
addFocusStylesToActiveCell,
|
|
82
82
|
refocusCellElement,
|
|
83
|
+
isCellElement,
|
|
83
84
|
} from './keyboard';
|
|
84
85
|
import {
|
|
85
86
|
getRowNumberOffset,
|
|
@@ -134,7 +135,13 @@ import {
|
|
|
134
135
|
import {
|
|
135
136
|
isViewportRenderingEnabled,
|
|
136
137
|
setViewportRendering,
|
|
138
|
+
getDTRows,
|
|
139
|
+
getDTRenderedRowCount,
|
|
140
|
+
setDTRenderedRowCount,
|
|
141
|
+
getDTWrapperHeight,
|
|
142
|
+
normalizeVirtualization,
|
|
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,
|
|
@@ -192,12 +200,14 @@ export default class LightningDatatable extends LightningElement {
|
|
|
192
200
|
_customerSelectedRows = null;
|
|
193
201
|
_datatableId = generateUniqueId('lgt-datatable');
|
|
194
202
|
_draftValues = [];
|
|
203
|
+
_firstVisibleIndex = 0; // first row that should be visible in viewport, used for virtualization
|
|
195
204
|
_isResizing = false; // Whether resizing is in progress
|
|
196
205
|
_privateTypes = {};
|
|
197
206
|
_privateWidthObserver = null; // Instance of LightningDatatableResizeObserver
|
|
198
207
|
_renderMode = 'table';
|
|
199
208
|
_renderedRowCount = 0;
|
|
200
209
|
_suppressBottomBar = false;
|
|
210
|
+
_virtualize = '';
|
|
201
211
|
|
|
202
212
|
/************************* PUBLIC PROPERTIES *************************/
|
|
203
213
|
|
|
@@ -493,6 +503,7 @@ export default class LightningDatatable extends LightningElement {
|
|
|
493
503
|
* @type {object}
|
|
494
504
|
* @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
505
|
* @property {number} rowHeight - Specifies the height of a row, in px
|
|
506
|
+
* @property {string} virtualize - specifies whether to enable virtualization. This requires the "role-based" render mode and a fixed-height container for lightning-datatable
|
|
496
507
|
*/
|
|
497
508
|
|
|
498
509
|
/**
|
|
@@ -508,10 +519,28 @@ export default class LightningDatatable extends LightningElement {
|
|
|
508
519
|
|
|
509
520
|
set renderConfig(value) {
|
|
510
521
|
if (typeof value === 'object' && !isIE11) {
|
|
511
|
-
const
|
|
512
|
-
setViewportRendering(this.state,
|
|
522
|
+
const { viewportRendering, virtualize } = value;
|
|
523
|
+
setViewportRendering(this.state, viewportRendering);
|
|
524
|
+
if (this.state.renderModeRoleBased) {
|
|
525
|
+
this._virtualize = normalizeVirtualization(virtualize);
|
|
526
|
+
}
|
|
513
527
|
|
|
514
|
-
this._renderManager.configure(
|
|
528
|
+
this._renderManager.configure(
|
|
529
|
+
this.getRows,
|
|
530
|
+
this.getWrapperHeight,
|
|
531
|
+
this.getRenderedRowCount,
|
|
532
|
+
this.setRenderedRowCount,
|
|
533
|
+
value
|
|
534
|
+
);
|
|
535
|
+
// if renderConfig already exists, update rendering
|
|
536
|
+
if (this._renderConfig) {
|
|
537
|
+
this._renderManager.updateViewportRendering(
|
|
538
|
+
this.state.rows,
|
|
539
|
+
this.setRenderedRowCount,
|
|
540
|
+
this.gridContainer,
|
|
541
|
+
true
|
|
542
|
+
);
|
|
543
|
+
}
|
|
515
544
|
this._renderConfig = value;
|
|
516
545
|
}
|
|
517
546
|
}
|
|
@@ -759,24 +788,38 @@ export default class LightningDatatable extends LightningElement {
|
|
|
759
788
|
|
|
760
789
|
get computedTableStyle() {
|
|
761
790
|
if (this._columnWidthManager.isAutoResizingUpdateQueued()) {
|
|
762
|
-
return ['table-layout:auto']
|
|
791
|
+
return styleToString(['table-layout:auto']);
|
|
763
792
|
}
|
|
764
|
-
return [
|
|
793
|
+
return styleToString([
|
|
765
794
|
'table-layout:fixed',
|
|
766
795
|
getCSSWidthStyleOfTable(this.widthsData),
|
|
767
|
-
]
|
|
796
|
+
]);
|
|
768
797
|
}
|
|
769
798
|
|
|
799
|
+
/**
|
|
800
|
+
* Resets row-number counter to offset to show
|
|
801
|
+
* correct value when row number column is present
|
|
802
|
+
* and adds necessary position and height styles when
|
|
803
|
+
* virtualization is enabled
|
|
804
|
+
*/
|
|
770
805
|
get computedTbodyStyle() {
|
|
806
|
+
const style = [];
|
|
771
807
|
if (
|
|
772
808
|
hasRowNumberColumn(this.state) &&
|
|
773
809
|
getRowNumberOffset(this.state) >= 0
|
|
774
810
|
) {
|
|
775
|
-
|
|
811
|
+
style.push(
|
|
776
812
|
'counter-reset: row-number ' + getRowNumberOffset(this.state)
|
|
777
813
|
);
|
|
778
814
|
}
|
|
779
|
-
|
|
815
|
+
if (this._virtualize) {
|
|
816
|
+
const length = this.state.rows.length;
|
|
817
|
+
style.push(
|
|
818
|
+
'position: relative',
|
|
819
|
+
`height:${length * DEFAULT_ROW_HEIGHT}px`
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
return styleToString(style);
|
|
780
823
|
}
|
|
781
824
|
|
|
782
825
|
/**
|
|
@@ -812,9 +855,7 @@ export default class LightningDatatable extends LightningElement {
|
|
|
812
855
|
styles['overflow-x'] = 'auto';
|
|
813
856
|
}
|
|
814
857
|
|
|
815
|
-
return
|
|
816
|
-
.map(([key, value]) => key + ':' + value)
|
|
817
|
-
.join(';');
|
|
858
|
+
return styleToString(styles);
|
|
818
859
|
}
|
|
819
860
|
|
|
820
861
|
/**
|
|
@@ -897,6 +938,14 @@ export default class LightningDatatable extends LightningElement {
|
|
|
897
938
|
}
|
|
898
939
|
|
|
899
940
|
get renderedRows() {
|
|
941
|
+
if (this._virtualize) {
|
|
942
|
+
const { firstIndex, lastIndex } =
|
|
943
|
+
this._renderManager.getRenderedRange(
|
|
944
|
+
this._firstVisibleIndex,
|
|
945
|
+
this._renderedRowCount
|
|
946
|
+
);
|
|
947
|
+
return this.state.rows.slice(firstIndex, lastIndex);
|
|
948
|
+
}
|
|
900
949
|
if (this.viewportRendering && !isIE11) {
|
|
901
950
|
return this.state.rows.slice(0, this._renderedRowCount);
|
|
902
951
|
}
|
|
@@ -936,6 +985,10 @@ export default class LightningDatatable extends LightningElement {
|
|
|
936
985
|
this.updateRowsAndCellIndexes = updateRowsAndCellIndexes.bind(this);
|
|
937
986
|
|
|
938
987
|
this._renderManager = new RenderManager();
|
|
988
|
+
this.getRenderedRowCount = getDTRenderedRowCount.bind(this);
|
|
989
|
+
this.setRenderedRowCount = setDTRenderedRowCount.bind(this);
|
|
990
|
+
this.getRows = getDTRows.bind(this);
|
|
991
|
+
this.getWrapperHeight = getDTWrapperHeight.bind(this);
|
|
939
992
|
}
|
|
940
993
|
|
|
941
994
|
/**
|
|
@@ -1095,16 +1148,24 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1095
1148
|
// set the previous focused cell to null after render is done
|
|
1096
1149
|
resetCellToFocusFromPrev(state);
|
|
1097
1150
|
|
|
1098
|
-
if (this.viewportRendering) {
|
|
1099
|
-
this.
|
|
1151
|
+
if (this.viewportRendering || this._virtualize) {
|
|
1152
|
+
const resizeTarget = this.template.querySelector(
|
|
1153
|
+
'div.dt-outer-container'
|
|
1154
|
+
);
|
|
1155
|
+
this._renderManager.connectResizeObserver(resizeTarget);
|
|
1100
1156
|
if (!this._renderManager.hasWrapperHeight()) {
|
|
1101
|
-
this._renderManager.updateWrapperHeight(this);
|
|
1157
|
+
this._renderManager.updateWrapperHeight(this.getWrapperHeight);
|
|
1102
1158
|
|
|
1103
1159
|
// Reset the row count if we already had one before updating the wrapper height.
|
|
1104
1160
|
// This can happen if the number of rows was calculated before the datatable
|
|
1105
1161
|
// was rendered.
|
|
1106
1162
|
if (this._renderedRowCount) {
|
|
1107
|
-
this._renderManager.updateViewportRendering(
|
|
1163
|
+
this._renderManager.updateViewportRendering(
|
|
1164
|
+
this.state.rows,
|
|
1165
|
+
this.setRenderedRowCount,
|
|
1166
|
+
this.gridContainer,
|
|
1167
|
+
true
|
|
1168
|
+
);
|
|
1108
1169
|
}
|
|
1109
1170
|
}
|
|
1110
1171
|
}
|
|
@@ -1187,9 +1248,16 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1187
1248
|
}
|
|
1188
1249
|
|
|
1189
1250
|
handleInlineEditPanelScroll.call(this, event);
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1251
|
+
if (this._virtualize) {
|
|
1252
|
+
this._firstVisibleIndex =
|
|
1253
|
+
this._renderManager.getFirstVisibleIndex(event);
|
|
1254
|
+
} else if (this.viewportRendering) {
|
|
1255
|
+
this._renderManager.handleScroll(
|
|
1256
|
+
this.state.rows,
|
|
1257
|
+
this._renderedRowCount,
|
|
1258
|
+
this.setRenderedRowCount,
|
|
1259
|
+
event
|
|
1260
|
+
);
|
|
1193
1261
|
}
|
|
1194
1262
|
}
|
|
1195
1263
|
|
|
@@ -1202,8 +1270,9 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1202
1270
|
handleCellClick(event) {
|
|
1203
1271
|
// handles the case when clicking on the margin/pading of the td/th
|
|
1204
1272
|
const targetTagName = event.target.tagName.toLowerCase();
|
|
1273
|
+
const targetRole = event.target.getAttribute('role');
|
|
1205
1274
|
|
|
1206
|
-
if (targetTagName
|
|
1275
|
+
if (isCellElement(targetTagName, targetRole)) {
|
|
1207
1276
|
// get the row/col key value from the primitive cell.
|
|
1208
1277
|
const { rowKeyValue, colKeyValue } =
|
|
1209
1278
|
event.target.querySelector(':first-child');
|
|
@@ -1464,8 +1533,12 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1464
1533
|
|
|
1465
1534
|
this.updateRowsAndCellIndexes(state);
|
|
1466
1535
|
|
|
1467
|
-
if (this.viewportRendering) {
|
|
1468
|
-
this._renderManager.updateViewportRendering(
|
|
1536
|
+
if (this.viewportRendering || this._virtualize) {
|
|
1537
|
+
this._renderManager.updateViewportRendering(
|
|
1538
|
+
this.state.rows,
|
|
1539
|
+
this.setRenderedRowCount,
|
|
1540
|
+
this.gridContainer
|
|
1541
|
+
);
|
|
1469
1542
|
}
|
|
1470
1543
|
|
|
1471
1544
|
this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
|
|
@@ -1508,7 +1581,7 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1508
1581
|
// Updates state.wrapText and when isWrapableType, sets internal header actions
|
|
1509
1582
|
updateHeaderActions(state);
|
|
1510
1583
|
this.updateRowsAndCellIndexes(state);
|
|
1511
|
-
|
|
1584
|
+
updateBulkSelectionState(state);
|
|
1512
1585
|
this._columnWidthManager.handleRowNumberOffsetChange(state, widthsData);
|
|
1513
1586
|
updateColumnWidthsMetadata(getColumns(state), widthsData);
|
|
1514
1587
|
// set the celltofocus next to null if the column still exists after indexes calculation
|