@aurodesignsystem/auro-formkit 6.0.3 → 6.1.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 (53) hide show
  1. package/CHANGELOG.md +20 -8
  2. package/components/checkbox/demo/customize.min.js +14 -4
  3. package/components/checkbox/demo/getting-started.min.js +14 -4
  4. package/components/checkbox/demo/index.min.js +14 -4
  5. package/components/checkbox/dist/index.js +14 -4
  6. package/components/checkbox/dist/registered.js +14 -4
  7. package/components/combobox/demo/customize.min.js +71 -10
  8. package/components/combobox/demo/getting-started.min.js +71 -10
  9. package/components/combobox/demo/index.min.js +71 -10
  10. package/components/combobox/dist/index.js +71 -10
  11. package/components/combobox/dist/registered.js +71 -10
  12. package/components/counter/demo/customize.min.js +2 -2
  13. package/components/counter/demo/index.min.js +2 -2
  14. package/components/counter/dist/index.js +2 -2
  15. package/components/counter/dist/registered.js +2 -2
  16. package/components/datepicker/demo/customize.min.js +64 -8
  17. package/components/datepicker/demo/index.min.js +64 -8
  18. package/components/datepicker/dist/index.js +64 -8
  19. package/components/datepicker/dist/registered.js +64 -8
  20. package/components/dropdown/demo/customize.min.js +1 -1
  21. package/components/dropdown/demo/getting-started.min.js +63 -7
  22. package/components/dropdown/demo/index.min.js +1 -1
  23. package/components/dropdown/dist/index.js +1 -1
  24. package/components/dropdown/dist/registered.js +1 -1
  25. package/components/form/demo/customize.min.js +241 -38
  26. package/components/form/demo/getting-started.min.js +241 -38
  27. package/components/form/demo/index.min.js +241 -38
  28. package/components/form/demo/registerDemoDeps.min.js +241 -38
  29. package/components/input/demo/api.md +1 -1
  30. package/components/input/demo/css-only.md +2 -2
  31. package/components/input/demo/customize.md +3 -3
  32. package/components/input/demo/customize.min.js +62 -6
  33. package/components/input/demo/getting-started.min.js +62 -6
  34. package/components/input/demo/index.min.js +62 -6
  35. package/components/input/demo/why-input.md +2 -3
  36. package/components/input/dist/auro-input.d.ts +8 -0
  37. package/components/input/dist/base-input.d.ts +2 -0
  38. package/components/input/dist/index.js +62 -6
  39. package/components/input/dist/registered.js +62 -6
  40. package/components/radio/demo/customize.min.js +15 -4
  41. package/components/radio/demo/getting-started.min.js +15 -4
  42. package/components/radio/demo/index.min.js +15 -4
  43. package/components/radio/dist/auro-radio-group.d.ts +1 -0
  44. package/components/radio/dist/index.js +15 -4
  45. package/components/radio/dist/registered.js +15 -4
  46. package/components/select/demo/customize.min.js +13 -4
  47. package/components/select/demo/getting-started.min.js +13 -4
  48. package/components/select/demo/index.min.js +13 -4
  49. package/components/select/dist/auro-select.d.ts +2 -0
  50. package/components/select/dist/index.js +13 -4
  51. package/components/select/dist/registered.js +13 -4
  52. package/custom-elements.json +1516 -1504
  53. package/package.json +1 -1
@@ -13,7 +13,7 @@ The `auro-input` element provides users a way to enter data into a text field.
13
13
  | `a11yControls` | `a11yControls` | | `string` | | The value for the aria-controls attribute. |
14
14
  | `a11yExpanded` | `a11yExpanded` | | `boolean` | | The value for the aria-expanded attribute. |
15
15
  | `a11yRole` | `a11yRole` | | `string` | | The value for the role attribute. |
16
- | `activeLabel` | `activeLabel` | | `boolean` | false | If set, the label will remain fixed in the active position. |
16
+ | `activeLabel` | `activeLabel` | | `boolean` | false | If set, the label will remain fixed in the active position.<br />Only applies to the classic/default layout; the emphasized and snowflake<br />layouts always render the label inside the field, so this has no effect there. |
17
17
  | `appearance` | `appearance` | | `'default' \| 'inverse'` | "'default'" | Defines whether the component will be on lighter or darker backgrounds. |
18
18
  | `autocapitalize` | `autocapitalize` | | `string` | | An enumerated attribute that controls whether and how text input is automatically capitalized as it is entered/edited by the user. [off/none, on/sentences, words, characters]. |
19
19
  | `autocomplete` | `autocomplete` | | `string` | | An enumerated attribute that defines what the user agent can suggest for autofill. At this time, only `autocomplete="off"` is supported. |
@@ -83,7 +83,7 @@
83
83
  <auro-header level="3">Input masking</auro-header>
84
84
  <p><code>auro-input</code> integrates IMask to apply format patterns as the user types — for example <code>format="(###) ###-####"</code> for phone numbers or <code>format="mm/dd/yyyy"</code> for dates. Native inputs have no concept of input masks, so you must integrate a third-party masking library and manage cursor position, paste handling, and value reconciliation yourself.</p>
85
85
  <auro-header level="3">Credit-card formatting and detection</auro-header>
86
- <p><code>auro-input</code> with <code>type="credit-card"</code> auto-detects Visa, Mastercard, American Express, Discover, Diners Club, and Alaska Airlines cards from the first digits, applies the correct digit grouping (e.g., 4-4-4-4 for Visa, 4-6-5 for Amex), displays the matching card brand icon, and validates with the Luhn algorithm. None of this is available natively.</p>
86
+ <p><code>auro-input</code> with <code>type="credit-card"</code> auto-detects Visa, Mastercard, American Express, Discover, Diners Club, JCB, China UnionPay, and Alaska Airlines cards from the first digits, applies the correct digit grouping (e.g., 4-4-4-4 for Visa, 4-6-5 for Amex), and displays the matching card brand icon. None of this is available natively.</p>
87
87
  <auro-header level="3">Password show/hide toggle</auro-header>
88
88
  <p><code>auro-input</code> with <code>type="password"</code> includes an accessible show/hide toggle with customizable ARIA labels via the <code>ariaLabel.password.show</code> and <code>ariaLabel.password.hide</code> slots. A native password input only masks the value — you must build the toggle button, swap the <code>type</code> attribute, and manage its accessible name yourself.</p>
89
89
  <auro-header level="3">Clear button</auro-header>
@@ -131,7 +131,7 @@
131
131
  <tr>
132
132
  <td>Credit-card detection and formatting</td>
133
133
  <td>Not supported</td>
134
- <td>Auto-detect with icon and Luhn check</td>
134
+ <td>Auto-detect with icon</td>
135
135
  </tr>
136
136
  <tr>
137
137
  <td>Password show/hide toggle</td>
@@ -30,7 +30,7 @@
30
30
  <auro-anchorlink fluid href="#min" class="level2 body-xs">Min</auro-anchorlink>
31
31
  <auro-anchorlink fluid href="#minLength" class="level2 body-xs">Min Length</auro-anchorlink>
32
32
  <auro-anchorlink fluid href="#name" class="level2 body-xs">Name</auro-anchorlink>
33
- <auro-anchorlink fluid href="#noValidate" class="level2 body-xs">No Validate</auro-anchorlink>
33
+ <auro-anchorlink fluid href="#noValidate" class="level2 body-xs">No Validation</auro-anchorlink>
34
34
  <auro-anchorlink fluid href="#pattern" class="level2 body-xs">Pattern</auro-anchorlink>
35
35
  <auro-anchorlink fluid href="#readonly" class="level2 body-xs">Readonly</auro-anchorlink>
36
36
  <auro-anchorlink fluid href="#required" class="level2 body-xs">Required</auro-anchorlink>
@@ -44,7 +44,7 @@
44
44
  <section>
45
45
  <auro-header level="2" id="appearance">Appearance</auro-header>
46
46
  <auro-header level="3" id="activeLabel">Active Label</auro-header>
47
- <p>Use the <code>activeLabel</code> attribute to make the label stay fixed in the active position.</p>
47
+ <p>Use the <code>activeLabel</code> attribute to make the label stay fixed in the active position. This applies to the classic/default layout only; the emphasized and snowflake layouts always render the label inside the field and are unaffected.</p>
48
48
  <div class="exampleWrapper">
49
49
  <!-- AURO-GENERATED-CONTENT:START (FILE:src=../apiExamples/active-label.html) -->
50
50
  <!-- The below content is automatically added from ../apiExamples/active-label.html -->
@@ -1042,7 +1042,7 @@
1042
1042
  &lt;/auro-input&gt;</code></pre>
1043
1043
  <!-- AURO-GENERATED-CONTENT:END -->
1044
1044
  </auro-accordion>
1045
- <auro-header level="3" id="noValidate">No Validate</auro-header>
1045
+ <auro-header level="3" id="noValidate">noValidate</auro-header>
1046
1046
  <p>For use cases where the field is <code>required</code>, but live validation is not wanted, use the <code>noValidate</code> attribute.</p>
1047
1047
  <div class="exampleWrapper">
1048
1048
  <!-- AURO-GENERATED-CONTENT:START (FILE:src=../apiExamples/no-validate.html) -->
@@ -10742,6 +10742,8 @@ class BaseInput extends AuroElement {
10742
10742
 
10743
10743
  /**
10744
10744
  * If set, the label will remain fixed in the active position.
10745
+ * Only applies to the classic/default layout; the emphasized and snowflake
10746
+ * layouts always render the label inside the field, so this has no effect there.
10745
10747
  */
10746
10748
  activeLabel: {
10747
10749
  type: Boolean,
@@ -11861,6 +11863,18 @@ class BaseInput extends AuroElement {
11861
11863
  cardIcon: 'cc-dinersclub',
11862
11864
  maskFormat: "0000 000000 0000"
11863
11865
  },
11866
+ {
11867
+ // JCB is variable length (16-19 digits), like UnionPay, so it reuses the
11868
+ // formatMinLength/formatLength range machinery. The 35 prefix overlaps no
11869
+ // other brand (Amex is 34|37, Diners is 30[0-5]|36|38).
11870
+ name: 'JCB',
11871
+ regex: /^(?<num>35)\d{0}/u,
11872
+ formatMinLength: 19,
11873
+ formatLength: 23,
11874
+ errorMessage: CreditCardValidationMessage,
11875
+ cardIcon: 'cc-jcb',
11876
+ maskFormat: "0000 0000 0000 0000 000"
11877
+ },
11864
11878
  {
11865
11879
  name: 'Visa',
11866
11880
  regex: /^(?<num>4)\d{0}/u,
@@ -11892,6 +11906,20 @@ class BaseInput extends AuroElement {
11892
11906
  errorMessage: CreditCardValidationMessage,
11893
11907
  cardIcon: 'cc-discover',
11894
11908
  maskFormat: "0000 0000 0000 0000"
11909
+ },
11910
+ {
11911
+ // China UnionPay is variable length (16-19 digits). It must come after
11912
+ // Discover so the last-match-wins loop below gives its 62 prefix
11913
+ // precedence over the generic `6` that resolves to Discover. 81 is used
11914
+ // by UnionPay cards issued outside mainland China and overlaps no other
11915
+ // brand. 60 is intentionally excluded (it overlaps real Discover 6011).
11916
+ name: 'China UnionPay',
11917
+ regex: /^(?<num>62|81)\d{0}/u,
11918
+ formatMinLength: 19,
11919
+ formatLength: 23,
11920
+ errorMessage: CreditCardValidationMessage,
11921
+ cardIcon: 'cc-unionpay',
11922
+ maskFormat: "0000 0000 0000 0000 000"
11895
11923
  }
11896
11924
  ];
11897
11925
 
@@ -11909,7 +11937,12 @@ class BaseInput extends AuroElement {
11909
11937
  }
11910
11938
  });
11911
11939
 
11912
- this.validationCCLength = type.formatLength;
11940
+ // Variable-length brands (both min and max defined, e.g. UnionPay) validate
11941
+ // against the minimum masked length so shorter-but-valid entries are not
11942
+ // flagged tooShort. Fixed-length brands keep their single formatLength.
11943
+ this.validationCCLength = type.formatMinLength && type.formatLength
11944
+ ? type.formatMinLength
11945
+ : type.formatLength;
11913
11946
 
11914
11947
  return type;
11915
11948
  }
@@ -12268,7 +12301,7 @@ class AuroHelpText extends i$3 {
12268
12301
  }
12269
12302
  }
12270
12303
 
12271
- var formkitVersion = '202608111803';
12304
+ var formkitVersion = '202608262225';
12272
12305
 
12273
12306
  /**
12274
12307
  * @license
@@ -12381,15 +12414,35 @@ class AuroInput extends BaseInput {
12381
12414
  * @private
12382
12415
  */
12383
12416
  get inputHidden() {
12417
+ // In the classic/default layout, activeLabel keeps the input row visible so
12418
+ // the label stays raised rather than collapsing to the centered placeholder
12419
+ // position. Emphasized/snowflake always render the label inside the field,
12420
+ // so activeLabel does not apply there. This only overrides the empty/
12421
+ // unfocused clause — the display-value clause (combobox/datepicker) is
12422
+ // preserved regardless.
12423
+ const activeLabelRaisesInput = this.activeLabel && this.isClassicLayout;
12424
+
12384
12425
  return (
12385
12426
  this.hasDisplayValueContent && !this.hasFocus && this.hasValue) ||
12386
12427
  (
12428
+ !activeLabelRaisesInput &&
12387
12429
  (!this.value || this.value.length === 0) &&
12388
12430
  !this.hasFocus &&
12389
12431
  (!this.placeholderStr || this.placeholderStr === '')
12390
12432
  );
12391
12433
  }
12392
12434
 
12435
+ /**
12436
+ * Whether the component is rendering the classic/default layout, meaning not
12437
+ * emphasized and not snowflake. Kept as a single source of truth so
12438
+ * layout-scoped behavior such as activeLabel stays consistent across getters.
12439
+ * @returns {boolean} - True for the classic/default layout.
12440
+ * @private
12441
+ */
12442
+ get isClassicLayout() {
12443
+ return !this.layout.startsWith('emphasized') && this.layout !== 'snowflake';
12444
+ }
12445
+
12393
12446
  /**
12394
12447
  * Determines if the input should display in a state with no focus or value indication.
12395
12448
  * Returns true when the input has display content without focus and has a value,
@@ -12435,7 +12488,7 @@ class AuroInput extends BaseInput {
12435
12488
  }
12436
12489
 
12437
12490
  // classic layout (default)
12438
- return ((!this.value || this.value.length === 0) && !this.placeholderStr && !this.hasFocus) ? 'body-default' : 'body-xs';
12491
+ return ((!this.value || this.value.length === 0) && !this.placeholderStr && !this.hasFocus && !this.activeLabel) ? 'body-default' : 'body-xs';
12439
12492
  }
12440
12493
 
12441
12494
  /**
@@ -12531,7 +12584,8 @@ class AuroInput extends BaseInput {
12531
12584
  'wrapper': true,
12532
12585
  'simple': this.simple,
12533
12586
  'withValue': this.hasValue,
12534
- 'hasFocus': this.hasFocus
12587
+ 'hasFocus': this.hasFocus,
12588
+ 'activeLabel': this.activeLabel
12535
12589
  };
12536
12590
  }
12537
12591
 
@@ -12681,7 +12735,10 @@ class AuroInput extends BaseInput {
12681
12735
  */
12682
12736
  definePattern() {
12683
12737
  if (this.type === 'credit-card' && !this.noValidate && this.maxLength) {
12684
- return `.{${this.maxLength},${this.maxLength}}`;
12738
+ // Variable-length brands (e.g. UnionPay) set minLength, so accept a range;
12739
+ // fixed-length brands leave minLength undefined and keep an exact length.
12740
+ const minPatternLength = this.minLength || this.maxLength;
12741
+ return `.{${minPatternLength},${this.maxLength}}`;
12685
12742
  }
12686
12743
 
12687
12744
  return this.pattern;
@@ -12742,7 +12799,6 @@ class AuroInput extends BaseInput {
12742
12799
  @input="${this.handleInput}"
12743
12800
  .placeholder=${this.placeholderStr}
12744
12801
  .role=${this.a11yRole}
12745
- ?activeLabel="${this.activeLabel}"
12746
12802
  ?disabled="${this.disabled}"
12747
12803
  ?required="${this.required}"
12748
12804
  aria-activedescendant=${o$2(this.a11yActivedescendant)}
@@ -10742,6 +10742,8 @@ class BaseInput extends AuroElement {
10742
10742
 
10743
10743
  /**
10744
10744
  * If set, the label will remain fixed in the active position.
10745
+ * Only applies to the classic/default layout; the emphasized and snowflake
10746
+ * layouts always render the label inside the field, so this has no effect there.
10745
10747
  */
10746
10748
  activeLabel: {
10747
10749
  type: Boolean,
@@ -11861,6 +11863,18 @@ class BaseInput extends AuroElement {
11861
11863
  cardIcon: 'cc-dinersclub',
11862
11864
  maskFormat: "0000 000000 0000"
11863
11865
  },
11866
+ {
11867
+ // JCB is variable length (16-19 digits), like UnionPay, so it reuses the
11868
+ // formatMinLength/formatLength range machinery. The 35 prefix overlaps no
11869
+ // other brand (Amex is 34|37, Diners is 30[0-5]|36|38).
11870
+ name: 'JCB',
11871
+ regex: /^(?<num>35)\d{0}/u,
11872
+ formatMinLength: 19,
11873
+ formatLength: 23,
11874
+ errorMessage: CreditCardValidationMessage,
11875
+ cardIcon: 'cc-jcb',
11876
+ maskFormat: "0000 0000 0000 0000 000"
11877
+ },
11864
11878
  {
11865
11879
  name: 'Visa',
11866
11880
  regex: /^(?<num>4)\d{0}/u,
@@ -11892,6 +11906,20 @@ class BaseInput extends AuroElement {
11892
11906
  errorMessage: CreditCardValidationMessage,
11893
11907
  cardIcon: 'cc-discover',
11894
11908
  maskFormat: "0000 0000 0000 0000"
11909
+ },
11910
+ {
11911
+ // China UnionPay is variable length (16-19 digits). It must come after
11912
+ // Discover so the last-match-wins loop below gives its 62 prefix
11913
+ // precedence over the generic `6` that resolves to Discover. 81 is used
11914
+ // by UnionPay cards issued outside mainland China and overlaps no other
11915
+ // brand. 60 is intentionally excluded (it overlaps real Discover 6011).
11916
+ name: 'China UnionPay',
11917
+ regex: /^(?<num>62|81)\d{0}/u,
11918
+ formatMinLength: 19,
11919
+ formatLength: 23,
11920
+ errorMessage: CreditCardValidationMessage,
11921
+ cardIcon: 'cc-unionpay',
11922
+ maskFormat: "0000 0000 0000 0000 000"
11895
11923
  }
11896
11924
  ];
11897
11925
 
@@ -11909,7 +11937,12 @@ class BaseInput extends AuroElement {
11909
11937
  }
11910
11938
  });
11911
11939
 
11912
- this.validationCCLength = type.formatLength;
11940
+ // Variable-length brands (both min and max defined, e.g. UnionPay) validate
11941
+ // against the minimum masked length so shorter-but-valid entries are not
11942
+ // flagged tooShort. Fixed-length brands keep their single formatLength.
11943
+ this.validationCCLength = type.formatMinLength && type.formatLength
11944
+ ? type.formatMinLength
11945
+ : type.formatLength;
11913
11946
 
11914
11947
  return type;
11915
11948
  }
@@ -12268,7 +12301,7 @@ class AuroHelpText extends i$3 {
12268
12301
  }
12269
12302
  }
12270
12303
 
12271
- var formkitVersion = '202608111803';
12304
+ var formkitVersion = '202608262225';
12272
12305
 
12273
12306
  /**
12274
12307
  * @license
@@ -12381,15 +12414,35 @@ class AuroInput extends BaseInput {
12381
12414
  * @private
12382
12415
  */
12383
12416
  get inputHidden() {
12417
+ // In the classic/default layout, activeLabel keeps the input row visible so
12418
+ // the label stays raised rather than collapsing to the centered placeholder
12419
+ // position. Emphasized/snowflake always render the label inside the field,
12420
+ // so activeLabel does not apply there. This only overrides the empty/
12421
+ // unfocused clause — the display-value clause (combobox/datepicker) is
12422
+ // preserved regardless.
12423
+ const activeLabelRaisesInput = this.activeLabel && this.isClassicLayout;
12424
+
12384
12425
  return (
12385
12426
  this.hasDisplayValueContent && !this.hasFocus && this.hasValue) ||
12386
12427
  (
12428
+ !activeLabelRaisesInput &&
12387
12429
  (!this.value || this.value.length === 0) &&
12388
12430
  !this.hasFocus &&
12389
12431
  (!this.placeholderStr || this.placeholderStr === '')
12390
12432
  );
12391
12433
  }
12392
12434
 
12435
+ /**
12436
+ * Whether the component is rendering the classic/default layout, meaning not
12437
+ * emphasized and not snowflake. Kept as a single source of truth so
12438
+ * layout-scoped behavior such as activeLabel stays consistent across getters.
12439
+ * @returns {boolean} - True for the classic/default layout.
12440
+ * @private
12441
+ */
12442
+ get isClassicLayout() {
12443
+ return !this.layout.startsWith('emphasized') && this.layout !== 'snowflake';
12444
+ }
12445
+
12393
12446
  /**
12394
12447
  * Determines if the input should display in a state with no focus or value indication.
12395
12448
  * Returns true when the input has display content without focus and has a value,
@@ -12435,7 +12488,7 @@ class AuroInput extends BaseInput {
12435
12488
  }
12436
12489
 
12437
12490
  // classic layout (default)
12438
- return ((!this.value || this.value.length === 0) && !this.placeholderStr && !this.hasFocus) ? 'body-default' : 'body-xs';
12491
+ return ((!this.value || this.value.length === 0) && !this.placeholderStr && !this.hasFocus && !this.activeLabel) ? 'body-default' : 'body-xs';
12439
12492
  }
12440
12493
 
12441
12494
  /**
@@ -12531,7 +12584,8 @@ class AuroInput extends BaseInput {
12531
12584
  'wrapper': true,
12532
12585
  'simple': this.simple,
12533
12586
  'withValue': this.hasValue,
12534
- 'hasFocus': this.hasFocus
12587
+ 'hasFocus': this.hasFocus,
12588
+ 'activeLabel': this.activeLabel
12535
12589
  };
12536
12590
  }
12537
12591
 
@@ -12681,7 +12735,10 @@ class AuroInput extends BaseInput {
12681
12735
  */
12682
12736
  definePattern() {
12683
12737
  if (this.type === 'credit-card' && !this.noValidate && this.maxLength) {
12684
- return `.{${this.maxLength},${this.maxLength}}`;
12738
+ // Variable-length brands (e.g. UnionPay) set minLength, so accept a range;
12739
+ // fixed-length brands leave minLength undefined and keep an exact length.
12740
+ const minPatternLength = this.minLength || this.maxLength;
12741
+ return `.{${minPatternLength},${this.maxLength}}`;
12685
12742
  }
12686
12743
 
12687
12744
  return this.pattern;
@@ -12742,7 +12799,6 @@ class AuroInput extends BaseInput {
12742
12799
  @input="${this.handleInput}"
12743
12800
  .placeholder=${this.placeholderStr}
12744
12801
  .role=${this.a11yRole}
12745
- ?activeLabel="${this.activeLabel}"
12746
12802
  ?disabled="${this.disabled}"
12747
12803
  ?required="${this.required}"
12748
12804
  aria-activedescendant=${o$2(this.a11yActivedescendant)}
@@ -10742,6 +10742,8 @@ class BaseInput extends AuroElement {
10742
10742
 
10743
10743
  /**
10744
10744
  * If set, the label will remain fixed in the active position.
10745
+ * Only applies to the classic/default layout; the emphasized and snowflake
10746
+ * layouts always render the label inside the field, so this has no effect there.
10745
10747
  */
10746
10748
  activeLabel: {
10747
10749
  type: Boolean,
@@ -11861,6 +11863,18 @@ class BaseInput extends AuroElement {
11861
11863
  cardIcon: 'cc-dinersclub',
11862
11864
  maskFormat: "0000 000000 0000"
11863
11865
  },
11866
+ {
11867
+ // JCB is variable length (16-19 digits), like UnionPay, so it reuses the
11868
+ // formatMinLength/formatLength range machinery. The 35 prefix overlaps no
11869
+ // other brand (Amex is 34|37, Diners is 30[0-5]|36|38).
11870
+ name: 'JCB',
11871
+ regex: /^(?<num>35)\d{0}/u,
11872
+ formatMinLength: 19,
11873
+ formatLength: 23,
11874
+ errorMessage: CreditCardValidationMessage,
11875
+ cardIcon: 'cc-jcb',
11876
+ maskFormat: "0000 0000 0000 0000 000"
11877
+ },
11864
11878
  {
11865
11879
  name: 'Visa',
11866
11880
  regex: /^(?<num>4)\d{0}/u,
@@ -11892,6 +11906,20 @@ class BaseInput extends AuroElement {
11892
11906
  errorMessage: CreditCardValidationMessage,
11893
11907
  cardIcon: 'cc-discover',
11894
11908
  maskFormat: "0000 0000 0000 0000"
11909
+ },
11910
+ {
11911
+ // China UnionPay is variable length (16-19 digits). It must come after
11912
+ // Discover so the last-match-wins loop below gives its 62 prefix
11913
+ // precedence over the generic `6` that resolves to Discover. 81 is used
11914
+ // by UnionPay cards issued outside mainland China and overlaps no other
11915
+ // brand. 60 is intentionally excluded (it overlaps real Discover 6011).
11916
+ name: 'China UnionPay',
11917
+ regex: /^(?<num>62|81)\d{0}/u,
11918
+ formatMinLength: 19,
11919
+ formatLength: 23,
11920
+ errorMessage: CreditCardValidationMessage,
11921
+ cardIcon: 'cc-unionpay',
11922
+ maskFormat: "0000 0000 0000 0000 000"
11895
11923
  }
11896
11924
  ];
11897
11925
 
@@ -11909,7 +11937,12 @@ class BaseInput extends AuroElement {
11909
11937
  }
11910
11938
  });
11911
11939
 
11912
- this.validationCCLength = type.formatLength;
11940
+ // Variable-length brands (both min and max defined, e.g. UnionPay) validate
11941
+ // against the minimum masked length so shorter-but-valid entries are not
11942
+ // flagged tooShort. Fixed-length brands keep their single formatLength.
11943
+ this.validationCCLength = type.formatMinLength && type.formatLength
11944
+ ? type.formatMinLength
11945
+ : type.formatLength;
11913
11946
 
11914
11947
  return type;
11915
11948
  }
@@ -12268,7 +12301,7 @@ class AuroHelpText extends i$3 {
12268
12301
  }
12269
12302
  }
12270
12303
 
12271
- var formkitVersion = '202608111803';
12304
+ var formkitVersion = '202608262225';
12272
12305
 
12273
12306
  /**
12274
12307
  * @license
@@ -12381,15 +12414,35 @@ class AuroInput extends BaseInput {
12381
12414
  * @private
12382
12415
  */
12383
12416
  get inputHidden() {
12417
+ // In the classic/default layout, activeLabel keeps the input row visible so
12418
+ // the label stays raised rather than collapsing to the centered placeholder
12419
+ // position. Emphasized/snowflake always render the label inside the field,
12420
+ // so activeLabel does not apply there. This only overrides the empty/
12421
+ // unfocused clause — the display-value clause (combobox/datepicker) is
12422
+ // preserved regardless.
12423
+ const activeLabelRaisesInput = this.activeLabel && this.isClassicLayout;
12424
+
12384
12425
  return (
12385
12426
  this.hasDisplayValueContent && !this.hasFocus && this.hasValue) ||
12386
12427
  (
12428
+ !activeLabelRaisesInput &&
12387
12429
  (!this.value || this.value.length === 0) &&
12388
12430
  !this.hasFocus &&
12389
12431
  (!this.placeholderStr || this.placeholderStr === '')
12390
12432
  );
12391
12433
  }
12392
12434
 
12435
+ /**
12436
+ * Whether the component is rendering the classic/default layout, meaning not
12437
+ * emphasized and not snowflake. Kept as a single source of truth so
12438
+ * layout-scoped behavior such as activeLabel stays consistent across getters.
12439
+ * @returns {boolean} - True for the classic/default layout.
12440
+ * @private
12441
+ */
12442
+ get isClassicLayout() {
12443
+ return !this.layout.startsWith('emphasized') && this.layout !== 'snowflake';
12444
+ }
12445
+
12393
12446
  /**
12394
12447
  * Determines if the input should display in a state with no focus or value indication.
12395
12448
  * Returns true when the input has display content without focus and has a value,
@@ -12435,7 +12488,7 @@ class AuroInput extends BaseInput {
12435
12488
  }
12436
12489
 
12437
12490
  // classic layout (default)
12438
- return ((!this.value || this.value.length === 0) && !this.placeholderStr && !this.hasFocus) ? 'body-default' : 'body-xs';
12491
+ return ((!this.value || this.value.length === 0) && !this.placeholderStr && !this.hasFocus && !this.activeLabel) ? 'body-default' : 'body-xs';
12439
12492
  }
12440
12493
 
12441
12494
  /**
@@ -12531,7 +12584,8 @@ class AuroInput extends BaseInput {
12531
12584
  'wrapper': true,
12532
12585
  'simple': this.simple,
12533
12586
  'withValue': this.hasValue,
12534
- 'hasFocus': this.hasFocus
12587
+ 'hasFocus': this.hasFocus,
12588
+ 'activeLabel': this.activeLabel
12535
12589
  };
12536
12590
  }
12537
12591
 
@@ -12681,7 +12735,10 @@ class AuroInput extends BaseInput {
12681
12735
  */
12682
12736
  definePattern() {
12683
12737
  if (this.type === 'credit-card' && !this.noValidate && this.maxLength) {
12684
- return `.{${this.maxLength},${this.maxLength}}`;
12738
+ // Variable-length brands (e.g. UnionPay) set minLength, so accept a range;
12739
+ // fixed-length brands leave minLength undefined and keep an exact length.
12740
+ const minPatternLength = this.minLength || this.maxLength;
12741
+ return `.{${minPatternLength},${this.maxLength}}`;
12685
12742
  }
12686
12743
 
12687
12744
  return this.pattern;
@@ -12742,7 +12799,6 @@ class AuroInput extends BaseInput {
12742
12799
  @input="${this.handleInput}"
12743
12800
  .placeholder=${this.placeholderStr}
12744
12801
  .role=${this.a11yRole}
12745
- ?activeLabel="${this.activeLabel}"
12746
12802
  ?disabled="${this.disabled}"
12747
12803
  ?required="${this.required}"
12748
12804
  aria-activedescendant=${o$2(this.a11yActivedescendant)}
@@ -22,17 +22,16 @@
22
22
  <p>There is no native way to detect a credit card type from input, apply the correct formatting mask, or display the appropriate card icon.</p>
23
23
  <p><code>auro-input</code> with <code>type="credit-card"</code> provides:</p>
24
24
  <ul>
25
- <li><strong>Auto-detection</strong> — Identifies Visa, Mastercard, American Express, Discover, Diners Club, and Alaska Airlines cards from the first digits typed.</li>
25
+ <li><strong>Auto-detection</strong> — Identifies Visa, Mastercard, American Express, Discover, Diners Club, JCB, China UnionPay, and Alaska Airlines cards from the first digits typed.</li>
26
26
  <li><strong>Dynamic formatting</strong> — Applies the correct digit grouping (e.g., 4-4-4-4 for Visa, 4-6-5 for Amex).</li>
27
27
  <li><strong>Card icon</strong> — Displays the detected card brand icon automatically.</li>
28
- <li><strong>Luhn validation</strong> — Validates the card number using the Luhn algorithm.</li>
29
28
  </ul>
30
29
  <auro-header level="2" id="validation">Validation</auro-header>
31
30
  <p>Native input validation provides <code>required</code>, <code>min</code>, <code>max</code>, <code>minlength</code>, <code>maxlength</code>, and <code>pattern</code>, but error messages are browser-controlled and cannot be customized.</p>
32
31
  <p><code>auro-input</code> provides:</p>
33
32
  <ul>
34
33
  <li>Custom error messages for every validity state: <code>setCustomValidityValueMissing</code>, <code>setCustomValidityRangeOverflow</code>, <code>setCustomValidityRangeUnderflow</code>, <code>setCustomValidityTooLong</code>, <code>setCustomValidityTooShort</code>, <code>setCustomValidityBadInput</code>, <code>setCustomValidityCustomError</code>, <code>setCustomValidityForType</code></li>
35
- <li>Type-specific validation (email format, credit card Luhn, phone format, date format)</li>
34
+ <li>Type-specific validation (email format, credit card format, phone format, date format)</li>
36
35
  <li>Validation timing control: on blur (default), on every input (<code>validateOnInput</code>), or disabled (<code>noValidate</code>)</li>
37
36
  <li>Programmatic vs. user input distinction — the component tracks whether a value change was user-initiated or programmatic</li>
38
37
  </ul>
@@ -66,6 +66,14 @@ export class AuroInput extends BaseInput {
66
66
  * @private
67
67
  */
68
68
  private get inputHidden();
69
+ /**
70
+ * Whether the component is rendering the classic/default layout, meaning not
71
+ * emphasized and not snowflake. Kept as a single source of truth so
72
+ * layout-scoped behavior such as activeLabel stays consistent across getters.
73
+ * @returns {boolean} - True for the classic/default layout.
74
+ * @private
75
+ */
76
+ private get isClassicLayout();
69
77
  /**
70
78
  * Determines if the input should display in a state with no focus or value indication.
71
79
  * Returns true when the input has display content without focus and has a value,
@@ -44,6 +44,8 @@ export default class BaseInput extends AuroElement {
44
44
  };
45
45
  /**
46
46
  * If set, the label will remain fixed in the active position.
47
+ * Only applies to the classic/default layout; the emphasized and snowflake
48
+ * layouts always render the label inside the field, so this has no effect there.
47
49
  */
48
50
  activeLabel: {
49
51
  type: BooleanConstructor;