lightning-base-components 1.19.3-alpha → 1.19.5-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.
Files changed (45) hide show
  1. package/metadata/raptor.json +2066 -1632
  2. package/package.json +5 -1
  3. package/scopedImports/@salesforce-label-LightningProgressIndicator.stageNotStarted.js +1 -0
  4. package/src/lightning/alert/__examples__disabled/basic/basic.html +1 -1
  5. package/src/lightning/ariaObserver/__docs__/ariaObserver.md +12 -4
  6. package/src/lightning/ariaObserver/__examples__/connectChild/connectChild.js +3 -1
  7. package/src/lightning/baseCombobox/baseCombobox.html +1 -0
  8. package/src/lightning/buttonMenu/buttonMenu.js +16 -1
  9. package/src/lightning/colorPickerPanel/colorPickerPanel.html +1 -1
  10. package/src/lightning/confirm/__examples__disabled/basic/basic.html +1 -1
  11. package/src/lightning/datatable/datatable.js +19 -0
  12. package/src/lightning/datatable/state.js +1 -0
  13. package/src/lightning/datatable/templates/div/div.html +4 -2
  14. package/src/lightning/datatable/templates/table/table.html +4 -2
  15. package/src/lightning/fileDownload/resourceResolver.js +4 -3
  16. package/src/lightning/input/input.js +43 -29
  17. package/src/lightning/inputUtils/inputUtils.js +0 -12
  18. package/src/lightning/modal/__docs__/modal.md +2 -2
  19. package/src/lightning/modal/__examples__disabled/all/all.html +2 -2
  20. package/src/lightning/modal/__examples__disabled/allform/allform.html +1 -1
  21. package/src/lightning/modal/__examples__disabled/allformfull/allformfull.html +1 -1
  22. package/src/lightning/modal/__examples__disabled/basic/basic.html +2 -2
  23. package/src/lightning/modal/__examples__disabled/footless/footless.html +2 -2
  24. package/src/lightning/modal/__examples__disabled/headless/headless.html +2 -2
  25. package/src/lightning/modal/__modalUtils__/modalContainerTestConstants.js +15 -2
  26. package/src/lightning/modal/__modalUtils__/modalContainerTestMethods.js +6 -6
  27. package/src/lightning/modalBase/modalBase.js +3 -3
  28. package/src/lightning/numberUtils/numberUtils.js +269 -5
  29. package/src/lightning/primitiveCustomCell/primitiveCustomCell.js +5 -5
  30. package/src/lightning/primitiveHeaderFactory/nonsortableHeader.html +3 -3
  31. package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +39 -0
  32. package/src/lightning/primitiveHeaderFactory/sortableHeader.html +2 -2
  33. package/src/lightning/primitiveInputFile/primitiveInputFile.html +1 -0
  34. package/src/lightning/primitiveInputFile/primitiveInputFile.js +4 -0
  35. package/src/lightning/primitiveInputSimple/primitiveInputSimple.js +33 -12
  36. package/src/lightning/progressStep/progressStep.js +13 -2
  37. package/src/lightning/prompt/__examples__disabled/basic/basic.html +1 -1
  38. package/src/lightning/resizeObserver/resizeObserver.js +10 -15
  39. package/src/lightning/slider/slider.js +2 -2
  40. package/src/lightning/tabBar/tabBar.js +3 -1
  41. package/src/lightning/timepicker/timepicker.html +3 -3
  42. package/src/lightning/tooltipLibrary/tooltipLibrary.js +3 -1
  43. package/src/lightning/utils/queryFocusable.js +33 -15
  44. package/src/lightning/utilsPrivate/videoUtils.js +35 -0
  45. 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-alpha",
3
+ "version": "1.19.5-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';
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="example">
3
3
  <button
4
- aria-haspopup="modal"
4
+ aria-haspopup="dialog"
5
5
  onclick={handleAlertModal}
6
6
  >Open the Alert Modal</button>
7
7
  </div>
@@ -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.ariaObserver.sync();
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 it's 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`.
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.root = parentRootNode;
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.ariaObserver.sync();
144
+ if (this.isConnected) {
145
+ this.ariaObserver.sync();
146
+ }
139
147
  }
140
148
 
141
149
  disconnectedCallback() {
@@ -22,7 +22,9 @@ export default class AriaObserverConnectChild extends LightningElement {
22
22
  }
23
23
 
24
24
  renderedCallback() {
25
- this.ariaObserver.sync();
25
+ if (this.isConnected) {
26
+ this.ariaObserver.sync();
27
+ }
26
28
  }
27
29
 
28
30
  _ariaLabelledBy = '';
@@ -104,6 +104,7 @@
104
104
  onmouseleave={handleDropdownMouseLeave}
105
105
  onclick={handleOptionClick}
106
106
  part="dropdown overlay"
107
+ aria-label={inputLabel}
107
108
  >
108
109
  <template if:true={_hasDropdownOpened}>
109
110
  <template for:each={_items} for:item="item">
@@ -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">
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="example">
3
3
  <button
4
- aria-haspopup="modal"
4
+ aria-haspopup="dialog"
5
5
  onclick={handleConfirmModal}
6
6
  >Open the Confirm Modal</button>
7
7
  </div>
@@ -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
 
@@ -25,6 +25,7 @@ export const getDefaultState = function () {
25
25
 
26
26
  headerIndexes: {},
27
27
  hideTableHeader: false,
28
+ wrapTableHeader: false,
28
29
 
29
30
  // keyboard
30
31
  keyboardMode: 'NAVIGATION',
@@ -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
- // retun url directly if path prefix is already added to site URL
57
- return url.indexOf(siteUrlPrefix) === 0 ? url : siteUrlPrefix + url;
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 (!this.cachedPrimitiveComponent) {
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(this._numberRawValue);
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._updateProxyInputAttributes('value');
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 `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
 
@@ -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 48em (~768 pixels or less), like mobile phone devices. On screens larger than 48em (~769 pixels or larger), like desktop monitors or tablets, a `size=full` modal has the same behavior as a modal with `size=large` set.
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
 
@@ -2,8 +2,8 @@
2
2
  <div class="example">
3
3
  <button
4
4
  onclick={handleDemoModal}
5
- aria-haspopup="modal"
6
- >Open the Modal</button>
5
+ aria-haspopup="dialog"
6
+ >Open the Modal</button>
7
7
  <p>Result: <code>{demoResult}</code></p>
8
8
  </div>
9
9
  </template>
@@ -2,7 +2,7 @@
2
2
  <div class="example">
3
3
  <button
4
4
  onclick={handleDemoModal}
5
- aria-haspopup="modal"
5
+ aria-haspopup="dialog"
6
6
  >Open Modal form, size=medium</button>
7
7
  <p>Result: <code>{demoResult}</code></p>
8
8
  </div>
@@ -2,7 +2,7 @@
2
2
  <div class="example">
3
3
  <button
4
4
  onclick={handleDemoModal}
5
- aria-haspopup="modal"
5
+ aria-haspopup="dialog"
6
6
  >Open Modal form, size=full</button>
7
7
  <p>Result: <code>{demoResult}</code></p>
8
8
  </div>
@@ -1,9 +1,9 @@
1
1
  <template>
2
2
  <div class="example">
3
3
  <button
4
- aria-haspopup="modal"
4
+ aria-haspopup="dialog"
5
5
  onclick={handleDemoModal}
6
- >Open the Demo Modal</button>
6
+ >Open the Demo Modal</button>
7
7
  <p>Result: <code>{demoResult}</code></p>
8
8
  </div>
9
9
  </template>
@@ -2,8 +2,8 @@
2
2
  <div class="example">
3
3
  <button
4
4
  onclick={handleDemoModal}
5
- aria-haspopup="modal"
6
- >Open the Footless Modal</button>
5
+ aria-haspopup="dialog"
6
+ >Open the Footless Modal</button>
7
7
  <p>Result: <code>{demoResult}</code></p>
8
8
  </div>
9
9
  </template>
@@ -2,8 +2,8 @@
2
2
  <div class="example">
3
3
  <button
4
4
  onclick={handleDemoModal}
5
- aria-haspopup="modal"
6
- >Open the Headless Modal</button>
5
+ aria-haspopup="dialog"
6
+ >Open the Headless Modal</button>
7
7
  <p>Result: <code>{demoResult}</code></p>
8
8
  </div>
9
9
  </template>
@@ -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
- const MODAL_FULL_SCREEN_SMALL_BREAKPOINT = 768;
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 <= 768
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 > 768) are normal modal behavior
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 <= 768
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 > 768) are normal modal behavior
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 <= 768
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 > 768) are normal modal behavior
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 = 768;
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 767 pixels (small = full screen modal behavior),
1114
- * or (b) at or above 768 (large = default modal behavior)
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() {