lightning-base-components 1.14.2-alpha → 1.14.6-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 (82) hide show
  1. package/metadata/raptor.json +33 -1
  2. package/package.json +20 -4
  3. package/scopedImports/@salesforce-label-LightningDualListbox.movedOptionsPlural.js +1 -0
  4. package/scopedImports/@salesforce-label-LightningDualListbox.movedOptionsSingular.js +1 -0
  5. package/scopedImports/@salesforce-label-LightningErrorMessage.validitySelectAtleastOne.js +1 -0
  6. package/scopedImports/@salesforce-label-LightningMap.titleWithAddress.js +1 -0
  7. package/scopedImports/@salesforce-label-LightningModalBase.cancelandclose.js +1 -0
  8. package/src/lightning/ariaObserver/__component__/ariaObserver.spec.js +9 -0
  9. package/src/lightning/ariaObserver/__docs__/ariaObserver.md +142 -0
  10. package/src/lightning/ariaObserver/ariaObserver.js +24 -35
  11. package/src/lightning/baseFormattedText/baseFormattedText.html +6 -1
  12. package/src/lightning/baseFormattedText/baseFormattedText.js +5 -0
  13. package/src/lightning/buttonMenu/keyboard.js +0 -10
  14. package/src/lightning/card/card.html +6 -0
  15. package/src/lightning/checkboxGroup/checkboxGroup.html +2 -2
  16. package/src/lightning/checkboxGroup/checkboxGroup.js +6 -1
  17. package/src/lightning/colorPickerCustom/colorPickerCustom.js +20 -1
  18. package/src/lightning/datatable/__docs__/datatable.md +55 -0
  19. package/src/lightning/datatable/__examples__/basic/basic.html +1 -1
  20. package/src/lightning/datatable/__examples__/withInfiniteLoading/fetchDataHelper.js +21 -0
  21. package/src/lightning/datatable/__examples__/withInfiniteLoading/withInfiniteLoading.html +13 -0
  22. package/src/lightning/datatable/__examples__/withInfiniteLoading/withInfiniteLoading.js +42 -0
  23. package/src/lightning/datatable/autoWidthStrategy.js +170 -61
  24. package/src/lightning/datatable/{resizer.js → columnResizer.js} +0 -0
  25. package/src/lightning/datatable/columnWidthManager.js +226 -44
  26. package/src/lightning/datatable/columns-shared.js +1 -1
  27. package/src/lightning/datatable/datatable.js +104 -33
  28. package/src/lightning/datatable/errors.js +20 -9
  29. package/src/lightning/datatable/fixedWidthStrategy.js +43 -8
  30. package/src/lightning/datatable/headerActions.js +77 -49
  31. package/src/lightning/datatable/infiniteLoading.js +100 -28
  32. package/src/lightning/datatable/inlineEdit.js +505 -379
  33. package/src/lightning/datatable/inlineEditShared.js +24 -0
  34. package/src/lightning/datatable/keyboard.js +162 -127
  35. package/src/lightning/datatable/renderManager.js +208 -133
  36. package/src/lightning/datatable/{datatableResizeObserver.js → resizeObserver.js} +46 -29
  37. package/src/lightning/datatable/resizeSensor.js +8 -0
  38. package/src/lightning/datatable/rowLevelActions.js +17 -13
  39. package/src/lightning/datatable/rowNumber.js +54 -20
  40. package/src/lightning/datatable/rowSelection.js +760 -0
  41. package/src/lightning/datatable/rowSelectionShared.js +79 -0
  42. package/src/lightning/datatable/rows.js +17 -6
  43. package/src/lightning/datatable/state.js +16 -2
  44. package/src/lightning/datatable/templates/div/div.css +4 -0
  45. package/src/lightning/datatable/templates/div/div.html +128 -117
  46. package/src/lightning/datatable/templates/table/table.html +5 -0
  47. package/src/lightning/datatable/utils.js +14 -0
  48. package/src/lightning/datatable/widthManagerShared.js +27 -3
  49. package/src/lightning/datatable/wrapText.js +77 -47
  50. package/src/lightning/dualListbox/dualListbox.html +1 -1
  51. package/src/lightning/dualListbox/dualListbox.js +42 -0
  52. package/src/lightning/formattedDateTime/__docs__/formattedDateTime.md +36 -3
  53. package/src/lightning/formattedDateTime/__examples__/datetime/datetime.html +2 -2
  54. package/src/lightning/formattedDateTime/__examples__/datetime/datetime.js +3 -1
  55. package/src/lightning/formattedDateTime/__examples__/time/time.html +1 -1
  56. package/src/lightning/formattedDateTime/__examples__/time/time.js +3 -1
  57. package/src/lightning/formattedDateTime/formattedDateTime.js +1 -0
  58. package/src/lightning/input/input.html +2 -5
  59. package/src/lightning/inputUtils/validity.js +12 -1
  60. package/src/lightning/pillContainer/__docs__/pillContainer.md +45 -1
  61. package/src/lightning/positionLibrary/positionLibrary.js +31 -43
  62. package/src/lightning/primitiveCellActions/primitiveCellActions.js +69 -12
  63. package/src/lightning/primitiveCellFactory/cellWithStandardLayout.html +13 -11
  64. package/src/lightning/primitiveCellFactory/primitiveCellFactory.js +13 -8
  65. package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.html +17 -14
  66. package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.js +167 -98
  67. package/src/lightning/primitiveDatatableIeditTypeFactory/primitiveDatatableIeditTypeFactory.js +94 -69
  68. package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.html +4 -4
  69. package/src/lightning/primitiveDatatableStatusBar/primitiveDatatableStatusBar.js +4 -4
  70. package/src/lightning/primitiveHeaderActions/primitiveHeaderActions.js +99 -37
  71. package/src/lightning/progressIndicator/progressIndicator.js +1 -1
  72. package/src/lightning/progressStep/progressStep.js +1 -1
  73. package/src/lightning/spinner/spinner.html +1 -1
  74. package/src/lightning/spinner/spinner.js +12 -0
  75. package/src/lightning/staticMap/staticMap.html +1 -0
  76. package/src/lightning/staticMap/staticMap.js +39 -2
  77. package/src/lightning/utils/classSet.js +4 -1
  78. package/src/lightning/utilsPrivate/phonify.js +1 -1
  79. package/scopedImports/@salesforce-label-LightningModalBase.close.js +0 -1
  80. package/src/lightning/datatable/inlineEdit-shared.js +0 -14
  81. package/src/lightning/datatable/selector-shared.js +0 -38
  82. package/src/lightning/datatable/selector.js +0 -527
@@ -52,6 +52,7 @@
52
52
  "analyticsDataServiceApi": {
53
53
  "minVersion": "52.0"
54
54
  },
55
+ "analyticsSmartDataDiscoveryApi": {},
55
56
  "analyticsWaveApi": {
56
57
  "minVersion": "52.0"
57
58
  },
@@ -1351,15 +1352,21 @@
1351
1352
  "iconUtils": {},
1352
1353
  "industriesCibApi": {},
1353
1354
  "industriesDecisionMatrixDesignerApi": {},
1355
+ "industriesEinsteinAIAcceleratorApi": {},
1354
1356
  "industriesExplainabilityApi": {},
1357
+ "industriesHealthcloudHpiApi": {},
1355
1358
  "industriesIdentityVerificationApi": {},
1356
1359
  "industriesInterestTaggingApi": {},
1357
1360
  "industriesLoyaltyEngineApi": {},
1361
+ "industriesPublicSectorApi": {},
1358
1362
  "industriesRcgTenantmanagementApi": {},
1359
1363
  "industriesRuleBuilderApi": {},
1364
+ "industriesSustainabilityBeiApi": {},
1365
+ "industriesSustainabilityDgfApi": {},
1360
1366
  "industriesSustainabilityRecalculateApi": {},
1361
1367
  "industriesSustainabilityRecordLockUnlockApi": {},
1362
1368
  "industriesSustainabilityReferenceDataApi": {},
1369
+ "industriesTimelineApi": {},
1363
1370
  "industriesVideoVisitsApi": {},
1364
1371
  "input": {
1365
1372
  "minVersion": "0.0",
@@ -2211,6 +2218,7 @@
2211
2218
  }
2212
2219
  ]
2213
2220
  },
2221
+ "marketingAssetcreationApi": {},
2214
2222
  "menuDivider": {
2215
2223
  "minVersion": "0.0",
2216
2224
  "slotNames": [],
@@ -3394,6 +3402,7 @@
3394
3402
  "uiAssistantPlatformApi": {},
3395
3403
  "uiDuplicatesApi": {},
3396
3404
  "uiLayoutApi": {},
3405
+ "uiLearningContentPlatformApi": {},
3397
3406
  "uiListApi": {
3398
3407
  "minVersion": "45.0"
3399
3408
  },
@@ -3406,12 +3415,35 @@
3406
3415
  },
3407
3416
  "uiRecordActionsApi": {},
3408
3417
  "uiRecordApi": {
3409
- "minVersion": "45.0"
3418
+ "minVersion": "46.0"
3410
3419
  },
3411
3420
  "uiRecordAvatarApi": {},
3412
3421
  "uiRelatedListApi": {
3413
3422
  "minVersion": "53.0"
3414
3423
  },
3424
+ "unstable_analyticsDataServiceApi": {},
3425
+ "unstable_analyticsSmartDataDiscoveryApi": {},
3426
+ "unstable_analyticsWaveApi": {},
3427
+ "unstable_cmsAuthoringApi": {},
3428
+ "unstable_cmsDeliveryApi": {},
3429
+ "unstable_cmsTypeApi": {},
3430
+ "unstable_commerceApi": {},
3431
+ "unstable_communityNavigationMenuApi": {},
3432
+ "unstable_communityRecordSeoPropertiesApi": {},
3433
+ "unstable_communitySitesSearchApi": {},
3434
+ "unstable_experienceMarketingIntegrationApi": {},
3435
+ "unstable_industriesCibApi": {},
3436
+ "unstable_industriesDecisionMatrixDesignerApi": {},
3437
+ "unstable_industriesExplainabilityApi": {},
3438
+ "unstable_industriesHealthcloudHpiApi": {},
3439
+ "unstable_industriesInterestTaggingApi": {},
3440
+ "unstable_industriesLoyaltyEngineApi": {},
3441
+ "unstable_industriesPublicSectorApi": {},
3442
+ "unstable_industriesRcgTenantmanagementApi": {},
3443
+ "unstable_industriesRuleBuilderApi": {},
3444
+ "unstable_platformAdminSuccessGuidanceApi": {},
3445
+ "unstable_platformInteractionOrchestratorApi": {},
3446
+ "unstable_platformScaleCenterApi": {},
3415
3447
  "unstable_uiActionsApi": {},
3416
3448
  "unstable_uiAppsApi": {},
3417
3449
  "unstable_uiDuplicatesApi": {},
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "lightning-base-components",
3
- "version": "1.14.2-alpha",
3
+ "version": "1.14.6-alpha",
4
4
  "engines": {
5
- "node": ">=12.18.3"
5
+ "node": ">=14.16.0"
6
6
  },
7
7
  "files": [
8
8
  "external",
@@ -57,6 +57,10 @@
57
57
  "name": "@salesforce/label/LightningErrorMessage.validityTooShort",
58
58
  "path": "scopedImports/@salesforce-label-LightningErrorMessage.validityTooShort.js"
59
59
  },
60
+ {
61
+ "name": "@salesforce/label/LightningErrorMessage.validitySelectAtleastOne",
62
+ "path": "scopedImports/@salesforce-label-LightningErrorMessage.validitySelectAtleastOne.js"
63
+ },
60
64
  {
61
65
  "name": "@salesforce/label/LightningCarousel.tabString",
62
66
  "path": "scopedImports/@salesforce-label-LightningCarousel.tabString.js"
@@ -369,6 +373,14 @@
369
373
  "name": "@salesforce/label/LightningDualListbox.requiredOptionError",
370
374
  "path": "scopedImports/@salesforce-label-LightningDualListbox.requiredOptionError.js"
371
375
  },
376
+ {
377
+ "name": "@salesforce/label/LightningDualListbox.movedOptionsSingular",
378
+ "path": "scopedImports/@salesforce-label-LightningDualListbox.movedOptionsSingular.js"
379
+ },
380
+ {
381
+ "name": "@salesforce/label/LightningDualListbox.movedOptionsPlural",
382
+ "path": "scopedImports/@salesforce-label-LightningDualListbox.movedOptionsPlural.js"
383
+ },
372
384
  {
373
385
  "name": "@salesforce/label/LightningProgressIndicator.stageComplete",
374
386
  "path": "scopedImports/@salesforce-label-LightningProgressIndicator.stageComplete.js"
@@ -861,6 +873,10 @@
861
873
  "name": "@salesforce/label/LightningMap.iframeTitle",
862
874
  "path": "scopedImports/@salesforce-label-LightningMap.iframeTitle.js"
863
875
  },
876
+ {
877
+ "name": "@salesforce/label/LightningMap.titleWithAddress",
878
+ "path": "scopedImports/@salesforce-label-LightningMap.titleWithAddress.js"
879
+ },
864
880
  {
865
881
  "name": "@salesforce/label/LightningPrimitiveCoordinate.selected",
866
882
  "path": "scopedImports/@salesforce-label-LightningPrimitiveCoordinate.selected.js"
@@ -942,8 +958,8 @@
942
958
  "path": "scopedImports/@salesforce-label-LightningRating.nStars.js"
943
959
  },
944
960
  {
945
- "name": "@salesforce/label/LightningModalBase.close",
946
- "path": "scopedImports/@salesforce-label-LightningModalBase.close.js"
961
+ "name": "@salesforce/label/LightningModalBase.cancelandclose",
962
+ "path": "scopedImports/@salesforce-label-LightningModalBase.cancelandclose.js"
947
963
  },
948
964
  {
949
965
  "name": "@salesforce/label/LightningModalBase.waitstate",
@@ -0,0 +1 @@
1
+ export default 'Items {0} moved to the list {1}';
@@ -0,0 +1 @@
1
+ export default 'Item {0} moved to the list {1}';
@@ -0,0 +1 @@
1
+ export default 'You must select at least one choice from this set.';
@@ -0,0 +1 @@
1
+ export default 'Map of {0}';
@@ -0,0 +1 @@
1
+ export default 'Cancel and close';
@@ -47,6 +47,15 @@ describe('AriaObserver', () => {
47
47
  expect(testElement.labelContent).toEqual('Foo\nBar');
48
48
  });
49
49
 
50
+ it('should work with label ids appearing in the opposite of document order', async () => {
51
+ const container = createTestElement();
52
+ container.updateAriaLabelledby('alt-label-id id-label');
53
+ await Promise.resolve();
54
+
55
+ const testElement = container.testElement;
56
+ expect(testElement.labelContent).toEqual('Bar\nFoo');
57
+ });
58
+
50
59
  it('should update the internal label content when external content changes', async () => {
51
60
  const container = createTestElement();
52
61
  container.updateLabelContent();
@@ -0,0 +1,142 @@
1
+ The `lightning/ariaObserver` module provides an easy way for users to write accessible component that works in both synthetic and native shadow.
2
+
3
+ ## Aria ID referencing in native shadow
4
+ Use the` AriaObserver` library to write accessible component that works where `ariaLabelledBy` would break native shadow.
5
+
6
+ Here's an example that won't work with native shadow. In the following code, we support attribute `ariaLabelledBy` in our component `c-foo`, so the `input` element is labelled by external elements.
7
+
8
+ ``` html
9
+ <template>
10
+ <input aria-labelledby={ariaLabelledBy}>
11
+ </template>
12
+ ```
13
+
14
+ ```
15
+ class Foo extends LightningElement {
16
+ @api ariaLabelledBy;
17
+ }
18
+ ```
19
+
20
+ This example uses the `aria-labelledby` attribute to use the internal input as an external label in `c-foo`.
21
+
22
+ ``` html
23
+ <span id="my-label">Input field</span>
24
+ <c-foo aria-labelledby="my-label"></c-foo>
25
+ ```
26
+
27
+ The above example works fine in synthetic shadow, but in native shadow mode, the `aria-labelledby` ID reference is broken. The `input` element is isolated in its own shadow DOM, so the label with id `my-label` isn't in the same shadow boundary.
28
+
29
+ ## Creating AriaObserver
30
+
31
+ To use `AriaObserver` in your component, first import it from `lightning/ariaObserver`. Then, instantiate the `AriaObserver` within your component.
32
+
33
+ The `AriaObserver` constructor takes one parameter:
34
+ - `cmpReference` The reference of the current component (`this`).
35
+
36
+ ``` js
37
+ import AriaObserver from 'lightning/ariaObserver';
38
+
39
+ class Foo extends LightningElement {
40
+ constructor() {
41
+ super();
42
+ this.ariaObserver = new AriaObserver(this);
43
+ }
44
+ }
45
+ ```
46
+
47
+ Next, use the `connect(options)` method to connect between the internal element and the external reference. It takes an options object with the following keys:
48
+ - `targetSelector` The selector to the internal element where the aria attribute should be attached.
49
+ - `attribute` The name of the aria attribute. Two supported options: `aria-labelledby`and `aria-describedby`.
50
+ - `id` The ID of the external element. Alternatively, you can use `ids` for multiple IDs.
51
+
52
+ This example uses `connect(options)` to display an aria label for the internal `input` element.
53
+ ``` js
54
+ @api
55
+ get ariaLabelledBy() {
56
+ return this._ariaLabelledBy;
57
+ }
58
+ set ariaLabelledBy(refs) {
59
+ this._ariaLabelledBy = refs;
60
+
61
+ this.ariaObserver.connect({
62
+ targetSelector: 'input',
63
+ attribute: 'aria-labelledby',
64
+ id: refs
65
+ });
66
+ }
67
+ ```
68
+
69
+ Then use the `sync()` method to synchronize the ID references when the template is re-rendered.
70
+
71
+ ``` js
72
+ renderedCallback() {
73
+ this.ariaObserver.sync();
74
+ }
75
+ ```
76
+
77
+ Finally, disconnect the aria observer and free the resources at the end of the component lifecycle.
78
+
79
+ ``` js
80
+ disconnectedCallback() {
81
+ if (this.ariaObserver) {
82
+ this.ariaObserver.disconnect();
83
+ this.ariaObserver = undefined;
84
+ }
85
+ }
86
+ ```
87
+
88
+ Here is all these steps combined into a complete example of a component using `AriaObserver`.
89
+
90
+ ``` html
91
+ <template>
92
+ <!-- element where the aria attribute is attached -->
93
+ <input>
94
+ </template>
95
+ ```
96
+
97
+ ``` js
98
+ import {api, LightningElement} from 'lwc';
99
+ import AriaObserver from 'lightning/ariaObserver';
100
+
101
+ export default class Foo extends LightningElement {
102
+ constructor() {
103
+ super();
104
+ this.ariaObserver = new AriaObserver(this);
105
+ }
106
+
107
+ _ariaLabelledBy = '';
108
+
109
+ @api
110
+ get ariaLabelledBy() {
111
+ return this._ariaLabelledBy;
112
+ }
113
+ set ariaLabelledBy(refs) {
114
+ this._ariaLabelledBy = refs;
115
+
116
+ /* Establish the connection between input and the external label */
117
+ this.ariaObserver.connect({
118
+ targetSelector: 'input',
119
+ attribute: 'aria-labelledby',
120
+ id: refs
121
+ });
122
+ }
123
+
124
+ renderedCallback() {
125
+ this.ariaObserver.sync();
126
+ }
127
+
128
+ disconnectedCallback() {
129
+ if (this.ariaObserver) {
130
+ this.ariaObserver.disconnect();
131
+ this.ariaObserver = undefined;
132
+ }
133
+ }
134
+ }
135
+ ```
136
+
137
+ ## Limitations
138
+ `AriaObserver` only works with text-only aria ID references.
139
+
140
+ Supported attributes:
141
+ - `aria-labelledby`
142
+ - `aria-describedby`
@@ -13,11 +13,13 @@ function getAttr(elm, attr) {
13
13
  return elm.getAttribute(attr);
14
14
  }
15
15
 
16
- function extractElements(root, selector) {
17
- if (typeof selector !== 'string' || selector === '') {
16
+ function extractElements(root, ids) {
17
+ if (typeof ids !== 'string' || ids === '') {
18
18
  return [];
19
19
  }
20
- return [].slice.call(root.querySelectorAll(selector));
20
+ // We must query the elements in the order of ids, so that
21
+ // the content will be extracted in the correct order.
22
+ return splitIds(ids).map((id) => root.querySelector(`#${id}`));
21
23
  }
22
24
 
23
25
  function extractContent(elements) {
@@ -113,38 +115,28 @@ export default class AriaObserver {
113
115
  connect({ targetSelector, attribute, id, ids }) {
114
116
  ids = ids || id;
115
117
 
116
- let attrState = this.state[attribute];
117
- if (attrState) {
118
- // note: we don't support linking to a different targetSelector, attribute
119
- if (!this.isNative) {
120
- const elm = this.template.querySelector(
121
- attrState.innerSelector
122
- );
123
- if (elm) {
124
- // removing the old ids if possible before setting the new ones
125
- removeAriaRefWhenPossible(elm, attribute, attrState.ids);
126
- }
127
- attrState.ids = ids;
118
+ this.state[attribute] = this.state[attribute] || {};
119
+ const attrState = this.state[attribute];
120
+
121
+ // note: we don't support linking to a different targetSelector
122
+ attrState.innerSelector = attrState.innerSelector || targetSelector;
123
+
124
+ // removing the old ids if possible before setting the new ones
125
+ if (!this.isNative && attrState.ids) {
126
+ const elm = this.template.querySelector(attrState.innerSelector);
127
+ if (elm) {
128
+ removeAriaRefWhenPossible(elm, attribute, attrState.ids);
128
129
  }
129
- } else {
130
- attrState = this.state[attribute] = {
131
- ids,
132
- innerSelector: targetSelector,
133
- };
134
130
  }
135
- if (this.isNative) {
136
- attrState.outerSelector = (ids + '')
137
- .trim()
138
- .split(/\s+/)
139
- .map((ref) => `#${ref}`)
140
- .join(',');
141
131
 
132
+ attrState.ids = ids;
133
+
134
+ if (this.isNative && !attrState.placeholder) {
142
135
  // create placeholder element for copied content
143
- if (!attrState.placeholder) {
144
- attrState.placeholder = document.createElement('span');
145
- attrState.placeholder.id = `auto-link-${attribute}-${this.guid}`;
146
- }
136
+ attrState.placeholder = document.createElement('span');
137
+ attrState.placeholder.id = `auto-link-${attribute}-${this.guid}`;
147
138
  }
139
+
148
140
  if (this.component.isConnected) {
149
141
  this.privateUpdate(attribute);
150
142
  }
@@ -213,12 +205,9 @@ export default class AriaObserver {
213
205
  }
214
206
  let computedIds;
215
207
  if (this.isNative) {
216
- const { outerSelector, content, placeholder } =
217
- this.state[attrName];
208
+ const { ids, content, placeholder } = this.state[attrName];
218
209
 
219
- const newContent = extractContent(
220
- extractElements(this.root, outerSelector)
221
- );
210
+ const newContent = extractContent(extractElements(this.root, ids));
222
211
  if (content !== newContent) {
223
212
  this.state[attrName].content = placeholder.textContent =
224
213
  newContent;
@@ -1,5 +1,10 @@
1
1
  <template>
2
- <template if:false={shouldFormat}>{normalizedValue}</template>
2
+ <template if:false={shouldFormat}>
3
+ <template if:true={ignoreRTL}>
4
+ <span dir="ltr">{normalizedValue}</span>
5
+ </template>
6
+ <template if:false={ignoreRTL}>{normalizedValue}</template>
7
+ </template>
3
8
  <template if:true={shouldFormat} for:each={formattedParts} for:item="part">
4
9
  <template if:true={part.isLink}>
5
10
  <a key={part.key} target='_blank' href={part.href} rel="noopener">{part.value}</a>
@@ -64,4 +64,9 @@ export default class BaseFormattedText extends LightningElement {
64
64
  }
65
65
  return parseToFormattedLinkifiedParts(this.value, true);
66
66
  }
67
+
68
+ get ignoreRTL() {
69
+ // Ignoring RTL for hex color codes
70
+ return this.isString && this.value.match(/^#[0-9abcdef]{6}$/i) !== null;
71
+ }
67
72
  }
@@ -113,16 +113,6 @@ export function handleKeyDownOnMenuTrigger(event, menuInterface) {
113
113
  menuInterface.toggleMenuVisibility();
114
114
  }
115
115
  break;
116
- // W3: Home and End: If arrow key wrapping is not supported, move focus to first and last item
117
- // Note: We do support wrapping, but it doesn't hurt to support these keys anyway.
118
- case keyCodes.home:
119
- preventDefaultAndStopPropagation(event);
120
- menuInterface.focusOnIndex(0);
121
- break;
122
- case keyCodes.end:
123
- preventDefaultAndStopPropagation(event);
124
- menuInterface.focusOnIndex(menuInterface.getTotalMenuItems() - 1);
125
- break;
126
116
  // W3: Escape: Close the menu and return focus to the element or context, e.g., menu button or
127
117
  // parent menu item, from which the menu was opened
128
118
  case keyCodes.escape:
@@ -40,5 +40,11 @@
40
40
  <slot name="footer"></slot>
41
41
  </div>
42
42
  </template>
43
+ <!-- This dummy placeholder slot is required because
44
+ a slot's presence is verified by assignedElements count
45
+ and not whether the slot itself is present or not -->
46
+ <template if:false={showFooter}>
47
+ <slot name="footer" class="slds-hide"></slot>
48
+ </template>
43
49
  </article>
44
50
  </template>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <fieldset aria-required={required}>
2
+ <fieldset aria-describedby={computearaiDescriedBy}>
3
3
 
4
4
  <legend class={computedLegendClass}>
5
5
  <template if:true={required}>
@@ -32,6 +32,6 @@
32
32
  <template if:true={_helpMessage}>
33
33
  <div id="helptext" data-helptext class="slds-form-element__help">{_helpMessage}</div>
34
34
  </template>
35
-
35
+
36
36
  </fieldset>
37
37
  </template>
@@ -295,7 +295,7 @@ export default class LightningCheckboxGroup extends LightningElement {
295
295
  get _constraint() {
296
296
  if (!this._constraintApi) {
297
297
  this._constraintApi = new FieldConstraintApi(() => this, {
298
- valueMissing: () =>
298
+ validitySelectAtleastOneValue: () =>
299
299
  !this.disabled && this.required && this.value.length === 0,
300
300
  });
301
301
  }
@@ -313,4 +313,9 @@ export default class LightningCheckboxGroup extends LightningElement {
313
313
  })
314
314
  .toString();
315
315
  }
316
+
317
+ computearaiDescriedBy() {
318
+ const helpMessage = this.template.querySelector('[data-helptext]');
319
+ return getRealDOMId(helpMessage);
320
+ }
316
321
  }
@@ -8,6 +8,7 @@ import labelHexLabel from '@salesforce/label/LightningColorPicker.hexLabel';
8
8
  import labelHueInput from '@salesforce/label/LightningColorPicker.hueInput';
9
9
  import labelRInput from '@salesforce/label/LightningColorPicker.rInput';
10
10
  import labelRedAbbr from '@salesforce/label/LightningColorPicker.redAbbr';
11
+ import formFactorPropertyName from '@salesforce/client/formFactor';
11
12
  import { LightningElement, api, track } from 'lwc';
12
13
  import { keyCodes } from 'lightning/utilsPrivate';
13
14
  import { generateUniqueId, getErrorMessage } from 'lightning/inputUtils';
@@ -58,7 +59,25 @@ export default class LightningColorPickerCustom extends LightningElement {
58
59
  if (!this._initialized) {
59
60
  // eslint-disable-next-line @lwc/lwc/no-async-operation
60
61
  requestAnimationFrame(() => {
61
- this.focus();
62
+ // (*1*)
63
+ if (formFactorPropertyName !== 'Large') {
64
+ /**
65
+ * We need to wait for one more animation frame and invoke .focus()
66
+ * in iOS. This is because the positionLibray.js initially sets the position
67
+ * of this color-picker element to "top: 0px" and then later repositions it asynchronously
68
+ * it the next animation frames. The first (*1*) rAF callback is fired between
69
+ * setting "top: 0px" and then later repositioning it. Calling .focus() in this callback
70
+ * triggers a re-paint step and the page is scrolled to the top due to "top: 0px" being
71
+ * present in the styles. To avoid this, we can delay the next re-paint after color-picker
72
+ * is repositioned correctly by positionLibrary.js. Hence we wait for next animation frame
73
+ * and then call .focus() to trigger the next re-paint after the color-picker is repositioned correctly
74
+ * which was initially positioned with "top: 0px" by positionLibrary.js
75
+ */
76
+ // eslint-disable-next-line @lwc/lwc/no-async-operation
77
+ requestAnimationFrame(() => this.focus());
78
+ } else {
79
+ this.focus();
80
+ }
62
81
  });
63
82
  this.gradient();
64
83
  this.handleUpdateAnchor();
@@ -244,6 +244,28 @@ Valid data types and their supported attributes include:
244
244
  | text | Displays text using [lightning-formatted-text](bundle/lightning-formatted-text/). This is the default data type. | linkify |
245
245
  | url | Displays a URL using [lightning-formatted-url](bundle/lightning-formatted-url/) | label, target, tooltip |
246
246
 
247
+ In some situations, multiple columns reference the same `fieldName` but have different `fieldApiNames` and different ways of working with the field information. To give a column a unique ID when using the same field name for two columns, use the attribute `columnKey` instead of `fieldName` on one of the column definitions.
248
+
249
+ ```javascript
250
+ get columns() {
251
+ return [
252
+ // Column using 'fieldName' as identifier
253
+ {
254
+ label: 'Lead',
255
+ fieldName: 'leadId',
256
+ ...
257
+ },
258
+ // Column using 'columnKey' as identifier
259
+ {
260
+ label: 'Company',
261
+ columnKey: 'leadCompany',
262
+ fieldName: 'leadId',
263
+ ...
264
+ }
265
+ ]
266
+ }
267
+ ```
268
+
247
269
  #### Custom Formatting Examples
248
270
 
249
271
  To customize the formatting based on the data type, pass in the attributes for
@@ -494,6 +516,21 @@ const columns = [
494
516
 
495
517
  Custom classes are currently not supported. To apply custom styling on your datatable cells, create a custom data type and then apply your custom CSS classes. See [Custom Data Type Layout and Styles](docs/component-library/documentation/lwc/lwc.data_table_custom_types_styling).
496
518
 
519
+ #### Displaying Indicators for Read-Only Fields
520
+
521
+ You can display a lock icon on read-only fields to specify they're not editable. To specify that a column's field as read-only, set the column attribute `editable` to `false` and the column attribute `displayReadOnlyIcon` to `true` in the associated column definition. This example displays a lock icon on each field in a column called "Website."
522
+
523
+ ```javascript
524
+ const columns = [
525
+ {
526
+ label: 'Website',
527
+ fieldName: 'website',
528
+ type: 'url',
529
+ editable: false,
530
+ displayReadOnlyIcon: true,
531
+ }
532
+ ```
533
+
497
534
  #### Using Infinite Scrolling to Load More Rows
498
535
 
499
536
  Infinite scrolling enables you to load a subset of data and then display more
@@ -1031,6 +1068,24 @@ handleSave(event) {
1031
1068
  }
1032
1069
  ```
1033
1070
 
1071
+ You can also program an external element, such as a button, to open an inline edit panel on the currently active cell or next editable cell in the datatable. Invoke the `openInlineEdit()` method in the external element that should direct a user to the first editable cell in your datatable component.
1072
+
1073
+ This example opens a datatable cell for inline edit when the user clicks an "Edit" button.
1074
+
1075
+ ```javascript
1076
+ import { LightningElement } from 'lwc';
1077
+ export default class DatatableWithInlineEdit extends LightningElement {
1078
+ data = [];
1079
+ columns = columns;
1080
+ rowOffset = 0;
1081
+
1082
+ handleClick() {
1083
+ const dt = this.template.querySelector('lightning-datatable');
1084
+ dt.openInlineEdit();
1085
+ }
1086
+ }
1087
+ ```
1088
+
1034
1089
  For more information, see [Display Data in a Table with Inline Editing](docs/component-library/documentation/lwc/lwc.data_table_inline_edit).
1035
1090
 
1036
1091
  #### Displaying Errors
@@ -5,5 +5,5 @@
5
5
  data={data}
6
6
  columns={columns}>
7
7
  </lightning-datatable>
8
- </div>
8
+ </div>
9
9
  </template>
@@ -0,0 +1,21 @@
1
+ const recordMetadata = {
2
+ name: 'name',
3
+ email: 'email',
4
+ website: 'url',
5
+ amount: 'currency',
6
+ phone: 'phoneNumber',
7
+ closeAt: 'dateInFuture',
8
+ };
9
+
10
+ export default function fetchData(amountOfRecords) {
11
+ return fetch('https://data-faker.herokuapp.com/collection', {
12
+ method: 'POST',
13
+ headers: {
14
+ 'Content-Type': 'application/json; charset=utf-8',
15
+ },
16
+ body: JSON.stringify({
17
+ amountOfRecords,
18
+ recordMetadata,
19
+ }),
20
+ }).then((response) => response.json());
21
+ }
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <p>Total Rows: {data.length}</p>
3
+ <div style="height: 300px;">
4
+ <lightning-datatable
5
+ key-field="id"
6
+ data={data}
7
+ columns={columns}
8
+ enable-infinite-loading
9
+ onloadmore={handleLoadMore}>
10
+ </lightning-datatable>
11
+ </div>
12
+ <p>{loadMoreStatus}</p>
13
+ </template>