lightning-base-components 1.17.1-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 +32 -17
- package/package.json +15 -11
- package/scopedImports/@salesforce-label-AddressAutocomplete.LookupButton.js +1 -0
- package/scopedImports/@salesforce-label-LightningDatatable.chooseARowSelectAll.js +1 -0
- package/scopedImports/@salesforce-label-LightningLookup.noAccess.js +1 -0
- package/scopedImports/@salesforce-label-LightningToast.close.js +1 -0
- package/src/lightning/accordionSection/accordionSection.html +2 -2
- package/src/lightning/accordionSection/accordionSection.js +21 -2
- package/src/lightning/baseCombobox/baseCombobox.html +1 -1
- package/src/lightning/baseCombobox/baseCombobox.js +56 -3
- package/src/lightning/baseCombobox/keyboard.js +26 -0
- package/src/lightning/breadcrumb/__docs__/breadcrumb.md +5 -6
- package/src/lightning/buttonGroup/buttonGroup.css +9 -0
- package/src/lightning/buttonGroup/buttonGroup.html +1 -1
- package/src/lightning/buttonStateful/buttonStateful.html +2 -1
- package/src/lightning/buttonStateful/buttonStateful.js +10 -0
- package/src/lightning/card/__docs__/card.md +2 -2
- package/src/lightning/card/card.html +3 -1
- package/src/lightning/card/card.js +51 -15
- package/src/lightning/card/utils.js +0 -14
- package/src/lightning/checkboxGroup/checkboxGroup.html +1 -1
- package/src/lightning/datatable/datatable.js +6 -15
- package/src/lightning/datatable/renderManager.js +14 -5
- package/src/lightning/datatable/rowSelection.js +4 -4
- package/src/lightning/datatable/rows.js +1 -0
- package/src/lightning/datatable/templates/div/div.html +4 -2
- package/src/lightning/datatable/templates/table/table.html +6 -2
- package/src/lightning/dialog/README.md +1 -1
- package/src/lightning/focusUtils/focus.js +42 -0
- package/src/lightning/focusUtils/focusUtils.js +1 -0
- package/src/lightning/formattedAddress/formattedAddress.js +1 -1
- package/src/lightning/input/__docs__/input.md +1 -1
- package/src/lightning/input/input.html +5 -2
- package/src/lightning/input/input.js +14 -2
- package/src/lightning/modal/__docs__/modal.md +187 -20
- package/src/lightning/modalBase/modalBase.js +7 -6
- package/src/lightning/positionLibrary/overlayDetector.js +10 -1
- package/src/lightning/primitiveBubble/primitiveBubble.css +9 -0
- package/src/lightning/primitiveBubble/primitiveBubble.js +3 -1
- package/src/lightning/primitiveCellActions/primitiveCellActions.html +1 -0
- package/src/lightning/primitiveCellActions/primitiveCellActions.js +1 -1
- package/src/lightning/primitiveCellCheckbox/primitiveCellCheckbox.js +15 -1
- package/src/lightning/primitiveCellFactory/cellWithStandardLayout.html +3 -1
- package/src/lightning/primitiveCellFactory/primitiveCellFactory.js +1 -0
- package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +29 -0
- package/src/lightning/primitiveHeaderFactory/selectableHeader.html +3 -6
- package/src/lightning/primitiveTreegridCellToggle/primitiveTreegridCellToggle.js +8 -3
- package/src/lightning/progressIndicator/progressIndicator.js +1 -1
- package/src/lightning/radioGroup/radioGroup.html +1 -1
- package/src/lightning/textarea/textarea.js +13 -1
- package/src/lightning/tooltipLibrary/tooltipLibrary.js +7 -0
- package/src/lightning/tree/tree.html +1 -1
- package/src/lightning/tree/tree.js +25 -1
- package/src/lightning/treeGrid/__docs__/treeGrid.md +15 -0
- package/src/lightning/treeGrid/treeGrid.js +25 -22
- package/src/lightning/utilsPrivate/ariaLevelHeadingUtils.js +11 -0
- package/src/lightning/utilsPrivate/normalize.js +22 -6
- package/src/lightning/utilsPrivate/os.js +36 -0
- package/src/lightning/utilsPrivate/utilsPrivate.js +7 -0
- package/src/lightning/verticalNavigationSection/verticalNavigationSection.html +1 -1
- package/src/lightning/verticalNavigationSection/verticalNavigationSection.js +22 -1
- package/scopedImports/@salesforce-label-LightningToast.missingToastLabel.js +0 -1
- package/scopedImports/@salesforce-label-LightningToastContainer.missingToastConfig.js +0 -1
- package/scopedImports/@salesforce-label-LightningToastContainer.missingToastProperty.js +0 -1
|
@@ -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.
|
|
@@ -10,7 +10,10 @@ import {
|
|
|
10
10
|
isAriaDescriptionSupported,
|
|
11
11
|
} from 'lightning/utilsPrivate';
|
|
12
12
|
import { instanceName, secure } from 'lightning/overlayUtils';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
getElementWithFocus,
|
|
15
|
+
returnFocusToElement,
|
|
16
|
+
} from 'lightning/focusUtils';
|
|
14
17
|
import closeButtonAltText from '@salesforce/label/LightningModalBase.cancelandclose';
|
|
15
18
|
import disableCloseBtnMessage from '@salesforce/label/LightningModalBase.waitstate';
|
|
16
19
|
|
|
@@ -147,7 +150,7 @@ export default class LightningModalBase extends LightningElement {
|
|
|
147
150
|
// we track both in order to handle transition correctly
|
|
148
151
|
const isSwitchingToDisabled =
|
|
149
152
|
!this.disableCloseButton && this.disableClose;
|
|
150
|
-
/* Future enhancement possibility - trigger setInterval to remove and
|
|
153
|
+
/* Future enhancement possibility - trigger setInterval to remove and
|
|
151
154
|
again add back 'Processing' text, as this will indicate to the screen
|
|
152
155
|
reader user that the interface continues to be busy
|
|
153
156
|
*/
|
|
@@ -349,10 +352,8 @@ export default class LightningModalBase extends LightningElement {
|
|
|
349
352
|
*/
|
|
350
353
|
returnFocusToBackground() {
|
|
351
354
|
const { savedActiveElement } = this;
|
|
352
|
-
const
|
|
353
|
-
if (
|
|
354
|
-
savedActiveElement.focus();
|
|
355
|
-
} else {
|
|
355
|
+
const elementWasFocused = returnFocusToElement(savedActiveElement);
|
|
356
|
+
if (!elementWasFocused) {
|
|
356
357
|
// eslint-disable-next-line no-console
|
|
357
358
|
console.warn('Modal :: Nothing to return focus to');
|
|
358
359
|
}
|
|
@@ -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
|
|
|
@@ -1,2 +1,11 @@
|
|
|
1
1
|
/* @import 'lightning/sldsCommon';
|
|
2
2
|
@import './tooltip.slds.css'; */
|
|
3
|
+
|
|
4
|
+
/* Fix for tooltip alignment issue, for details see: W-11677142
|
|
5
|
+
*
|
|
6
|
+
* fix-tooltip_alignment - the custom class that edits min-width
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
.fix-popover_tooltip_alignment {
|
|
10
|
+
min-width: inherit;
|
|
11
|
+
}
|
|
@@ -102,7 +102,9 @@ export default class LightningPrimitiveBubble extends LightningElement {
|
|
|
102
102
|
|
|
103
103
|
// compute class value for this bubble
|
|
104
104
|
get computedPopoverClass() {
|
|
105
|
-
const classes = classSet('slds-popover')
|
|
105
|
+
const classes = classSet('slds-popover')
|
|
106
|
+
.add('slds-popover_tooltip')
|
|
107
|
+
.add('fix-popover_tooltip_alignment'); // fix for W-11677142
|
|
106
108
|
|
|
107
109
|
// show or hide bubble
|
|
108
110
|
classes.add({
|
|
@@ -33,13 +33,13 @@ export default class PrimitiveCellActions extends LightningElement {
|
|
|
33
33
|
static delegatesFocus = true;
|
|
34
34
|
_isLoadingActions;
|
|
35
35
|
_menuAlignment = DEFAULT_MENU_ALIGNMENT;
|
|
36
|
-
_internalTabIndex = false;
|
|
37
36
|
|
|
38
37
|
/************************** PUBLIC ATTRIBUTES ***************************/
|
|
39
38
|
|
|
40
39
|
@api rowKeyValue;
|
|
41
40
|
@api colKeyValue;
|
|
42
41
|
@api rowActions;
|
|
42
|
+
@api internalTabIndex;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Defines the current menu alignment
|
|
@@ -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') {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
<template if:true={hasTreeData}>
|
|
9
9
|
<lightning-primitive-treegrid-cell-toggle row-key-value={rowKeyValue}
|
|
10
10
|
col-key-value={colKeyValue}
|
|
11
|
+
display-value={displayValue}
|
|
11
12
|
value={value}
|
|
12
13
|
has-children={typeAttribute21}
|
|
13
14
|
is-expanded={typeAttribute22}
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
row-key-value={rowKeyValue}
|
|
34
35
|
col-key-value={colKeyValue}
|
|
35
36
|
tabindex={internalTabIndex}
|
|
37
|
+
internal-tab-index={internalTabIndex}
|
|
36
38
|
menu-alignment={typeAttribute0}
|
|
37
39
|
row-actions={typeAttribute1}>
|
|
38
40
|
</lightning-primitive-cell-actions>
|
|
@@ -278,7 +280,7 @@
|
|
|
278
280
|
</button>
|
|
279
281
|
</template>
|
|
280
282
|
<!-- TODO: displayReadOnlyIcon is true only when the cell's "editable" property is false and its "displayReadOnlyIcon"
|
|
281
|
-
property is true. The markup in this template therefore cannot be rendered concurrently with the template above that checks
|
|
283
|
+
property is true. The markup in this template therefore cannot be rendered concurrently with the template above that checks
|
|
282
284
|
the editable property. -->
|
|
283
285
|
<template if:true={shouldDisplayReadOnlyIcon}>
|
|
284
286
|
<!-- TODO: Update the svg-classes once the SLDS team updates their read only icon design to not use classes that have the word 'button'
|
|
@@ -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>
|
|
@@ -2,7 +2,7 @@ import labelCollapseBranch from '@salesforce/label/LightningPrimitiveCellTree.co
|
|
|
2
2
|
import labelExpandBranch from '@salesforce/label/LightningPrimitiveCellTree.expandBranch';
|
|
3
3
|
import { LightningElement, api } from 'lwc';
|
|
4
4
|
import { classSet, formatLabel } from 'lightning/utils';
|
|
5
|
-
import { normalizeBoolean } from 'lightning/utilsPrivate';
|
|
5
|
+
import { normalizeString, normalizeBoolean } from 'lightning/utilsPrivate';
|
|
6
6
|
|
|
7
7
|
const i18n = {
|
|
8
8
|
collapseBranch: labelCollapseBranch,
|
|
@@ -13,6 +13,7 @@ export default class PrivateTreeGridCellToggle extends LightningElement {
|
|
|
13
13
|
@api rowKeyValue;
|
|
14
14
|
@api colKeyValue;
|
|
15
15
|
@api value;
|
|
16
|
+
@api displayValue;
|
|
16
17
|
|
|
17
18
|
_expanded = false;
|
|
18
19
|
_hasChildren = false;
|
|
@@ -60,10 +61,14 @@ export default class PrivateTreeGridCellToggle extends LightningElement {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
get buttonTitle() {
|
|
64
|
+
let title =
|
|
65
|
+
normalizeString(this.displayValue) !== ''
|
|
66
|
+
? this.displayValue
|
|
67
|
+
: this.value;
|
|
63
68
|
if (this.isExpanded) {
|
|
64
|
-
return formatLabel(i18n.collapseBranch,
|
|
69
|
+
return formatLabel(i18n.collapseBranch, title);
|
|
65
70
|
}
|
|
66
|
-
return formatLabel(i18n.expandBranch,
|
|
71
|
+
return formatLabel(i18n.expandBranch, title);
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
handleChevronClick() {
|
|
@@ -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
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
</div>
|
|
59
59
|
|
|
60
60
|
<template if:true={_helpMessage}>
|
|
61
|
-
<div data-help-message id="help-message" class="slds-form-element__help">{_helpMessage}</div>
|
|
61
|
+
<div data-help-message id="help-message" role="alert" class="slds-form-element__help">{_helpMessage}</div>
|
|
62
62
|
</template>
|
|
63
63
|
|
|
64
64
|
</fieldset>
|
|
@@ -102,6 +102,12 @@ export default class LightningTextarea extends LightningElement {
|
|
|
102
102
|
@track _helpMessage;
|
|
103
103
|
@track _fieldLevelHelp;
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Aria Described by value on parent lighting-textarea
|
|
107
|
+
* @type {string}
|
|
108
|
+
*/
|
|
109
|
+
@api ariaDescribedBy;
|
|
110
|
+
|
|
105
111
|
connectedCallback() {
|
|
106
112
|
this.classList.add('slds-form-element');
|
|
107
113
|
this.updateClassList();
|
|
@@ -433,7 +439,13 @@ export default class LightningTextarea extends LightningElement {
|
|
|
433
439
|
|
|
434
440
|
get computedUniqueHelpElementId() {
|
|
435
441
|
const helpMessage = this.template.querySelector('[data-help-message]');
|
|
436
|
-
|
|
442
|
+
let spaceSeperatedDescribedByIds = getRealDOMId(helpMessage);
|
|
443
|
+
if (this.ariaDescribedBy && spaceSeperatedDescribedByIds) {
|
|
444
|
+
spaceSeperatedDescribedByIds += ` ${this.ariaDescribedBy}`;
|
|
445
|
+
} else if (this.ariaDescribedBy) {
|
|
446
|
+
spaceSeperatedDescribedByIds = this.ariaDescribedBy;
|
|
447
|
+
}
|
|
448
|
+
return spaceSeperatedDescribedByIds;
|
|
437
449
|
}
|
|
438
450
|
|
|
439
451
|
_setInputValue(value) {
|