lightning-base-components 1.17.2-alpha → 1.17.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 +7 -4
- package/package.json +9 -1
- package/scopedImports/@salesforce-label-AddressAutocomplete.LookupButton.js +1 -0
- package/scopedImports/@salesforce-label-LightningDatatable.chooseARowSelectAll.js +1 -0
- package/src/lightning/baseCombobox/baseCombobox.js +39 -1
- package/src/lightning/breadcrumb/__docs__/breadcrumb.md +5 -6
- package/src/lightning/card/__docs__/card.md +1 -1
- package/src/lightning/card/card.js +1 -1
- package/src/lightning/datatable/datatable.js +6 -15
- package/src/lightning/datatable/templates/div/div.html +4 -2
- package/src/lightning/datatable/templates/table/table.html +4 -2
- package/src/lightning/dialog/README.md +1 -1
- package/src/lightning/input/__docs__/input.md +1 -1
- package/src/lightning/input/input.js +1 -1
- package/src/lightning/modal/__docs__/modal.md +187 -20
- package/src/lightning/positionLibrary/overlayDetector.js +10 -1
- package/src/lightning/primitiveCellCheckbox/primitiveCellCheckbox.js +15 -1
- package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +29 -0
- package/src/lightning/primitiveHeaderFactory/selectableHeader.html +3 -6
- package/src/lightning/progressIndicator/progressIndicator.js +1 -1
- package/src/lightning/treeGrid/__docs__/treeGrid.md +3 -0
- package/src/lightning/treeGrid/treeGrid.js +25 -30
- package/src/lightning/utilsPrivate/normalize.js +22 -6
package/metadata/raptor.json
CHANGED
|
@@ -1537,8 +1537,10 @@
|
|
|
1537
1537
|
"iconUtils": {},
|
|
1538
1538
|
"industriesActionPlanApi": {},
|
|
1539
1539
|
"industriesActionablelistApi": {},
|
|
1540
|
+
"industriesAssessmentApi": {},
|
|
1540
1541
|
"industriesCibApi": {},
|
|
1541
1542
|
"industriesClmApi": {},
|
|
1543
|
+
"industriesDataloadingApi": {},
|
|
1542
1544
|
"industriesDecisionMatrixDesignerApi": {},
|
|
1543
1545
|
"industriesDocgenApi": {},
|
|
1544
1546
|
"industriesEinsteinAIAcceleratorApi": {},
|
|
@@ -2315,13 +2317,13 @@
|
|
|
2315
2317
|
"name": "disabled"
|
|
2316
2318
|
},
|
|
2317
2319
|
{
|
|
2318
|
-
"name": "
|
|
2320
|
+
"name": "entityOptions"
|
|
2319
2321
|
},
|
|
2320
2322
|
{
|
|
2321
|
-
"name": "
|
|
2323
|
+
"name": "errorMessage"
|
|
2322
2324
|
},
|
|
2323
2325
|
{
|
|
2324
|
-
"name": "
|
|
2326
|
+
"name": "fieldLevelHelp"
|
|
2325
2327
|
},
|
|
2326
2328
|
{
|
|
2327
2329
|
"name": "items"
|
|
@@ -2365,7 +2367,7 @@
|
|
|
2365
2367
|
"slotNames": [],
|
|
2366
2368
|
"properties": [
|
|
2367
2369
|
{
|
|
2368
|
-
"name": "
|
|
2370
|
+
"name": "entityOptions"
|
|
2369
2371
|
},
|
|
2370
2372
|
{
|
|
2371
2373
|
"name": "items"
|
|
@@ -3671,6 +3673,7 @@
|
|
|
3671
3673
|
"uiGraphQLApi": {
|
|
3672
3674
|
"minVersion": "57.0"
|
|
3673
3675
|
},
|
|
3676
|
+
"uiGraphQLBatchApi": {},
|
|
3674
3677
|
"uiLayoutApi": {},
|
|
3675
3678
|
"uiLearningContentPlatformApi": {},
|
|
3676
3679
|
"uiListApi": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightning-base-components",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.3-alpha",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"external",
|
|
@@ -506,6 +506,10 @@
|
|
|
506
506
|
"name": "@salesforce/label/LightningDatatable.chooseARow",
|
|
507
507
|
"path": "scopedImports/@salesforce-label-LightningDatatable.chooseARow.js"
|
|
508
508
|
},
|
|
509
|
+
{
|
|
510
|
+
"name": "@salesforce/label/LightningDatatable.chooseARowSelectAll",
|
|
511
|
+
"path": "scopedImports/@salesforce-label-LightningDatatable.chooseARowSelectAll.js"
|
|
512
|
+
},
|
|
509
513
|
{
|
|
510
514
|
"name": "@salesforce/label/LightningDatatable.save",
|
|
511
515
|
"path": "scopedImports/@salesforce-label-LightningDatatable.save.js"
|
|
@@ -1082,6 +1086,10 @@
|
|
|
1082
1086
|
"name": "@salesforce/label/Global_Entity.last_modified_by",
|
|
1083
1087
|
"path": "scopedImports/@salesforce-label-Global_Entity.last_modified_by.js"
|
|
1084
1088
|
},
|
|
1089
|
+
{
|
|
1090
|
+
"name": "@salesforce/label/AddressAutocomplete.LookupButton",
|
|
1091
|
+
"path": "scopedImports/@salesforce-label-AddressAutocomplete.LookupButton.js"
|
|
1092
|
+
},
|
|
1085
1093
|
{
|
|
1086
1094
|
"name": "@salesforce/i18n/lang",
|
|
1087
1095
|
"path": "scopedImports/@salesforce-i18n-lang.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'Search Address';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'Choose a Row';
|
|
@@ -69,7 +69,6 @@ export default class LightningBaseCombobox extends LightningElement {
|
|
|
69
69
|
@api inputMaxlength;
|
|
70
70
|
@api showInputActivityIndicator = false;
|
|
71
71
|
@api required = false;
|
|
72
|
-
@api dropdownAlignment = 'left';
|
|
73
72
|
@api placeholder = i18n.placeholder;
|
|
74
73
|
@api inputLabel;
|
|
75
74
|
|
|
@@ -93,6 +92,7 @@ export default class LightningBaseCombobox extends LightningElement {
|
|
|
93
92
|
_inputAriaControls;
|
|
94
93
|
_activeElementDomId;
|
|
95
94
|
_autocomplete = 'off';
|
|
95
|
+
_dropdownAlignment = 'left';
|
|
96
96
|
originDisableDefaultHighlight;
|
|
97
97
|
privateDisableDefaultHighlight;
|
|
98
98
|
_editingMode = false;
|
|
@@ -115,6 +115,7 @@ export default class LightningBaseCombobox extends LightningElement {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
connectedCallback() {
|
|
118
|
+
this.overrideDropdownAlignment();
|
|
118
119
|
this.classList.add('slds-combobox_container');
|
|
119
120
|
this._connected = true;
|
|
120
121
|
this._keyboardInterface = this.dropdownKeyboardInterface();
|
|
@@ -125,6 +126,15 @@ export default class LightningBaseCombobox extends LightningElement {
|
|
|
125
126
|
this._listBoxElementCache = undefined;
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
@api
|
|
130
|
+
get dropdownAlignment() {
|
|
131
|
+
return this._dropdownAlignment;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
set dropdownAlignment(value) {
|
|
135
|
+
this._dropdownAlignment = value;
|
|
136
|
+
}
|
|
137
|
+
|
|
128
138
|
@api
|
|
129
139
|
get inputControlsElement() {
|
|
130
140
|
return this._inputAriaControls;
|
|
@@ -896,6 +906,7 @@ export default class LightningBaseCombobox extends LightningElement {
|
|
|
896
906
|
this._selectableItems < 3
|
|
897
907
|
? SMALL_MIN_HEIGHT
|
|
898
908
|
: MEDIUM_MIN_HEIGHT,
|
|
909
|
+
keepInViewport: true,
|
|
899
910
|
});
|
|
900
911
|
}
|
|
901
912
|
|
|
@@ -1064,6 +1075,33 @@ export default class LightningBaseCombobox extends LightningElement {
|
|
|
1064
1075
|
this.template.host.getAttribute('data-aria-invalid');
|
|
1065
1076
|
return computeAriaInvalid(ariaInvalid, true);
|
|
1066
1077
|
}
|
|
1078
|
+
|
|
1079
|
+
isShadowRoot(node) {
|
|
1080
|
+
return node && node.nodeType === 11;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
parentNodeContainsClass(host, className) {
|
|
1084
|
+
let element = host;
|
|
1085
|
+
while (element.parentNode) {
|
|
1086
|
+
element = this.isShadowRoot(element.parentNode)
|
|
1087
|
+
? element.parentNode.host
|
|
1088
|
+
: element.parentNode;
|
|
1089
|
+
if (element.classList && element.classList.contains(className)) {
|
|
1090
|
+
return true;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
return false;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
overrideDropdownAlignment() {
|
|
1097
|
+
let isModal = this.parentNodeContainsClass(
|
|
1098
|
+
this.template.host,
|
|
1099
|
+
'slds-modal'
|
|
1100
|
+
);
|
|
1101
|
+
if (isModal) {
|
|
1102
|
+
this._dropdownAlignment = 'auto';
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1067
1105
|
}
|
|
1068
1106
|
|
|
1069
1107
|
function scrollIntoViewIfNeeded(element, scrollingParent) {
|
|
@@ -23,11 +23,9 @@ Here is an example.
|
|
|
23
23
|
|
|
24
24
|
#### Creating Links Using Breadcrumbs
|
|
25
25
|
|
|
26
|
-
The behavior of a breadcrumb is similar to a link. If a link is not provided
|
|
27
|
-
|
|
28
|
-
provide custom navigation, use an `onclick` handler with `lightning-navigation`. If you provide a link in the `href` attribute,
|
|
29
|
-
calling `event.preventDefault()` enables you to bypass the link and use your
|
|
30
|
-
custom navigation instead.
|
|
26
|
+
The behavior of a breadcrumb is similar to a link for the purpose of navigation. If a link is not provided via the `href` attribute, the value defaults to `#`. Since a breadcrumb is used as navigation, we don't recommend leaving out the `href` attribute since `#` links to the same page when middle-clicked or opened in a new tab.
|
|
27
|
+
|
|
28
|
+
To provide custom navigation, use an `onclick` handler with `lightning-navigation`. If you provide a link in the `href` attribute, calling `event.preventDefault()` enables you to bypass the link and use your custom navigation instead.
|
|
31
29
|
|
|
32
30
|
```html
|
|
33
31
|
<template>
|
|
@@ -67,7 +65,8 @@ handleNavigateToCustomPage2(event) {
|
|
|
67
65
|
|
|
68
66
|
#### Generating Breadcrumbs with Iteration
|
|
69
67
|
|
|
70
|
-
Iterate over a list of items using `for:each` to generate breadcrumbs.
|
|
68
|
+
Iterate over a list of items using `for:each` to generate breadcrumbs. If you don't provide a link with an `onclick` handler, `href` defaults to `#`.
|
|
69
|
+
|
|
71
70
|
For example, you can create an array of breadcrumbs with label and name
|
|
72
71
|
values.
|
|
73
72
|
|
|
@@ -58,7 +58,7 @@ For a View All link, set the href value of the tag to a URL to take the user to
|
|
|
58
58
|
<lightning-button label="Old" slot="actions"></lightning-button>
|
|
59
59
|
<p class="slds-p-horizontal_small">Card Body (custom component)</p>
|
|
60
60
|
<div slot="footer">
|
|
61
|
-
<a class="slds-card__footer-action" href="
|
|
61
|
+
<a class="slds-card__footer-action" href="#"
|
|
62
62
|
>View All
|
|
63
63
|
<span class="slds-assistive-text">Accounts</span>
|
|
64
64
|
</a>
|
|
@@ -140,7 +140,7 @@ export default class LightningCard extends LightningElement {
|
|
|
140
140
|
get computedHidden() {
|
|
141
141
|
if (!this.label && this.hideHeader) {
|
|
142
142
|
console.warn(
|
|
143
|
-
'
|
|
143
|
+
'A `lightning-card` with `hide-header` requires `label` to be set.'
|
|
144
144
|
);
|
|
145
145
|
}
|
|
146
146
|
return !this.hideHeader;
|
|
@@ -213,6 +213,7 @@ export default class LightningDatatable extends LightningElement {
|
|
|
213
213
|
_renderMode = 'table';
|
|
214
214
|
_shouldResetFocus = false; // used to ensure focus isn't lost from changes in renderedRows
|
|
215
215
|
_suppressBottomBar = false;
|
|
216
|
+
_checkboxColumnHeaderId;
|
|
216
217
|
|
|
217
218
|
/************************* PUBLIC PROPERTIES *************************/
|
|
218
219
|
|
|
@@ -864,27 +865,13 @@ export default class LightningDatatable extends LightningElement {
|
|
|
864
865
|
return styleToString(styles);
|
|
865
866
|
}
|
|
866
867
|
|
|
867
|
-
/**
|
|
868
|
-
* Private method to get datatable header element
|
|
869
|
-
* used when getting checkboxColumnHeaderId for
|
|
870
|
-
* aria-labelledby in checkbox column
|
|
871
|
-
* @returns {(HTMLElement|null)}
|
|
872
|
-
*/
|
|
873
|
-
get checkboxColumnHeaderElement() {
|
|
874
|
-
return this.template.querySelector(
|
|
875
|
-
'lightning-primitive-header-factory'
|
|
876
|
-
);
|
|
877
|
-
}
|
|
878
|
-
|
|
879
868
|
/**
|
|
880
869
|
* Private method to get computedCheckboxColumnHeaderId
|
|
881
870
|
* from checkboxColumnHeaderElement for
|
|
882
871
|
* aria-labelledby in checkbox column
|
|
883
872
|
*/
|
|
884
873
|
get computedCheckboxColumnHeaderId() {
|
|
885
|
-
return this.
|
|
886
|
-
? this.checkboxColumnHeaderElement.computedColumnHeaderId
|
|
887
|
-
: '';
|
|
874
|
+
return this._checkboxColumnHeaderId;
|
|
888
875
|
}
|
|
889
876
|
|
|
890
877
|
get computedAriaLiveClassForNavMode() {
|
|
@@ -1344,6 +1331,10 @@ export default class LightningDatatable extends LightningElement {
|
|
|
1344
1331
|
this.fireSortedColumnChange(fieldName, columnKey, sortDirection);
|
|
1345
1332
|
}
|
|
1346
1333
|
|
|
1334
|
+
handleCheckboxHeaderId(event) {
|
|
1335
|
+
this._checkboxColumnHeaderId = event.detail;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1347
1338
|
/**
|
|
1348
1339
|
* Handles the `resizecol` event on lightning-datatable
|
|
1349
1340
|
*
|
|
@@ -84,7 +84,8 @@
|
|
|
84
84
|
sorted-direction={def.sortedDirection}
|
|
85
85
|
column-width={def.columnWidth}
|
|
86
86
|
show-checkbox={showSelectAllCheckbox}
|
|
87
|
-
hide-header={hideTableHeader}
|
|
87
|
+
hide-header={hideTableHeader}
|
|
88
|
+
onprivatecolumnheaderid={handleCheckboxHeaderId}>
|
|
88
89
|
</lightning-primitive-header-factory>
|
|
89
90
|
</template>
|
|
90
91
|
<template if:false={def.fixedWidth}>
|
|
@@ -105,7 +106,8 @@
|
|
|
105
106
|
column-width={def.columnWidth}
|
|
106
107
|
resizable={hasResizebleColumns}
|
|
107
108
|
resizestep={widthsData.resizeStep}
|
|
108
|
-
hide-header={hideTableHeader}
|
|
109
|
+
hide-header={hideTableHeader}
|
|
110
|
+
onprivatecolumnheaderid={handleCheckboxHeaderId}>
|
|
109
111
|
</lightning-primitive-header-factory>
|
|
110
112
|
</template>
|
|
111
113
|
</div>
|
|
@@ -73,7 +73,8 @@
|
|
|
73
73
|
sorted-direction={def.sortedDirection}
|
|
74
74
|
column-width={def.columnWidth}
|
|
75
75
|
show-checkbox={showSelectAllCheckbox}
|
|
76
|
-
hide-header={hideTableHeader}
|
|
76
|
+
hide-header={hideTableHeader}
|
|
77
|
+
onprivatecolumnheaderid={handleCheckboxHeaderId}>
|
|
77
78
|
</lightning-primitive-header-factory>
|
|
78
79
|
</template>
|
|
79
80
|
<template if:false={def.fixedWidth}>
|
|
@@ -94,7 +95,8 @@
|
|
|
94
95
|
column-width={def.columnWidth}
|
|
95
96
|
resizable={hasResizebleColumns}
|
|
96
97
|
resizestep={widthsData.resizeStep}
|
|
97
|
-
hide-header={hideTableHeader}
|
|
98
|
+
hide-header={hideTableHeader}
|
|
99
|
+
onprivatecolumnheaderid={handleCheckboxHeaderId}>
|
|
98
100
|
</lightning-primitive-header-factory>
|
|
99
101
|
</template>
|
|
100
102
|
</th>
|
|
@@ -336,7 +336,7 @@ When `multiple` is used, the email field expects a single email address or a com
|
|
|
336
336
|
|
|
337
337
|
#### File
|
|
338
338
|
|
|
339
|
-
An input field for selecting files to upload using an `Upload Files` button or a drag-and-drop zone.
|
|
339
|
+
An input field for selecting files to upload using an `Upload Files` button or a drag-and-drop zone. This field accepts files up to 3.5 MB.
|
|
340
340
|
|
|
341
341
|
To retrieve the list of selected files, use
|
|
342
342
|
`event.target.files` in the `onchange` event handler. Your selected files are returned in a `FileList` object, each specified as a `File` object with the `size` and `type` attributes.
|
|
@@ -574,7 +574,7 @@ export default class LightningInput extends LightningElement {
|
|
|
574
574
|
}
|
|
575
575
|
|
|
576
576
|
/**
|
|
577
|
-
* A
|
|
577
|
+
* A boolean value that controls whether accessibility tools read empty required textboxes as invalid. Default value is false.
|
|
578
578
|
* @type {boolean}
|
|
579
579
|
*/
|
|
580
580
|
@api
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
A `lightningModal` component overlays a message modal on top of the current app window. A modal interrupts a user’s workflow and draws attention to the message.
|
|
1
|
+
A `lightningModal` component overlays a message modal on top of the current app window. A modal interrupts a user’s workflow and draws attention to the message.
|
|
2
2
|
|
|
3
3
|
`LightningModal` implements the SLDS [modals](https://www.lightningdesignsystem.com/components/modals/) blueprint.
|
|
4
4
|
|
|
5
5
|
Create a modal component in response to a user action, such as clicking a button or link. The modal blocks interaction with everything else on the page until the user acts upon or dismisses the modal.
|
|
6
6
|
|
|
7
|
-
Unlike other components, this component doesn't use a `lightning-modal` tag or extend `LightningElement`. There is no `lightning-modal` component. Instead, you create a modal by extending `LightningModal` and using these helper `lightning-modal-*` components to provide a header, footer and the body of the modal.
|
|
7
|
+
Unlike other components, this component doesn't use a `lightning-modal` tag or extend `LightningElement`. There is no `lightning-modal` component. Instead, you create a modal by extending `LightningModal` and using these helper `lightning-modal-*` components to provide a header, footer and the body of the modal.
|
|
8
8
|
- `lightning-modal-body`
|
|
9
9
|
- `lightning-modal-header`
|
|
10
10
|
- `lightning-modal-footer`
|
|
11
11
|
|
|
12
12
|
To create a modal component, import `LightningModal` from `lightning/modal`. The component has access to the normal LWC resources as well as the special container, helper components, methods, and events of the `lightning/modal` module.
|
|
13
13
|
|
|
14
|
-
In this example, the `content` property passes data to the modal from the component that invokes it.
|
|
14
|
+
In this example, the `content` property passes data to the modal from the component that invokes it.
|
|
15
15
|
|
|
16
16
|
```js
|
|
17
17
|
/* c/myModal.js */
|
|
@@ -28,7 +28,7 @@ export default class MyModal extends LightningModal {
|
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
The modal’s HTML template uses helper `lightning-modal-*` components to provide a header, footer, and the body of the modal. In this example, the content for the modal body comes from the `content` property we defined in the modal's JavaScript file.
|
|
31
|
+
The modal’s HTML template uses helper `lightning-modal-*` components to provide a header, footer, and the body of the modal. In this example, the content for the modal body comes from the `content` property we defined in the modal's JavaScript file.
|
|
32
32
|
|
|
33
33
|
```html
|
|
34
34
|
<!-- c/myModal.html -->
|
|
@@ -42,19 +42,19 @@ The modal’s HTML template uses helper `lightning-modal-*` components to provid
|
|
|
42
42
|
</template>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
The `lightning-modal-body` component is required for the modal template.
|
|
45
|
+
The `lightning-modal-body` component is required for the modal template.
|
|
46
46
|
|
|
47
|
-
The `lightning-modal-header` and `lightning-modal-footer` components are optional, but recommended. The `lightning-modal-*` components render in the order they appear in the template. Place the `lightning-modal-body` component after `lightning-modal-header` and before the `lightning-modal-footer` component.
|
|
47
|
+
The `lightning-modal-header` and `lightning-modal-footer` components are optional, but recommended. The `lightning-modal-*` components render in the order they appear in the template. Place the `lightning-modal-body` component after `lightning-modal-header` and before the `lightning-modal-footer` component.
|
|
48
48
|
|
|
49
49
|
#### Open a Modal Instance
|
|
50
50
|
|
|
51
51
|
`LightningModal` provides an `.open()` method which opens a modal and returns a promise that asynchronously resolves with the result of the user’s interaction with the modal.
|
|
52
52
|
|
|
53
|
-
Each invocation of a modal component’s `.open()` method creates a unique instance of the modal. You can think of a modal as a self-contained application that starts from scratch when it opens. It displays the content you pass in through the `.open()` method or that you set within the modal's HTML template.
|
|
53
|
+
Each invocation of a modal component’s `.open()` method creates a unique instance of the modal. You can think of a modal as a self-contained application that starts from scratch when it opens. It displays the content you pass in through the `.open()` method or that you set within the modal's HTML template.
|
|
54
54
|
|
|
55
|
-
When you close a modal, the modal instance is destroyed, not hidden. On close, the modal must save the user’s input data or pass it to the invoking component as the promise result. Otherwise, the data is lost when the modal instance is closed.
|
|
55
|
+
When you close a modal, the modal instance is destroyed, not hidden. On close, the modal must save the user’s input data or pass it to the invoking component as the promise result. Otherwise, the data is lost when the modal instance is closed.
|
|
56
56
|
|
|
57
|
-
The `.open()` method lets you assign values to the modal's properties. `LightningModal` provides these properties.
|
|
57
|
+
The `.open()` method lets you assign values to the modal's properties. `LightningModal` provides these properties.
|
|
58
58
|
|
|
59
59
|
* `label` - Required. Sets the modal's title and assistive device label. If the modal has a header, set `label` in the `lightning-modal-header` component. If the modal doesn't have a header, set the `label` property when opening the modal.
|
|
60
60
|
|
|
@@ -95,14 +95,14 @@ The HTML template for this app contains a button that opens the modal and displa
|
|
|
95
95
|
<template>
|
|
96
96
|
<lightning-button
|
|
97
97
|
onclick={handleClick}
|
|
98
|
-
aria-haspopup="
|
|
98
|
+
aria-haspopup="dialog"
|
|
99
99
|
label="Open My Modal">
|
|
100
|
-
</lightning-button>
|
|
100
|
+
</lightning-button>
|
|
101
101
|
<p>Result: {result}</p>
|
|
102
102
|
</template>
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
You can also use `.open()` to pass data from your invoking component into the modal with custom properties decorated with `@api`. These properties can be any type, such as a string or an object that’s an array of key/value pairs to be assigned to the new modal instance.
|
|
105
|
+
You can also use `.open()` to pass data from your invoking component into the modal with custom properties decorated with `@api`. These properties can be any type, such as a string or an object that’s an array of key/value pairs to be assigned to the new modal instance.
|
|
106
106
|
|
|
107
107
|
For example, this app component sets an `options` property to a set of key/value pairs in `MyModal.open()`. The promise is handled using an arrow function that logs the result to the console.
|
|
108
108
|
|
|
@@ -155,14 +155,14 @@ export default class MyModal extends LightningModal {
|
|
|
155
155
|
>
|
|
156
156
|
{option.label}
|
|
157
157
|
</lightning-button>
|
|
158
|
-
</template>
|
|
158
|
+
</template>
|
|
159
159
|
</lightning-modal-body>
|
|
160
160
|
</template>
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
#### Close a Modal Instance
|
|
164
164
|
|
|
165
|
-
Use `this.close(result)` to close the modal, where `result` is anything you want to return from the modal. The `.close()` operation is asynchronous to display a brief fade out animation before the modal is destroyed. The `result` data can’t be modified after the close operation begins.
|
|
165
|
+
Use `this.close(result)` to close the modal, where `result` is anything you want to return from the modal. The `.close()` operation is asynchronous to display a brief fade out animation before the modal is destroyed. The `result` data can’t be modified after the close operation begins.
|
|
166
166
|
|
|
167
167
|
You can also close the modal with the default close button, the X at the top right corner. Closing a modal like this is the same as calling `this.close()` with an `undefined` result, so any data input is lost.
|
|
168
168
|
|
|
@@ -320,7 +320,7 @@ export default class MyModalForm extends LightningModal {
|
|
|
320
320
|
|
|
321
321
|
A modal can only fire events captured by the component that opened it, not the modal itself. Normal techniques can't catch events that fire from the modal, because the events bubble up to a top root element outside of the component that opened the modal.
|
|
322
322
|
|
|
323
|
-
To capture modal events, attach them in the `.open()` method invoked by the component that opens the modal.
|
|
323
|
+
To capture modal events, attach them in the `.open()` method invoked by the component that opens the modal.
|
|
324
324
|
|
|
325
325
|
For example, here's a custom `select` event dispatched from `MyModal`.
|
|
326
326
|
|
|
@@ -374,18 +374,185 @@ handleOpenModal() {
|
|
|
374
374
|
|
|
375
375
|
See [Create and Dispatch Events](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/events_create_dispatch) in the LWC Dev Guide for more information about events.
|
|
376
376
|
|
|
377
|
+
#### Modal Events with Aura
|
|
378
|
+
|
|
379
|
+
For `LightningModal`, only the top level LWC component or application can communicate to the parent Aura component or application layer with eventing. This topmost component is usually the one that opens the `LightningModal`. `LightningModal`'s child components can't event to a parent Aura component or application layer.
|
|
380
|
+
|
|
381
|
+
All required eventing that should occur during the `LightningModal`'s life cycle must be passed in when you call `Modal.open()`. See `onselect` within `.open()` in the **Modal Events** section.
|
|
382
|
+
|
|
383
|
+
If you want the Aura layer to respond to events within child components embedded in the `LightningModal`, use event bubbling to move any data that you want to make available to the Aura layer into the topmost LWC component that opened the modal. Then, send the event from the LWC component.
|
|
384
|
+
|
|
385
|
+
With this in mind, there are two suggested methods for extracting data from the `LightningModal` to the Aura layer.
|
|
386
|
+
|
|
387
|
+
1. To only communicate data out of modal after it's closed, first, close the modal, and pass the data out with `this.close({ data })`, and handle the data received in `.then((result) { ... })` where the Modal is initially opened.
|
|
388
|
+
2. To continuously communicate data out of the `LightningModal` while the modal remains open, use events created and passed in when opening the modal from `Modal.open({ size, title, onmyevent })`.
|
|
389
|
+
|
|
390
|
+
These extracting methods fit into the larger LWC Modal-to-Aura event workflow.
|
|
391
|
+
|
|
392
|
+
1. Pass any events that should occur within the modal through `LightningModal`'s `.open()` method
|
|
393
|
+
2. Have the `LightningModal` JavaScript code fire any custom events
|
|
394
|
+
3. In the topmost LWC component that opened the modal, create an event handler to process the events, including stopping propagation.
|
|
395
|
+
4. Fire a separate event containing the LWC-processed event details and send it to the Aura parent component.
|
|
396
|
+
5. Use an Aura-based event handler to handle and process the event.
|
|
397
|
+
|
|
398
|
+
For more information, see [Send Events to an Enclosing Aura Component](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.events_sending_to_aura_components) and [Events Best Practices](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/events_best_practices).
|
|
399
|
+
|
|
400
|
+
Let's see this workflow in action. In this example, we'll create a button (`lightning-button`) that launches a modal (`LightningModal`) containing a tree grid component (`lightning-tree-grid`) with a button in each record row that automatically navigates our user to that record's page (`lightning-navigation`). This use case requires data passing between our LWC components and a parent Aura component.
|
|
401
|
+
|
|
402
|
+
Because `lightning-navigation` requires you to pass in a `recordId` to construct a page reference, we need to pass the record's data out of `LightningModal`, and then use the methods provided by `lightning-navigation`. With modal's limitations for event bubbling to the Aura layer, we can't just wrap the button or treegrid with `lightning-navigation`. We need to pull that data up to the topmost LWC component, where the `LightningModal` `.open()` is called, for our Aura wrapper to handle the navigation.
|
|
403
|
+
|
|
404
|
+
So, we `import` the `lightning-navigation` component into the topmost LWC component that sits within the Aura layer by passing the data through `LightningModal`'s close method, `this.close({ data })`. Then the parent LWC component invokes the methods provided by `lightning-navigation`, which handles the navigation away from the page after the modal exits. From a UX perspective, this also lets us close the modal first, since `lightning-navigation` takes the user away from the current page.
|
|
405
|
+
|
|
406
|
+
Note that this sample code isn't fully functional. We're only showing the relevant code that makes the `lightning-navigation` use case work with `LightningModal`.
|
|
407
|
+
|
|
408
|
+
Here's our Aura component, containing our topmost LWC component, `myLwcAppModalLauncher`.
|
|
409
|
+
|
|
410
|
+
```html
|
|
411
|
+
/* c/myApp.cmp */
|
|
412
|
+
<aura:component>
|
|
413
|
+
<!-- <c:myLwcTreeGridWithNavigation/> component is a child component
|
|
414
|
+
inside of <c:myLwcAppModalLauncher/>
|
|
415
|
+
-->
|
|
416
|
+
<c:myLwcAppModalLauncher/>
|
|
417
|
+
</aura:component>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
The topmost component, `myLwcAppModalLauncher`, launches and handles events that occur within our modal (`MyModal`). `myLwcAppModalLauncher` is also where we import the `lightning-navigation` component and use the `rowId` handed up through modal's `this.close({ ..., rowId })` function.
|
|
421
|
+
|
|
422
|
+
```html
|
|
423
|
+
<!-- c/myLwcAppModalLauncher.html -->
|
|
424
|
+
|
|
425
|
+
<template>
|
|
426
|
+
<lightning-button
|
|
427
|
+
onclick={handleModalOpen}
|
|
428
|
+
aria-haspopup="dialog"
|
|
429
|
+
label="Launch Navigation Modal">
|
|
430
|
+
</lightning-button>
|
|
431
|
+
</template>
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
```js
|
|
435
|
+
/* c/myLwcAppModalLauncher.js */
|
|
436
|
+
|
|
437
|
+
import { LightningElement, wire } from 'lwc';
|
|
438
|
+
import { NavigationMixin } from 'lightning/navigation';
|
|
439
|
+
import MyModal from 'c/myModalWithTreeGridNavigation';
|
|
440
|
+
|
|
441
|
+
export default class MyLwcAppModalLauncher extends NavigationMixin(LightningElement) {
|
|
442
|
+
|
|
443
|
+
/// ... other modal code
|
|
444
|
+
|
|
445
|
+
handleModalOpen() {
|
|
446
|
+
// open up the Modal
|
|
447
|
+
MyModal.open({
|
|
448
|
+
size: 'medium',
|
|
449
|
+
heading: 'Navigate to Record Page',
|
|
450
|
+
description: 'Navigate to a record page by clicking the row button',
|
|
451
|
+
options: [{ data }, { data }],
|
|
452
|
+
}).then((result) => {
|
|
453
|
+
// when the LightningModal closes, result is whatever
|
|
454
|
+
// data that was passed out using this.close({ data })
|
|
455
|
+
if (result === null) {
|
|
456
|
+
// do something else
|
|
457
|
+
} else {
|
|
458
|
+
// shouldNavigate is boolean, arbitrary
|
|
459
|
+
// rowId is what's needed for lightning-navigation
|
|
460
|
+
const { shouldNavigate, rowId } = result;
|
|
461
|
+
if (shouldNavigate) {
|
|
462
|
+
this.navigateToObjectHome(rowId);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
navigateToObjectHome(rowId) {
|
|
469
|
+
// construct the page ref
|
|
470
|
+
const pageRef = {
|
|
471
|
+
type: 'standard__recordPage',
|
|
472
|
+
attributes: {
|
|
473
|
+
recordId: rowId,
|
|
474
|
+
actionName: 'view'
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
// then call the .Navigate method with the pageRef
|
|
478
|
+
this[NavigationMixin.Navigate](pageRef);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/* ... other modal code */
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
This `template` is our modal, containing a tree grid with the navigation buttons, named `c-my-lwc-tree-grid-with-navigation`. The `handleNavSelection` function in this component processes the `rowId` data for the modal component to pass to its parent.
|
|
485
|
+
|
|
486
|
+
```html
|
|
487
|
+
<!-- c/myModalWithTreeGridNavigation.html -->
|
|
488
|
+
<template>
|
|
489
|
+
<lightning-modal-header label="My Modal Heading">
|
|
490
|
+
The modal tagline.
|
|
491
|
+
</lightning-modal-header>
|
|
492
|
+
<lightning-modal-body>
|
|
493
|
+
<h2>Choose a record to navigate to:</h2>
|
|
494
|
+
<!-- custom event listener when button clicked inside tree grid -->
|
|
495
|
+
<div onnavselection={handleNavSelection}>
|
|
496
|
+
<c-my-lwc-tree-grid-with-navigation></c-my-lwc-tree-grid-with-navigation>
|
|
497
|
+
</div>
|
|
498
|
+
</lightning-modal-body>
|
|
499
|
+
<!-- no <lightning-modal-footer> in this example -->
|
|
500
|
+
</template>
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
```js
|
|
504
|
+
/* c/myModalWithTreeGridNavigation.js */
|
|
505
|
+
handleNavSelection(event) {
|
|
506
|
+
event.stopPropagation();
|
|
507
|
+
const { detail: { rowId } } = event;
|
|
508
|
+
if (rowId) {
|
|
509
|
+
// rowId value is important to lightning-navigation
|
|
510
|
+
// passing this data out through the LightningModal's
|
|
511
|
+
// .close() method, then handled in the .then((result) {})
|
|
512
|
+
// see code above: c/myLwcAppModalLauncher.js
|
|
513
|
+
this.close({ shouldNavigate: true, rowId });
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
```js
|
|
519
|
+
/* c/myLwcTreeGridWithNavigation.js */
|
|
520
|
+
|
|
521
|
+
dispatchNavSelectionEvent(rowId) {
|
|
522
|
+
// add rowId to event.detail
|
|
523
|
+
// this custom event listener exists in
|
|
524
|
+
// LightningModal body code, see code above:
|
|
525
|
+
// c/myModalWithTreeGridNavigation.html
|
|
526
|
+
const eventToFire = new CustomEvent('navselection', {
|
|
527
|
+
detail: { rowId },
|
|
528
|
+
bubbles: true,
|
|
529
|
+
cancelable: false
|
|
530
|
+
});
|
|
531
|
+
// dispatch custom event
|
|
532
|
+
// see event listener added to lightning-modal-body
|
|
533
|
+
this.dispatchEvent(eventToFire);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
handleRowButtonClick(event) {
|
|
537
|
+
// simplified handler to get row.Id
|
|
538
|
+
// from the tree grid row button that was clicked
|
|
539
|
+
const row = event.detail.row;
|
|
540
|
+
this.dispatchNavSelectionEvent(row.Id);
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
377
544
|
#### Styling Variants
|
|
378
545
|
|
|
379
|
-
The `lightning-modal-header` and `lightning-modal-footer` child components are optional, and you can choose to not include one or the other in your modal.
|
|
546
|
+
The `lightning-modal-header` and `lightning-modal-footer` child components are optional, and you can choose to not include one or the other in your modal.
|
|
380
547
|
|
|
381
548
|
The headerless variant of `LightningModal` has these additional requirements.
|
|
382
549
|
- Must set a descriptive modal title with the `label` property using `Modal.open({ label })` or you’ll get a console error.
|
|
383
|
-
- The `label` property is required for all variants of `LightningModal`. Assistive devices read the `label` value, even though the headerless modal variant doesn't display the label.
|
|
550
|
+
- The `label` property is required for all variants of `LightningModal`. Assistive devices read the `label` value, even though the headerless modal variant doesn't display the label.
|
|
384
551
|
- Because this variant doesn't use `lightning-modal-header`, you have to manually create an `<h1>` heading in `lightning-modal-body`. Provide accessible structure by starting with heading level `<h1>` and using levels up to `<h6>` appropriately. For more information, see [Semantic Structure, Headings on WebAim.org](https://webaim.org/techniques/semanticstructure/#headings).
|
|
385
552
|
|
|
386
553
|
The `LightningModal` component also supports the SLDS [Directional variant](https://www.lightningdesignsystem.com/components/modals/#Directional) modal blueprint pattern.
|
|
387
554
|
|
|
388
|
-
To achieve the directional button layout, place the buttons in a `div` with the `slds-modal__footer_directional` class.
|
|
555
|
+
To achieve the directional button layout, place the buttons in a `div` with the `slds-modal__footer_directional` class.
|
|
389
556
|
|
|
390
557
|
```html
|
|
391
558
|
<!-- c/modalDirectional.html -->
|
|
@@ -403,7 +570,7 @@ To achieve the directional button layout, place the buttons in a `div` with the
|
|
|
403
570
|
|
|
404
571
|
#### Styling Hooks
|
|
405
572
|
|
|
406
|
-
The `lightning-modal-*` helper components support [style hooks](https://www.lightningdesignsystem.com/components/modals/#Styling-Hooks-Overview). The styling hooks for the template that invokes the helper components doesn't carry over to them, so you must style each helper component individually.
|
|
573
|
+
The `lightning-modal-*` helper components support [style hooks](https://www.lightningdesignsystem.com/components/modals/#Styling-Hooks-Overview). The styling hooks for the template that invokes the helper components doesn't carry over to them, so you must style each helper component individually.
|
|
407
574
|
|
|
408
575
|
Customizing the styling on the white modal frame and background, close button, or gray backdrop isn't supported.
|
|
409
576
|
|
|
@@ -411,4 +578,4 @@ Customizing the styling on the white modal frame and background, close button, o
|
|
|
411
578
|
|
|
412
579
|
The `lightning-modal-header` component renders the `label` value in an `<h1>` element. If your modal uses the header, begin any additional heading levels in the modal with `<h2>` for accessibility. Provide accessible structure by using heading levels up to `<h6>` appropriately. For more information, see [Semantic Structure, Headings on WebAim.org](https://webaim.org/techniques/semanticstructure/#headings).
|
|
413
580
|
|
|
414
|
-
To include tagline text or link content for the header section, add it between the `<lightning-modal-header>` tags.
|
|
581
|
+
To include tagline text or link content for the header section, add it between the `<lightning-modal-header>` tags.
|
|
@@ -6,6 +6,7 @@ export const OVERLAY_TYPE = {
|
|
|
6
6
|
DIALOG: 'lightning-dialog',
|
|
7
7
|
POPOVER: 'lightning-popover',
|
|
8
8
|
PANEL: 'uiPanel',
|
|
9
|
+
SLDSMODAL: 'slds-modal',
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export function isOverlay(element) {
|
|
@@ -30,6 +31,13 @@ export function isOverlay(element) {
|
|
|
30
31
|
if (isPanel) {
|
|
31
32
|
return OVERLAY_TYPE.PANEL;
|
|
32
33
|
}
|
|
34
|
+
|
|
35
|
+
const isSldsModal =
|
|
36
|
+
element.classList && element.classList.contains(OVERLAY_TYPE.SLDSMODAL);
|
|
37
|
+
if (isSldsModal) {
|
|
38
|
+
return OVERLAY_TYPE.SLDSMODAL;
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
return OVERLAY_TYPE.NONE;
|
|
34
42
|
}
|
|
35
43
|
|
|
@@ -80,7 +88,8 @@ export class OverlayDetector {
|
|
|
80
88
|
return (
|
|
81
89
|
this.isInside &&
|
|
82
90
|
(this._detection.type === OVERLAY_TYPE.MODAL ||
|
|
83
|
-
this._detection.type === OVERLAY_TYPE.DIALOG
|
|
91
|
+
this._detection.type === OVERLAY_TYPE.DIALOG ||
|
|
92
|
+
this._detection.type === OVERLAY_TYPE.SLDSMODAL)
|
|
84
93
|
);
|
|
85
94
|
}
|
|
86
95
|
|
|
@@ -11,12 +11,26 @@ const i18n = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export default class PrimitiveCellCheckbox extends PrimitiveDatatableCell {
|
|
14
|
+
_columnHeaderId = '';
|
|
14
15
|
@api rowIndex = 0;
|
|
15
16
|
@api isSelected = false;
|
|
16
17
|
@api isDisabled = false;
|
|
17
18
|
@api type = 'checkbox';
|
|
18
19
|
@api dtContextId;
|
|
19
|
-
@api
|
|
20
|
+
@api
|
|
21
|
+
get columnHeaderId() {
|
|
22
|
+
return this._columnHeaderId;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
set columnHeaderId(id) {
|
|
26
|
+
this._columnHeaderId = id || '';
|
|
27
|
+
const labelId = this.computedLabelId;
|
|
28
|
+
if (labelId) {
|
|
29
|
+
synchronizeAttrs(this.template.querySelector('input'), {
|
|
30
|
+
'aria-labelledby': `${labelId} ${this._columnHeaderId}`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
20
34
|
|
|
21
35
|
render() {
|
|
22
36
|
if (this.type === 'radio') {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import labelChooseARow from '@salesforce/label/LightningDatatable.chooseARow';
|
|
2
|
+
import labelChooseARowSelectAll from '@salesforce/label/LightningDatatable.chooseARowSelectAll';
|
|
2
3
|
import labelSelectAll from '@salesforce/label/LightningDatatable.selectAll';
|
|
3
4
|
import labelSort from '@salesforce/label/LightningDatatable.sort';
|
|
4
5
|
import labelSortAsc from '@salesforce/label/LightningDatatable.sortAsc';
|
|
@@ -15,6 +16,7 @@ import nonsortable from './nonsortableHeader.html';
|
|
|
15
16
|
|
|
16
17
|
const i18n = {
|
|
17
18
|
chooseARow: labelChooseARow,
|
|
19
|
+
chooseARowSelectAll: labelChooseARowSelectAll,
|
|
18
20
|
selectAll: labelSelectAll,
|
|
19
21
|
sort: labelSort,
|
|
20
22
|
sortAsc: labelSortAsc,
|
|
@@ -201,6 +203,17 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
201
203
|
);
|
|
202
204
|
}
|
|
203
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Computes column header label
|
|
208
|
+
*
|
|
209
|
+
* @return {string} The computed column header label
|
|
210
|
+
*/
|
|
211
|
+
get computedColumnHeaderLabel() {
|
|
212
|
+
return this.showCheckbox
|
|
213
|
+
? this.i18n.chooseARowSelectAll
|
|
214
|
+
: this.i18n.chooseARow;
|
|
215
|
+
}
|
|
216
|
+
|
|
204
217
|
/**
|
|
205
218
|
* Returns the header's aria role
|
|
206
219
|
*
|
|
@@ -316,6 +329,22 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
316
329
|
if (this.isSelectableHeader && this.showCheckbox) {
|
|
317
330
|
this.updateBulkSelectionCheckbox();
|
|
318
331
|
}
|
|
332
|
+
if (this.isSelectableHeader) {
|
|
333
|
+
const columnHeaderId = this.computedColumnHeaderId;
|
|
334
|
+
const columnHeaderEvent = new CustomEvent('privatecolumnheaderid', {
|
|
335
|
+
detail: columnHeaderId,
|
|
336
|
+
});
|
|
337
|
+
this.dispatchEvent(columnHeaderEvent);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
disconnectedCallback() {
|
|
342
|
+
if (this.isSelectableHeader) {
|
|
343
|
+
const columnHeaderEvent = new CustomEvent('privatecolumnheaderid', {
|
|
344
|
+
detail: null,
|
|
345
|
+
});
|
|
346
|
+
this.dispatchEvent(columnHeaderEvent);
|
|
347
|
+
}
|
|
319
348
|
}
|
|
320
349
|
|
|
321
350
|
/************************** EVENT HANDLERS ***************************/
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
<span id="column-group-header" class="slds-assistive-text" data-column-header>
|
|
3
|
+
{computedColumnHeaderLabel}
|
|
4
|
+
</span>
|
|
2
5
|
<!-- Header Content -->
|
|
3
6
|
<div class="slds-th__action slds-th__action_form slds-cell-fixed" style={columnStyles}>
|
|
4
7
|
<template if:true={showCheckbox}>
|
|
5
8
|
<span class="slds-checkbox">
|
|
6
|
-
|
|
7
9
|
<!-- Selectable Checkbox -->
|
|
8
10
|
<input
|
|
9
11
|
type="checkbox"
|
|
@@ -23,10 +25,5 @@
|
|
|
23
25
|
</label>
|
|
24
26
|
</span>
|
|
25
27
|
</template>
|
|
26
|
-
<template if:false={showCheckbox}>
|
|
27
|
-
<span id="column-group-header" class="slds-assistive-text" data-column-header>
|
|
28
|
-
{i18n.chooseARow}
|
|
29
|
-
</span>
|
|
30
|
-
</template>
|
|
31
28
|
</div>
|
|
32
29
|
</template>
|
|
@@ -33,7 +33,7 @@ export default class LightningProgressIndicator extends LightningElement {
|
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Changes the appearance of the progress indicator for the base type only.
|
|
36
|
-
* Valid values are base or
|
|
36
|
+
* Valid values are base or shade. The shade variant adds a light gray border to the step indicators.
|
|
37
37
|
* The default is base.
|
|
38
38
|
* @type {string}
|
|
39
39
|
* @default base
|
|
@@ -36,6 +36,9 @@ include:
|
|
|
36
36
|
- Selecting of rows
|
|
37
37
|
- Text wrapping and clipping
|
|
38
38
|
|
|
39
|
+
This component provides styling for up to 20 nested levels. For tree grids that require more than 20 nested levels,
|
|
40
|
+
build your own component.
|
|
41
|
+
|
|
39
42
|
A checkbox is displayed by default in the first column. The `hide-checkbox-column` attribute
|
|
40
43
|
removes the checkbox.
|
|
41
44
|
|
|
@@ -272,39 +272,34 @@ export default class LightningTreeGrid extends LightningElement {
|
|
|
272
272
|
|
|
273
273
|
handleRowSelection(event) {
|
|
274
274
|
event.stopPropagation();
|
|
275
|
-
let selectedRowKeys;
|
|
276
275
|
// pass the event through
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
276
|
+
if (event.detail.config) {
|
|
277
|
+
switch (event.detail.config.action) {
|
|
278
|
+
case ROWS_ACTION.ROW_SELECT:
|
|
279
|
+
this._selectedRowKeys.push(event.detail.config.value);
|
|
280
|
+
break;
|
|
281
|
+
case ROWS_ACTION.ROW_DESELECT: {
|
|
282
|
+
const index = this._selectedRowKeys.indexOf(
|
|
283
|
+
event.detail.config.value
|
|
284
|
+
);
|
|
285
|
+
this._selectedRowKeys.splice(index, 1);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
case ROWS_ACTION.SELECT_ALL_ROWS:
|
|
289
|
+
this._selectedRowKeys = this.getSelectedRowKeys(
|
|
290
|
+
event.detail.selectedRows
|
|
291
|
+
);
|
|
292
|
+
break;
|
|
293
|
+
case ROWS_ACTION.DESELECT_ALL_ROWS:
|
|
294
|
+
this._selectedRowKeys = this.getSelectedRowKeys(
|
|
295
|
+
event.detail.selectedRows
|
|
296
|
+
);
|
|
297
|
+
break;
|
|
298
|
+
default:
|
|
299
|
+
break;
|
|
289
300
|
}
|
|
290
|
-
|
|
291
|
-
selectedRowKeys = this._selectedRowKeys.slice();
|
|
292
|
-
this._selectedRowKeys = this.getSelectedRowKeys(
|
|
293
|
-
event.detail.selectedRows
|
|
294
|
-
);
|
|
295
|
-
break;
|
|
296
|
-
case ROWS_ACTION.DESELECT_ALL_ROWS:
|
|
297
|
-
selectedRowKeys = this._selectedRowKeys.slice();
|
|
298
|
-
this._selectedRowKeys = this.getSelectedRowKeys(
|
|
299
|
-
event.detail.selectedRows
|
|
300
|
-
);
|
|
301
|
-
break;
|
|
302
|
-
default:
|
|
303
|
-
this._selectedRowKeys.push(event.detail.config.value);
|
|
304
|
-
selectedRowKeys = this._selectedRowKeys.slice();
|
|
305
|
-
break;
|
|
301
|
+
event.detail.config.selectedRowKeys = this._selectedRowKeys.slice();
|
|
306
302
|
}
|
|
307
|
-
event.detail.config.selectedRowKeys = selectedRowKeys;
|
|
308
303
|
this.fireSelectedRowsChange(event.detail);
|
|
309
304
|
}
|
|
310
305
|
|
|
@@ -25,6 +25,23 @@ export function normalizeBoolean(value) {
|
|
|
25
25
|
return typeof value === 'string' || !!value;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
const isNotNumber = (value) => {
|
|
29
|
+
// Need to make sure it is a number than check isNaN
|
|
30
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN#difference_between_number.isnan_and_global_isnan
|
|
31
|
+
if (
|
|
32
|
+
Number.isNaN(value) ||
|
|
33
|
+
value === null ||
|
|
34
|
+
value === undefined ||
|
|
35
|
+
value === '' ||
|
|
36
|
+
Array.isArray(value)
|
|
37
|
+
) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
// to eliminate non numeric string or other non numeric-typed objects
|
|
41
|
+
const convertedNumber = Number(value);
|
|
42
|
+
return Number.isNaN(convertedNumber);
|
|
43
|
+
};
|
|
44
|
+
|
|
28
45
|
/**
|
|
29
46
|
* A number normalization utility for attributes.
|
|
30
47
|
* @param {number} value - The value to normalize.
|
|
@@ -39,18 +56,17 @@ export function normalizeNumber(value, config = {}) {
|
|
|
39
56
|
const returnValueIfInvalid =
|
|
40
57
|
(typeof fallbackValue === 'number' && fallbackValue) || undefined;
|
|
41
58
|
|
|
42
|
-
|
|
43
|
-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN#difference_between_number.isnan_and_global_isnan
|
|
44
|
-
if (typeof value !== 'number' || Number.isNaN(value)) {
|
|
59
|
+
if (isNotNumber(value)) {
|
|
45
60
|
return returnValueIfInvalid;
|
|
46
61
|
}
|
|
47
|
-
if (
|
|
62
|
+
if (!isNotNumber(value) && value < minValue) {
|
|
48
63
|
return returnValueIfInvalid;
|
|
49
64
|
}
|
|
50
|
-
if (
|
|
65
|
+
if (!isNotNumber(value) && value > maxValue) {
|
|
51
66
|
return returnValueIfInvalid;
|
|
52
67
|
}
|
|
53
|
-
|
|
68
|
+
// multiplying 1 is to make sure to convert from a numeric string to a number
|
|
69
|
+
return value * 1;
|
|
54
70
|
}
|
|
55
71
|
|
|
56
72
|
export function normalizeArray(value) {
|