lightning-base-components 1.19.2-alpha → 1.19.4-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/metadata/raptor.json +2066 -1632
- package/package.json +5 -1
- package/scopedImports/@salesforce-label-LightningProgressIndicator.stageNotStarted.js +1 -0
- package/src/lightning/alert/__examples__disabled/basic/basic.html +1 -1
- package/src/lightning/ariaObserver/__docs__/ariaObserver.md +12 -4
- package/src/lightning/ariaObserver/__examples__/connectChild/connectChild.js +3 -1
- package/src/lightning/baseCombobox/baseCombobox.html +1 -0
- package/src/lightning/buttonMenu/buttonMenu.js +16 -1
- package/src/lightning/colorPickerPanel/colorPickerPanel.html +1 -1
- package/src/lightning/confirm/__examples__disabled/basic/basic.html +1 -1
- package/src/lightning/datatable/datatable.js +19 -0
- package/src/lightning/datatable/state.js +1 -0
- package/src/lightning/datatable/templates/div/div.html +4 -2
- package/src/lightning/datatable/templates/table/table.html +4 -2
- package/src/lightning/fileDownload/resourceResolver.js +4 -3
- package/src/lightning/input/input.js +43 -29
- package/src/lightning/inputUtils/inputUtils.js +0 -12
- package/src/lightning/modal/__docs__/modal.md +2 -2
- package/src/lightning/modal/__examples__disabled/all/all.html +2 -2
- package/src/lightning/modal/__examples__disabled/allform/allform.html +1 -1
- package/src/lightning/modal/__examples__disabled/allformfull/allformfull.html +1 -1
- package/src/lightning/modal/__examples__disabled/basic/basic.html +2 -2
- package/src/lightning/modal/__examples__disabled/footless/footless.html +2 -2
- package/src/lightning/modal/__examples__disabled/headless/headless.html +2 -2
- package/src/lightning/modal/__modalUtils__/modalContainerTestConstants.js +15 -2
- package/src/lightning/modal/__modalUtils__/modalContainerTestMethods.js +6 -6
- package/src/lightning/modalBase/modalBase.js +3 -3
- package/src/lightning/numberUtils/numberUtils.js +269 -5
- package/src/lightning/primitiveCustomCell/primitiveCustomCell.js +5 -5
- package/src/lightning/primitiveHeaderFactory/nonsortableHeader.html +3 -3
- package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +39 -0
- package/src/lightning/primitiveHeaderFactory/sortableHeader.html +2 -2
- package/src/lightning/primitiveInputFile/primitiveInputFile.html +1 -0
- package/src/lightning/primitiveInputFile/primitiveInputFile.js +4 -0
- package/src/lightning/primitiveInputSimple/primitiveInputSimple.js +33 -12
- package/src/lightning/progressStep/progressStep.js +13 -2
- package/src/lightning/prompt/__examples__disabled/basic/basic.html +1 -1
- package/src/lightning/resizeObserver/resizeObserver.js +10 -15
- package/src/lightning/slider/slider.js +2 -2
- package/src/lightning/tabBar/tabBar.js +3 -1
- package/src/lightning/timepicker/timepicker.html +3 -3
- package/src/lightning/tooltipLibrary/tooltipLibrary.js +3 -1
- package/src/lightning/utils/queryFocusable.js +33 -15
- package/src/lightning/utilsPrivate/videoUtils.js +35 -0
- package/src/lightning/inputUtils/number.js +0 -267
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightning-base-components",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.4-alpha",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"external",
|
|
@@ -458,6 +458,10 @@
|
|
|
458
458
|
"name": "@salesforce/label/LightningProgressIndicator.currentStage",
|
|
459
459
|
"path": "scopedImports/@salesforce-label-LightningProgressIndicator.currentStage.js"
|
|
460
460
|
},
|
|
461
|
+
{
|
|
462
|
+
"name": "@salesforce/label/LightningProgressIndicator.stageNotStarted",
|
|
463
|
+
"path": "scopedImports/@salesforce-label-LightningProgressIndicator.stageNotStarted.js"
|
|
464
|
+
},
|
|
461
465
|
{
|
|
462
466
|
"name": "@salesforce/label/LightningListView.loadMore",
|
|
463
467
|
"path": "scopedImports/@salesforce-label-LightningListView.loadMore.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'Stage Not Started';
|
|
@@ -73,18 +73,24 @@ Then use the `sync(isNativeShadow)` method to synchronize the ID references when
|
|
|
73
73
|
Used when the `targetSelector` or `targetNode` is within a shadow boundary, but the parent component where AriaObserver has been
|
|
74
74
|
instantiated is not. Example: `lightning-primitive-input-simple` may be rendered in native shadow, but `lightning-input` may not be.
|
|
75
75
|
|
|
76
|
+
It is important to protect the call to `sync` by checking if the component `isConnected`. This is because there are some cases where a component may be rendered but not connected and calling `sync` when a component is not connected will fail.
|
|
77
|
+
|
|
76
78
|
``` js
|
|
77
79
|
renderedCallback() {
|
|
78
|
-
this.
|
|
80
|
+
if (this.isConnected) {
|
|
81
|
+
this.ariaObserver.sync();
|
|
82
|
+
}
|
|
79
83
|
}
|
|
80
84
|
```
|
|
81
85
|
|
|
82
86
|
When the containing component is native shadow enabled, AriaObserver observes the component's root node to find and link
|
|
83
87
|
the related elements. This can be overridden in cases where the component's root node does not contain the related elements,
|
|
84
|
-
but one of
|
|
88
|
+
but one of its ancestor nodes does. For example, `lightning-base-combobox` is contained within `lightning-combobox` so the root of `lightning-combobox` should be used in place of the root of `lightning-base-combobox`. It is important to protect this assignment by checking if `ariaObserver` is defined. This is because the root node setters can be called after `ariaObserver` is set to `undefined` in the `disconnectedCallback`.
|
|
85
89
|
|
|
86
90
|
```js
|
|
87
|
-
this.ariaObserver
|
|
91
|
+
if (this.ariaObserver) {
|
|
92
|
+
this.ariaObserver.root = parentRootNode;
|
|
93
|
+
}
|
|
88
94
|
```
|
|
89
95
|
|
|
90
96
|
Finally, disconnect the aria observer and free the resources at the end of the component lifecycle.
|
|
@@ -135,7 +141,9 @@ export default class Foo extends LightningElement {
|
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
renderedCallback() {
|
|
138
|
-
this.
|
|
144
|
+
if (this.isConnected) {
|
|
145
|
+
this.ariaObserver.sync();
|
|
146
|
+
}
|
|
139
147
|
}
|
|
140
148
|
|
|
141
149
|
disconnectedCallback() {
|
|
@@ -717,8 +717,23 @@ export default class LightningButtonMenu extends LightningElement {
|
|
|
717
717
|
}
|
|
718
718
|
}
|
|
719
719
|
|
|
720
|
+
getChildNodes(element, selector) {
|
|
721
|
+
if (!element) {
|
|
722
|
+
return [];
|
|
723
|
+
}
|
|
724
|
+
if (element.matches && element.matches(selector)) {
|
|
725
|
+
return [element];
|
|
726
|
+
}
|
|
727
|
+
return Array.from(element.childNodes).reduce((arr, node) => {
|
|
728
|
+
return [...arr, ...this.getChildNodes(node, selector)];
|
|
729
|
+
}, []);
|
|
730
|
+
}
|
|
731
|
+
|
|
720
732
|
getMenuItems() {
|
|
721
|
-
return Array.from(this.querySelectorAll(menuItemSelectors));
|
|
733
|
+
// return Array.from(this.querySelectorAll(menuItemSelectors));
|
|
734
|
+
// Nested <slot><slot></slot></slot> commonly used in composite
|
|
735
|
+
// components will not be found with querySelectorAll.
|
|
736
|
+
return this.getChildNodes(this, menuItemSelectors);
|
|
722
737
|
}
|
|
723
738
|
|
|
724
739
|
getMenuItemByIndex(index) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
onupdateselectedcolor={handleUpdateSelectedColor}
|
|
8
8
|
onkeydown={handleKeydown}>
|
|
9
9
|
|
|
10
|
-
<div class="slds-popover__body" id="dialog-body-id">
|
|
10
|
+
<div class="slds-popover__body" tabindex="0" id="dialog-body-id">
|
|
11
11
|
<lightning-color-picker-custom current-color={currentColor}></lightning-color-picker-custom>
|
|
12
12
|
<!-- [a11y] Remove until raptor tabset is supported. -->
|
|
13
13
|
<!-- <div class="slds-tabs_default">
|
|
@@ -409,6 +409,20 @@ export default class LightningDatatable extends LightningElement {
|
|
|
409
409
|
this.state.hideTableHeader = normalizeBoolean(value);
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
+
/**
|
|
413
|
+
* If present, the table header is wrapped.
|
|
414
|
+
* @type {boolean}
|
|
415
|
+
* @default false
|
|
416
|
+
*/
|
|
417
|
+
@api
|
|
418
|
+
get wrapTableHeader() {
|
|
419
|
+
return this.state.wrapTableHeader;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
set wrapTableHeader(value) {
|
|
423
|
+
this.state.wrapTableHeader = normalizeBoolean(value);
|
|
424
|
+
}
|
|
425
|
+
|
|
412
426
|
/**
|
|
413
427
|
* If present, a spinner is shown to indicate that more data is loading.
|
|
414
428
|
* @type {boolean}
|
|
@@ -866,6 +880,11 @@ export default class LightningDatatable extends LightningElement {
|
|
|
866
880
|
styles['overflow-x'] = 'auto';
|
|
867
881
|
}
|
|
868
882
|
|
|
883
|
+
if (this.wrapTableHeader) {
|
|
884
|
+
// increase padding from 2rem to 3rem on the top when header wraps
|
|
885
|
+
styles['padding-top'] = '3rem';
|
|
886
|
+
}
|
|
887
|
+
|
|
869
888
|
return styleToString(styles);
|
|
870
889
|
}
|
|
871
890
|
|
|
@@ -85,7 +85,8 @@
|
|
|
85
85
|
column-width={def.columnWidth}
|
|
86
86
|
show-checkbox={showSelectAllCheckbox}
|
|
87
87
|
hide-header={hideTableHeader}
|
|
88
|
-
onprivatecolumnheaderid={handleCheckboxHeaderId}
|
|
88
|
+
onprivatecolumnheaderid={handleCheckboxHeaderId}
|
|
89
|
+
wrap-table-header={wrapTableHeader}>
|
|
89
90
|
</lightning-primitive-header-factory>
|
|
90
91
|
</template>
|
|
91
92
|
<template if:false={def.fixedWidth}>
|
|
@@ -107,7 +108,8 @@
|
|
|
107
108
|
resizable={hasResizebleColumns}
|
|
108
109
|
resizestep={widthsData.resizeStep}
|
|
109
110
|
hide-header={hideTableHeader}
|
|
110
|
-
onprivatecolumnheaderid={handleCheckboxHeaderId}
|
|
111
|
+
onprivatecolumnheaderid={handleCheckboxHeaderId}
|
|
112
|
+
wrap-table-header={wrapTableHeader}>
|
|
111
113
|
</lightning-primitive-header-factory>
|
|
112
114
|
</template>
|
|
113
115
|
</div>
|
|
@@ -75,7 +75,8 @@
|
|
|
75
75
|
column-width={def.columnWidth}
|
|
76
76
|
show-checkbox={showSelectAllCheckbox}
|
|
77
77
|
hide-header={hideTableHeader}
|
|
78
|
-
onprivatecolumnheaderid={handleCheckboxHeaderId}
|
|
78
|
+
onprivatecolumnheaderid={handleCheckboxHeaderId}
|
|
79
|
+
wrap-table-header={wrapTableHeader}>
|
|
79
80
|
</lightning-primitive-header-factory>
|
|
80
81
|
</template>
|
|
81
82
|
<template if:false={def.fixedWidth}>
|
|
@@ -97,7 +98,8 @@
|
|
|
97
98
|
resizable={hasResizebleColumns}
|
|
98
99
|
resizestep={widthsData.resizeStep}
|
|
99
100
|
hide-header={hideTableHeader}
|
|
100
|
-
onprivatecolumnheaderid={handleCheckboxHeaderId}
|
|
101
|
+
onprivatecolumnheaderid={handleCheckboxHeaderId}
|
|
102
|
+
wrap-table-header={wrapTableHeader}>
|
|
101
103
|
</lightning-primitive-header-factory>
|
|
102
104
|
</template>
|
|
103
105
|
</th>
|
|
@@ -44,7 +44,7 @@ export function resolveFileTypeToURL(recordId) {
|
|
|
44
44
|
/partners is the path prefix. Returns null if the prefix isn’t defined.
|
|
45
45
|
If the current request is not a site request, then this field returns an empty string.
|
|
46
46
|
*/
|
|
47
|
-
function getUrlWithSitePrefix(url) {
|
|
47
|
+
export function getUrlWithSitePrefix(url) {
|
|
48
48
|
let siteUrlPrefix = getPathPrefix();
|
|
49
49
|
|
|
50
50
|
// remove /s in siteUrlPrefix
|
|
@@ -53,6 +53,7 @@ function getUrlWithSitePrefix(url) {
|
|
|
53
53
|
? siteUrlPrefix.slice(0, siteUrlPrefix.length - 2)
|
|
54
54
|
: siteUrlPrefix;
|
|
55
55
|
|
|
56
|
-
//
|
|
57
|
-
|
|
56
|
+
// return url directly if path prefix is already added to site URL
|
|
57
|
+
// Edge Case: `sf` would accidentally match `sfc` without the `/`
|
|
58
|
+
return url.startsWith(`${siteUrlPrefix}/`) ? url : siteUrlPrefix + url;
|
|
58
59
|
}
|
|
@@ -35,13 +35,13 @@ import {
|
|
|
35
35
|
normalizeUTCDateTime,
|
|
36
36
|
} from './dateTimeUtil';
|
|
37
37
|
import { isAfter, isBefore } from 'lightning/internationalizationLibrary';
|
|
38
|
+
import { isValidNumber } from 'lightning/numberUtils';
|
|
38
39
|
import {
|
|
39
40
|
FieldConstraintApiWithProxyInput,
|
|
40
41
|
InteractingState,
|
|
41
42
|
normalizeVariant,
|
|
42
43
|
VARIANT,
|
|
43
44
|
normalizeInput,
|
|
44
|
-
isValidNumber,
|
|
45
45
|
isValidEmail,
|
|
46
46
|
isValidMultipleEmails,
|
|
47
47
|
} from 'lightning/inputUtils';
|
|
@@ -99,6 +99,12 @@ const VALID_INPUT_TYPES = [
|
|
|
99
99
|
'toggle',
|
|
100
100
|
'color',
|
|
101
101
|
'range',
|
|
102
|
+
// the following types are not listed as supported
|
|
103
|
+
// as of 246, but have historically worked and are
|
|
104
|
+
// relied on by customers
|
|
105
|
+
'datetime-local',
|
|
106
|
+
'month',
|
|
107
|
+
'week',
|
|
102
108
|
];
|
|
103
109
|
const VALID_NUMBER_FORMATTERS = [
|
|
104
110
|
'decimal',
|
|
@@ -269,6 +275,14 @@ export default class LightningInput extends LightningElement {
|
|
|
269
275
|
*/
|
|
270
276
|
@api dateAriaLabel;
|
|
271
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Describes the time input to assistive technologies when type='datetime'. On mobile devices,
|
|
280
|
+
* this label is merged with aria-label and date-aria-label to describe the native date time input.
|
|
281
|
+
* @type {string}
|
|
282
|
+
*
|
|
283
|
+
*/
|
|
284
|
+
@api timeAriaLabel;
|
|
285
|
+
|
|
272
286
|
@track _timeAriaDescribedBy;
|
|
273
287
|
@track _timeAriaLabelledBy;
|
|
274
288
|
@track _timeAriaControls;
|
|
@@ -296,14 +310,12 @@ export default class LightningInput extends LightningElement {
|
|
|
296
310
|
@track _minLength;
|
|
297
311
|
@track _accept;
|
|
298
312
|
@track _variant;
|
|
299
|
-
@track _numberRawValue = '';
|
|
300
313
|
@track _ariaInvalid;
|
|
301
314
|
@track _autocomplete;
|
|
302
315
|
|
|
303
316
|
_shouldShowHelpMessage = true;
|
|
304
317
|
_helpMessageChanged = false;
|
|
305
318
|
_formatter = DEFAULT_FORMATTER;
|
|
306
|
-
_showRawNumber = false;
|
|
307
319
|
_initialValueSet = false;
|
|
308
320
|
_rendered;
|
|
309
321
|
|
|
@@ -656,6 +668,7 @@ export default class LightningInput extends LightningElement {
|
|
|
656
668
|
}
|
|
657
669
|
|
|
658
670
|
set type(value) {
|
|
671
|
+
const wasTypeSimple = this.isTypeSimple;
|
|
659
672
|
const normalizedValue = normalizeString(value);
|
|
660
673
|
this._type =
|
|
661
674
|
normalizedValue === 'datetime' ? 'datetime-local' : normalizedValue;
|
|
@@ -665,6 +678,11 @@ export default class LightningInput extends LightningElement {
|
|
|
665
678
|
this._type = 'text';
|
|
666
679
|
}
|
|
667
680
|
|
|
681
|
+
// If the type change was not primitive to primitive, we must update the cached component.
|
|
682
|
+
if (!wasTypeSimple || !this.isTypeSimple) {
|
|
683
|
+
this._primitiveComponentRefreshNeeded = true;
|
|
684
|
+
}
|
|
685
|
+
|
|
668
686
|
this._inputElementRefreshNeeded = true;
|
|
669
687
|
|
|
670
688
|
if (this._rendered) {
|
|
@@ -902,20 +920,18 @@ export default class LightningInput extends LightningElement {
|
|
|
902
920
|
if (subcomponent) {
|
|
903
921
|
subcomponent.value = this._value;
|
|
904
922
|
}
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
this._updateProxyInputAttributes('value');
|
|
908
|
-
|
|
909
|
-
// Again, due to the interop layer we need to check whether the value being set
|
|
910
|
-
// is different, otherwise we're duplicating the sets on the input, which result
|
|
911
|
-
// in different bugs like Japanese IME duplication of characters in Safari (likely a browser bug) or
|
|
912
|
-
// character position re-set in IE11.
|
|
913
|
-
if (
|
|
923
|
+
} else if (
|
|
914
924
|
this._rendered &&
|
|
915
925
|
this._inputElement.value !== this._displayedValue
|
|
916
926
|
) {
|
|
927
|
+
// Again, due to the interop layer we need to check whether the value being set
|
|
928
|
+
// is different, otherwise we're duplicating the sets on the input, which result
|
|
929
|
+
// in different bugs like Japanese IME duplication of characters in Safari (likely a browser bug) or
|
|
930
|
+
// character position re-set in IE11.
|
|
917
931
|
this._setInputValue(this._displayedValue);
|
|
918
932
|
}
|
|
933
|
+
|
|
934
|
+
this._updateProxyInputAttributes('value');
|
|
919
935
|
}
|
|
920
936
|
}
|
|
921
937
|
|
|
@@ -1324,6 +1340,8 @@ export default class LightningInput extends LightningElement {
|
|
|
1324
1340
|
type === 'search' ||
|
|
1325
1341
|
type === 'password' ||
|
|
1326
1342
|
type === 'range' ||
|
|
1343
|
+
type === 'month' ||
|
|
1344
|
+
type === 'week' ||
|
|
1327
1345
|
!type ||
|
|
1328
1346
|
(!this._isDesktopBrowser() &&
|
|
1329
1347
|
(type === 'date' ||
|
|
@@ -1342,10 +1360,14 @@ export default class LightningInput extends LightningElement {
|
|
|
1342
1360
|
}
|
|
1343
1361
|
|
|
1344
1362
|
get _primitiveComponent() {
|
|
1345
|
-
if (
|
|
1363
|
+
if (
|
|
1364
|
+
!this.cachedPrimitiveComponent ||
|
|
1365
|
+
this._primitiveComponentRefreshNeeded
|
|
1366
|
+
) {
|
|
1346
1367
|
this.cachedPrimitiveComponent = this.template.querySelector(
|
|
1347
1368
|
this.primitiveSelector
|
|
1348
1369
|
);
|
|
1370
|
+
this._primitiveComponentRefreshNeeded = false;
|
|
1349
1371
|
}
|
|
1350
1372
|
return this.cachedPrimitiveComponent;
|
|
1351
1373
|
}
|
|
@@ -1507,7 +1529,9 @@ export default class LightningInput extends LightningElement {
|
|
|
1507
1529
|
}
|
|
1508
1530
|
|
|
1509
1531
|
if (this.isTypeNumber) {
|
|
1510
|
-
return !isValidNumber(
|
|
1532
|
+
return !isValidNumber(
|
|
1533
|
+
this._primitiveComponent?.getNumberRawValue()
|
|
1534
|
+
);
|
|
1511
1535
|
}
|
|
1512
1536
|
|
|
1513
1537
|
if (!this.isNativeInput) {
|
|
@@ -1679,6 +1703,9 @@ export default class LightningInput extends LightningElement {
|
|
|
1679
1703
|
}
|
|
1680
1704
|
|
|
1681
1705
|
handlePrimitiveInputFileChange() {
|
|
1706
|
+
// kept for legacy support @W-14118679
|
|
1707
|
+
this._dispatchCommitEvent();
|
|
1708
|
+
|
|
1682
1709
|
const detail = {
|
|
1683
1710
|
files: this.files,
|
|
1684
1711
|
value: this._inputElement.value,
|
|
@@ -1695,9 +1722,9 @@ export default class LightningInput extends LightningElement {
|
|
|
1695
1722
|
);
|
|
1696
1723
|
}
|
|
1697
1724
|
|
|
1698
|
-
handlePrimitiveInputSimpleChange() {
|
|
1725
|
+
handlePrimitiveInputSimpleChange(event) {
|
|
1699
1726
|
this.interactingState.enter();
|
|
1700
|
-
this.
|
|
1727
|
+
this._updateValueAndValidityAttribute(event.detail.value);
|
|
1701
1728
|
}
|
|
1702
1729
|
|
|
1703
1730
|
_dispatchCommitEvent() {
|
|
@@ -1827,19 +1854,6 @@ export default class LightningInput extends LightningElement {
|
|
|
1827
1854
|
}
|
|
1828
1855
|
}
|
|
1829
1856
|
|
|
1830
|
-
_updateInputDisplayValueIfTypeNumber() {
|
|
1831
|
-
// Displayed value depends on the format number, so if we're not showing the raw
|
|
1832
|
-
// number we should update the value
|
|
1833
|
-
if (
|
|
1834
|
-
this._rendered &&
|
|
1835
|
-
this.isTypeNumber &&
|
|
1836
|
-
!this._showRawNumber &&
|
|
1837
|
-
this._inputElement
|
|
1838
|
-
) {
|
|
1839
|
-
this._setInputValue(this._displayedValue);
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
1857
|
/**
|
|
1844
1858
|
* Updates the class list on the host element based on the variant
|
|
1845
1859
|
*/
|
|
@@ -8,16 +8,4 @@ export {
|
|
|
8
8
|
} from './validity';
|
|
9
9
|
export { normalizeInput, normalizeVariant, VARIANT } from './normalize';
|
|
10
10
|
export { isValidEmail, isValidMultipleEmails } from './email';
|
|
11
|
-
export {
|
|
12
|
-
calculateFractionDigitsFromStep,
|
|
13
|
-
formatNumber,
|
|
14
|
-
fromIsoDecimal,
|
|
15
|
-
hasValidNumberShortcut,
|
|
16
|
-
hasValidNumberSymbol,
|
|
17
|
-
increaseNumberByStep,
|
|
18
|
-
isValidNumber,
|
|
19
|
-
isValidNumberCharacter,
|
|
20
|
-
stringifyNumber,
|
|
21
|
-
toIsoDecimal,
|
|
22
|
-
} from './number';
|
|
23
11
|
export { isEmptyString, isEmptyObject } from './utils';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
A `
|
|
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
|
|
|
@@ -560,7 +560,7 @@ The headerless variant of `LightningModal` has these additional requirements.
|
|
|
560
560
|
- 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.
|
|
561
561
|
- 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).
|
|
562
562
|
|
|
563
|
-
You can also create a full-screen modal component by setting the `size` attribute to `full`. This variant resizes the modal to the full width and height of the viewport on screens up to
|
|
563
|
+
You can also create a full-screen modal component by setting the `size` attribute to `full`. This variant resizes the modal to the full width and height of the viewport on screens up to 30em (~480 pixels or less), like mobile phone devices. On screens larger than 30em (~481 pixels or larger), like desktop monitors or tablets, a `size=full` modal has the same behavior as a modal with `size=large` set.
|
|
564
564
|
|
|
565
565
|
The `LightningModal` component also supports the SLDS [Directional variant](https://www.lightningdesignsystem.com/components/modals/#Directional) modal blueprint pattern.
|
|
566
566
|
|
|
@@ -58,6 +58,7 @@ const MODAL_CLOSE_BTN_FULL_CLASS = 'slds-modal_full-close-button';
|
|
|
58
58
|
// modal screen size testing
|
|
59
59
|
// utilized by full screen modal tests
|
|
60
60
|
const SCREEN_SIZE_SMALL = 'SMALL';
|
|
61
|
+
const SCREEN_SIZE_SMALL_MID = 'SMALL_MID';
|
|
61
62
|
const SCREEN_SIZE_MEDIUM = 'MEDIUM';
|
|
62
63
|
const SCREEN_SIZE_LARGE = 'LARGE';
|
|
63
64
|
const SCREEN_SIZE_XLARGE = 'XLARGE';
|
|
@@ -78,7 +79,11 @@ const BODY_HEADLESS_SELECTOR = 'slds-modal__content_headless';
|
|
|
78
79
|
const BODY_FOOTLESS_SELECTOR = 'slds-modal__content_footless';
|
|
79
80
|
|
|
80
81
|
// modal size measurements and values
|
|
81
|
-
|
|
82
|
+
// during release 248, breakpoint was altered
|
|
83
|
+
// to narrow the device's targeted by size=full
|
|
84
|
+
// from 768 to 480
|
|
85
|
+
// this will be backported, so it will effect 246.x
|
|
86
|
+
const MODAL_FULL_SCREEN_SMALL_BREAKPOINT = 480;
|
|
82
87
|
// <lightning-modal> element location, medium+ screen
|
|
83
88
|
const MODAL_DEFAULT_PX_OFFSET_X = 25;
|
|
84
89
|
const MODAL_DEFAULT_PX_OFFSET_Y = 50;
|
|
@@ -158,11 +163,18 @@ const SCREEN_SIZE = {
|
|
|
158
163
|
// based on iPhone 14
|
|
159
164
|
// close to iPhone 12 Pro, Pixel 5
|
|
160
165
|
// when Modal size='full',
|
|
161
|
-
// full screen behavior will be applied
|
|
166
|
+
// full screen behavior (mobile screens) will be applied
|
|
167
|
+
// when Modal api size=full is set
|
|
162
168
|
SMALL: {
|
|
163
169
|
width: 393,
|
|
164
170
|
height: 852,
|
|
165
171
|
},
|
|
172
|
+
// rest of SCREEN_SIZE below all are greater than 480px
|
|
173
|
+
// so will render as normal desktop Modal UX
|
|
174
|
+
SMALL_MID: {
|
|
175
|
+
width: 481,
|
|
176
|
+
height: 852,
|
|
177
|
+
},
|
|
166
178
|
SMALL_LANDSCAPE: {
|
|
167
179
|
width: 852,
|
|
168
180
|
height: 393,
|
|
@@ -225,6 +237,7 @@ module.exports = {
|
|
|
225
237
|
MODAL_CLOSE_BUTTON_FULL_VARIANT,
|
|
226
238
|
MODAL_CLOSE_BUTTON_NORMAL_VARIANT,
|
|
227
239
|
SCREEN_SIZE_SMALL,
|
|
240
|
+
SCREEN_SIZE_SMALL_MID,
|
|
228
241
|
SCREEN_SIZE_MEDIUM,
|
|
229
242
|
SCREEN_SIZE_LARGE,
|
|
230
243
|
SCREEN_SIZE_XLARGE,
|
|
@@ -317,7 +317,7 @@ async function validateModalCloseButtonAttributes(config) {
|
|
|
317
317
|
expect(modalCloseButtonCssClass).toContain(MODAL_CLOSE_BTN_CLASS);
|
|
318
318
|
|
|
319
319
|
// the only time size='full' actual renders full page width and height
|
|
320
|
-
// is when windowWidth is set <=
|
|
320
|
+
// is when windowWidth is set <= 480px (30em)
|
|
321
321
|
if (
|
|
322
322
|
modalSize === MODAL_SIZE_FULL &&
|
|
323
323
|
windowWidth <= MODAL_FULL_SCREEN_SMALL_BREAKPOINT
|
|
@@ -328,7 +328,7 @@ async function validateModalCloseButtonAttributes(config) {
|
|
|
328
328
|
|
|
329
329
|
expect(modalCloseButtonCssClass).toContain(MODAL_CLOSE_BTN_FULL_CLASS);
|
|
330
330
|
} else {
|
|
331
|
-
// 'small', 'medium', 'large', and ('full' when windowWidth is set >
|
|
331
|
+
// 'small', 'medium', 'large', and ('full' when windowWidth is set > 480px (30em)) are normal modal behavior
|
|
332
332
|
expect(modalCloseButtonVariant).toEqual(
|
|
333
333
|
MODAL_CLOSE_BUTTON_NORMAL_VARIANT
|
|
334
334
|
);
|
|
@@ -414,7 +414,7 @@ async function validateModalHeightBehavior(config) {
|
|
|
414
414
|
const modalBodyStyleProps = parseStyleAttributes(modalBodyOuterDivStyle);
|
|
415
415
|
const { x: modalElemX, y: modalElemY } = modalElem.offset;
|
|
416
416
|
// the only time size='full' actual renders full page width and height
|
|
417
|
-
// is when windowWidth is set <=
|
|
417
|
+
// is when windowWidth is set <= 480px (30em)
|
|
418
418
|
// note: reliably testing outer div element was not possible as
|
|
419
419
|
// webdriver getSize didn't provide correct values for comparison
|
|
420
420
|
// the tests below verify that the code path for setting full height are invoked
|
|
@@ -433,7 +433,7 @@ async function validateModalHeightBehavior(config) {
|
|
|
433
433
|
expect(modalBodyStyleProps[MAX_HEIGHT]).toBeUndefined();
|
|
434
434
|
expect(modalBodyStyleProps[MIN_HEIGHT]).toBeUndefined();
|
|
435
435
|
} else {
|
|
436
|
-
// 'small', 'medium', 'large', and ('full' when windowWidth is set >
|
|
436
|
+
// 'small', 'medium', 'large', and ('full' when windowWidth is set > 480px (30em)) are normal modal behavior
|
|
437
437
|
// the div.slds-modal__container element is consistently accurate for
|
|
438
438
|
// location measurment in the CI
|
|
439
439
|
// location values vary based on screen and size value
|
|
@@ -473,14 +473,14 @@ async function validateModalWidthBehavior(config, modalIndex = 0) {
|
|
|
473
473
|
await modalContainerElem.getSize();
|
|
474
474
|
|
|
475
475
|
// the only time size='full' actual renders full page width and height
|
|
476
|
-
// is when windowWidth is set <=
|
|
476
|
+
// is when windowWidth is set <= 480px
|
|
477
477
|
if (
|
|
478
478
|
modalSize === MODAL_SIZE_FULL &&
|
|
479
479
|
windowWidth <= MODAL_FULL_SCREEN_SMALL_BREAKPOINT
|
|
480
480
|
) {
|
|
481
481
|
expect(modalContainerElemWidth).toEqual(windowWidth);
|
|
482
482
|
} else {
|
|
483
|
-
// 'small', 'medium', 'large', and ('full' when windowWidth is set >
|
|
483
|
+
// 'small', 'medium', 'large', and ('full' when windowWidth is set > 480px) are normal modal behavior
|
|
484
484
|
expect(modalContainerElemWidth).toBeLessThan(windowWidth);
|
|
485
485
|
}
|
|
486
486
|
}
|
|
@@ -19,7 +19,7 @@ import closeButtonAltText from '@salesforce/label/LightningModalBase.cancelandcl
|
|
|
19
19
|
import disableCloseBtnMessage from '@salesforce/label/LightningModalBase.waitstate';
|
|
20
20
|
|
|
21
21
|
const DEBOUNCE_RESIZE = 300;
|
|
22
|
-
const SMALL_SCREEN_SIZE =
|
|
22
|
+
const SMALL_SCREEN_SIZE = 480;
|
|
23
23
|
const SIZE_SMALL = 'small';
|
|
24
24
|
const SIZE_MEDIUM = 'medium';
|
|
25
25
|
const SIZE_LARGE = 'large';
|
|
@@ -1110,8 +1110,8 @@ export default class LightningModalBase extends LightningElement {
|
|
|
1110
1110
|
* determine if the current screen is less than SMALL_SCREEN_SIZE
|
|
1111
1111
|
* for Modal, screen size detection is simplified to what's required
|
|
1112
1112
|
* for the size="full" feature addition, which is a single breakpoint
|
|
1113
|
-
* either (a) at or below
|
|
1114
|
-
* or (b) at or above
|
|
1113
|
+
* either (a) at or below 480 pixels (small = full screen modal behavior),
|
|
1114
|
+
* or (b) at or above 480 (large = default modal behavior)
|
|
1115
1115
|
* @private
|
|
1116
1116
|
*/
|
|
1117
1117
|
setIsSmallScreenSize() {
|