lightning-base-components 1.19.2-alpha → 1.19.4-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,3 +1,271 @@
1
+ import groupingSeparator from '@salesforce/i18n/number.groupingSeparator';
2
+ import decimalSeparator from '@salesforce/i18n/number.decimalSeparator';
3
+ import {
4
+ fromLocalizedDigits,
5
+ toLocalizedDigits,
6
+ numberFormat,
7
+ } from 'lightning/internationalizationLibrary';
8
+ import { isEmptyString } from 'lightning/inputUtils';
9
+ import { normalizeNumber } from 'lightning/utilsPrivate';
10
+
11
+ const VALID_NUMBER_CHARACTERS_EXPRESSION = new RegExp(
12
+ // eslint-disable-next-line no-useless-escape
13
+ '^[-+0-9kKmMbBtTeE.,\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9' +
14
+ '\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF' +
15
+ '\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF' +
16
+ '\u0D66-\u0D6F\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9' +
17
+ '\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9' +
18
+ '\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89' +
19
+ '\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49' +
20
+ '\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909' +
21
+ '\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9' +
22
+ ']$'
23
+ );
24
+
25
+ const SHORTCUT_FACTORS = {
26
+ k: 3,
27
+ m: 6,
28
+ b: 9,
29
+ t: 12,
30
+ };
31
+ const SHORTCUTS = ['k', 'm', 'b', 't'];
32
+
33
+ const NUMBER_SYMBOLS = ['+', '-'];
34
+
35
+ export function toIsoDecimal(numberAsString) {
36
+ const result = transformLocalizedNumberToIsoDecimal(numberAsString);
37
+ if (isNaN(result)) {
38
+ return '';
39
+ }
40
+ return result;
41
+ }
42
+
43
+ export function isValidNumber(numberAsString) {
44
+ return !isNaN(transformLocalizedNumberToIsoDecimal(numberAsString));
45
+ }
46
+
47
+ export function fromIsoDecimal(numberAsString) {
48
+ return toLocalizedDigits(numberAsString.replace('.', decimalSeparator));
49
+ }
50
+
51
+ // TODO: Too many options, simplify
52
+ export function increaseNumberByStep({
53
+ value,
54
+ increment,
55
+ step,
56
+ fractionDigits,
57
+ }) {
58
+ const startingValue = value === '' || value == null ? '0' : value;
59
+
60
+ const stepAsFloat = parseFloat(step);
61
+
62
+ let result;
63
+ if (isNaN(stepAsFloat)) {
64
+ result = parseFloat(startingValue) + increment;
65
+ } else {
66
+ // ideally we'd round the value to the closest correct step, so that if say the step is '2', and the
67
+ // current value is '1' it would increment to '2' instead of '3', since the former would be the valid
68
+ // number given the step constraint, however this would significantly complicate the code, keeping
69
+ // it simple for now.
70
+ const increaseBy = increment * stepAsFloat;
71
+ result = parseFloat(startingValue) + increaseBy;
72
+ }
73
+ return result.toFixed(fractionDigits);
74
+ }
75
+
76
+ export function calculateFractionDigitsFromStep(step) {
77
+ let calculatedFractionDigits;
78
+
79
+ if (step) {
80
+ const stepAsString = String(step).toLowerCase();
81
+ if (stepAsString !== 'any') {
82
+ // lowering the case because we're checking for exponent format as well
83
+ let fractionDigits = 0;
84
+ if (
85
+ stepAsString.indexOf('.') >= 0 &&
86
+ stepAsString.indexOf('e') < 0
87
+ ) {
88
+ const fractionalPart = stepAsString.split('.')[1];
89
+ // we're parsing to account for cases where the step is
90
+ // '1.0', or '1.000', etc.
91
+ if (parseInt(fractionalPart, 10) > 0) {
92
+ fractionDigits = fractionalPart.length;
93
+ }
94
+ } else if (stepAsString.indexOf('e-') > 0) {
95
+ // exponent form eg. 1.5e-5
96
+ const splitOnExponent = stepAsString.split('e-');
97
+ const fractionalPart = splitOnExponent[0].split('.')[1];
98
+ const exponentPart = splitOnExponent[1];
99
+ const fractionalPartLength = fractionalPart
100
+ ? fractionalPart.length
101
+ : 0;
102
+ fractionDigits =
103
+ parseInt(exponentPart, 10) + fractionalPartLength;
104
+ }
105
+ calculatedFractionDigits = fractionDigits;
106
+ }
107
+ }
108
+ return calculatedFractionDigits;
109
+ }
110
+
111
+ export function formatNumber(numberAsString, options) {
112
+ if (isEmptyString(numberAsString)) {
113
+ return '';
114
+ }
115
+
116
+ let formattedValue = numberAsString;
117
+ let inputValue = numberAsString;
118
+
119
+ // set formatter style & default options
120
+ const formatStyle = options.style;
121
+ const formatOptions = { style: formatStyle };
122
+
123
+ formatOptions.minimumFractionDigits = options.minimumFractionDigits;
124
+ formatOptions.maximumFractionDigits = options.maximumFractionDigits;
125
+
126
+ if (formatStyle === 'percent-fixed') {
127
+ // percent-fixed just uses percent format and divides the value by 100
128
+ // before passing to the library, this is to deal with the
129
+ // fact that percentages in salesforce are 0-100, not 0-1
130
+ formatOptions.style = 'percent';
131
+ const inputValueAsString = inputValue.toString();
132
+ const normalisedNumberInPercent = parseFloat(inputValue) / 100;
133
+
134
+ // If the number contains fraction digits and is not in an exponent format
135
+ if (
136
+ inputValueAsString.indexOf('.') > 0 &&
137
+ inputValueAsString.indexOf('e') < 0
138
+ ) {
139
+ // Depending on the input number, division by 100 may lead to rounding errors
140
+ // (e.g 0.785 / 100 is 0.007850000000000001), so we need to round back
141
+ // to the correct precision, that is - existing number of fractional digits
142
+ // plus extra 2 for division by 100.
143
+ inputValue = normalisedNumberInPercent.toFixed(
144
+ inputValueAsString.split('.')[1].length + 2
145
+ );
146
+ } else {
147
+ inputValue = normalisedNumberInPercent;
148
+ }
149
+ }
150
+
151
+ try {
152
+ formattedValue = numberFormat(formatOptions).format(inputValue) || '';
153
+ } catch (ignore) {
154
+ // ignore any errors
155
+ }
156
+ return formattedValue;
157
+ }
158
+
159
+ // Exporting only to test, separators are only overridden in the tests
160
+ export function transformLocalizedNumberToIsoDecimal(
161
+ numberAsString,
162
+ separators
163
+ ) {
164
+ if (numberAsString == null || numberAsString.length === 0) {
165
+ return '';
166
+ }
167
+
168
+ const decimalSymbol = separators
169
+ ? separators.decimalSeparator
170
+ : decimalSeparator;
171
+ const groupingSymbol = separators
172
+ ? separators.groupSeparator
173
+ : groupingSeparator;
174
+
175
+ // remove the grouping separator
176
+ let result = numberAsString.split(groupingSymbol).join('');
177
+ if (decimalSymbol !== '.') {
178
+ // replace the local decimal separator with a
179
+ result = result.replace(decimalSymbol, '.');
180
+ }
181
+ return expandShortcuts(addLeadingZeroIfNeeded(fromLocalizedDigits(result)));
182
+ }
183
+
184
+ export function isValidNumberCharacter(character) {
185
+ return VALID_NUMBER_CHARACTERS_EXPRESSION.test(character);
186
+ }
187
+
188
+ /**
189
+ * validate the string-typed number and return the number string
190
+ * @param {String} value, number string to be validated
191
+ * @returns a valid number in string-typed, otherwise, empty string
192
+ */
193
+ export function stringifyNumber(value) {
194
+ const numericValue = typeof value === 'string' ? Number(value) : value;
195
+ const normalizedNumber = normalizeNumber(numericValue);
196
+ return normalizedNumber === undefined ? '' : String(value);
197
+ }
198
+
199
+ export function hasValidNumberSymbol(value) {
200
+ const validSymbols = NUMBER_SYMBOLS.join('');
201
+ const matchSymbols = new RegExp(`[${validSymbols}]`);
202
+ return value.match(matchSymbols) ? true : false;
203
+ }
204
+
205
+ export function hasValidNumberShortcut(value) {
206
+ const result = value.toLowerCase().trim();
207
+ const kmb = SHORTCUTS.join('');
208
+ // Cannot have two shortcuts /([kmb])/g
209
+ const matchShortcuts = new RegExp(`([${kmb}])`, 'g');
210
+ const shortcutMatch = result.match(matchShortcuts);
211
+ if (shortcutMatch && shortcutMatch.length > 1) {
212
+ return false;
213
+ }
214
+ // Must end with 'm', 'k', 'b' and more than just a single letter
215
+ const matchEndsWith = new RegExp(`[${kmb}]$`);
216
+ const endsWithShortcut = result.match(matchEndsWith) !== null;
217
+ // has 'm' / 'k' / 'b' and more than just them (ie. result of 'm' / 'k' / 'b' are not valid.
218
+ return endsWithShortcut && result.length > 1;
219
+ }
220
+
221
+ // Exported for testing only
222
+ export function expandShortcuts(isoValue) {
223
+ if (!hasValidNumberShortcut(isoValue)) {
224
+ return isoValue;
225
+ }
226
+ let result = isoValue.toLowerCase().trim();
227
+ const shortcut = result.charAt(result.length - 1);
228
+ // remove the suffix
229
+ result = result.substring(0, result.length - 1);
230
+ if (isNaN(result)) {
231
+ return isoValue;
232
+ }
233
+ const parts = result.split('.');
234
+ let fractionDigits = 0;
235
+ const hasDecimalPart = parts.length > 1;
236
+ if (hasDecimalPart) {
237
+ fractionDigits = parts[1].length;
238
+ }
239
+ const exponent = SHORTCUT_FACTORS[shortcut];
240
+ // since multiplication may result in loss of precision on javascript's part,
241
+ // we're calculating here the number of fraction digits needed and formatting
242
+ // the number at that
243
+ const newFractionDigits = Math.max(0, fractionDigits - exponent);
244
+ return parseFloat(result * Math.pow(10, exponent)).toFixed(
245
+ newFractionDigits
246
+ );
247
+ }
248
+
249
+ function addLeadingZeroIfNeeded(result) {
250
+ // If the number starts with +. OR -. OR . ; insert a 0 before the decimal separator.
251
+ // eg. -.2 -> -0.2
252
+ const decimalSeparatorLocation = result.indexOf('.');
253
+ if (decimalSeparatorLocation === 0 || decimalSeparatorLocation === 1) {
254
+ const firstCharacter = result.charAt(0);
255
+ if (
256
+ firstCharacter === '+' ||
257
+ firstCharacter === '-' ||
258
+ firstCharacter === '.'
259
+ ) {
260
+ result =
261
+ result.substring(0, decimalSeparatorLocation) +
262
+ '0' +
263
+ result.substring(decimalSeparatorLocation);
264
+ }
265
+ }
266
+ return result;
267
+ }
268
+
1
269
  /*
2
270
  Returns a number of decimal places
3
271
  ex:
@@ -9,7 +277,7 @@
9
277
  decimalPlaces('.5e1') -> 0
10
278
  decimalPlaces('.25e1') -> 1
11
279
  */
12
- function decimalPlaces(num) {
280
+ export function getDecimalPlaces(num) {
13
281
  const match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
14
282
  if (!match) {
15
283
  return 0;
@@ -22,7 +290,3 @@ function decimalPlaces(num) {
22
290
  (match[2] ? +match[2] : 0)
23
291
  );
24
292
  }
25
-
26
- export default {
27
- decimalPlaces,
28
- };
@@ -42,13 +42,13 @@ export default class PrimitiveCustomCell extends LightningElement {
42
42
  const typeAttributes = this.types.getType(
43
43
  this.columnType
44
44
  ).typeAttributes;
45
+ const attrs = {};
45
46
  if (Array.isArray(typeAttributes)) {
46
- return typeAttributes.reduce((seed, attrName, index) => {
47
- seed[attrName] = this[`typeAttribute${index}`];
48
- return seed;
49
- }, {});
47
+ for (let i = 0, { length } = typeAttributes; i < length; i += 1) {
48
+ attrs[typeAttributes[i]] = this[`typeAttribute${i}`];
49
+ }
50
50
  }
51
- return {};
51
+ return attrs;
52
52
  }
53
53
 
54
54
  @api
@@ -2,17 +2,17 @@
2
2
  <div class={computedClass} style={columnStyles}>
3
3
 
4
4
  <!-- Header Content -->
5
- <span class="slds-th__action">
5
+ <span class="slds-th__action" style={thActionStyles}>
6
6
  <template if:true={def.iconName}>
7
7
  <div class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
8
8
  <lightning-icon icon-name={def.iconName} size="x-small" class="slds-icon_container slds-m-right_xx-small" alternative-text={def.label} title={def.label}></lightning-icon>
9
9
  <template if:false={def.hideLabel} class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
10
- <span class="slds-truncate">{def.label}</span>
10
+ <span class={getHeaderLabelStyle}>{def.label}</span>
11
11
  </template>
12
12
  </div>
13
13
  </template>
14
14
  <template if:false={def.iconName}>
15
- <span class="slds-truncate" if:true={def.label} title={def.label}>{def.label}</span>
15
+ <span class={getHeaderLabelStyle} if:true={def.label} title={def.label}>{def.label}</span>
16
16
  <span class="slds-truncate" if:false={def.label} title={def.ariaLabel}></span>
17
17
  </template>
18
18
 
@@ -35,6 +35,7 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
35
35
  _resizable;
36
36
  _sortable = false;
37
37
  _hideHeader = false;
38
+ _wrapTableHeader = false;
38
39
 
39
40
  /************************** PUBLIC ATTRIBUTES ***************************/
40
41
 
@@ -88,6 +89,21 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
88
89
  this.updateElementClasses();
89
90
  }
90
91
 
92
+ /**
93
+ * Defines whether the table header is wrapped
94
+ *
95
+ * @type {boolean}
96
+ */
97
+ @api
98
+ get wrapTableHeader() {
99
+ return this._wrapTableHeader;
100
+ }
101
+
102
+ set wrapTableHeader(value) {
103
+ this._wrapTableHeader = value;
104
+ this.updateElementClasses();
105
+ }
106
+
91
107
  /**
92
108
  * Defines whether the column is resizable
93
109
  *
@@ -150,11 +166,25 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
150
166
  const widthStyle = this.columnWidth
151
167
  ? `width: ${this.columnWidth}px;`
152
168
  : '';
169
+ const heightStyle = this._wrapTableHeader ? 'min-height: 3rem' : '';
153
170
 
154
171
  return `
155
172
  ${widthStyle}
156
173
  ${outlineStyle}
157
174
  ${offsetStyle}
175
+ ${heightStyle}
176
+ `;
177
+ }
178
+
179
+ /**
180
+ * Get th Action styles
181
+ *
182
+ * @return {string} The computed classes
183
+ */
184
+ get thActionStyles() {
185
+ const heightStyle = this._wrapTableHeader ? 'min-height: 3rem' : '';
186
+ return `
187
+ ${heightStyle}
158
188
  `;
159
189
  }
160
190
 
@@ -182,6 +212,15 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
182
212
  .toString();
183
213
  }
184
214
 
215
+ /**
216
+ * Computes styling for header label
217
+ */
218
+ get getHeaderLabelStyle() {
219
+ return this._wrapTableHeader
220
+ ? 'slds-line-clamp_small '
221
+ : 'slds-truncate';
222
+ }
223
+
185
224
  /**
186
225
  * Computes an option name
187
226
  *
@@ -18,7 +18,7 @@
18
18
  <div class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
19
19
  <lightning-icon icon-name={def.iconName} size="x-small" class="slds-icon_container slds-m-right_xx-small" alternative-text={def.label} title={def.label}></lightning-icon>
20
20
  <template if:false={def.hideLabel} class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
21
- <span class="slds-truncate">{def.label}</span>
21
+ <span class={getHeaderLabelStyle}>{def.label}</span>
22
22
  </template>
23
23
 
24
24
  <!-- Arrow Icon - Rotates based on sorting direction -->
@@ -31,7 +31,7 @@
31
31
  </div>
32
32
  </template>
33
33
  <template if:false={def.iconName}>
34
- <span class="slds-truncate" title={def.label}>{def.label}</span>
34
+ <span class={getHeaderLabelStyle} title={def.label}>{def.label}</span>
35
35
  <!-- Arrow Icon - Rotates based on sorting direction -->
36
36
  <lightning-primitive-icon
37
37
  class="slds-icon_container"
@@ -15,6 +15,7 @@
15
15
  class="slds-file-selector__input slds-assistive-text"
16
16
  onblur={handleBlur}
17
17
  onfocus={handleFocus}
18
+ onclick={handleFileClick}
18
19
  onchange={handleChange}
19
20
  accept={accept}
20
21
  multiple={multiple}
@@ -89,6 +89,10 @@ export default class LightningPrimitiveInputFile extends LightningElement {
89
89
  this.dispatchEvent(new CustomEvent('focus'));
90
90
  }
91
91
 
92
+ handleFileClick() {
93
+ this.inputElement.value = null;
94
+ }
95
+
92
96
  handleChange() {
93
97
  this._files = this.inputElement.files;
94
98
  this.dispatchEvent(new CustomEvent('change'));
@@ -19,7 +19,7 @@ import {
19
19
  isValidNumberCharacter,
20
20
  stringifyNumber,
21
21
  toIsoDecimal,
22
- } from 'lightning/inputUtils';
22
+ } from 'lightning/numberUtils';
23
23
 
24
24
  import {
25
25
  reflectAttribute,
@@ -50,6 +50,8 @@ const VALID_NUMBER_FORMATTERS = [
50
50
  const DEFAULT_FORMATTER = VALID_NUMBER_FORMATTERS[0];
51
51
 
52
52
  export default class LightningPrimitiveInputSimple extends LightningElement {
53
+ _type;
54
+
53
55
  @api hasExternalLabel;
54
56
  @api computedLabelClass;
55
57
  @api required;
@@ -172,26 +174,40 @@ export default class LightningPrimitiveInputSimple extends LightningElement {
172
174
 
173
175
  set value(value) {
174
176
  const previousValue = this._value;
175
-
176
177
  this._value = normalizeInput(value);
177
178
 
178
- if (this._rendered && this.isTypeNumber) {
179
- this._value = stringifyNumber(value);
180
- // the extra check for whether the value has changed is done for cases
181
- // when the same value is set back in a change handler, this is to avoid
182
- // the raw number from changing formatting under the user
183
- // (eg. if the user typed 1,000 we want to preserve that formatting as the user
184
- // types the value)
185
- if (this.validity.badInput || this._value !== previousValue) {
186
- this.updateNumberValue(value);
179
+ if (this._rendered) {
180
+ const badInput = this.validity.badInput;
181
+
182
+ if (this.isTypeNumber) {
183
+ this._value = stringifyNumber(value);
184
+ // the extra check for whether the value has changed is done for cases
185
+ // when the same value is set back in a change handler, this is to avoid
186
+ // the raw number from changing formatting under the user
187
+ // (eg. if the user typed 1,000 we want to preserve that formatting as the user
188
+ // types the value)
189
+ if (this._value !== previousValue) {
190
+ this.updateNumberValue(value);
191
+ }
192
+
193
+ // If updated value is invalid or not null, it should be updated
194
+ // Invalid numeric values should stay as-is to avoid programatically wiping a user-provided invalid
195
+ // value, such as '2e' from the input element. See @W-14121203
196
+ if (!badInput || !!value) {
197
+ this.setInputValueIfNeeded();
198
+ }
199
+ } else {
200
+ this.setInputValueIfNeeded();
187
201
  }
188
202
  }
203
+ }
189
204
 
205
+ setInputValueIfNeeded() {
190
206
  // Again, due to the interop layer we need to check whether the value being set
191
207
  // is different, otherwise we're duplicating the sets on the input, which result
192
208
  // in different bugs like Japanese IME duplication of characters in Safari (likely a browser bug) or
193
209
  // character position re-set in IE11.
194
- if (this._rendered && this.inputElement.value !== this.displayedValue) {
210
+ if (this.inputElement.value !== this.displayedValue) {
195
211
  this.setInputValue(this.getDisplayedValue());
196
212
  }
197
213
  }
@@ -247,6 +263,11 @@ export default class LightningPrimitiveInputSimple extends LightningElement {
247
263
  return this._value;
248
264
  }
249
265
 
266
+ @api
267
+ getNumberRawValue() {
268
+ return this._numberRawValue;
269
+ }
270
+
250
271
  /********* PRIVATE VARIABLES *********/
251
272
  _formatter = DEFAULT_FORMATTER;
252
273
  _showRawNumber = false;
@@ -1,5 +1,6 @@
1
1
  import labelCurrentStage from '@salesforce/label/LightningProgressIndicator.currentStage';
2
2
  import labelStageComplete from '@salesforce/label/LightningProgressIndicator.stageComplete';
3
+ import labelNotStartedStage from '@salesforce/label/LightningProgressIndicator.stageNotStarted';
3
4
  import { LightningElement, api, track } from 'lwc';
4
5
  import { classSet } from 'lightning/utils';
5
6
  import { classListMutation } from 'lightning/utilsPrivate';
@@ -13,6 +14,7 @@ import base from './base.html';
13
14
  const i18n = {
14
15
  currentStage: labelCurrentStage,
15
16
  stageComplete: labelStageComplete,
17
+ notStartedStage: labelNotStartedStage,
16
18
  };
17
19
 
18
20
  // Maps the status of the base progress-step to the icon it should render
@@ -35,6 +37,13 @@ export default class LightningProgressStep extends LightningElement {
35
37
 
36
38
  @track state = {};
37
39
 
40
+ /**
41
+ * getter for the i18 constant containing the localized strings
42
+ */
43
+ get i18n() {
44
+ return i18n;
45
+ }
46
+
38
47
  updateInternal(newStatus, newType, newIndex, newActive, shouldFocus) {
39
48
  classListMutation(
40
49
  this.classList,
@@ -148,9 +157,11 @@ export default class LightningProgressStep extends LightningElement {
148
157
 
149
158
  get assistiveText() {
150
159
  if (this.state.status === 'completed') {
151
- return `${this.label} - ${i18n.stageComplete}`;
160
+ return `${this.label} - ${this.i18n.stageComplete}`;
152
161
  } else if (this.state.status === 'current') {
153
- return `${this.label} - ${i18n.currentStage}`;
162
+ return `${this.label} - ${this.i18n.currentStage}`;
163
+ } else if (this.state.status === 'incomplete') {
164
+ return `${this.label} - ${this.i18n.notStartedStage}`;
154
165
  }
155
166
  return this.state.type === 'path' ? '' : this.label;
156
167
  }
@@ -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={handlePromptModal}
6
6
  >Open the Prompt Modal</button>
7
7
  </div>
@@ -1,29 +1,24 @@
1
- import { timeout, animationFrame } from 'lightning/utilsPrivate';
1
+ const DELAY_TIMEOUT = 16;
2
2
 
3
- const DELAY_TIMEOUT = 200;
4
3
  export class LightningResizeObserver {
5
4
  constructor(resizeCallback) {
6
5
  this._resizeObserverAvailable = typeof ResizeObserver === 'function';
7
-
8
- const delayedCallback = (callback) => {
6
+ this._delayedResizeCallback = () => {
9
7
  if (this._running) {
10
8
  return;
11
9
  }
12
10
  this._running = true;
13
-
14
- timeout(DELAY_TIMEOUT)
15
- // requestAnimationFrame is used to guard against the callback directly reading layout dimensions
16
- // which may be mutating at the same time leading to layout thrashing
17
- .then(() => animationFrame())
18
- .then(() => {
19
- callback();
11
+ // requestAnimationFrame is used to guard against the callback directly reading layout dimensions
12
+ // which may be mutating at the same time leading to layout thrashing
13
+ // eslint-disable-next-line @lwc/lwc/no-async-operation
14
+ setTimeout(() => {
15
+ // eslint-disable-next-line @lwc/lwc/no-async-operation
16
+ requestAnimationFrame(() => {
17
+ resizeCallback();
20
18
  this._running = false;
21
19
  });
20
+ }, DELAY_TIMEOUT);
22
21
  };
23
- this._delayedResizeCallback = delayedCallback.bind(
24
- this,
25
- resizeCallback
26
- );
27
22
  if (this._resizeObserverAvailable) {
28
23
  this._resizeObserver = new ResizeObserver(
29
24
  this._delayedResizeCallback
@@ -5,7 +5,7 @@ import {
5
5
  normalizeBoolean,
6
6
  normalizeString as normalize,
7
7
  } from 'lightning/utilsPrivate';
8
- import numberUtils from 'lightning/numberUtils';
8
+ import { getDecimalPlaces } from 'lightning/numberUtils';
9
9
  import { numberFormat } from 'lightning/internationalizationLibrary';
10
10
  import {
11
11
  InteractingState,
@@ -283,7 +283,7 @@ export default class LightningSlider extends LightningElement {
283
283
  }
284
284
 
285
285
  // calculate decimal points from the step attribute
286
- const decimalPlaces = numberUtils.decimalPlaces(this._step);
286
+ const decimalPlaces = getDecimalPlaces(this._step);
287
287
  const formatConfig = { style: 'decimal' };
288
288
 
289
289
  if (decimalPlaces > 0) {
@@ -53,7 +53,9 @@ export default class LightningTabBar extends LightningElement {
53
53
  this._queueSynchronizeA11 = false;
54
54
  }
55
55
 
56
- this.ariaObserver.sync();
56
+ if (this.isConnected) {
57
+ this.ariaObserver.sync();
58
+ }
57
59
  }
58
60
 
59
61
  disconnectedCallback() {
@@ -1,9 +1,9 @@
1
1
  <template>
2
2
  <template if:false={hasExternalLabel}>
3
+ <template if:true={required}>
4
+ <abbr class="slds-required" title={i18n.required}>*</abbr>
5
+ </template>
3
6
  <label class={computedLabelClass}>
4
- <template if:true={required}>
5
- <abbr class="slds-required" title={i18n.required}>*</abbr>
6
- </template>
7
7
  {label}
8
8
  </label>
9
9
  <lightning-helptext if:true={fieldLevelHelp} content={fieldLevelHelp} alternative-text={helptextAlternativeText}></lightning-helptext>
@@ -308,7 +308,9 @@ export class Tooltip {
308
308
  tooltip.visible = this._visible;
309
309
  tooltip.content = this._value;
310
310
 
311
- this._ariaObserver.sync();
311
+ if (this._root && this._root.isConnected) {
312
+ this._ariaObserver.sync();
313
+ }
312
314
 
313
315
  this.startPositioning();
314
316
  document.addEventListener('keydown', this.handleEscape);