lightning-base-components 1.18.6-alpha → 1.18.7-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 (160) hide show
  1. package/metadata/raptor.json +5 -0
  2. package/package.json +10 -59
  3. package/scopedImports/@salesforce-label-LightningPill.delete.js +1 -1
  4. package/scopedImports/@salesforce-label-LightningPill.deleteAndNavigate.js +1 -1
  5. package/scopedImports/@salesforce-label-LightningPill.remove.js +1 -1
  6. package/scopedImports/@salesforce-label-LightningRecordPicker.dataSourceErrorMessage.js +1 -0
  7. package/scopedImports/@salesforce-label-LightningRecordPicker.invalidConfigurationErrorMessage.js +1 -0
  8. package/src/lightning/accordion/accordion.css +2 -2
  9. package/src/lightning/accordion/accordion.js +2 -4
  10. package/src/lightning/accordionSection/accordionSection.css +2 -2
  11. package/src/lightning/accordionSection/accordionSection.js +2 -4
  12. package/src/lightning/avatar/avatar.css +2 -2
  13. package/src/lightning/avatar/avatar.js +2 -3
  14. package/src/lightning/baseCombobox/baseCombobox.css +2 -2
  15. package/src/lightning/baseCombobox/baseCombobox.js +37 -85
  16. package/src/lightning/baseComboboxItem/baseComboboxItem.js +2 -4
  17. package/src/lightning/baseComboboxItem/inline.css +2 -2
  18. package/src/lightning/breadcrumb/breadcrumb.css +2 -2
  19. package/src/lightning/breadcrumb/breadcrumb.js +2 -4
  20. package/src/lightning/breadcrumbs/breadcrumbs.css +2 -2
  21. package/src/lightning/breadcrumbs/breadcrumbs.js +2 -3
  22. package/src/lightning/button/button.css +2 -2
  23. package/src/lightning/buttonGroup/buttonGroup.css +2 -2
  24. package/src/lightning/buttonGroup/buttonGroup.js +2 -3
  25. package/src/lightning/buttonIcon/buttonIcon.css +2 -2
  26. package/src/lightning/buttonIcon/buttonIcon.js +0 -1
  27. package/src/lightning/buttonIconStateful/buttonIconStateful.css +2 -2
  28. package/src/lightning/buttonMenu/buttonMenu.css +2 -2
  29. package/src/lightning/buttonMenu/buttonMenu.js +2 -4
  30. package/src/lightning/buttonStateful/buttonStateful.css +2 -2
  31. package/src/lightning/buttonStateful/buttonStateful.js +2 -3
  32. package/src/lightning/calendar/calendar.css +2 -2
  33. package/src/lightning/calendar/calendar.js +2 -4
  34. package/src/lightning/card/card.css +2 -2
  35. package/src/lightning/card/card.js +2 -3
  36. package/src/lightning/colorPickerCustom/colorPickerCustom.css +2 -2
  37. package/src/lightning/colorPickerCustom/colorPickerCustom.js +2 -3
  38. package/src/lightning/colorPickerPanel/colorPickerPanel.css +2 -2
  39. package/src/lightning/colorPickerPanel/colorPickerPanel.js +2 -4
  40. package/src/lightning/combobox/combobox.css +2 -2
  41. package/src/lightning/combobox/combobox.js +2 -4
  42. package/src/lightning/datepicker/datepicker.css +2 -2
  43. package/src/lightning/datepicker/datepicker.js +2 -4
  44. package/src/lightning/datetimepicker/datetimepicker.css +2 -2
  45. package/src/lightning/datetimepicker/datetimepicker.js +2 -4
  46. package/src/lightning/dualListbox/dualListbox.css +2 -2
  47. package/src/lightning/dualListbox/dualListbox.js +2 -4
  48. package/src/lightning/dynamicIcon/dynamicIcon.js +2 -3
  49. package/src/lightning/dynamicIcon/ellie.css +1 -1
  50. package/src/lightning/dynamicIcon/eq.css +1 -1
  51. package/src/lightning/dynamicIcon/score.css +1 -1
  52. package/src/lightning/dynamicIcon/strength.css +1 -1
  53. package/src/lightning/dynamicIcon/trend.css +1 -1
  54. package/src/lightning/dynamicIcon/waffle.css +1 -1
  55. package/src/lightning/f6Controller/f6Controller.js +1 -1
  56. package/src/lightning/formattedRichText/formattedRichText.css +2 -2
  57. package/src/lightning/formattedRichText/formattedRichText.js +2 -4
  58. package/src/lightning/formattedText/formattedText.css +1 -1
  59. package/src/lightning/formattedText/formattedText.js +2 -3
  60. package/src/lightning/helptext/helptext.css +2 -2
  61. package/src/lightning/helptext/helptext.js +2 -3
  62. package/src/lightning/icon/icon.css +2 -2
  63. package/src/lightning/icon/icon.js +3 -10
  64. package/src/lightning/input/__examples__/checkboxbutton/checkboxbutton.html +1 -2
  65. package/src/lightning/input/__examples__/checkboxbutton/checkboxbutton.js +1 -1
  66. package/src/lightning/input/__examples__/number/number.html +5 -0
  67. package/src/lightning/input/input.css +4 -2
  68. package/src/lightning/input/input.html +239 -149
  69. package/src/lightning/input/input.js +532 -209
  70. package/src/lightning/{inputUtils/number.js → input/numberUtil.js} +1 -1
  71. package/src/lightning/inputUtils/inputUtils.js +20 -15
  72. package/src/lightning/inputUtils/normalize.js +0 -7
  73. package/src/lightning/layout/layout.css +2 -2
  74. package/src/lightning/layout/layout.js +2 -6
  75. package/src/lightning/layoutItem/layoutItem.css +2 -2
  76. package/src/lightning/layoutItem/layoutItem.js +2 -6
  77. package/src/lightning/menuDivider/menuDivider.css +2 -2
  78. package/src/lightning/menuDivider/menuDivider.js +2 -4
  79. package/src/lightning/menuItem/menuItem.css +2 -2
  80. package/src/lightning/menuItem/menuItem.js +2 -4
  81. package/src/lightning/menuSubheader/menuSubheader.css +2 -2
  82. package/src/lightning/menuSubheader/menuSubheader.js +2 -4
  83. package/src/lightning/pill/link.css +2 -2
  84. package/src/lightning/pill/link.html +8 -7
  85. package/src/lightning/pill/pill.js +9 -6
  86. package/src/lightning/pill/plain.css +2 -2
  87. package/src/lightning/pill/plain.html +2 -2
  88. package/src/lightning/pill/plainLink.css +2 -2
  89. package/src/lightning/pill/plainLink.html +6 -6
  90. package/src/lightning/pillContainer/barePillContainer.css +2 -2
  91. package/src/lightning/pillContainer/pillContainer.js +2 -4
  92. package/src/lightning/pillContainer/standardPillContainer.css +2 -2
  93. package/src/lightning/popup/popup.css +2 -2
  94. package/src/lightning/popup/popup.js +2 -3
  95. package/src/lightning/primitiveBubble/primitiveBubble.css +2 -2
  96. package/src/lightning/primitiveBubble/primitiveBubble.js +2 -4
  97. package/src/lightning/primitiveButton/primitiveButton.js +2 -3
  98. package/src/lightning/primitiveColorpickerButton/primitiveColorpickerButton.css +2 -2
  99. package/src/lightning/primitiveColorpickerButton/primitiveColorpickerButton.js +2 -3
  100. package/src/lightning/primitiveIcon/primitiveIcon.css +2 -2
  101. package/src/lightning/primitiveIcon/primitiveIcon.js +2 -3
  102. package/src/lightning/radioGroup/radioGroup.css +3 -2
  103. package/src/lightning/radioGroup/radioGroup.js +2 -4
  104. package/src/lightning/routingService/routingService.js +2 -1
  105. package/src/lightning/select/select.css +2 -2
  106. package/src/lightning/select/select.js +2 -4
  107. package/src/lightning/select/select.js-meta.xml +2 -0
  108. package/src/lightning/spinner/spinner.css +2 -2
  109. package/src/lightning/spinner/spinner.js +5 -11
  110. package/src/lightning/tabBar/tabBar.css +2 -2
  111. package/src/lightning/tabBar/tabBar.js +2 -4
  112. package/src/lightning/timepicker/timepicker.css +2 -2
  113. package/src/lightning/timepicker/timepicker.js +2 -4
  114. package/src/lightning/toast/__docs__/toast.md +2 -2
  115. package/src/lightning/toast/toast.css +2 -2
  116. package/src/lightning/toast/toast.js +2 -4
  117. package/src/lightning/toastContainer/toastContainer.css +2 -2
  118. package/src/lightning/verticalNavigation/verticalNavigation.css +3 -2
  119. package/src/lightning/verticalNavigation/verticalNavigation.js +2 -3
  120. package/src/lightning/verticalNavigationSection/verticalNavigationSection.css +3 -2
  121. package/src/lightning/verticalNavigationSection/verticalNavigationSection.js +2 -3
  122. package/src/lightning/input/__examples__/checkboxbutton/checkboxbutton.css +0 -6
  123. package/src/lightning/inputUtils/utils.js +0 -18
  124. package/src/lightning/primitiveInputCheckbox/form-element.slds.css +0 -281
  125. package/src/lightning/primitiveInputCheckbox/primitiveInputCheckbox.css +0 -3
  126. package/src/lightning/primitiveInputCheckbox/primitiveInputCheckbox.html +0 -48
  127. package/src/lightning/primitiveInputCheckbox/primitiveInputCheckbox.js +0 -139
  128. package/src/lightning/primitiveInputCheckboxButton/form-element.slds.css +0 -281
  129. package/src/lightning/primitiveInputCheckboxButton/input-checkbox-button.slds.css +0 -126
  130. package/src/lightning/primitiveInputCheckboxButton/primitiveInputCheckboxButton.css +0 -6
  131. package/src/lightning/primitiveInputCheckboxButton/primitiveInputCheckboxButton.html +0 -24
  132. package/src/lightning/primitiveInputCheckboxButton/primitiveInputCheckboxButton.js +0 -176
  133. package/src/lightning/primitiveInputColor/form-element.slds.css +0 -281
  134. package/src/lightning/primitiveInputColor/input-color.slds.css +0 -35
  135. package/src/lightning/primitiveInputColor/primitiveInputColor.css +0 -4
  136. package/src/lightning/primitiveInputColor/primitiveInputColor.html +0 -50
  137. package/src/lightning/primitiveInputColor/primitiveInputColor.js +0 -184
  138. package/src/lightning/primitiveInputFile/button.slds.css +0 -527
  139. package/src/lightning/primitiveInputFile/form-element.slds.css +0 -281
  140. package/src/lightning/primitiveInputFile/input-file.slds.css +0 -62
  141. package/src/lightning/primitiveInputFile/primitiveInputFile.css +0 -5
  142. package/src/lightning/primitiveInputFile/primitiveInputFile.html +0 -45
  143. package/src/lightning/primitiveInputFile/primitiveInputFile.js +0 -111
  144. package/src/lightning/primitiveInputRadio/primitiveInputRadio.html +0 -24
  145. package/src/lightning/primitiveInputRadio/primitiveInputRadio.js +0 -103
  146. package/src/lightning/primitiveInputSimple/form-element.slds.css +0 -281
  147. package/src/lightning/primitiveInputSimple/input-text.slds.css +0 -398
  148. package/src/lightning/primitiveInputSimple/primitiveInputSimple.css +0 -9
  149. package/src/lightning/primitiveInputSimple/primitiveInputSimple.html +0 -65
  150. package/src/lightning/primitiveInputSimple/primitiveInputSimple.js +0 -585
  151. package/src/lightning/primitiveInputToggle/form-element.slds.css +0 -281
  152. package/src/lightning/primitiveInputToggle/input-toggle.slds.css +0 -170
  153. package/src/lightning/primitiveInputToggle/primitiveInputToggle.css +0 -3
  154. package/src/lightning/primitiveInputToggle/primitiveInputToggle.html +0 -34
  155. package/src/lightning/primitiveInputToggle/primitiveInputToggle.js +0 -164
  156. /package/src/lightning/{inputUtils/email.js → input/emailUtil.js} +0 -0
  157. /package/src/lightning/{primitiveInputCheckbox → input}/input-checkbox.slds.css +0 -0
  158. /package/src/lightning/{primitiveInputColor → input}/input-text.slds.css +0 -0
  159. /package/src/lightning/{primitiveInputSimple → input}/normalize.js +0 -0
  160. /package/src/lightning/{primitiveInputSimple → input}/selection.js +0 -0
@@ -1,4 +1,6 @@
1
1
  import labelA11yTriggerText from '@salesforce/label/LightningColorPicker.a11yTriggerText';
2
+ import labelInputFileBodyText from '@salesforce/label/LightningInputFile.bodyText';
3
+ import labelInputFileButtonLabel from '@salesforce/label/LightningInputFile.buttonLabel';
2
4
  import labelMessageToggleActive from '@salesforce/label/LightningControl.activeCapitalized';
3
5
  import labelMessageToggleInactive from '@salesforce/label/LightningControl.inactiveCapitalized';
4
6
  import labelRequired from '@salesforce/label/LightningControl.required';
@@ -11,17 +13,20 @@ import labelHelpTextAlternativeText from '@salesforce/label/LightningInput.helpt
11
13
  import userTimeZone from '@salesforce/i18n/timeZone';
12
14
  import formFactor from '@salesforce/client/formFactor';
13
15
 
14
- import { api, track } from 'lwc';
15
- import LightningShadowBaseClass from 'lightning/shadowBaseClassPrivate';
16
+ import { LightningElement, api, track } from 'lwc';
16
17
  import { classSet, formatLabel } from 'lightning/utils';
17
18
  import {
18
19
  assert,
19
20
  classListMutation,
21
+ getRealDOMId,
20
22
  reflectAttribute,
23
+ isSafari,
21
24
  isNativeComponent,
25
+ isNotUndefinedOrNull,
22
26
  isUndefinedOrNull,
23
27
  normalizeAriaAttribute,
24
28
  normalizeBoolean,
29
+ normalizeKeyValue,
25
30
  normalizeString,
26
31
  synchronizeAttrs,
27
32
  decorateInputForDragon,
@@ -29,6 +34,7 @@ import {
29
34
  computeAriaInvalid,
30
35
  } from 'lightning/utilsPrivate';
31
36
  import AriaObserver from 'lightning/ariaObserver';
37
+ import { normalizeInput } from './normalize';
32
38
  import {
33
39
  normalizeDate,
34
40
  normalizeDateTimeToUTC,
@@ -41,14 +47,26 @@ import {
41
47
  InteractingState,
42
48
  normalizeVariant,
43
49
  VARIANT,
44
- normalizeInput,
45
- isValidNumber,
46
- isValidEmail,
47
- isValidMultipleEmails,
48
50
  } from 'lightning/inputUtils';
51
+ import {
52
+ calculateFractionDigitsFromStep,
53
+ formatNumber,
54
+ fromIsoDecimal,
55
+ hasValidNumberShortcut,
56
+ hasValidNumberSymbol,
57
+ increaseNumberByStep,
58
+ isValidNumber,
59
+ isValidNumberCharacter,
60
+ stringifyNumber,
61
+ toIsoDecimal,
62
+ } from './numberUtil';
63
+ import { isValidEmail, isValidMultipleEmails } from './emailUtil';
64
+ import { InputSelectionCache } from './selection';
49
65
 
50
66
  const i18n = {
51
67
  a11yTriggerText: labelA11yTriggerText,
68
+ inputFileBodyText: labelInputFileBodyText,
69
+ inputFileButtonLabel: labelInputFileButtonLabel,
52
70
  messageToggleActive: labelMessageToggleActive,
53
71
  messageToggleInactive: labelMessageToggleInactive,
54
72
  numberIncrementCounter: labelNumberIncrementCounter,
@@ -88,12 +106,13 @@ const VALID_NUMBER_FORMATTERS = [
88
106
  'percent-fixed',
89
107
  'currency',
90
108
  ];
109
+ const DEFAULT_COLOR = '#000000';
91
110
  const DEFAULT_FORMATTER = VALID_NUMBER_FORMATTERS[0];
92
111
 
93
112
  /**
94
113
  * Represents interactive controls that accept user input depending on the type attribute.
95
114
  */
96
- export default class LightningInput extends LightningShadowBaseClass {
115
+ export default class LightningInput extends LightningElement {
97
116
  static delegatesFocus = true;
98
117
 
99
118
  /**
@@ -282,12 +301,12 @@ export default class LightningInput extends LightningShadowBaseClass {
282
301
  @track _ariaInvalid;
283
302
  @track _autocomplete;
284
303
 
285
- _shouldShowHelpMessage = true;
286
- _helpMessageChanged = false;
287
304
  _formatter = DEFAULT_FORMATTER;
288
305
  _showRawNumber = false;
289
306
  _initialValueSet = false;
307
+ _files = null;
290
308
  _rendered;
309
+ _selectionCache;
291
310
 
292
311
  constructor() {
293
312
  super();
@@ -295,11 +314,15 @@ export default class LightningInput extends LightningShadowBaseClass {
295
314
 
296
315
  // Native Shadow Root will return [native code].
297
316
  // Our synthetic method will return the function source.
298
- this._isNativeShadow = isNativeComponent(this);
317
+ this.isNative = isNativeComponent(this);
318
+
319
+ // The selection cache allows us an input to remember what text was selected
320
+ // in cases where we change the text on blur or in browsers (Safari) that
321
+ // don't track it properly.
322
+ this._selectionCache = new InputSelectionCache();
299
323
  }
300
324
 
301
325
  connectedCallback() {
302
- super.connectedCallback();
303
326
  if (!this.ariaObserver) {
304
327
  this.ariaObserver = new AriaObserver(this);
305
328
  }
@@ -311,11 +334,15 @@ export default class LightningInput extends LightningShadowBaseClass {
311
334
 
312
335
  this.classList.add('slds-form-element');
313
336
 
314
- this.updateClassListForVariant();
315
- this.validateRequiredAttributes();
337
+ this._updateClassList();
338
+ this._validateRequiredAttributes();
316
339
 
317
340
  this.interactingState = new InteractingState();
318
341
  this.interactingState.onleave(() => this.reportValidity());
342
+
343
+ if (this.isTypeNumber) {
344
+ this._updateNumberValue(this._value);
345
+ }
319
346
  }
320
347
 
321
348
  disconnectedCallback() {
@@ -329,15 +356,18 @@ export default class LightningInput extends LightningShadowBaseClass {
329
356
  }
330
357
 
331
358
  renderedCallback() {
359
+ // For W-7962838: In Safari, focus doesn't scroll input into view.
360
+ // Attach the event listener used to cache the selected text when selection changes.
361
+ if (isSafari) {
362
+ this._inputElement.addEventListener(
363
+ 'select',
364
+ this.handleSelect.bind(this)
365
+ );
366
+ }
367
+
332
368
  if (this.isConnected) {
333
369
  this.ariaObserver.sync(this.isNativeShadow);
334
370
 
335
- // If the help message changed, the help message element needs to be (un)related
336
- if (this._helpMessageChanged) {
337
- this.connectAriaDescribedBy();
338
- this._helpMessageChanged = false;
339
- }
340
-
341
371
  if (!this._rendered) {
342
372
  this.connectAriaDescribedBy();
343
373
  this.connectAriaLabelledBy();
@@ -348,6 +378,10 @@ export default class LightningInput extends LightningShadowBaseClass {
348
378
  if (!this._initialValueSet && this._inputElement) {
349
379
  this._rendered = true;
350
380
 
381
+ if (this.isTypeNumber) {
382
+ this._numberRawValue = fromIsoDecimal(this._value);
383
+ }
384
+
351
385
  this._setInputValue(this._displayedValue);
352
386
  if (this.isTypeCheckable) {
353
387
  this._inputElement.checked = this._checked;
@@ -363,7 +397,17 @@ export default class LightningInput extends LightningShadowBaseClass {
363
397
  * @type {number}
364
398
  *
365
399
  */
366
- @api formatFractionDigits;
400
+ @api
401
+ get formatFractionDigits() {
402
+ return this._formatFractionDigits;
403
+ }
404
+
405
+ set formatFractionDigits(value) {
406
+ this._formatFractionDigits = value;
407
+ if (this._rendered && this.isTypeNumber) {
408
+ this._setInputValue(this._displayedValue);
409
+ }
410
+ }
367
411
 
368
412
  /**
369
413
  * A space-separated list of element IDs whose presence or content is controlled by the
@@ -607,22 +651,15 @@ export default class LightningInput extends LightningShadowBaseClass {
607
651
  */
608
652
  @api
609
653
  get formatter() {
610
- // Formatters are applicable to the number type
611
- // If the primitive exists, retrieve value from primitive-input-simple
612
- if (this.isTypeNumber && this._primitiveComponent) {
613
- return this._primitiveComponent.formatter;
614
- }
615
654
  return this._formatter;
616
655
  }
617
656
 
618
657
  set formatter(value) {
619
- this._formatter = value;
620
-
621
- // If the primitive exists, retrieve value from primitive-input-simple
622
- // The primitive will normalize the value
623
- if (this.isTypeNumber && this._primitiveComponent) {
624
- this._primitiveComponent.formatter = this._formatter;
625
- }
658
+ this._formatter = normalizeString(value, {
659
+ fallbackValue: DEFAULT_FORMATTER,
660
+ validValues: VALID_NUMBER_FORMATTERS,
661
+ });
662
+ this._updateInputDisplayValueIfTypeNumber();
626
663
  }
627
664
 
628
665
  /**
@@ -806,6 +843,7 @@ export default class LightningInput extends LightningShadowBaseClass {
806
843
  }
807
844
 
808
845
  this._updateProxyInputAttributes('step');
846
+ this._updateInputDisplayValueIfTypeNumber();
809
847
  }
810
848
 
811
849
  /**
@@ -827,11 +865,7 @@ export default class LightningInput extends LightningShadowBaseClass {
827
865
  this._checked = normalizeBoolean(value);
828
866
 
829
867
  if (this._rendered) {
830
- if (this.isTypeCheckbox) {
831
- this._primitiveComponent.checked = this._checked;
832
- } else {
833
- this._inputElement.checked = this._checked;
834
- }
868
+ this._inputElement.checked = this._checked;
835
869
  }
836
870
 
837
871
  // Update proxy input should be set after _inputElement is updated.
@@ -862,29 +896,29 @@ export default class LightningInput extends LightningShadowBaseClass {
862
896
  */
863
897
  @api
864
898
  get value() {
865
- if (this.isTypeSimple) {
866
- const subcomponent = this._primitiveComponent;
867
- if (subcomponent) {
868
- return subcomponent.value;
869
- }
870
- }
871
899
  return this._value;
872
900
  }
873
901
 
874
902
  set value(value) {
875
- // Setting value of a type='file' isn't allowed
876
- if (!this.isTypeFile) {
877
- this._value = normalizeInput(value);
878
-
879
- if (this.isTypeSimple) {
880
- const subcomponent = this._primitiveComponent;
881
- if (subcomponent) {
882
- subcomponent.value = this._value;
883
- }
903
+ const previousValue = this._value;
904
+
905
+ this._value = normalizeInput(value);
906
+
907
+ if (this._rendered && this.isTypeNumber) {
908
+ this._value = stringifyNumber(value);
909
+ // the extra check for whether the value has changed is done for cases
910
+ // when the same value is set back in a change handler, this is to avoid
911
+ // the raw number from changing formatting under the user
912
+ // (eg. if the user typed 1,000 we want to preserve that formatting as the user
913
+ // types the value)
914
+ if (this.validity.badInput || this._value !== previousValue) {
915
+ this._updateNumberValue(value);
884
916
  }
917
+ }
885
918
 
886
- this._updateProxyInputAttributes('value');
887
-
919
+ this._updateProxyInputAttributes('value');
920
+ // Setting value of a type='file' isn't allowed
921
+ if (!this.isTypeFile) {
888
922
  // Again, due to the interop layer we need to check whether the value being set
889
923
  // is different, otherwise we're duplicating the sets on the input, which result
890
924
  // in different bugs like Japanese IME duplication of characters in Safari (likely a browser bug) or
@@ -915,7 +949,7 @@ export default class LightningInput extends LightningShadowBaseClass {
915
949
 
916
950
  set variant(value) {
917
951
  this._variant = normalizeVariant(value);
918
- this.updateClassListForVariant();
952
+ this._updateClassList();
919
953
  reflectAttribute(this, 'variant', this._variant);
920
954
  }
921
955
 
@@ -1019,7 +1053,7 @@ export default class LightningInput extends LightningShadowBaseClass {
1019
1053
  @api
1020
1054
  get files() {
1021
1055
  if (this.isTypeFile) {
1022
- return this._primitiveComponent.files;
1056
+ return this._files;
1023
1057
  }
1024
1058
  return null;
1025
1059
  }
@@ -1034,14 +1068,6 @@ export default class LightningInput extends LightningShadowBaseClass {
1034
1068
  return this._constraint.validity;
1035
1069
  }
1036
1070
 
1037
- /**
1038
- * Not moving selectionStart and selectionEnd to the inner component. Looks like
1039
- * one of the expected error/fail cases is that the component throws an error in the console,
1040
- * if the user attempts to set it on a non-supported type (like range, file, checkbox).
1041
- * That can only happen from `lightning-input`. To avoid duplicating code, it's best to keep
1042
- * this here.
1043
- */
1044
-
1045
1071
  /**
1046
1072
  * Specifies the index of the first character to select in the input element.
1047
1073
  * This attribute is supported only for text type.
@@ -1116,13 +1142,9 @@ export default class LightningInput extends LightningShadowBaseClass {
1116
1142
  }
1117
1143
  if (this._rendered && !this.isNativeInput) {
1118
1144
  this._inputElement.showHelpMessage(message);
1119
- return;
1120
- }
1121
- if (this._rendered && this.isTypePrimitiveInput) {
1122
- this._shouldShowHelpMessage = false;
1123
- this._helpMessageChanged = true;
1145
+ } else {
1146
+ this._helpMessage = message;
1124
1147
  }
1125
- this._helpMessage = message;
1126
1148
  });
1127
1149
  }
1128
1150
 
@@ -1155,47 +1177,195 @@ export default class LightningInput extends LightningShadowBaseClass {
1155
1177
  }
1156
1178
  }
1157
1179
 
1158
- get primitiveSelector() {
1159
- if (this.isTypeSimple) {
1160
- return 'lightning-primitive-input-simple';
1180
+ get isNativeInput() {
1181
+ return !(
1182
+ this.isTypeDesktopDate ||
1183
+ this.isTypeDesktopDateTime ||
1184
+ this.isTypeDesktopTime
1185
+ );
1186
+ }
1187
+
1188
+ get computedAriaLabel() {
1189
+ const ariaValues = [];
1190
+
1191
+ // merge all date & time arias on mobile since it's displayed as a single field
1192
+ if (this.isTypeMobileDateTime) {
1193
+ ariaValues.push(this.dateAriaLabel);
1194
+ ariaValues.push(this.timeAriaLabel);
1161
1195
  }
1162
- if (this.isTypeCheckboxButton) {
1163
- return 'lightning-primitive-input-checkbox-button';
1196
+ if (this.ariaLabel) {
1197
+ ariaValues.push(this.ariaLabel);
1164
1198
  }
1199
+
1200
+ return normalizeAriaAttribute(ariaValues);
1201
+ }
1202
+
1203
+ get computedAriaLabelledBy() {
1204
+ const ariaValues = [];
1205
+
1206
+ if (this.isTypeFile) {
1207
+ ariaValues.push(this.computedUniqueFileElementLabelledById);
1208
+ }
1209
+ // merge all date & time arias on mobile since it's displayed as a single field
1210
+ if (this.isTypeMobileDateTime) {
1211
+ ariaValues.push(this.dateAriaLabelledBy);
1212
+ ariaValues.push(this.timeAriaLabelledBy);
1213
+ }
1214
+ if (this.ariaLabelledBy) {
1215
+ ariaValues.push(this.ariaLabelledBy);
1216
+ }
1217
+
1218
+ return normalizeAriaAttribute(ariaValues);
1219
+ }
1220
+
1221
+ get computedAriaDescribedBy() {
1222
+ const ariaValues = [];
1223
+
1224
+ if (this._helpMessage) {
1225
+ ariaValues.push(this.computedUniqueHelpElementId);
1226
+ }
1227
+ // The toggle type is described by a secondary element
1165
1228
  if (this.isTypeToggle) {
1166
- return 'lightning-primitive-input-toggle';
1229
+ ariaValues.push(this.computedUniqueToggleElementDescribedById);
1167
1230
  }
1168
- if (this.isTypeColor) {
1169
- return 'lightning-primitive-input-color';
1231
+ // merge all date & time arias on mobile since it's displayed as a single field
1232
+ if (this.isTypeMobileDateTime) {
1233
+ ariaValues.push(this.dateAriaDescribedBy);
1234
+ ariaValues.push(this.timeAriaDescribedBy);
1170
1235
  }
1171
- if (this.isTypeCheckbox) {
1172
- return 'lightning-primitive-input-checkbox';
1236
+ if (this.ariaDescribedBy) {
1237
+ ariaValues.push(this.ariaDescribedBy);
1173
1238
  }
1174
- if (this.isTypeRadio) {
1175
- return 'lightning-primitive-input-radio';
1239
+
1240
+ return normalizeAriaAttribute(ariaValues);
1241
+ }
1242
+
1243
+ get computedAriaInvalid() {
1244
+ // W-8796658: aria-invalid should always follow the visual indication of errors
1245
+ return computeAriaInvalid(
1246
+ this._helpMessage,
1247
+ this.value,
1248
+ this.ariaInvalid
1249
+ );
1250
+ }
1251
+
1252
+ get isLabelHidden() {
1253
+ return this.variant === VARIANT.LABEL_HIDDEN;
1254
+ }
1255
+
1256
+ get isLabelStacked() {
1257
+ return this.variant === VARIANT.LABEL_STACKED;
1258
+ }
1259
+
1260
+ get accesskey() {
1261
+ return this._accesskey;
1262
+ }
1263
+
1264
+ get colorInputElementValue() {
1265
+ return this.validity.valid && this.value ? this.value : DEFAULT_COLOR;
1266
+ }
1267
+
1268
+ get colorInputStyle() {
1269
+ return `background: ${this.value || '#5679C0'};`;
1270
+ }
1271
+
1272
+ get computedUniqueHelpElementId() {
1273
+ return getRealDOMId(this.template.querySelector('[data-help-message]'));
1274
+ }
1275
+
1276
+ get computedUniqueToggleElementDescribedById() {
1277
+ if (this.isTypeToggle) {
1278
+ const toggle = this.template.querySelector(
1279
+ '[data-toggle-description]'
1280
+ );
1281
+ return getRealDOMId(toggle);
1176
1282
  }
1283
+ return null;
1284
+ }
1285
+
1286
+ get computedUniqueFormLabelId() {
1177
1287
  if (this.isTypeFile) {
1178
- return 'lightning-primitive-input-file';
1288
+ const formLabel = this.template.querySelector('[data-form-label]');
1289
+ return getRealDOMId(formLabel);
1179
1290
  }
1180
1291
  return null;
1181
1292
  }
1182
1293
 
1183
- get shouldShowHelpMessage() {
1184
- return this._shouldShowHelpMessage && this._helpMessage;
1294
+ get computedUniqueFileSelectorLabelId() {
1295
+ if (this.isTypeFile) {
1296
+ const fileBodyLabel = this.template.querySelector(
1297
+ '[data-file-selector-label]'
1298
+ );
1299
+ return getRealDOMId(fileBodyLabel);
1300
+ }
1301
+ return null;
1185
1302
  }
1186
1303
 
1187
- /************************* INPUT TYPE GETTERS *************************/
1304
+ get computedUniqueFileElementLabelledById() {
1305
+ if (this.isTypeFile) {
1306
+ const labelIds = [
1307
+ this.computedUniqueFormLabelId,
1308
+ this.computedUniqueFileSelectorLabelId,
1309
+ ];
1310
+ return labelIds.join(' ');
1311
+ }
1312
+ return null;
1313
+ }
1188
1314
 
1189
- get isTypePrimitiveInput() {
1190
- return (
1191
- this.isTypeSimple ||
1192
- this.isTypeCheckboxButton ||
1193
- this.isTypeCheckbox ||
1194
- this.isTypeToggle ||
1195
- this.isTypeColor ||
1196
- this.isTypeRadio ||
1197
- this.isTypeFile
1198
- );
1315
+ get computedFormElementClass() {
1316
+ const classes = classSet('slds-form-element__control slds-grow');
1317
+
1318
+ if (this.isTypeSearch) {
1319
+ classes.add('slds-input-has-icon slds-input-has-icon_left-right');
1320
+ }
1321
+
1322
+ return classes.toString();
1323
+ }
1324
+
1325
+ get i18n() {
1326
+ return i18n;
1327
+ }
1328
+
1329
+ get computedLabelClass() {
1330
+ const classnames = classSet('slds-form-element__label');
1331
+ if (this.isTypeCheckable || this.isTypeFile) {
1332
+ // do nothing
1333
+ } else if (this.isTypeToggle) {
1334
+ classnames.add('slds-m-bottom_none');
1335
+ } else {
1336
+ classnames.add('slds-no-flex');
1337
+ }
1338
+ return classnames
1339
+ .add({ 'slds-assistive-text': this.isLabelHidden })
1340
+ .toString();
1341
+ }
1342
+
1343
+ get computedNumberClass() {
1344
+ return classSet('slds-input')
1345
+ .add({ 'slds-is-disabled': this.disabled })
1346
+ .toString();
1347
+ }
1348
+
1349
+ get computedColorLabelClass() {
1350
+ return classSet(
1351
+ 'slds-form-element__label slds-color-picker__summary-label'
1352
+ )
1353
+ .add({ 'slds-assistive-text': this.isLabelHidden })
1354
+ .toString();
1355
+ }
1356
+
1357
+ get computedCheckboxClass() {
1358
+ return classSet('slds-checkbox')
1359
+ .add({ 'slds-checkbox_standalone': !this.isStandardVariant })
1360
+ .toString();
1361
+ }
1362
+
1363
+ get normalizedMax() {
1364
+ return this._normalizeDateTimeString(this.max);
1365
+ }
1366
+
1367
+ get normalizedMin() {
1368
+ return this._normalizeDateTimeString(this.min);
1199
1369
  }
1200
1370
 
1201
1371
  get isTypeNumber() {
@@ -1224,6 +1394,10 @@ export default class LightningInput extends LightningShadowBaseClass {
1224
1394
  );
1225
1395
  }
1226
1396
 
1397
+ get isTypeSearch() {
1398
+ return this.type === 'search';
1399
+ }
1400
+
1227
1401
  get isTypeToggle() {
1228
1402
  return this.type === 'toggle';
1229
1403
  }
@@ -1302,85 +1476,6 @@ export default class LightningInput extends LightningShadowBaseClass {
1302
1476
  );
1303
1477
  }
1304
1478
 
1305
- get isNativeInput() {
1306
- return !(
1307
- this.isTypeDesktopDate ||
1308
- this.isTypeDesktopDateTime ||
1309
- this.isTypeDesktopTime
1310
- );
1311
- }
1312
-
1313
- get _primitiveComponent() {
1314
- return this.template.querySelector(this.primitiveSelector);
1315
- }
1316
- /************************* GETTERS *************************/
1317
-
1318
- /*** Accessibility ***/
1319
-
1320
- get computedAriaLabel() {
1321
- const ariaValues = [];
1322
-
1323
- // merge all date & time arias on mobile since it's displayed as a single field
1324
- if (this.isTypeMobileDateTime) {
1325
- ariaValues.push(this.dateAriaLabel);
1326
- ariaValues.push(this.timeAriaLabel);
1327
- }
1328
- if (this.ariaLabel) {
1329
- ariaValues.push(this.ariaLabel);
1330
- }
1331
-
1332
- return normalizeAriaAttribute(ariaValues);
1333
- }
1334
-
1335
- get computedAriaInvalid() {
1336
- // W-8796658: aria-invalid should always follow the visual indication of errors
1337
- return computeAriaInvalid(
1338
- this._helpMessage,
1339
- this.value,
1340
- this.ariaInvalid
1341
- );
1342
- }
1343
-
1344
- /****** ******/
1345
-
1346
- get isLabelHidden() {
1347
- return this.variant === VARIANT.LABEL_HIDDEN;
1348
- }
1349
-
1350
- get isLabelStacked() {
1351
- return this.variant === VARIANT.LABEL_STACKED;
1352
- }
1353
-
1354
- get accesskey() {
1355
- return this._accesskey;
1356
- }
1357
-
1358
- get i18n() {
1359
- return i18n;
1360
- }
1361
-
1362
- get computedLabelClass() {
1363
- const classnames = classSet('slds-form-element__label');
1364
- if (this.isTypeCheckable || this.isTypeFile) {
1365
- // do nothing
1366
- } else if (this.isTypeToggle) {
1367
- classnames.add('slds-m-bottom_none');
1368
- } else {
1369
- classnames.add('slds-no-flex');
1370
- }
1371
- return classnames
1372
- .add({ 'slds-assistive-text': this.isLabelHidden })
1373
- .toString();
1374
- }
1375
-
1376
- get normalizedMax() {
1377
- return this._normalizeDateTimeString(this.max);
1378
- }
1379
-
1380
- get normalizedMin() {
1381
- return this._normalizeDateTimeString(this.min);
1382
- }
1383
-
1384
1479
  get _inputElement() {
1385
1480
  if (!this._cachedInputElement || this._inputElementRefreshNeeded) {
1386
1481
  this._inputDragonDecorated = false;
@@ -1397,8 +1492,6 @@ export default class LightningInput extends LightningShadowBaseClass {
1397
1492
  inputElement = this.template.querySelector(
1398
1493
  'lightning-timepicker'
1399
1494
  );
1400
- } else if (this.isTypePrimitiveInput) {
1401
- inputElement = this._primitiveComponent.inputElement;
1402
1495
  } else {
1403
1496
  inputElement = this.template.querySelector('input');
1404
1497
  this._inputDragonDecorated = true;
@@ -1437,8 +1530,34 @@ export default class LightningInput extends LightningShadowBaseClass {
1437
1530
 
1438
1531
  get _displayedValue() {
1439
1532
  if (this.isTypeNumber) {
1440
- const subcomponent = this._primitiveComponent;
1441
- return subcomponent.getDisplayedValue();
1533
+ // When only a symbol is entered by the user, set the display value as the user's input.
1534
+ // This will not affect the value dispatched by input via the change event, as it only dispatches a valid decimal number.
1535
+ // Due to the above, in integrations like input-field, the user's initial input of a symbol
1536
+ // like a minus sign will not be overwritten by an empty string value.
1537
+ // See description in PR for more details: https://github.com/salesforce-experience-platform/lightning-components/pull/3843
1538
+ if (
1539
+ this._inputElement.value.length === 1 &&
1540
+ hasValidNumberSymbol(this._inputElement.value)
1541
+ ) {
1542
+ return this._inputElement.value;
1543
+ }
1544
+
1545
+ // If the number is not valid (bad input, step mismatch, etc.) show the raw number as
1546
+ // well, otherwise the formatted value ends up being 'NaN' which makes it hard to
1547
+ // see mistakes
1548
+ if (this._showRawNumber || !this.validity.valid) {
1549
+ if (
1550
+ hasValidNumberShortcut(this._numberRawValue) &&
1551
+ isValidNumber(this._numberRawValue)
1552
+ ) {
1553
+ this._numberRawValue = fromIsoDecimal(this._value);
1554
+ }
1555
+ return this._numberRawValue;
1556
+ }
1557
+ return formatNumber(
1558
+ this._value,
1559
+ this._buildFormatNumberOptions(this.formatter)
1560
+ );
1442
1561
  }
1443
1562
 
1444
1563
  if (
@@ -1452,6 +1571,18 @@ export default class LightningInput extends LightningShadowBaseClass {
1452
1571
  return this._value;
1453
1572
  }
1454
1573
 
1574
+ /**
1575
+ * Gets the value for the actual 'type' attribute on the input element.
1576
+ */
1577
+ get _internalType() {
1578
+ // Maps number->text to support shorthand input strings like '1k'.
1579
+ if (this.isTypeNumber || this.isTypeEmail) {
1580
+ return 'text';
1581
+ }
1582
+
1583
+ return this._type;
1584
+ }
1585
+
1455
1586
  get isStandardVariant() {
1456
1587
  return (
1457
1588
  this.variant === VARIANT.STANDARD ||
@@ -1459,14 +1590,34 @@ export default class LightningInput extends LightningShadowBaseClass {
1459
1590
  );
1460
1591
  }
1461
1592
 
1593
+ get _showClearButton() {
1594
+ return (
1595
+ this.isTypeSearch &&
1596
+ isNotUndefinedOrNull(this._value) &&
1597
+ this._value !== ''
1598
+ );
1599
+ }
1600
+
1462
1601
  get _ignoreRequired() {
1463
1602
  // If uploading via the drop zone or via the input directly, we should
1464
1603
  // ignore the required flag as a file has been uploaded
1465
1604
  return (
1466
- this.isTypeFile && this._required && this.files && this.files.length
1605
+ this.isTypeFile &&
1606
+ this._required &&
1607
+ (this.fileUploadedViaDroppableZone ||
1608
+ (this._files && this._files.length > 0))
1467
1609
  );
1468
1610
  }
1469
1611
 
1612
+ get _inputMode() {
1613
+ if (this.isTypeNumber) {
1614
+ return 'decimal';
1615
+ } else if (this.isTypeEmail) {
1616
+ return 'email';
1617
+ }
1618
+ return null;
1619
+ }
1620
+
1470
1621
  get _constraint() {
1471
1622
  if (!this._constraintApi) {
1472
1623
  const overrides = {
@@ -1610,6 +1761,37 @@ export default class LightningInput extends LightningShadowBaseClass {
1610
1761
  return this.template.host.getRootNode();
1611
1762
  }
1612
1763
 
1764
+ handleFileClick() {
1765
+ this._setInputValue(null);
1766
+ this._updateValueAndValidityAttribute(null);
1767
+ }
1768
+
1769
+ handleDropFiles(event) {
1770
+ // drop doesn't trigger focus nor blur, so set state to interacting
1771
+ // and auto leave when there's no more action
1772
+ this.interactingState.interacting();
1773
+
1774
+ this.fileUploadedViaDroppableZone = true;
1775
+ this._files = event.dataTransfer && event.dataTransfer.files;
1776
+
1777
+ this._updateProxyInputAttributes('required');
1778
+
1779
+ this._dispatchChangeEventWithDetail({
1780
+ files: this._files,
1781
+ });
1782
+ }
1783
+
1784
+ /**
1785
+ * Handle text selection.
1786
+ * Dynamically bound to the select event by `renderedCallback`.
1787
+ * This allows us to cache text selection in Safari, which doesn't preserve selection.
1788
+ */
1789
+ handleSelect() {
1790
+ if (isSafari) {
1791
+ this._selectionCache.preserve(this._inputElement);
1792
+ }
1793
+ }
1794
+
1613
1795
  handleFocus() {
1614
1796
  this.interactingState.enter();
1615
1797
 
@@ -1617,11 +1799,24 @@ export default class LightningInput extends LightningShadowBaseClass {
1617
1799
  this._isColorPickerPanelOpen = false;
1618
1800
  }
1619
1801
 
1802
+ // Focusing a number input causes the value displayed to be modified.
1803
+ // Changing the value resets selection, so we save and restore selection.
1804
+ if (this._rendered && this.isTypeNumber) {
1805
+ this._showRawNumber = true;
1806
+ this._selectionCache.preserve(this._inputElement);
1807
+ this._inputElement.value = this._displayedValue;
1808
+ this._selectionCache.restore(this._inputElement);
1809
+ }
1810
+
1620
1811
  this.dispatchEvent(new CustomEvent('focus'));
1621
1812
  }
1622
1813
 
1623
1814
  handleBlur(event) {
1624
1815
  this.interactingState.leave();
1816
+ if (this._rendered && this.isTypeNumber) {
1817
+ this._showRawNumber = false;
1818
+ this._setInputValue(this._displayedValue);
1819
+ }
1625
1820
 
1626
1821
  if (
1627
1822
  !event.relatedTarget ||
@@ -1639,34 +1834,87 @@ export default class LightningInput extends LightningShadowBaseClass {
1639
1834
 
1640
1835
  handleChange(event) {
1641
1836
  event.stopPropagation();
1837
+
1642
1838
  this._dispatchCommitEvent();
1839
+
1840
+ if (this.isTypeSimple && this.value === event.target.value) {
1841
+ return;
1842
+ }
1843
+
1643
1844
  this._dispatchChangeEvent();
1644
1845
  }
1645
1846
 
1646
- handleCommit() {
1647
- this._dispatchCommitEvent();
1847
+ handleInput(event) {
1848
+ event.stopPropagation();
1849
+
1850
+ if (this.isTypeNumber) {
1851
+ // for invalid numbers the value might stay the same as the user
1852
+ // changed the invalid input, so we need to update the raw value
1853
+ this._numberRawValue = this._inputElement.value;
1854
+ }
1855
+
1856
+ if (this.isTypeSimple && this.value === event.target.value) {
1857
+ return;
1858
+ }
1859
+
1860
+ this._dispatchChangeEvent();
1648
1861
  }
1649
1862
 
1650
- handlePrimitiveInputFileChange() {
1651
- const detail = {
1652
- files: this.files,
1653
- value: this._inputElement.value,
1654
- };
1655
- this._updateProxyInputAttributes('required');
1656
- this._updateValueAndValidityAttribute(detail.value);
1863
+ handleKeyDown(event) {
1864
+ if (this.isTypeNumber) {
1865
+ // we're letting "Shift" through to prevent capital letters, other special symbols for type="number"
1866
+ const hasMetaOrCtrlModifier = event.metaKey || event.ctrlKey;
1867
+ // need to check that event.key is valid for "autofill" cases
1868
+ if (!hasMetaOrCtrlModifier && !this.readOnly && event.key) {
1869
+ const key = normalizeKeyValue(event.key);
1870
+
1871
+ if (key.length === 1 && !isValidNumberCharacter(key)) {
1872
+ event.preventDefault();
1873
+ }
1657
1874
 
1658
- this.dispatchEvent(
1659
- new CustomEvent('change', {
1660
- composed: true,
1661
- bubbles: true,
1662
- detail,
1663
- })
1664
- );
1875
+ if (key === 'ArrowUp') {
1876
+ event.preventDefault();
1877
+ this._numberStepUpAndDispatchEvents(1);
1878
+ } else if (key === 'ArrowDown') {
1879
+ event.preventDefault();
1880
+ this._numberStepUpAndDispatchEvents(-1);
1881
+ }
1882
+ }
1883
+ }
1884
+ }
1885
+
1886
+ handleColorChange(event) {
1887
+ const selectedColor = event.detail.color;
1888
+ if (selectedColor !== this._inputElement.value) {
1889
+ this._setInputValue(selectedColor);
1890
+ this._updateValueAndValidityAttribute(selectedColor);
1891
+ this.focus();
1892
+ this._dispatchChangeEventWithDetail({ value: selectedColor });
1893
+ this._dispatchCommitEvent();
1894
+ }
1895
+ this.template
1896
+ .querySelector('lightning-primitive-colorpicker-button')
1897
+ .focus();
1665
1898
  }
1666
1899
 
1667
- handlePrimitiveInputSimpleChange() {
1900
+ _clearAndSetFocusOnInput(event) {
1901
+ // TODO: Discuss this, it seems the wrong thing to do.
1902
+ // button is removed from template, but
1903
+ // event still is propagated, For example, captured by panel,
1904
+ // then cause panel think is clicked outside.
1905
+ event.stopPropagation();
1906
+
1668
1907
  this.interactingState.enter();
1669
- this._updateProxyInputAttributes('value');
1908
+ this._setInputValue('');
1909
+ this._updateValueAndValidityAttribute('');
1910
+
1911
+ this._inputElement.focus();
1912
+
1913
+ this._dispatchChangeEventWithDetail({
1914
+ value: this._value,
1915
+ });
1916
+
1917
+ this._dispatchCommitEvent();
1670
1918
  }
1671
1919
 
1672
1920
  _dispatchCommitEvent() {
@@ -1703,11 +1951,7 @@ export default class LightningInput extends LightningShadowBaseClass {
1703
1951
  }
1704
1952
  }
1705
1953
 
1706
- /**
1707
- * Label is a required attribute.
1708
- * Throw error if an invalid value is passed to the label attribute
1709
- */
1710
- validateRequiredAttributes() {
1954
+ _validateRequiredAttributes() {
1711
1955
  const { label } = this;
1712
1956
  assert(
1713
1957
  typeof label === 'string' && label.length,
@@ -1729,8 +1973,6 @@ export default class LightningInput extends LightningShadowBaseClass {
1729
1973
  }
1730
1974
 
1731
1975
  _dispatchChangeEvent() {
1732
- // TODO: investigate removing this in a future update
1733
- // possibly phase out the interactingState entirely
1734
1976
  this.interactingState.enter();
1735
1977
 
1736
1978
  const detail = {};
@@ -1738,10 +1980,20 @@ export default class LightningInput extends LightningShadowBaseClass {
1738
1980
  if (this.isTypeCheckable) {
1739
1981
  this._updateCheckedAndValidityAttribute(this._inputElement.checked);
1740
1982
  detail.checked = this._checked;
1983
+ } else if (this.isTypeFile) {
1984
+ this._files = this._inputElement.files;
1985
+
1986
+ // LWC does not proxy dom elements any more. So there is no need to call lwc.unwrap here anymore
1987
+ detail.files = this._files;
1988
+
1989
+ this._updateProxyInputAttributes('required');
1741
1990
  }
1742
1991
 
1743
1992
  if (!this.isTypeCheckable) {
1744
- if (!this.isTypeNumber) {
1993
+ if (this.isTypeNumber) {
1994
+ this._numberRawValue = this._inputElement.value;
1995
+ detail.value = toIsoDecimal(this._inputElement.value);
1996
+ } else {
1745
1997
  detail.value = this._inputElement.value;
1746
1998
  }
1747
1999
 
@@ -1795,9 +2047,36 @@ export default class LightningInput extends LightningShadowBaseClass {
1795
2047
  }
1796
2048
 
1797
2049
  /**
1798
- * Updates the class list on the host element based on the variant
2050
+ * Increases (if increment is positive, decreases otherwise) the number value of the input by the increment
2051
+ * multiple of the given 'step'. Additionally dispatches the 'change' and 'commit' events.
2052
+ *
2053
+ * @param {Number} increment A multiple of the step to increase, when step is 'any',
2054
+ * the step is assumed to be 1.
2055
+ * @private
1799
2056
  */
1800
- updateClassListForVariant() {
2057
+ _numberStepUpAndDispatchEvents(increment) {
2058
+ if (this._readOnly || this._disabled) {
2059
+ return;
2060
+ }
2061
+ this._value = increaseNumberByStep({
2062
+ value: this._value,
2063
+ step: this.step,
2064
+ increment,
2065
+ fractionDigits: this._buildFormatNumberOptions(this.formatter)
2066
+ .minimumFractionDigits,
2067
+ });
2068
+
2069
+ // Raw value is the value the user entered (we preserve a user's input),
2070
+ // since we're generating a new value we're overriding it
2071
+ this._numberRawValue = fromIsoDecimal(this._value);
2072
+
2073
+ this._setInputValue(this._displayedValue);
2074
+
2075
+ this._dispatchChangeEvent();
2076
+ this._dispatchCommitEvent();
2077
+ }
2078
+
2079
+ _updateClassList() {
1801
2080
  classListMutation(this.classList, {
1802
2081
  'slds-form-element_stacked': this.variant === VARIANT.LABEL_STACKED,
1803
2082
  'slds-form-element_horizontal':
@@ -1805,6 +2084,39 @@ export default class LightningInput extends LightningShadowBaseClass {
1805
2084
  });
1806
2085
  }
1807
2086
 
2087
+ _updateNumberValue(value) {
2088
+ const newValue = stringifyNumber(value);
2089
+ this._value = newValue;
2090
+ this._numberRawValue = fromIsoDecimal(newValue);
2091
+ }
2092
+
2093
+ _buildFormatNumberOptions(formatter) {
2094
+ const options = {
2095
+ style: formatter,
2096
+ };
2097
+ // Use the min/max fraction digits from the formatFractionDigits provided by the user if available.
2098
+ // Otherwise, use the number of digits calculated from step
2099
+ if (this._formatFractionDigits !== undefined) {
2100
+ options.minimumFractionDigits = this._formatFractionDigits;
2101
+ options.maximumFractionDigits = this._formatFractionDigits;
2102
+ } else {
2103
+ let digitsFromStep = calculateFractionDigitsFromStep(this._step);
2104
+ // if formatting percentages, when calculating digits from step, take into
2105
+ // consideration that the formatted number is effectively multiplied by 10^2, ie. 0.1 is 10%
2106
+ // so we need to subtract 2 digits;
2107
+ if (formatter === 'percent' && typeof digitsFromStep === 'number') {
2108
+ digitsFromStep -= 2;
2109
+ if (digitsFromStep < 0) {
2110
+ digitsFromStep = 0;
2111
+ }
2112
+ }
2113
+
2114
+ options.minimumFractionDigits = digitsFromStep;
2115
+ options.maximumFractionDigits = digitsFromStep;
2116
+ }
2117
+ return options;
2118
+ }
2119
+
1808
2120
  _normalizeDateTimeString(value) {
1809
2121
  let result = value;
1810
2122
  if (this.isTypeDate) {
@@ -1817,6 +2129,14 @@ export default class LightningInput extends LightningShadowBaseClass {
1817
2129
  return result;
1818
2130
  }
1819
2131
 
2132
+ _updateInputA11y(elem) {
2133
+ synchronizeAttrs(elem, {
2134
+ [ARIA_LABELLEDBY]: this.computedAriaLabelledBy,
2135
+ [ARIA_DESCRIBEDBY]: this.computedAriaDescribedBy,
2136
+ [ARIA_LABEL]: this.computedAriaLabel,
2137
+ });
2138
+ }
2139
+
1820
2140
  _updateDateOrTimePickerA11y(elem) {
1821
2141
  synchronizeAttrs(elem, {
1822
2142
  ariaLabelledByElement: this._ariaLabelledBy,
@@ -1844,6 +2164,7 @@ export default class LightningInput extends LightningShadowBaseClass {
1844
2164
  _synchronizeA11y() {
1845
2165
  // each of these templates are mutually exclusive and are selected
1846
2166
  // depending on the [type] of input.
2167
+ const input = this.template.querySelector('input');
1847
2168
  const datepicker = this.template.querySelector('lightning-datepicker');
1848
2169
  const timepicker = this.template.querySelector('lightning-timepicker');
1849
2170
  const datetimepicker = this.template.querySelector(
@@ -1851,7 +2172,9 @@ export default class LightningInput extends LightningShadowBaseClass {
1851
2172
  );
1852
2173
  // determine which template type is present,
1853
2174
  // and update a11y props accordingly
1854
- if (datepicker) {
2175
+ if (input) {
2176
+ this._updateInputA11y(input);
2177
+ } else if (datepicker) {
1855
2178
  this._updateDateOrTimePickerA11y(datepicker);
1856
2179
  } else if (timepicker) {
1857
2180
  this._updateDateOrTimePickerA11y(timepicker);