@aurodesignsystem-dev/auro-formkit 0.0.0-pr1503.2 → 0.0.0-pr1505.0

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 (62) hide show
  1. package/components/checkbox/demo/customize.min.js +2 -2
  2. package/components/checkbox/demo/getting-started.min.js +2 -2
  3. package/components/checkbox/demo/index.min.js +2 -2
  4. package/components/checkbox/dist/index.js +2 -2
  5. package/components/checkbox/dist/registered.js +2 -2
  6. package/components/combobox/demo/customize.md +7 -3
  7. package/components/combobox/demo/customize.min.js +1450 -1662
  8. package/components/combobox/demo/getting-started.min.js +1450 -1662
  9. package/components/combobox/demo/index.min.js +1450 -1662
  10. package/components/combobox/dist/auro-combobox.d.ts +5 -0
  11. package/components/combobox/dist/index.js +504 -141
  12. package/components/combobox/dist/registered.js +504 -141
  13. package/components/counter/demo/customize.min.js +3 -3
  14. package/components/counter/demo/index.min.js +3 -3
  15. package/components/counter/dist/index.js +3 -3
  16. package/components/counter/dist/registered.js +3 -3
  17. package/components/datepicker/demo/api.md +2 -0
  18. package/components/datepicker/demo/customize.md +195 -33
  19. package/components/datepicker/demo/customize.min.js +145 -60
  20. package/components/datepicker/demo/index.min.js +137 -59
  21. package/components/datepicker/dist/index.js +137 -59
  22. package/components/datepicker/dist/registered.js +137 -59
  23. package/components/datepicker/dist/src/auro-datepicker.d.ts +2 -0
  24. package/components/dropdown/demo/customize.min.js +1 -1
  25. package/components/dropdown/demo/getting-started.min.js +1 -1
  26. package/components/dropdown/demo/index.min.js +1 -1
  27. package/components/dropdown/dist/index.js +1 -1
  28. package/components/dropdown/dist/registered.js +1 -1
  29. package/components/form/demo/customize.min.js +2209 -2237
  30. package/components/form/demo/getting-started.min.js +2209 -2237
  31. package/components/form/demo/index.min.js +2209 -2237
  32. package/components/form/demo/registerDemoDeps.min.js +2207 -2235
  33. package/components/input/demo/customize.md +56 -55
  34. package/components/input/demo/customize.min.js +131 -56
  35. package/components/input/demo/getting-started.min.js +131 -56
  36. package/components/input/demo/index.md +2 -2
  37. package/components/input/demo/index.min.js +131 -56
  38. package/components/input/dist/base-input.d.ts +16 -0
  39. package/components/input/dist/index.js +131 -56
  40. package/components/input/dist/registered.js +131 -56
  41. package/components/menu/demo/api.md +41 -45
  42. package/components/menu/demo/customize.md +0 -28
  43. package/components/menu/demo/index.min.js +779 -1354
  44. package/components/menu/dist/auro-menu.d.ts +95 -110
  45. package/components/menu/dist/auro-menuoption.d.ts +32 -138
  46. package/components/menu/dist/index.js +753 -1308
  47. package/components/menu/dist/registered.js +765 -1308
  48. package/components/radio/demo/customize.min.js +2 -2
  49. package/components/radio/demo/getting-started.min.js +2 -2
  50. package/components/radio/demo/index.min.js +2 -2
  51. package/components/radio/dist/index.js +2 -2
  52. package/components/radio/dist/registered.js +2 -2
  53. package/components/select/demo/customize.md +7 -3
  54. package/components/select/demo/customize.min.js +1072 -1616
  55. package/components/select/demo/getting-started.min.js +1072 -1616
  56. package/components/select/demo/index.min.js +1072 -1616
  57. package/components/select/dist/index.js +46 -15
  58. package/components/select/dist/registered.js +46 -15
  59. package/components/select/dist/selectUtils.d.ts +12 -0
  60. package/custom-elements.json +384 -1022
  61. package/package.json +1 -3
  62. package/components/menu/dist/auro-menu.context.d.ts +0 -238
@@ -4548,7 +4548,7 @@ class AuroFormValidation {
4548
4548
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-input') && elem.errorMessage === '') {
4549
4549
  const input = elem.renderRoot.querySelector('input');
4550
4550
 
4551
- if (input.validationMessage.length > 0) {
4551
+ if (input && input.validationMessage.length > 0) {
4552
4552
  elem.errorMessage = input.validationMessage;
4553
4553
  }
4554
4554
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-combobox') && elem.errorMessage === '') {
@@ -10389,7 +10389,6 @@ class AuroInputUtilities {
10389
10389
  const maskOptions = this.getMaskOptions('date', normalizedFormat);
10390
10390
 
10391
10391
  if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
10392
- console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
10393
10392
  return undefined;
10394
10393
  }
10395
10394
 
@@ -11092,7 +11091,7 @@ class BaseInput extends AuroElement {
11092
11091
  * @returns {Date|undefined}
11093
11092
  */
11094
11093
  get valueObject() {
11095
- return this._valueObject;
11094
+ return this._valueObject || this._computeDateObjectFallback(this.value);
11096
11095
  }
11097
11096
 
11098
11097
  /**
@@ -11100,7 +11099,7 @@ class BaseInput extends AuroElement {
11100
11099
  * @returns {Date|undefined}
11101
11100
  */
11102
11101
  get minObject() {
11103
- return this._minObject;
11102
+ return this._minObject || this._computeDateObjectFallback(this.min);
11104
11103
  }
11105
11104
 
11106
11105
  /**
@@ -11108,7 +11107,31 @@ class BaseInput extends AuroElement {
11108
11107
  * @returns {Date|undefined}
11109
11108
  */
11110
11109
  get maxObject() {
11111
- return this._maxObject;
11110
+ return this._maxObject || this._computeDateObjectFallback(this.max);
11111
+ }
11112
+
11113
+ /**
11114
+ * Parses a date string into a Date object when the corresponding `_*Object`
11115
+ * field hasn't been synced yet by `updated()`. Returns undefined when the
11116
+ * input type/format isn't a full date or the string is not a valid date.
11117
+ *
11118
+ * Why this exists: a parent (datepicker) can call `inputN.validate()` from
11119
+ * inside its own `updated()` before this input's `updated()` has run
11120
+ * `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
11121
+ * and range checks would otherwise silently no-op (flipping the result to
11122
+ * `valid` or `patternMismatch`).
11123
+ * @private
11124
+ * @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
11125
+ * @returns {Date|undefined}
11126
+ */
11127
+ _computeDateObjectFallback(dateStr) {
11128
+ if (!dateStr || !this.util || !this.util.isFullDateFormat(this.type, this.format)) {
11129
+ return undefined;
11130
+ }
11131
+ if (!dateFormatter.isValidDate(dateStr)) {
11132
+ return undefined;
11133
+ }
11134
+ return dateFormatter.stringToDateInstance(dateStr);
11112
11135
  }
11113
11136
 
11114
11137
  /**
@@ -11133,8 +11156,30 @@ class BaseInput extends AuroElement {
11133
11156
  connectedCallback() {
11134
11157
  super.connectedCallback();
11135
11158
 
11159
+ // Mark for query selectors when registered under a versioned tag (e.g. inside
11160
+ // a datepicker/combobox). Must run before parent components call validate() on
11161
+ // their inner inputs — the validation framework matches via tag-or-attribute,
11162
+ // and parents trigger validation during their own updated() cycle, which can
11163
+ // precede this input's firstUpdated().
11164
+ if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
11165
+ this.setAttribute('auro-input', '');
11166
+ }
11167
+
11136
11168
  this.locale = this.domHandler.getLocale(this);
11137
11169
  notifyOnLangChange(this);
11170
+
11171
+ // Pre-compute lengthForType and date-object fields so a parent (e.g. datepicker)
11172
+ // calling our validate() synchronously during its own updated() cycle sees
11173
+ // populated values. Without this, range validation silently no-ops because
11174
+ // `max.length === lengthForType` fails when lengthForType is still undefined.
11175
+ // Rebuild util here (constructor seeded with en-US default) so configureDataForType's
11176
+ // locale-derived format lookup uses the actual locale just resolved above.
11177
+ this.util = new AuroInputUtilities({
11178
+ locale: this.locale,
11179
+ format: this.format
11180
+ });
11181
+ this.configureDataForType();
11182
+ this.syncDateValues();
11138
11183
  }
11139
11184
 
11140
11185
  disconnectedCallback() {
@@ -11155,8 +11200,8 @@ class BaseInput extends AuroElement {
11155
11200
  }
11156
11201
 
11157
11202
  // add attribute for query selectors when auro-input is registered under a custom name
11158
- if (this.tagName.toLowerCase() !== 'auro-input') {
11159
- this.setAttribute('auro-input', true);
11203
+ if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
11204
+ this.setAttribute('auro-input', '');
11160
11205
  }
11161
11206
  this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
11162
11207
 
@@ -11204,6 +11249,12 @@ class BaseInput extends AuroElement {
11204
11249
  return;
11205
11250
  }
11206
11251
 
11252
+ // While configureAutoFormatting is running, imask's internal updateControl
11253
+ // writes el.value to align display with the masked value. A synthetic input
11254
+ // event from that write would re-enter handleInput → processCreditCard mid-setup
11255
+ // and clobber a Lit value that was just pushed by the parent combobox.
11256
+ if (component._configuringMask) return;
11257
+
11207
11258
  // If all guard clauses are passed, dispatch the event
11208
11259
  const inputEvent = new InputEvent('input', {
11209
11260
  bubbles: true,
@@ -11322,7 +11373,16 @@ class BaseInput extends AuroElement {
11322
11373
 
11323
11374
  if (formattedValue !== this.inputElement.value) {
11324
11375
  this.skipNextProgrammaticInputEvent = true;
11325
- if (formattedValue) {
11376
+ if (this.maskInstance && this.type === 'credit-card') {
11377
+ // Route through the mask so its _value and el.value stay in lock-step
11378
+ // (set value calls updateControl which writes el.value = displayValue).
11379
+ // Writing el.value directly leaves the mask thinking displayValue is
11380
+ // stale; _saveSelection on the next focus/click then warns. Scoped to
11381
+ // credit-card so date's own formattedValue (raw ISO when calendar-invalid)
11382
+ // isn't re-masked through the mm/dd/yyyy mask, which would truncate it
11383
+ // and flip validity from patternMismatch to tooShort.
11384
+ this.maskInstance.value = formattedValue || '';
11385
+ } else if (formattedValue) {
11326
11386
  this.inputElement.value = formattedValue;
11327
11387
  } else {
11328
11388
  this.inputElement.value = '';
@@ -11431,58 +11491,73 @@ class BaseInput extends AuroElement {
11431
11491
  * @returns {void}
11432
11492
  */
11433
11493
  configureAutoFormatting() {
11434
- if (this.maskInstance) {
11435
- this.maskInstance.destroy();
11436
- }
11437
-
11438
- // Pass new format to util
11439
- this.util.updateFormat(this.format);
11440
-
11441
- const maskOptions = this.util.getMaskOptions(this.type, this.format);
11442
-
11443
- if (this.inputElement && maskOptions.mask) {
11444
-
11445
- // Stash and clear any existing value before IMask init.
11446
- // IMask's constructor processes the current input value which requires
11447
- // selection state — clearing first avoids that scenario entirely.
11448
- // When the format changes (e.g. locale switch) and we have a valid ISO
11449
- // model value, compute the display string for the NEW format instead of
11450
- // re-using the old display string, which may be invalid in the new mask.
11451
- let existingValue = this.inputElement.value;
11452
- if (
11453
- this.util.isFullDateFormat(this.type, this.format) &&
11454
- this.value &&
11455
- dateFormatter.isValidDate(this.value) &&
11456
- this.valueObject instanceof Date &&
11457
- !Number.isNaN(this.valueObject.getTime()) &&
11458
- typeof maskOptions.format === 'function'
11459
- ) {
11460
- existingValue = maskOptions.format(this.valueObject);
11494
+ // Re-entrancy guard. The patched-setter's synthetic input event (suppressed
11495
+ // by _configuringMask above) could otherwise trigger handleInput →
11496
+ // processCreditCard → configureAutoFormatting before the outer call's
11497
+ // set value has finished its alignCursor pass.
11498
+ if (this._configuringMask) return;
11499
+ this._configuringMask = true;
11500
+ try {
11501
+ if (this.maskInstance) {
11502
+ this.maskInstance.destroy();
11461
11503
  }
11462
11504
 
11463
- this.skipNextProgrammaticInputEvent = true;
11464
- this.inputElement.value = '';
11465
-
11466
- this.maskInstance = IMask(this.inputElement, maskOptions);
11505
+ // Pass new format to util
11506
+ this.util.updateFormat(this.format);
11467
11507
 
11468
- this.maskInstance.on('accept', () => {
11469
- this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11470
- if (this.type === "date") {
11471
- this._rawMaskValue = this.maskInstance.value;
11508
+ const maskOptions = this.util.getMaskOptions(this.type, this.format);
11509
+
11510
+ if (this.inputElement && maskOptions.mask) {
11511
+
11512
+ // Stash and clear any existing value before IMask init.
11513
+ // IMask's constructor processes the current input value which requires
11514
+ // selection state — clearing first avoids that scenario entirely.
11515
+ // When the format changes (e.g. locale switch) and we have a valid ISO
11516
+ // model value, compute the display string for the NEW format instead of
11517
+ // re-using the old display string, which may be invalid in the new mask.
11518
+ let existingValue = this.inputElement.value;
11519
+ if (
11520
+ this.util.isFullDateFormat(this.type, this.format) &&
11521
+ this.value &&
11522
+ dateFormatter.isValidDate(this.value) &&
11523
+ this.valueObject instanceof Date &&
11524
+ !Number.isNaN(this.valueObject.getTime()) &&
11525
+ typeof maskOptions.format === 'function'
11526
+ ) {
11527
+ existingValue = maskOptions.format(this.valueObject);
11472
11528
  }
11473
- });
11474
11529
 
11475
- this.maskInstance.on('complete', () => {
11476
- this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11477
- if (this.type === "date") {
11478
- this._rawMaskValue = this.maskInstance.value;
11479
- }
11480
- });
11530
+ this.skipNextProgrammaticInputEvent = true;
11531
+ this.inputElement.value = '';
11532
+
11533
+ this.maskInstance = IMask(this.inputElement, maskOptions);
11534
+
11535
+ this.maskInstance.on('accept', () => {
11536
+ // Suppress propagation during configureAutoFormatting's own value-restoration
11537
+ // (line below) — the mask emits 'accept' on every value-set, including ours,
11538
+ // and we don't want to overwrite a value the parent just pushed.
11539
+ if (this._configuringMask) return;
11540
+ this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11541
+ if (this.type === "date") {
11542
+ this._rawMaskValue = this.maskInstance.value;
11543
+ }
11544
+ });
11481
11545
 
11482
- // Restore the stashed value through IMask so it's properly masked
11483
- if (existingValue) {
11484
- this.maskInstance.value = existingValue;
11546
+ this.maskInstance.on('complete', () => {
11547
+ if (this._configuringMask) return;
11548
+ this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11549
+ if (this.type === "date") {
11550
+ this._rawMaskValue = this.maskInstance.value;
11551
+ }
11552
+ });
11553
+
11554
+ // Restore the stashed value through IMask so it's properly masked
11555
+ if (existingValue) {
11556
+ this.maskInstance.value = existingValue;
11557
+ }
11485
11558
  }
11559
+ } finally {
11560
+ this._configuringMask = false;
11486
11561
  }
11487
11562
  }
11488
11563
 
@@ -11769,10 +11844,10 @@ class BaseInput extends AuroElement {
11769
11844
  },
11770
11845
  {
11771
11846
  name: 'Diners club',
11772
- regex: /^(?<num>36|38)\d{0}/u,
11847
+ regex: /^(?<num>30[0-5]|36|38)\d{0}/u,
11773
11848
  formatLength: 16,
11774
11849
  errorMessage: CreditCardValidationMessage,
11775
- cardIcon: 'credit-card',
11850
+ cardIcon: 'cc-dinersclub',
11776
11851
  maskFormat: "0000 000000 0000"
11777
11852
  },
11778
11853
  {
@@ -12182,7 +12257,7 @@ class AuroHelpText extends i$3 {
12182
12257
  }
12183
12258
  }
12184
12259
 
12185
- var formkitVersion = '202606151650';
12260
+ var formkitVersion = '202606171946';
12186
12261
 
12187
12262
  /**
12188
12263
  * @license
@@ -151,7 +151,7 @@
151
151
  <!-- AURO-GENERATED-CONTENT:END -->
152
152
  <!-- AURO-GENERATED-CONTENT:START (FILE:src=./../apiExamples/month-day-year.html) -->
153
153
  <!-- The below content is automatically added from ./../apiExamples/month-day-year.html -->
154
- <auro-input type="date">
154
+ <auro-input type="date" locale="badsads">
155
155
  <span slot="label">Arrival date</span>
156
156
  <span slot="helpText">Help Text</span>
157
157
  </auro-input>
@@ -175,7 +175,7 @@
175
175
  <!-- AURO-GENERATED-CONTENT:END -->
176
176
  <!-- AURO-GENERATED-CONTENT:START (CODE:src=./../apiExamples/month-day-year.html) -->
177
177
  <!-- The below code snippet is automatically added from ./../apiExamples/month-day-year.html -->
178
- <pre class="language-html"><code class="language-html">&lt;auro-input type="date"&gt;
178
+ <pre class="language-html"><code class="language-html">&lt;auro-input type="date" locale="badsads"&gt;
179
179
  &lt;span slot="label"&gt;Arrival date&lt;/span&gt;
180
180
  &lt;span slot="helpText"&gt;Help Text&lt;/span&gt;
181
181
  &lt;/auro-input&gt;</code></pre>
@@ -4548,7 +4548,7 @@ class AuroFormValidation {
4548
4548
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-input') && elem.errorMessage === '') {
4549
4549
  const input = elem.renderRoot.querySelector('input');
4550
4550
 
4551
- if (input.validationMessage.length > 0) {
4551
+ if (input && input.validationMessage.length > 0) {
4552
4552
  elem.errorMessage = input.validationMessage;
4553
4553
  }
4554
4554
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-combobox') && elem.errorMessage === '') {
@@ -10389,7 +10389,6 @@ class AuroInputUtilities {
10389
10389
  const maskOptions = this.getMaskOptions('date', normalizedFormat);
10390
10390
 
10391
10391
  if (!(valueObject instanceof Date) || Number.isNaN(valueObject.getTime()) || !maskOptions || typeof maskOptions.format !== 'function') {
10392
- console.debug('Invalid date object or mask options for formatting', { valueObject, maskOptions }); // eslint-disable-line no-console
10393
10392
  return undefined;
10394
10393
  }
10395
10394
 
@@ -11092,7 +11091,7 @@ class BaseInput extends AuroElement {
11092
11091
  * @returns {Date|undefined}
11093
11092
  */
11094
11093
  get valueObject() {
11095
- return this._valueObject;
11094
+ return this._valueObject || this._computeDateObjectFallback(this.value);
11096
11095
  }
11097
11096
 
11098
11097
  /**
@@ -11100,7 +11099,7 @@ class BaseInput extends AuroElement {
11100
11099
  * @returns {Date|undefined}
11101
11100
  */
11102
11101
  get minObject() {
11103
- return this._minObject;
11102
+ return this._minObject || this._computeDateObjectFallback(this.min);
11104
11103
  }
11105
11104
 
11106
11105
  /**
@@ -11108,7 +11107,31 @@ class BaseInput extends AuroElement {
11108
11107
  * @returns {Date|undefined}
11109
11108
  */
11110
11109
  get maxObject() {
11111
- return this._maxObject;
11110
+ return this._maxObject || this._computeDateObjectFallback(this.max);
11111
+ }
11112
+
11113
+ /**
11114
+ * Parses a date string into a Date object when the corresponding `_*Object`
11115
+ * field hasn't been synced yet by `updated()`. Returns undefined when the
11116
+ * input type/format isn't a full date or the string is not a valid date.
11117
+ *
11118
+ * Why this exists: a parent (datepicker) can call `inputN.validate()` from
11119
+ * inside its own `updated()` before this input's `updated()` has run
11120
+ * `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
11121
+ * and range checks would otherwise silently no-op (flipping the result to
11122
+ * `valid` or `patternMismatch`).
11123
+ * @private
11124
+ * @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
11125
+ * @returns {Date|undefined}
11126
+ */
11127
+ _computeDateObjectFallback(dateStr) {
11128
+ if (!dateStr || !this.util || !this.util.isFullDateFormat(this.type, this.format)) {
11129
+ return undefined;
11130
+ }
11131
+ if (!dateFormatter.isValidDate(dateStr)) {
11132
+ return undefined;
11133
+ }
11134
+ return dateFormatter.stringToDateInstance(dateStr);
11112
11135
  }
11113
11136
 
11114
11137
  /**
@@ -11133,8 +11156,30 @@ class BaseInput extends AuroElement {
11133
11156
  connectedCallback() {
11134
11157
  super.connectedCallback();
11135
11158
 
11159
+ // Mark for query selectors when registered under a versioned tag (e.g. inside
11160
+ // a datepicker/combobox). Must run before parent components call validate() on
11161
+ // their inner inputs — the validation framework matches via tag-or-attribute,
11162
+ // and parents trigger validation during their own updated() cycle, which can
11163
+ // precede this input's firstUpdated().
11164
+ if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
11165
+ this.setAttribute('auro-input', '');
11166
+ }
11167
+
11136
11168
  this.locale = this.domHandler.getLocale(this);
11137
11169
  notifyOnLangChange(this);
11170
+
11171
+ // Pre-compute lengthForType and date-object fields so a parent (e.g. datepicker)
11172
+ // calling our validate() synchronously during its own updated() cycle sees
11173
+ // populated values. Without this, range validation silently no-ops because
11174
+ // `max.length === lengthForType` fails when lengthForType is still undefined.
11175
+ // Rebuild util here (constructor seeded with en-US default) so configureDataForType's
11176
+ // locale-derived format lookup uses the actual locale just resolved above.
11177
+ this.util = new AuroInputUtilities({
11178
+ locale: this.locale,
11179
+ format: this.format
11180
+ });
11181
+ this.configureDataForType();
11182
+ this.syncDateValues();
11138
11183
  }
11139
11184
 
11140
11185
  disconnectedCallback() {
@@ -11155,8 +11200,8 @@ class BaseInput extends AuroElement {
11155
11200
  }
11156
11201
 
11157
11202
  // add attribute for query selectors when auro-input is registered under a custom name
11158
- if (this.tagName.toLowerCase() !== 'auro-input') {
11159
- this.setAttribute('auro-input', true);
11203
+ if (this.tagName.toLowerCase() !== 'auro-input' && !this.hasAttribute('auro-input')) {
11204
+ this.setAttribute('auro-input', '');
11160
11205
  }
11161
11206
  this.inputId = this.id ? `${this.id}-input` : window.crypto.randomUUID();
11162
11207
 
@@ -11204,6 +11249,12 @@ class BaseInput extends AuroElement {
11204
11249
  return;
11205
11250
  }
11206
11251
 
11252
+ // While configureAutoFormatting is running, imask's internal updateControl
11253
+ // writes el.value to align display with the masked value. A synthetic input
11254
+ // event from that write would re-enter handleInput → processCreditCard mid-setup
11255
+ // and clobber a Lit value that was just pushed by the parent combobox.
11256
+ if (component._configuringMask) return;
11257
+
11207
11258
  // If all guard clauses are passed, dispatch the event
11208
11259
  const inputEvent = new InputEvent('input', {
11209
11260
  bubbles: true,
@@ -11322,7 +11373,16 @@ class BaseInput extends AuroElement {
11322
11373
 
11323
11374
  if (formattedValue !== this.inputElement.value) {
11324
11375
  this.skipNextProgrammaticInputEvent = true;
11325
- if (formattedValue) {
11376
+ if (this.maskInstance && this.type === 'credit-card') {
11377
+ // Route through the mask so its _value and el.value stay in lock-step
11378
+ // (set value calls updateControl which writes el.value = displayValue).
11379
+ // Writing el.value directly leaves the mask thinking displayValue is
11380
+ // stale; _saveSelection on the next focus/click then warns. Scoped to
11381
+ // credit-card so date's own formattedValue (raw ISO when calendar-invalid)
11382
+ // isn't re-masked through the mm/dd/yyyy mask, which would truncate it
11383
+ // and flip validity from patternMismatch to tooShort.
11384
+ this.maskInstance.value = formattedValue || '';
11385
+ } else if (formattedValue) {
11326
11386
  this.inputElement.value = formattedValue;
11327
11387
  } else {
11328
11388
  this.inputElement.value = '';
@@ -11431,58 +11491,73 @@ class BaseInput extends AuroElement {
11431
11491
  * @returns {void}
11432
11492
  */
11433
11493
  configureAutoFormatting() {
11434
- if (this.maskInstance) {
11435
- this.maskInstance.destroy();
11436
- }
11437
-
11438
- // Pass new format to util
11439
- this.util.updateFormat(this.format);
11440
-
11441
- const maskOptions = this.util.getMaskOptions(this.type, this.format);
11442
-
11443
- if (this.inputElement && maskOptions.mask) {
11444
-
11445
- // Stash and clear any existing value before IMask init.
11446
- // IMask's constructor processes the current input value which requires
11447
- // selection state — clearing first avoids that scenario entirely.
11448
- // When the format changes (e.g. locale switch) and we have a valid ISO
11449
- // model value, compute the display string for the NEW format instead of
11450
- // re-using the old display string, which may be invalid in the new mask.
11451
- let existingValue = this.inputElement.value;
11452
- if (
11453
- this.util.isFullDateFormat(this.type, this.format) &&
11454
- this.value &&
11455
- dateFormatter.isValidDate(this.value) &&
11456
- this.valueObject instanceof Date &&
11457
- !Number.isNaN(this.valueObject.getTime()) &&
11458
- typeof maskOptions.format === 'function'
11459
- ) {
11460
- existingValue = maskOptions.format(this.valueObject);
11494
+ // Re-entrancy guard. The patched-setter's synthetic input event (suppressed
11495
+ // by _configuringMask above) could otherwise trigger handleInput →
11496
+ // processCreditCard → configureAutoFormatting before the outer call's
11497
+ // set value has finished its alignCursor pass.
11498
+ if (this._configuringMask) return;
11499
+ this._configuringMask = true;
11500
+ try {
11501
+ if (this.maskInstance) {
11502
+ this.maskInstance.destroy();
11461
11503
  }
11462
11504
 
11463
- this.skipNextProgrammaticInputEvent = true;
11464
- this.inputElement.value = '';
11465
-
11466
- this.maskInstance = IMask(this.inputElement, maskOptions);
11505
+ // Pass new format to util
11506
+ this.util.updateFormat(this.format);
11467
11507
 
11468
- this.maskInstance.on('accept', () => {
11469
- this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11470
- if (this.type === "date") {
11471
- this._rawMaskValue = this.maskInstance.value;
11508
+ const maskOptions = this.util.getMaskOptions(this.type, this.format);
11509
+
11510
+ if (this.inputElement && maskOptions.mask) {
11511
+
11512
+ // Stash and clear any existing value before IMask init.
11513
+ // IMask's constructor processes the current input value which requires
11514
+ // selection state — clearing first avoids that scenario entirely.
11515
+ // When the format changes (e.g. locale switch) and we have a valid ISO
11516
+ // model value, compute the display string for the NEW format instead of
11517
+ // re-using the old display string, which may be invalid in the new mask.
11518
+ let existingValue = this.inputElement.value;
11519
+ if (
11520
+ this.util.isFullDateFormat(this.type, this.format) &&
11521
+ this.value &&
11522
+ dateFormatter.isValidDate(this.value) &&
11523
+ this.valueObject instanceof Date &&
11524
+ !Number.isNaN(this.valueObject.getTime()) &&
11525
+ typeof maskOptions.format === 'function'
11526
+ ) {
11527
+ existingValue = maskOptions.format(this.valueObject);
11472
11528
  }
11473
- });
11474
11529
 
11475
- this.maskInstance.on('complete', () => {
11476
- this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11477
- if (this.type === "date") {
11478
- this._rawMaskValue = this.maskInstance.value;
11479
- }
11480
- });
11530
+ this.skipNextProgrammaticInputEvent = true;
11531
+ this.inputElement.value = '';
11532
+
11533
+ this.maskInstance = IMask(this.inputElement, maskOptions);
11534
+
11535
+ this.maskInstance.on('accept', () => {
11536
+ // Suppress propagation during configureAutoFormatting's own value-restoration
11537
+ // (line below) — the mask emits 'accept' on every value-set, including ours,
11538
+ // and we don't want to overwrite a value the parent just pushed.
11539
+ if (this._configuringMask) return;
11540
+ this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11541
+ if (this.type === "date") {
11542
+ this._rawMaskValue = this.maskInstance.value;
11543
+ }
11544
+ });
11481
11545
 
11482
- // Restore the stashed value through IMask so it's properly masked
11483
- if (existingValue) {
11484
- this.maskInstance.value = existingValue;
11546
+ this.maskInstance.on('complete', () => {
11547
+ if (this._configuringMask) return;
11548
+ this.value = this.util.toModelValue(this.maskInstance.value, this.format);
11549
+ if (this.type === "date") {
11550
+ this._rawMaskValue = this.maskInstance.value;
11551
+ }
11552
+ });
11553
+
11554
+ // Restore the stashed value through IMask so it's properly masked
11555
+ if (existingValue) {
11556
+ this.maskInstance.value = existingValue;
11557
+ }
11485
11558
  }
11559
+ } finally {
11560
+ this._configuringMask = false;
11486
11561
  }
11487
11562
  }
11488
11563
 
@@ -11769,10 +11844,10 @@ class BaseInput extends AuroElement {
11769
11844
  },
11770
11845
  {
11771
11846
  name: 'Diners club',
11772
- regex: /^(?<num>36|38)\d{0}/u,
11847
+ regex: /^(?<num>30[0-5]|36|38)\d{0}/u,
11773
11848
  formatLength: 16,
11774
11849
  errorMessage: CreditCardValidationMessage,
11775
- cardIcon: 'credit-card',
11850
+ cardIcon: 'cc-dinersclub',
11776
11851
  maskFormat: "0000 000000 0000"
11777
11852
  },
11778
11853
  {
@@ -12182,7 +12257,7 @@ class AuroHelpText extends i$3 {
12182
12257
  }
12183
12258
  }
12184
12259
 
12185
- var formkitVersion = '202606151650';
12260
+ var formkitVersion = '202606171946';
12186
12261
 
12187
12262
  /**
12188
12263
  * @license
@@ -453,6 +453,21 @@ export default class BaseInput extends AuroElement {
453
453
  * @returns {Date|undefined}
454
454
  */
455
455
  get maxObject(): Date | undefined;
456
+ /**
457
+ * Parses a date string into a Date object when the corresponding `_*Object`
458
+ * field hasn't been synced yet by `updated()`. Returns undefined when the
459
+ * input type/format isn't a full date or the string is not a valid date.
460
+ *
461
+ * Why this exists: a parent (datepicker) can call `inputN.validate()` from
462
+ * inside its own `updated()` before this input's `updated()` has run
463
+ * `syncDateValues()` — so `_valueObject`/`_maxObject` are still `undefined`
464
+ * and range checks would otherwise silently no-op (flipping the result to
465
+ * `valid` or `patternMismatch`).
466
+ * @private
467
+ * @param {string|undefined} dateStr - ISO date string from `value`/`min`/`max`.
468
+ * @returns {Date|undefined}
469
+ */
470
+ private _computeDateObjectFallback;
456
471
  /**
457
472
  * Internal setter for readonly date object properties.
458
473
  * @private
@@ -523,6 +538,7 @@ export default class BaseInput extends AuroElement {
523
538
  * @returns {void}
524
539
  */
525
540
  private configureAutoFormatting;
541
+ _configuringMask: boolean | undefined;
526
542
  maskInstance: import("imask").InputMask<any> | undefined;
527
543
  /**
528
544
  * Sends event notifying that the input has changed it's value.