lightning-base-components 1.13.1-alpha → 1.13.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 (103) hide show
  1. package/package.json +33 -1
  2. package/scopedImports/@salesforce-label-LightningInput.helptextAlternativeText.js +1 -0
  3. package/scopedImports/@salesforce-label-LightningOutputField.helptextAlternativeText.js +1 -0
  4. package/scopedImports/@salesforce-label-LightningRating.nStars.js +1 -0
  5. package/scopedImports/@salesforce-label-LightningRating.oneStar.js +1 -0
  6. package/scopedImports/@salesforce-label-LightningRating.rating.js +1 -0
  7. package/scopedImports/@salesforce-label-LightningRating.readOnlyAssistiveText.js +1 -0
  8. package/scopedImports/@salesforce-label-LightningRating.selectRating.js +1 -0
  9. package/scopedImports/@salesforce-label-LightningRecordForm.edit.js +1 -0
  10. package/src/lightning/baseCombobox/baseCombobox.js +8 -0
  11. package/src/lightning/baseCombobox/keyboard.js +9 -1
  12. package/src/lightning/datatable/datatable.html +1 -0
  13. package/src/lightning/datatable/datatable.js +5 -2
  14. package/src/lightning/datatable/infiniteLoading.js +4 -1
  15. package/src/lightning/datatable/inlineEdit.js +133 -2
  16. package/src/lightning/datatable/keyboard.js +2 -6
  17. package/src/lightning/datatable/selector.js +19 -3
  18. package/src/lightning/focusTrap/focusTrap.js +0 -2
  19. package/src/lightning/focusUtils/focus.js +63 -12
  20. package/src/lightning/formattedRichText/richTextConfig.js +1 -0
  21. package/src/lightning/input/input.html +4 -4
  22. package/src/lightning/input/input.js +8 -1
  23. package/src/lightning/positionLibrary/__docs__/positionLibrary.md +3 -0
  24. package/src/lightning/positionLibrary/__examples__/components/components.html +41 -0
  25. package/src/lightning/positionLibrary/__examples__/components/components.js +29 -0
  26. package/src/lightning/positionLibrary/__examples__/playground/playground.css +84 -0
  27. package/src/lightning/positionLibrary/__examples__/playground/playground.html +122 -0
  28. package/src/lightning/positionLibrary/__examples__/playground/playground.js +103 -0
  29. package/src/lightning/positionLibrary/__examples__/playgroundShadowScroll/playgroundShadowScroll.html +8 -0
  30. package/src/lightning/positionLibrary/__examples__/playgroundShadowScroll/playgroundShadowScroll.js +9 -0
  31. package/src/lightning/positionLibrary/elementProxy.js +13 -1
  32. package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.html +1 -0
  33. package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.js +2 -1
  34. package/src/lightning/primitiveDatatableIeditTypeFactory/primitiveDatatableIeditTypeFactory.js +1 -7
  35. package/src/lightning/primitiveDatatableLoadingIndicator/primitiveDatatableLoadingIndicator.html +1 -1
  36. package/src/lightning/tabBar/tabBar.js +8 -12
  37. package/src/lightning/tooltipLibrary/tooltipLibrary.js +2 -1
  38. package/src/lightning/utilsPrivate/utilsPrivate.js +10 -4
  39. package/src/lightning/accordion/__utam__/accordion.utam.json +0 -13
  40. package/src/lightning/accordionSection/__utam__/accordionSection.utam.json +0 -71
  41. package/src/lightning/avatar/__utam__/avatar.utam.json +0 -79
  42. package/src/lightning/badge/__utam__/badge.utam.json +0 -13
  43. package/src/lightning/baseCombobox/__utam__/baseCombobox.utam.json +0 -91
  44. package/src/lightning/baseComboboxItem/__utam__/baseComboboxItem.utam.json +0 -46
  45. package/src/lightning/breadcrumbs/__utam__/breadcrumbs.utam.json +0 -69
  46. package/src/lightning/button/__utam__/button.utam.json +0 -61
  47. package/src/lightning/buttonGroup/__utam__/buttonGroup.utam.json +0 -18
  48. package/src/lightning/buttonIcon/__utam__/buttonIcon.utam.json +0 -54
  49. package/src/lightning/buttonIconStateful/__utam__/buttonIconStateful.utam.json +0 -86
  50. package/src/lightning/buttonMenu/__utam__/buttonMenu.utam.json +0 -120
  51. package/src/lightning/buttonStateful/__utam__/buttonStateful.utam.json +0 -87
  52. package/src/lightning/calendar/__utam__/calendar.utam.json +0 -136
  53. package/src/lightning/card/__utam__/card.utam.json +0 -111
  54. package/src/lightning/carousel/__utam__/carousel.utam.json +0 -44
  55. package/src/lightning/carouselImage/__utam__/carouselImage.utam.json +0 -108
  56. package/src/lightning/checkboxGroup/__utam__/checkboxGroup.utam.json +0 -29
  57. package/src/lightning/combobox/__utam__/combobox.utam.json +0 -56
  58. package/src/lightning/datatable/__utam__/datatable.utam.json +0 -591
  59. package/src/lightning/datepicker/__utam__/datepicker.utam.json +0 -104
  60. package/src/lightning/datetimepicker/__utam__/datetimepicker.utam.json +0 -56
  61. package/src/lightning/dualListbox/__utam__/dualListbox.utam.json +0 -210
  62. package/src/lightning/formattedAddress/__utam__/formattedAddress.utam.json +0 -50
  63. package/src/lightning/formattedDateTime/__utam__/formattedDateTime.utam.json +0 -13
  64. package/src/lightning/formattedEmail/__utam__/formattedEmail.utam.json +0 -45
  65. package/src/lightning/formattedLocation/__utam__/formattedLocation.utam.json +0 -13
  66. package/src/lightning/formattedLookup/__utam__/formattedLookup.utam.json +0 -13
  67. package/src/lightning/formattedName/__utam__/formattedName.utam.json +0 -13
  68. package/src/lightning/formattedNumber/__utam__/formattedNumber.utam.json +0 -13
  69. package/src/lightning/formattedPhone/__utam__/formattedPhone.utam.json +0 -13
  70. package/src/lightning/formattedRichText/__utam__/formattedRichText.utam.json +0 -13
  71. package/src/lightning/formattedText/__utam__/formattedText.utam.json +0 -13
  72. package/src/lightning/formattedUrl/__utam__/formattedUrl.utam.json +0 -30
  73. package/src/lightning/groupedCombobox/__utam__/groupedCombobox.utam.json +0 -56
  74. package/src/lightning/helptext/__utam__/helptext.utam.json +0 -23
  75. package/src/lightning/icon/__utam__/icon.utam.json +0 -31
  76. package/src/lightning/input/__utam__/input.utam.json +0 -267
  77. package/src/lightning/inputAddress/__utam__/inputAddress.utam.json +0 -94
  78. package/src/lightning/inputLocation/__utam__/inputLocation.utam.json +0 -37
  79. package/src/lightning/inputName/__utam__/inputName.utam.json +0 -71
  80. package/src/lightning/layout/__utam__/layout.utam.json +0 -20
  81. package/src/lightning/layoutItem/__utam__/layoutItem.utam.json +0 -12
  82. package/src/lightning/menuItem/__utam__/menuItem.utam.json +0 -40
  83. package/src/lightning/menuSubheader/__utam__/menuSubHeader.utam.json +0 -22
  84. package/src/lightning/picklist/__utam__/picklist.utam.json +0 -24
  85. package/src/lightning/pill/__utam__/pill.utam.json +0 -55
  86. package/src/lightning/pillContainer/__utam__/pillContainer.utam.json +0 -15
  87. package/src/lightning/primitiveBubble/__utam__/primitiveBubble.utam.json +0 -17
  88. package/src/lightning/primitiveFileDroppableZone/__utam__/primitiveFileDroppableZone.utam.json +0 -40
  89. package/src/lightning/primitiveIcon/__utam__/primitiveIcon.utam.json +0 -25
  90. package/src/lightning/progressBar/__utam__/progressBar.utam.json +0 -58
  91. package/src/lightning/progressIndicator/__utam__/progressIndicator.utam.json +0 -69
  92. package/src/lightning/progressRing/__utam__/progressRing.utam.json +0 -88
  93. package/src/lightning/progressStep/__utam__/progressStep.utam.json +0 -47
  94. package/src/lightning/radioGroup/__utam__/radioGroup.utam.json +0 -50
  95. package/src/lightning/select/__utam__/select.utam.json +0 -118
  96. package/src/lightning/spinner/__utam__/spinner.utam.json +0 -41
  97. package/src/lightning/tabBar/__utam__/tabBar.utam.json +0 -56
  98. package/src/lightning/tabset/__utam__/tabset.utam.json +0 -24
  99. package/src/lightning/textarea/__utam__/textarea.utam.json +0 -83
  100. package/src/lightning/tile/__utam__/tile.utam.json +0 -105
  101. package/src/lightning/timepicker/__utam__/timepicker.utam.json +0 -87
  102. package/src/lightning/tree/__utam__/tree.utam.json +0 -12
  103. package/src/lightning/treeItem/__utam__/treeItem.utam.json +0 -101
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightning-base-components",
3
- "version": "1.13.1-alpha",
3
+ "version": "1.13.5-alpha",
4
4
  "engines": {
5
5
  "node": ">=12.18.3"
6
6
  },
@@ -745,6 +745,10 @@
745
745
  "name": "@salesforce/label/LightningRecordForm.loading",
746
746
  "path": "scopedImports/@salesforce-label-LightningRecordForm.loading.js"
747
747
  },
748
+ {
749
+ "name": "@salesforce/label/LightningRecordForm.edit",
750
+ "path": "scopedImports/@salesforce-label-LightningRecordForm.edit.js"
751
+ },
748
752
  {
749
753
  "name": "@salesforce/label/LightningLookup.add",
750
754
  "path": "scopedImports/@salesforce-label-LightningLookup.add.js"
@@ -901,6 +905,34 @@
901
905
  "name": "@salesforce/label/LightningServiceCloudVoiceToolkitApi.missingNbaParams",
902
906
  "path": "scopedImports/@salesforce-label-LightningServiceCloudVoiceToolkitApi.missingNbaParams.js"
903
907
  },
908
+ {
909
+ "name": "@salesforce/label/LightningOutputField.helptextAlternativeText",
910
+ "path": "scopedImports/@salesforce-label-LightningOutputField.helptextAlternativeText.js"
911
+ },
912
+ {
913
+ "name": "@salesforce/label/LightningInput.helptextAlternativeText",
914
+ "path": "scopedImports/@salesforce-label-LightningInput.helptextAlternativeText.js"
915
+ },
916
+ {
917
+ "name": "@salesforce/label/LightningRating.readOnlyAssistiveText",
918
+ "path": "scopedImports/@salesforce-label-LightningRating.readOnlyAssistiveText.js"
919
+ },
920
+ {
921
+ "name": "@salesforce/label/LightningRating.selectRating",
922
+ "path": "scopedImports/@salesforce-label-LightningRating.selectRating.js"
923
+ },
924
+ {
925
+ "name": "@salesforce/label/LightningRating.rating",
926
+ "path": "scopedImports/@salesforce-label-LightningRating.rating.js"
927
+ },
928
+ {
929
+ "name": "@salesforce/label/LightningRating.oneStar",
930
+ "path": "scopedImports/@salesforce-label-LightningRating.oneStar.js"
931
+ },
932
+ {
933
+ "name": "@salesforce/label/LightningRating.nStars",
934
+ "path": "scopedImports/@salesforce-label-LightningRating.nStars.js"
935
+ },
904
936
  {
905
937
  "name": "@salesforce/i18n/lang",
906
938
  "path": "scopedImports/@salesforce-i18n-lang.js"
@@ -0,0 +1 @@
1
+ export default '{0} Help Info';
@@ -0,0 +1 @@
1
+ export default '{0} Help Info';
@@ -0,0 +1 @@
1
+ export default '{0} Stars';
@@ -0,0 +1 @@
1
+ export default '1 Star';
@@ -0,0 +1 @@
1
+ export default 'Rating';
@@ -0,0 +1 @@
1
+ export default '{0} out of {1}';
@@ -0,0 +1 @@
1
+ export default 'Select a rating';
@@ -0,0 +1 @@
1
+ export default 'Edit: {0}';
@@ -931,6 +931,14 @@ export default class LightningBaseCombobox extends LightningElement {
931
931
  isInputReadOnly() {
932
932
  return that._inputAriaReadOnly;
933
933
  },
934
+ shouldPreventInputDeletion() {
935
+ let isAutocompleteEnabled =
936
+ that.autocomplete && that.autocomplete !== 'off',
937
+ isStandardVariant = that.variant === VARIANT.STANDARD,
938
+ isDefaultReadOnlyTypes =
939
+ isStandardVariant || that.hasInputPill;
940
+ return isAutocompleteEnabled && isDefaultReadOnlyTypes;
941
+ },
934
942
  highlightOptionWithText(currentIndex, text) {
935
943
  // This only supports a flat structure, groups are not supported
936
944
  for (
@@ -102,6 +102,12 @@ function handleEscapeOrTabKey({ event, dropdownInterface }) {
102
102
  }
103
103
  }
104
104
 
105
+ function handleDeletionKeys({ event, dropdownInterface }) {
106
+ if (dropdownInterface.shouldPreventInputDeletion()) {
107
+ event.preventDefault();
108
+ }
109
+ }
110
+
105
111
  function handleTypedCharacters({ event, currentIndex, dropdownInterface }) {
106
112
  if (event.key && event.key.length > 1) {
107
113
  // not a printable character
@@ -146,6 +152,9 @@ const eventKeyToHandlerMap = {
146
152
  Esc: handleEscapeOrTabKey, // IE11/Edge specific
147
153
  Escape: handleEscapeOrTabKey,
148
154
  Tab: handleEscapeOrTabKey,
155
+
156
+ Backspace: handleDeletionKeys,
157
+ Delete: handleDeletionKeys,
149
158
  };
150
159
 
151
160
  export function handleKeyDownOnInput({
@@ -154,7 +163,6 @@ export function handleKeyDownOnInput({
154
163
  dropdownInterface,
155
164
  }) {
156
165
  const parameters = { event, currentIndex, dropdownInterface };
157
-
158
166
  if (eventKeyToHandlerMap[event.key]) {
159
167
  eventKeyToHandlerMap[event.key](parameters);
160
168
  } else {
@@ -14,6 +14,7 @@
14
14
  column-def={state.inlineEdit.columnDef}
15
15
  is-mass-edit-enabled={state.inlineEdit.massEditEnabled}
16
16
  number-of-selected-rows={state.inlineEdit.massEditSelectedRows}
17
+ resolved-type-attributes={state.inlineEdit.resolvedTypeAttributes}
17
18
  onieditfinished={handleInlineEditFinish}
18
19
  onmasscheckboxchange={handleMassCheckboxChange}
19
20
  ></lightning-primitive-datatable-iedit-panel>
@@ -965,14 +965,17 @@ export default class LightningDatatable extends LightningElement {
965
965
  }
966
966
 
967
967
  get computedTableContainerClass() {
968
- return classSet('slds-table_header-fixed_container')
968
+ return classSet({
969
+ 'slds-table_header-fixed_container': !this.hideTableHeader,
970
+ })
969
971
  .add({ 'slds-scrollable_x': !this._isResizing })
970
972
  .toString();
971
973
  }
972
974
 
973
975
  get computedTableClass() {
976
+ const headerType = this.hideTableHeader ? 'hidden' : 'fixed';
974
977
  return classSet(
975
- 'slds-table slds-table_header-fixed slds-table_bordered slds-table_edit'
978
+ `slds-table slds-table_header-${headerType} slds-table_bordered slds-table_edit`
976
979
  )
977
980
  .add({ 'slds-table_resizable-cols': this.hasResizebleColumns })
978
981
  .add({ 'slds-tree slds-table_tree': hasTreeDataType(this.state) })
@@ -82,7 +82,10 @@ export function handlePrefetch(root, state) {
82
82
  if (
83
83
  !isInfiniteLoadingEnabled(state) ||
84
84
  isLoading(state) ||
85
- !hasData(root)
85
+ !hasData(root) ||
86
+ (this.viewportRendering &&
87
+ this._renderManager &&
88
+ !this._renderManager.hasWrapperHeight())
86
89
  ) {
87
90
  // dont prefetch if already loading or data is not set yet
88
91
  return;
@@ -11,7 +11,12 @@ import {
11
11
  getCellElementByIndexes,
12
12
  updateActiveCell,
13
13
  } from './keyboard';
14
- import { updateRowsAndCellIndexes, getRowByKey, getKeyField } from './rows';
14
+ import {
15
+ updateRowsAndCellIndexes,
16
+ getRowByKey,
17
+ getKeyField,
18
+ getUserRowByCellKeys,
19
+ } from './rows';
15
20
  import {
16
21
  getColumnIndexByColumnKey,
17
22
  getColumns,
@@ -26,6 +31,7 @@ import {
26
31
  getCurrentSelectionLength,
27
32
  getSelectedRowsKeys,
28
33
  } from './selector';
34
+ import { isObjectLike } from './utils';
29
35
 
30
36
  export { getDirtyValue } from './inlineEdit-shared';
31
37
 
@@ -179,7 +185,7 @@ function getFirstEditableCell(dt) {
179
185
  function openInlineEdit(dt, target) {
180
186
  startPanelPositioning(dt, target.parentElement);
181
187
 
182
- const { state, template } = dt;
188
+ const { state, template, privateTypes: types } = dt;
183
189
  const inlineEdit = state.inlineEdit;
184
190
 
185
191
  if (inlineEdit.isPanelVisible) {
@@ -198,6 +204,7 @@ function openInlineEdit(dt, target) {
198
204
  inlineEdit.isPanelVisible = true;
199
205
  inlineEdit.rowKeyValue = rowKeyValue;
200
206
  inlineEdit.colKeyValue = colKeyValue;
207
+
201
208
  inlineEdit.editedValue = getCellValue(state, rowKeyValue, colKeyValue);
202
209
  inlineEdit.massEditSelectedRows = getCurrentSelectionLength(state);
203
210
  inlineEdit.massEditEnabled =
@@ -207,6 +214,20 @@ function openInlineEdit(dt, target) {
207
214
  // pass the column definition
208
215
  const colIndex = getStateColumnIndex(state, colKeyValue);
209
216
  inlineEdit.columnDef = getColumns(state)[colIndex];
217
+ const typeAttributesFromColumnDef =
218
+ inlineEdit.columnDef && inlineEdit.columnDef.typeAttributes;
219
+ if (typeAttributesFromColumnDef) {
220
+ // when open the inline edit panel resolve the typeAttributes if it's available
221
+ // then assign the resolved values to inlineEdit.resolvedTypeAttributes
222
+ inlineEdit.resolvedTypeAttributes = resolveNestedTypeAttributes(
223
+ state,
224
+ rowKeyValue,
225
+ colKeyValue,
226
+ types,
227
+ typeAttributesFromColumnDef,
228
+ colIndex
229
+ );
230
+ }
210
231
 
211
232
  markSelectedCell(state, rowKeyValue, colKeyValue);
212
233
 
@@ -218,6 +239,116 @@ function openInlineEdit(dt, target) {
218
239
  }, 0);
219
240
  }
220
241
 
242
+ /**
243
+ * Returns the resolved typeAttributes
244
+ *
245
+ * @param {Object} state - state of the datatable
246
+ * @param {String} rowKeyValue - row key
247
+ * @param {String} colKeyValue - column key
248
+ * @param {object} types - types
249
+ * @param {object} typeAttributesFromColumnDef - values of typeAttributes from column definition
250
+ * @param {number} stateColIndex - state column index
251
+ *
252
+ * @return {Object} the resolved typeAttributes.
253
+ */
254
+ export function resolveNestedTypeAttributes(
255
+ state,
256
+ rowKeyValue,
257
+ colKeyValue,
258
+ types,
259
+ typeAttributesFromColumnDef,
260
+ stateColIndex
261
+ ) {
262
+ const rowData = getUserRowByCellKeys(state, rowKeyValue, colKeyValue);
263
+ const column = state.columns[stateColIndex];
264
+ const validTypeAttributes = types.getType(column.type).typeAttributes;
265
+ const resolvedTypeAttributes = {};
266
+
267
+ // Check if typeAttributesValues and typeAttributes are available
268
+ if (isObjectLike(typeAttributesFromColumnDef) && validTypeAttributes) {
269
+ // We only want to resolve typeAttributes based on the custom types configuration
270
+ // If the attribute is not in that configuration, the value of typeAttributesValues
271
+ // for that will be undefined. This behavior is consistent with view cell.
272
+
273
+ Object.keys(validTypeAttributes).forEach((key) => {
274
+ const typeAttributeName = validTypeAttributes[key];
275
+ const typeAttributesValue =
276
+ typeAttributesFromColumnDef[typeAttributeName];
277
+ if (typeAttributesValue) {
278
+ resolvedTypeAttributes[typeAttributeName] =
279
+ resolveNestedTypeAttributesHelper(
280
+ rowData,
281
+ typeAttributesValue
282
+ );
283
+ }
284
+ });
285
+ return resolvedTypeAttributes;
286
+ }
287
+ return typeAttributesFromColumnDef;
288
+ }
289
+
290
+ /**
291
+ * Helper function to recursively traverse and resolve the nested typeAttributesValues object.
292
+ * For example, resolve {
293
+ * editTypeAttributes: {
294
+ * value: {
295
+ * fieldName: 'name'
296
+ * }
297
+ * }
298
+ * } to be {
299
+ * editTypeAttributes: {
300
+ * value: 'resolvedValue'
301
+ * }
302
+ * }
303
+ */
304
+ function resolveNestedTypeAttributesHelper(rowData, typeAttributesValue) {
305
+ let resolvedTypeAttributes = {};
306
+ if (typeAttributesValue !== undefined) {
307
+ if (isObjectLike(typeAttributesValue)) {
308
+ Object.keys(typeAttributesValue).forEach((key) => {
309
+ const value = typeAttributesValue[key];
310
+ if (value !== undefined) {
311
+ // since resolveNestedTypeAttributes will be creating the top level attribute
312
+ // and we resolve values while creating the new object, the typeAttributesValue passed in
313
+ // could be something like {fieldName: 'someField'}.
314
+ // For example, if the typeAttributes is { targetName: {fieldName: 'name'}},
315
+ // {fieldName: 'name'} will be the typeAttributesValue passed in to the function,
316
+ // so we need to check if key is 'fieldName' or not and resolve it immediately.
317
+ if (key === 'fieldName') {
318
+ resolvedTypeAttributes = rowData[value];
319
+ } else if (isObjectLike(value)) {
320
+ // This is the case when typeAttributesValue is something like {label: {fieldName: 'name'}}.
321
+ // It's an object but the value maps a field name
322
+ if (value.fieldName) {
323
+ resolvedTypeAttributes[key] =
324
+ rowData[value.fieldName];
325
+ } else {
326
+ // Nested object case, need to recursively resolve it.
327
+ // For example, { targetName: {value: {fieldName: 'name'}}}}.
328
+ resolvedTypeAttributes[key] =
329
+ resolveNestedTypeAttributesHelper(
330
+ rowData,
331
+ value
332
+ );
333
+ }
334
+ } else {
335
+ // Primitive value
336
+ resolvedTypeAttributes[key] = value;
337
+ }
338
+ }
339
+ });
340
+ } else {
341
+ // Primitive value.
342
+ // For example, if the typeAttributes is { count: 5},
343
+ // 5 will be the typeAttributesValue passed in to the function.
344
+ // nothing needs to be resolved, just return it.
345
+ return typeAttributesValue;
346
+ }
347
+ }
348
+
349
+ return resolvedTypeAttributes;
350
+ }
351
+
221
352
  export function handleInlineEditFinish(event) {
222
353
  stopPanelPositioning(this);
223
354
 
@@ -353,10 +353,8 @@ export const setFocusActiveCell = function (element, state, direction, info) {
353
353
  cellElement.parentElement.focus();
354
354
  cellElement.setMode(keyboardMode, info);
355
355
 
356
- const scrollingParent = element.querySelector(
357
- '.slds-table_header-fixed_container'
358
- );
359
356
  const scrollableY = element.querySelector('.slds-scrollable_y');
357
+ const scrollingParent = scrollableY.parentElement;
360
358
  const parentRect = scrollingParent.getBoundingClientRect();
361
359
  const findMeRect = cellElement.getBoundingClientRect();
362
360
  if (findMeRect.top < parentRect.top + TOP_MARGIN) {
@@ -436,10 +434,8 @@ export const setFocusActiveRow = function (element, state) {
436
434
  const row = getRowElementByIndexes(element, rowIndex);
437
435
  row.focus();
438
436
 
439
- const scrollingParent = element.querySelector(
440
- '.slds-table_header-fixed_container'
441
- );
442
437
  const scrollableY = element.querySelector('.slds-scrollable_y');
438
+ const scrollingParent = scrollableY.parentElement;
443
439
  const parentRect = scrollingParent.getBoundingClientRect();
444
440
  const findMeRect = row.getBoundingClientRect();
445
441
  if (findMeRect.top < parentRect.top + TOP_MARGIN) {
@@ -259,11 +259,30 @@ export function getHideSelectAllCheckbox(state) {
259
259
  return getMaxRowSelection(state) === 1;
260
260
  }
261
261
 
262
+ /**
263
+ * sets maxRowSelection to provided value,
264
+ * only keeping up to maxRowSelection values selected
265
+ * Use input type checkbox if maxRowSelection > 1
266
+ * and input type is radio if maxRowSelection = 1.
267
+ * Invalid values are set to default and log an error
268
+ * @param {Object} state - the datatable state.
269
+ * @param {Number | String} - value to set for maxRowSelection
270
+ */
262
271
  export function setMaxRowSelection(state, value) {
272
+ const previousSelectedRowsKeys = getSelectedRowsKeys(state);
263
273
  markAllRowsDeselected(state);
264
274
  if (isNonNegativeInteger(value)) {
265
275
  const previousMaxRowSelection = getMaxRowSelection(state);
266
276
  state.maxRowSelection = Number(value);
277
+ const newMaxRowSelection = getMaxRowSelection(state);
278
+ // reselect up to maxRowSelection rows
279
+ const numberOfRows = Math.min(
280
+ previousSelectedRowsKeys.length,
281
+ newMaxRowSelection
282
+ );
283
+ for (let i = 0; i < numberOfRows; i++) {
284
+ markRowSelected(state, previousSelectedRowsKeys[i]);
285
+ }
267
286
  if (
268
287
  inputTypeNeedsToChange(
269
288
  previousMaxRowSelection,
@@ -305,11 +324,8 @@ export function updateRowSelectionInputType(state) {
305
324
  const type = getRowSelectionInputType(state);
306
325
  const rows = getRows(state);
307
326
 
308
- resetSelectedRowsKeys(state);
309
327
  rows.forEach((row) => {
310
328
  row.inputType = type;
311
- row.isSelected = false;
312
- row.ariaSelected = false;
313
329
  row.isDisabled = isDisabledRow(state, row.key);
314
330
  });
315
331
  }
@@ -2,8 +2,6 @@ import { api, LightningElement } from 'lwc';
2
2
  import { findAllTabbableElements } from 'lightning/focusUtils';
3
3
 
4
4
  export default class FocusTrap extends LightningElement {
5
- static delegatesFocus = true;
6
-
7
5
  _startNode;
8
6
  _endNode;
9
7
 
@@ -1,3 +1,6 @@
1
+ import { BUBBLE_PREFIX } from 'lightning/tooltipLibrary';
2
+
3
+ const IGNORE_AUTOFOCUS = 'ignore-autofocus';
1
4
  /**
2
5
  *
3
6
  * Returns all tabbable elements within a containing element. Tabbable elements are:
@@ -196,23 +199,71 @@ function isTabbable({ element, rootContainer }) {
196
199
  );
197
200
  }
198
201
 
202
+ /**
203
+ * Test if element has role='tooltip'
204
+ * @param {Element} Element that has focus.
205
+ * @returns {boolean} element has role='tooltip'
206
+ */
207
+ const elemHasRoleTooltip = (elem) => {
208
+ return elem.getAttribute('role') === 'tooltip';
209
+ };
210
+
211
+ /**
212
+ * Test if the element has class='ignore-autofocus'
213
+ * @param {Element} Element that has focus.
214
+ * @returns {boolean} element has class='ignore-autofocus'
215
+ */
216
+ const elemHasIgnoreAutofocus = (elem) => {
217
+ return elem.classList.contains(IGNORE_AUTOFOCUS);
218
+ };
219
+
220
+ /**
221
+ * Test if element has unique properties of <lightning-helptext>
222
+ * @param {Element} Element that needs to be tested
223
+ * @returns {boolean} element matches criteria of <lightning-helptext>
224
+ */
225
+ const elemIsHelpTextComponent = (elem) => {
226
+ // properties of <lightning-helptext>
227
+ const tagNameIsButton = elem.tagName.toLowerCase() === 'button';
228
+ const ariaDescValue = elem.getAttribute('aria-describedby');
229
+ // ie11 doesn't support .startsWith()
230
+ const ariaValueMatchesPrefix = ariaDescValue
231
+ ? String(ariaDescValue).indexOf(BUBBLE_PREFIX) === 0
232
+ : false;
233
+ return tagNameIsButton && ariaValueMatchesPrefix;
234
+ };
235
+
236
+ /**
237
+ * Verify element doesn't have tooltip properties by running tooltip tests
238
+ * Primary use in autofocus feature of LighningModal
239
+ * @param {Element} Element to verify is not a tooltip
240
+ * @returns {boolean} element is not a tooltip
241
+ */
242
+ const elemIsNotTooltip = (elem) => {
243
+ if (!elem) {
244
+ return false;
245
+ }
246
+ // evaluate whether element has properties of a tooltip
247
+ // if any tooltip test is true, the element is a tooltip
248
+ const elemIsTooltip = [
249
+ // array of tooltip tests
250
+ elemHasRoleTooltip(elem),
251
+ elemIsHelpTextComponent(elem),
252
+ elemHasIgnoreAutofocus(elem),
253
+ ].some((val) => val === true);
254
+ return !elemIsTooltip;
255
+ };
256
+
199
257
  /**
200
258
  *
201
- * Returns tabbable elements filtered to remove any tooltips
202
- * @param {Array} elemsArray The element references array to filter of tooltip elements.
203
- * @returns {Array} Tabbable elements.
259
+ * Returns tabbable elements, filtered to remove any tooltips
260
+ * @param {Array} elemsArray Array of elements to filter tooltips from
261
+ * @returns {Array} Filtered tabbable elements with no tooltips
204
262
  */
205
263
  export function filterTooltips(elemsArray) {
206
- // reference SLDS tooltip patterns && global focus in focusFirstElement
207
- // TODO discovery if there are common CSS classes for tooltips as Salesforce
264
+ // reference SLDS tooltip patterns && global focus in
265
+ // modalBase focusFirstElement() -> used to autofocus first element
208
266
  // https://www.lightningdesignsystem.com/accessibility/patterns/tooltip/
209
- const elemIsNotTooltip = (elem) => {
210
- if (!elem) {
211
- return false;
212
- }
213
- const elemRole = elem.getAttribute('role');
214
- return elemRole !== 'tooltip';
215
- };
216
267
  return elemsArray && Array.isArray(elemsArray) && elemsArray.length > 0
217
268
  ? elemsArray.filter(elemIsNotTooltip)
218
269
  : [];
@@ -158,6 +158,7 @@ const uriAllowList = Object.freeze([
158
158
  'cid',
159
159
  'xmpp',
160
160
  'ciscotel',
161
+ 'navision',
161
162
  ]);
162
163
 
163
164
  const uriAllowListString = uriAllowList.join('|');
@@ -8,7 +8,7 @@
8
8
  </template>
9
9
  {label}
10
10
  </label>
11
- <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp}></lightning-helptext>
11
+ <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp} alternative-text={helptextAlternativeText}></lightning-helptext>
12
12
  </template>
13
13
  <div class={computedFormElementClass}>
14
14
  <input type={_internalType}
@@ -91,7 +91,7 @@
91
91
  </template>
92
92
  <span class={computedLabelClass}>{label}</span>
93
93
  </label>
94
- <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp}></lightning-helptext>
94
+ <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp} alternative-text={helptextAlternativeText}></lightning-helptext>
95
95
  </template>
96
96
  <div class={computedFormElementClass}>
97
97
  <span class={computedCheckboxClass}>
@@ -118,7 +118,7 @@
118
118
  <span class="slds-checkbox_faux"></span>
119
119
  <span class={computedLabelClass}>{label}</span>
120
120
  </label>
121
- <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp}></lightning-helptext>
121
+ <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp} alternative-text={helptextAlternativeText}></lightning-helptext>
122
122
  </template>
123
123
  </span>
124
124
  </div>
@@ -241,7 +241,7 @@
241
241
  </div>
242
242
  </div>
243
243
  <template if:false={hasExternalLabel}>
244
- <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp}></lightning-helptext>
244
+ <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp} alternative-text={helptextAlternativeText}></lightning-helptext>
245
245
  </template>
246
246
  </div>
247
247
  </div>
@@ -8,11 +8,13 @@ import labelClearInput from '@salesforce/label/LightningControl.clear';
8
8
  import labelLoadingIndicator from '@salesforce/label/LightningControl.loading';
9
9
  import labelNumberIncrementCounter from '@salesforce/label/LightningInputNumber.incrementCounter';
10
10
  import labelNumberDecrementCounter from '@salesforce/label/LightningInputNumber.decrementCounter';
11
+ import labelHelpTextAlternativeText from '@salesforce/label/LightningInput.helptextAlternativeText';
12
+
11
13
  import userTimeZone from '@salesforce/i18n/timeZone';
12
14
  import formFactor from '@salesforce/client/formFactor';
13
15
 
14
16
  import { api, LightningElement, track } from 'lwc';
15
- import { classSet } from 'lightning/utils';
17
+ import { classSet, formatLabel } from 'lightning/utils';
16
18
  import {
17
19
  assert,
18
20
  classListMutation,
@@ -69,6 +71,7 @@ const i18n = {
69
71
  required: labelRequired,
70
72
  clear: labelClearInput,
71
73
  loading: labelLoadingIndicator,
74
+ helpTextAlternativeText: labelHelpTextAlternativeText,
72
75
  };
73
76
 
74
77
  const ARIA_CONTROLS = 'aria-controls';
@@ -1664,6 +1667,10 @@ export default class LightningInput extends LightningElement {
1664
1667
  );
1665
1668
  }
1666
1669
 
1670
+ get helptextAlternativeText() {
1671
+ return formatLabel(i18n.helpTextAlternativeText, this.label);
1672
+ }
1673
+
1667
1674
  handleFileClick() {
1668
1675
  this._setInputValue(null);
1669
1676
  this._updateValueAndValidityAttribute(null);
@@ -0,0 +1,3 @@
1
+ Position Library playground can be used to test positon library for `helptext`, `button-menu`, `combobox` and `datepicker`.
2
+
3
+ To use the playground, go to `ui-lightning-stubs/src/main/modules/demo/app/app.html` and add the tag `<positionLibrary-playground></positionLibrary-playground>` in the template.
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <template if:true={isHelpText}>
3
+ <lightning-helptext
4
+ content="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vel orci porta non pulvinar neque."
5
+ ></lightning-helptext>
6
+ </template>
7
+
8
+ <template if:true={isButtonMenu}>
9
+ <lightning-button-menu alternative-text="Show menu">
10
+ <lightning-menu-item
11
+ value="MenuItemOne"
12
+ label="Menu Item One"
13
+ ></lightning-menu-item>
14
+ <lightning-menu-item
15
+ value="MenuItemTwo"
16
+ label="Menu Item Two"
17
+ ></lightning-menu-item>
18
+ <lightning-menu-item
19
+ value="MenuItemThree"
20
+ label="Menu Item Three"
21
+ ></lightning-menu-item>
22
+ <lightning-menu-item
23
+ value="MenuItemFour"
24
+ label="Menu Item Four"
25
+ ></lightning-menu-item>
26
+ </lightning-button-menu>
27
+ </template>
28
+
29
+ <template if:true={isComboBox}>
30
+ <lightning-combobox
31
+ name="progress"
32
+ label="Status"
33
+ placeholder="Select Progress"
34
+ options={comboBoxOptions}
35
+ ></lightning-combobox>
36
+ </template>
37
+
38
+ <template if:true={isDatePicker}>
39
+ <lightning-datepicker label="Select a date"></lightning-datepicker>
40
+ </template>
41
+ </template>