@aurodesignsystem-dev/auro-formkit 0.0.0-pr1504.0 → 0.0.0-pr1506.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 (60) 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 +1435 -1666
  8. package/components/combobox/demo/getting-started.min.js +1435 -1666
  9. package/components/combobox/demo/index.min.js +1435 -1666
  10. package/components/combobox/dist/auro-combobox.d.ts +14 -0
  11. package/components/combobox/dist/index.js +489 -145
  12. package/components/combobox/dist/registered.js +489 -145
  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/customize.min.js +140 -61
  18. package/components/datepicker/demo/index.min.js +140 -61
  19. package/components/datepicker/dist/index.js +140 -61
  20. package/components/datepicker/dist/registered.js +140 -61
  21. package/components/dropdown/demo/customize.min.js +1 -1
  22. package/components/dropdown/demo/getting-started.min.js +1 -1
  23. package/components/dropdown/demo/index.min.js +1 -1
  24. package/components/dropdown/dist/index.js +1 -1
  25. package/components/dropdown/dist/registered.js +1 -1
  26. package/components/form/demo/customize.min.js +2336 -2269
  27. package/components/form/demo/getting-started.min.js +2336 -2269
  28. package/components/form/demo/index.min.js +2336 -2269
  29. package/components/form/demo/registerDemoDeps.min.js +2334 -2267
  30. package/components/input/demo/customize.min.js +138 -57
  31. package/components/input/demo/getting-started.min.js +138 -57
  32. package/components/input/demo/index.min.js +138 -57
  33. package/components/input/dist/base-input.d.ts +16 -0
  34. package/components/input/dist/index.js +138 -57
  35. package/components/input/dist/registered.js +138 -57
  36. package/components/menu/demo/api.md +41 -45
  37. package/components/menu/demo/customize.md +0 -28
  38. package/components/menu/demo/index.min.js +779 -1354
  39. package/components/menu/dist/auro-menu.d.ts +95 -110
  40. package/components/menu/dist/auro-menuoption.d.ts +32 -138
  41. package/components/menu/dist/index.js +753 -1308
  42. package/components/menu/dist/registered.js +765 -1308
  43. package/components/radio/demo/customize.min.js +2 -2
  44. package/components/radio/demo/getting-started.min.js +2 -2
  45. package/components/radio/demo/index.min.js +2 -2
  46. package/components/radio/dist/index.js +2 -2
  47. package/components/radio/dist/registered.js +2 -2
  48. package/components/select/demo/api.md +1 -0
  49. package/components/select/demo/customize.md +78 -3
  50. package/components/select/demo/customize.min.js +1140 -1577
  51. package/components/select/demo/getting-started.min.js +1140 -1577
  52. package/components/select/demo/index.min.js +1140 -1577
  53. package/components/select/demo/keyboard-behavior.md +18 -0
  54. package/components/select/dist/auro-select.d.ts +38 -2
  55. package/components/select/dist/index.js +177 -39
  56. package/components/select/dist/registered.js +177 -39
  57. package/components/select/dist/selectUtils.d.ts +24 -0
  58. package/custom-elements.json +503 -1037
  59. package/package.json +1 -1
  60. package/components/menu/dist/auro-menu.context.d.ts +0 -238
@@ -623,7 +623,7 @@ class AuroFormValidation {
623
623
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-input') && elem.errorMessage === '') {
624
624
  const input = elem.renderRoot.querySelector('input');
625
625
 
626
- if (input.validationMessage.length > 0) {
626
+ if (input && input.validationMessage.length > 0) {
627
627
  elem.errorMessage = input.validationMessage;
628
628
  }
629
629
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-combobox') && elem.errorMessage === '') {
@@ -835,6 +835,36 @@ function navigateArrow(component, direction, options = {}) {
835
835
  }
836
836
  }
837
837
 
838
+ /**
839
+ * Returns the enabled (non-disabled) options for a menu, safely.
840
+ *
841
+ * Auro-menu's `options` getter returns `undefined` when the menu has no items
842
+ * (initItems sets `items` to undefined for empty menus). Callers that reach for
843
+ * `.find()` / `[...spread]` would otherwise crash; this helper normalizes the
844
+ * empty case to `[]` so array methods are always safe.
845
+ *
846
+ * @param {HTMLElement | null | undefined} menu - The auro-menu element.
847
+ * @returns {Array<HTMLElement>} Non-disabled options, empty array when none.
848
+ */
849
+ function getEnabledOptions(menu) {
850
+ return (menu?.options || []).filter((option) => !option.disabled);
851
+ }
852
+
853
+ /**
854
+ * Returns the active (selectable + visible) options for type-ahead navigation.
855
+ *
856
+ * Uses auro-menuoption's `isActive` getter, which excludes disabled, hidden,
857
+ * and static options (e.g. `static nomatch` placeholders) so the type-ahead
858
+ * cursor never lands on a non-actionable item. Same empty-safe handling as
859
+ * `getEnabledOptions`.
860
+ *
861
+ * @param {HTMLElement | null | undefined} menu - The auro-menu element.
862
+ * @returns {Array<HTMLElement>} Active options, empty array when none.
863
+ */
864
+ function getActiveOptions(menu) {
865
+ return (menu?.options || []).filter((option) => option.isActive);
866
+ }
867
+
838
868
  /* eslint-disable new-cap */
839
869
 
840
870
  const selectKeyboardStrategy = {
@@ -867,6 +897,14 @@ const selectKeyboardStrategy = {
867
897
  },
868
898
 
869
899
  Escape(component, evt, ctx) {
900
+ // Always clear the type-ahead buffer — Escape is a universal cancel.
901
+ // Safe to call when the buffer is empty.
902
+ // eslint-disable-next-line no-underscore-dangle
903
+ if (typeof component._clearTypeaheadBuffer === 'function') {
904
+ // eslint-disable-next-line no-underscore-dangle
905
+ component._clearTypeaheadBuffer();
906
+ }
907
+
870
908
  if (!ctx.isExpanded) {
871
909
  return;
872
910
  }
@@ -883,7 +921,8 @@ const selectKeyboardStrategy = {
883
921
  }
884
922
  evt.preventDefault();
885
923
  evt.stopPropagation();
886
- const lastOption = [...component.menu.menuService.menuOptions].reverse().find((option) => !option.disabled);
924
+ // `pop()` is safe here: getEnabledOptions returns a fresh filtered array.
925
+ const lastOption = getEnabledOptions(component.menu).pop();
887
926
  if (lastOption) {
888
927
  component.menu.updateActiveOption(lastOption);
889
928
  }
@@ -905,7 +944,7 @@ const selectKeyboardStrategy = {
905
944
  }
906
945
  evt.preventDefault();
907
946
  evt.stopPropagation();
908
- const firstOption = component.menu.menuService.menuOptions.find((option) => !option.disabled);
947
+ const [firstOption] = getEnabledOptions(component.menu);
909
948
  if (firstOption) {
910
949
  component.menu.updateActiveOption(firstOption);
911
950
  }
@@ -925,16 +964,25 @@ const selectKeyboardStrategy = {
925
964
  },
926
965
 
927
966
  default(component, evt, ctx) {
928
- component.updateActiveOptionBasedOnKey(evt.key);
967
+ // Space resolves to either typeahead-buffer extension or bib toggle
968
+ // depending on whether a type-ahead buffer is active. Mirrors native
969
+ // <select> and the WAI-ARIA APG Listbox guidance: mid-typeahead space
970
+ // is a search character (e.g. "San Francisco"); otherwise it toggles.
929
971
  if (evt.key === ' ') {
930
972
  evt.preventDefault();
931
973
  evt.stopPropagation();
974
+ if (component.typeaheadBuffer && component.typeaheadBuffer.length > 0) {
975
+ component.updateActiveOptionBasedOnKey(evt.key);
976
+ return;
977
+ }
932
978
  if (ctx.isExpanded) {
933
979
  component.dropdown.hide();
934
- return;
980
+ } else {
981
+ component.dropdown.show();
935
982
  }
936
- component.dropdown.show();
983
+ return;
937
984
  }
985
+ component.updateActiveOptionBasedOnKey(evt.key);
938
986
  },
939
987
  };
940
988
 
@@ -4846,7 +4894,7 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
4846
4894
  }
4847
4895
  };
4848
4896
 
4849
- var formkitVersion$1 = '202606141505';
4897
+ var formkitVersion$1 = '202606190840';
4850
4898
 
4851
4899
  class AuroElement extends LitElement {
4852
4900
  static get properties() {
@@ -6859,7 +6907,7 @@ class AuroHelpText extends LitElement {
6859
6907
  }
6860
6908
  }
6861
6909
 
6862
- var formkitVersion = '202606141505';
6910
+ var formkitVersion = '202606190840';
6863
6911
 
6864
6912
  var styleCss = css`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}.body-default{font-size:var(--wcss-body-default-font-size, 1rem);font-weight:var(--wcss-body-default-weight, );line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-default,.body-default-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-default-emphasized{font-size:var(--wcss-body-default-emphasized-font-size, 1rem);font-weight:var(--wcss-body-default-emphasized-weight, );line-height:var(--wcss-body-default-emphasized-line-height, 1.5rem)}.body-lg{font-size:var(--wcss-body-lg-font-size, 1.125rem);font-weight:var(--wcss-body-lg-weight, );line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-lg,.body-lg-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-lg-emphasized{font-size:var(--wcss-body-lg-emphasized-font-size, 1.125rem);font-weight:var(--wcss-body-lg-emphasized-weight, );line-height:var(--wcss-body-lg-emphasized-line-height, 1.625rem)}.body-sm{font-size:var(--wcss-body-sm-font-size, 0.875rem);font-weight:var(--wcss-body-sm-weight, );line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-sm,.body-sm-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-sm-emphasized{font-size:var(--wcss-body-sm-emphasized-font-size, 0.875rem);font-weight:var(--wcss-body-sm-emphasized-weight, );line-height:var(--wcss-body-sm-emphasized-line-height, 1.25rem)}.body-xs{font-size:var(--wcss-body-xs-font-size, 0.75rem);font-weight:var(--wcss-body-xs-weight, );line-height:var(--wcss-body-xs-line-height, 1rem)}.body-xs,.body-xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-xs-emphasized{font-size:var(--wcss-body-xs-emphasized-font-size, 0.75rem);font-weight:var(--wcss-body-xs-emphasized-weight, );line-height:var(--wcss-body-xs-emphasized-line-height, 1rem)}.body-2xs{font-size:var(--wcss-body-2xs-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-weight, );line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.body-2xs,.body-2xs-emphasized{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;letter-spacing:var(--wcss-body-letter-spacing, 0)}.body-2xs-emphasized{font-size:var(--wcss-body-2xs-emphasized-font-size, 0.625rem);font-weight:var(--wcss-body-2xs-emphasized-weight, );line-height:var(--wcss-body-2xs-emphasized-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem));font-weight:var(--wcss-display-2xl-weight, 300);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);line-height:var(--wcss-display-2xl-line-height, 1.3)}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem));font-weight:var(--wcss-display-xl-weight, 300);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);line-height:var(--wcss-display-xl-line-height, 1.3)}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem));font-weight:var(--wcss-display-lg-weight, 300);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);line-height:var(--wcss-display-lg-line-height, 1.3)}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem));font-weight:var(--wcss-display-md-weight, 300);letter-spacing:var(--wcss-display-md-letter-spacing, 0);line-height:var(--wcss-display-md-line-height, 1.3)}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem));font-weight:var(--wcss-display-sm-weight, 300);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);line-height:var(--wcss-display-sm-line-height, 1.3)}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem));font-weight:var(--wcss-display-xs-weight, 300);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);line-height:var(--wcss-display-xs-line-height, 1.3)}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem));font-weight:var(--wcss-heading-xl-weight, 300);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);line-height:var(--wcss-heading-xl-line-height, 1.3)}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem));font-weight:var(--wcss-heading-lg-weight, 300);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);line-height:var(--wcss-heading-lg-line-height, 1.3)}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem));font-weight:var(--wcss-heading-md-weight, 300);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);line-height:var(--wcss-heading-md-line-height, 1.3)}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem));font-weight:var(--wcss-heading-sm-weight, 300);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);line-height:var(--wcss-heading-sm-line-height, 1.3)}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem));font-weight:var(--wcss-heading-xs-weight, 300);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);line-height:var(--wcss-heading-xs-line-height, 1.3)}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem));font-weight:var(--wcss-heading-2xs-weight, 300);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);line-height:var(--wcss-heading-2xs-line-height, 1.3)}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));font-weight:var(--wcss-accent-2xl-weight, 450);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-2xl-line-height, 1)}.accent-2xl,.accent-xl{text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));font-weight:var(--wcss-accent-xl-weight, 450);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);line-height:var(--wcss-accent-xl-line-height, 1.3)}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));font-weight:var(--wcss-accent-lg-weight, 450);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);line-height:var(--wcss-accent-lg-line-height, 1.3)}.accent-lg,.accent-md{text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));font-weight:var(--wcss-accent-md-weight, 500);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);line-height:var(--wcss-accent-md-line-height, 1.3)}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));font-weight:var(--wcss-accent-sm-weight, 500);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);line-height:var(--wcss-accent-sm-line-height, 1.3)}.accent-sm,.accent-xs{text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));font-weight:var(--wcss-accent-xs-weight, 500);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-xs-line-height, 1.3)}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));font-weight:var(--wcss-accent-2xs-weight, 450);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);line-height:var(--wcss-accent-2xs-line-height, 1.3);text-transform:uppercase}[auro-dropdown]{--ds-auro-dropdown-trigger-border-color: var(--ds-auro-select-border-color);--ds-auro-dropdown-trigger-background-color: var(--ds-auro-select-background-color);--ds-auro-dropdown-trigger-container-color: var(--ds-auro-select-background-color);--ds-auro-dropdown-trigger-outline-color: var(--ds-auro-select-outline-color)}:host{display:inline-block;text-align:left;vertical-align:top}:host([layout*=emphasized]) [auro-dropdown],:host([layout*=snowflake]) [auro-dropdown]{--ds-auro-select-border-color: transparent}:host([layout*=emphasized]) .mainContent,:host([layout*=snowflake]) .mainContent{text-align:center}.mainContent{position:relative;display:flex;overflow:hidden;flex:1;flex-direction:column;align-items:center;justify-content:center}.valueContainer [slot=displayValue]{display:none}.accents{display:flex;flex-direction:row;align-items:center;justify-content:center}::slotted([slot=typeIcon]){margin-right:var(--ds-size-100, 0.5rem)}.displayValue{display:block}.displayValue:not(.force){display:none}.displayValue:not(.force).hasContent:is(.withValue):not(.hasFocus){display:block}.triggerContent{display:flex;width:100%;align-items:center;justify-content:center}:host([layout*=emphasized]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem) 0 var(--ds-size-300, 1.5rem)}:host([layout*=snowflake]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem) 0 var(--ds-size-200, 1rem)}:host([layout*=snowflake]) label{padding-block:var(--ds-size-25, 0.125rem)}:host([layout*=classic]) .triggerContent{padding:0 var(--ds-size-100, 0.5rem)}:host([layout*=classic]) .mainContent{align-items:start}:host([layout*=classic]) label{overflow:hidden;cursor:text;text-overflow:ellipsis;white-space:nowrap}:host([layout*=classic]) .value{height:auto}label{color:var(--ds-auro-select-label-text-color)}:host(:is([validity]:not([validity=valid]))) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-basic-color-status-error, #e31f26);--ds-auro-select-outline-color: var(--ds-basic-color-status-error, #e31f26);--ds-auro-dropdown-helptext-text-color: var(--ds-basic-color-texticon-default, #2a2a2a)}:host([ondark]:is([validity]:not([validity=valid]))) [auro-dropdown],:host([appearance=inverse]:is([validity]:not([validity=valid]))) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8);--ds-auro-select-outline-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8);--ds-auro-dropdown-helptext-text-color: var(--ds-basic-color-texticon-inverse, #ffffff)}#slotHolder{display:none}:host([fluid]){width:100%}:host([disabled]){pointer-events:none;user-select:none}:host([disabled]:not([ondark])) [auro-dropdown],:host([disabled]:not([appearance=inverse])) [auro-dropdown]{--ds-auro-select-border-color: var(--ds-basic-color-border-subtle, #dddddd)}:host(:not([layout*=classic])[disabled][ondark]) [auro-dropdown],:host(:not([layout*=classic])[disabled][appearance=inverse]) [auro-dropdown]{--ds-auro-select-border-color: transparent}`;
6865
6913
 
@@ -6964,6 +7012,16 @@ class AuroSelect extends AuroElement$1 {
6964
7012
  * @private
6965
7013
  */
6966
7014
  this.hasDisplayValueContent = false;
7015
+
7016
+ /**
7017
+ * @private
7018
+ */
7019
+ this.typeaheadBuffer = '';
7020
+
7021
+ /**
7022
+ * @private
7023
+ */
7024
+ this._typeaheadTimeout = null;
6967
7025
  }
6968
7026
 
6969
7027
  /**
@@ -6976,6 +7034,7 @@ class AuroSelect extends AuroElement$1 {
6976
7034
  this.fullscreenBreakpoint = 'sm';
6977
7035
  this.onDark = false;
6978
7036
  this.isPopoverVisible = false;
7037
+ this.typeaheadTimeoutMs = 500;
6979
7038
 
6980
7039
  // Layout Config
6981
7040
  this.layout = 'classic';
@@ -7279,6 +7338,16 @@ class AuroSelect extends AuroElement$1 {
7279
7338
  attribute: false
7280
7339
  },
7281
7340
 
7341
+ /**
7342
+ * Milliseconds of keyboard inactivity before the type-ahead buffer resets.
7343
+ * Increase for users who type slowly.
7344
+ * @default 500
7345
+ */
7346
+ typeaheadTimeoutMs: {
7347
+ type: Number,
7348
+ reflect: true
7349
+ },
7350
+
7282
7351
  /**
7283
7352
  * Specifies the `validityState` this element is in.
7284
7353
  */
@@ -7411,7 +7480,7 @@ class AuroSelect extends AuroElement$1 {
7411
7480
  this.menu.updateActiveOption(this.optionSelected[0]);
7412
7481
  } else {
7413
7482
  // If no activeOption has yet to be set, then make the first enabled option active by default
7414
- const firstActive = this.menu.menuService.menuOptions.find((option) => !option.disabled);
7483
+ const [firstActive] = getEnabledOptions(this.menu);
7415
7484
  this.menu.updateActiveOption(firstActive);
7416
7485
  }
7417
7486
  }
@@ -7635,12 +7704,23 @@ class AuroSelect extends AuroElement$1 {
7635
7704
  this.menu.multiSelect = this.multiSelect;
7636
7705
  }
7637
7706
 
7707
+ // Menu's items are populated by initItems() during its firstUpdated/slotchange.
7708
+ // Since the parent select's firstUpdated runs before the child menu's, call initItems()
7709
+ // here so renderNativeSelect can render the native <option> list on first paint.
7710
+ if (typeof this.menu.initItems === 'function') {
7711
+ this.menu.initItems();
7712
+ }
7638
7713
  this.options = this.menu.options;
7639
7714
  this.updateOptionPositions();
7640
7715
  this.menu.addEventListener("auroMenu-loadingChange", (event) => this.handleMenuLoadingChange(event));
7641
7716
 
7642
- this.menu.addEventListener("auroMenu-deselectPrevented", () => {
7643
- this.hideBib();
7717
+ this.menu.addEventListener("auroMenu-selectValueFailure", () => {
7718
+ this.value = undefined;
7719
+ this.optionSelected = this.multiSelect ? [] : undefined;
7720
+ // The trigger label is rendered imperatively into #value, so a property
7721
+ // change alone won't clear it. Refresh so stale text doesn't linger when
7722
+ // a runtime value change fails to match any option.
7723
+ this.updateDisplayedValue();
7644
7724
  });
7645
7725
 
7646
7726
  this.menu.addEventListener('auroMenu-activatedOption', (evt) => {
@@ -7662,16 +7742,20 @@ class AuroSelect extends AuroElement$1 {
7662
7742
  }
7663
7743
  });
7664
7744
 
7665
- this.menu.addEventListener('auroMenu-selectedOption', (event) => {
7745
+ this.menu.addEventListener('auroMenu-selectedOption', () => {
7666
7746
 
7667
7747
  // Update the displayed value
7668
7748
  this.updateDisplayedValue();
7669
7749
 
7670
- const options = event.detail.options || [];
7671
-
7672
- this.value = event.detail.stringValue;
7750
+ this.value = this.menu.value;
7673
7751
 
7674
- this.optionSelected = this.multiSelect ? options : options[0];
7752
+ // Clone the multiselect array so external mutation of select.optionSelected
7753
+ // can't reach back into menu's internal state through a shared reference.
7754
+ let nextSelected = this.menu.optionSelected;
7755
+ if (this.multiSelect) {
7756
+ nextSelected = Array.isArray(nextSelected) ? [...nextSelected] : [];
7757
+ }
7758
+ this.optionSelected = nextSelected;
7675
7759
 
7676
7760
  if (this.dropdown.isPopoverVisible && !this.multiSelect) {
7677
7761
  this.dropdown.hide();
@@ -7680,7 +7764,7 @@ class AuroSelect extends AuroElement$1 {
7680
7764
 
7681
7765
  // Announce the selection after the dropdown closes so it isn't
7682
7766
  // overridden by VoiceOver's "collapsed" announcement from aria-expanded.
7683
- const selectedValue = event.detail.stringValue;
7767
+ const selectedValue = this.menu.currentLabel;
7684
7768
  const announcementDelay = 300;
7685
7769
  setTimeout(() => {
7686
7770
  announceToScreenReader(this._getAnnouncementRoot(), `${selectedValue}, selected`);
@@ -7703,6 +7787,7 @@ class AuroSelect extends AuroElement$1 {
7703
7787
  this.addEventListener('blur', () => {
7704
7788
  this.validate();
7705
7789
  this.hasFocus = false;
7790
+ this._clearTypeaheadBuffer();
7706
7791
  });
7707
7792
  }
7708
7793
 
@@ -7716,41 +7801,89 @@ class AuroSelect extends AuroElement$1 {
7716
7801
  }
7717
7802
  }
7718
7803
 
7804
+ /**
7805
+ * Returns the lowercase, trimmed text content of a menu option.
7806
+ * @private
7807
+ * @param {HTMLElement} option - The menu option element.
7808
+ * @returns {string}
7809
+ */
7810
+ _getOptionDisplayText(option) {
7811
+ return (option.textContent || '').trim().toLowerCase();
7812
+ }
7813
+
7814
+ /**
7815
+ * Empties the type-ahead buffer and cancels any pending reset timeout.
7816
+ * Called when focus leaves the component, when Escape closes the bib, and on disconnect
7817
+ * so a stale buffer never bridges into a fresh interaction.
7818
+ * @private
7819
+ */
7820
+ _clearTypeaheadBuffer() {
7821
+ if (this._typeaheadTimeout) {
7822
+ clearTimeout(this._typeaheadTimeout);
7823
+ this._typeaheadTimeout = null;
7824
+ }
7825
+ this.typeaheadBuffer = '';
7826
+ }
7827
+
7719
7828
  /**
7720
7829
  * Updates the active option in the menu based on keyboard input.
7830
+ *
7831
+ * Implements the WAI-ARIA APG Listbox type-ahead pattern: accumulates printable
7832
+ * keystrokes into a buffer that resets after `typeaheadTimeoutMs` of inactivity.
7833
+ * A multi-character buffer matches the first option whose displayed text starts
7834
+ * with the buffer; repeating a single character cycles through options that start
7835
+ * with that character.
7721
7836
  * @private
7722
7837
  * @param {string} _key - The key pressed by the user.
7723
7838
  * @returns {void}
7724
7839
  */
7725
7840
  updateActiveOptionBasedOnKey(_key) {
7841
+ // Ignore non-printable keys (Shift, ArrowDown, Tab, etc.)
7842
+ if (typeof _key !== 'string' || _key.length !== 1) {
7843
+ return;
7844
+ }
7726
7845
 
7727
- // Get a lowercase version of the key pressed
7728
- const key = _key.toLowerCase();
7729
-
7730
- // Calculate how many times the same letter has been pressed
7731
- this.sameLetterTimes = key === this.lastLetter ? this.sameLetterTimes + 1 : 0;
7846
+ // No selectable options to match against clear any stale buffer/timer so
7847
+ // Space stays a bib toggle and the next keystroke after fresh options load
7848
+ // starts cleanly. `getActiveOptions` excludes disabled, hidden, and static
7849
+ // options (e.g. `static nomatch` placeholders). Checked BEFORE mutating
7850
+ // the buffer.
7851
+ const options = getActiveOptions(this.menu);
7852
+ if (!options.length) {
7853
+ this._clearTypeaheadBuffer();
7854
+ return;
7855
+ }
7732
7856
 
7733
- // Set last letter for tracking
7734
- this.lastLetter = key;
7857
+ const key = _key.toLowerCase();
7735
7858
 
7736
- // Get all the options that start with the last letter pressed
7737
- const letterOptions = this.menu.options.filter((option) => {
7738
- const optionText = option.value || '';
7739
- return optionText.toLowerCase().startsWith(this.lastLetter);
7740
- });
7859
+ // Reset the buffer after a period of inactivity
7860
+ if (this._typeaheadTimeout) {
7861
+ clearTimeout(this._typeaheadTimeout);
7862
+ }
7863
+ this._typeaheadTimeout = setTimeout(() => {
7864
+ this._clearTypeaheadBuffer();
7865
+ }, this.typeaheadTimeoutMs);
7741
7866
 
7742
- // If we have options that match the letter pressed
7743
- if (letterOptions.length) {
7867
+ this.typeaheadBuffer += key;
7744
7868
 
7745
- // Show the dropdown if it is not already visible
7746
- this.dropdown.show();
7869
+ const isRepeatedChar = this.typeaheadBuffer.length > 1 && new Set(this.typeaheadBuffer).size === 1;
7747
7870
 
7748
- // Get the index we're after based on how many times the letter has been pressed and the length of the letterOptions array
7749
- const index = this.sameLetterTimes < letterOptions.length ? this.sameLetterTimes : this.sameLetterTimes % letterOptions.length;
7871
+ let match = null;
7872
+ if (isRepeatedChar) {
7873
+ const matches = options.filter((option) => this._getOptionDisplayText(option).startsWith(key));
7874
+ if (matches.length) {
7875
+ const cycleIndex = (this.typeaheadBuffer.length - 1) % matches.length;
7876
+ match = matches[cycleIndex];
7877
+ }
7878
+ } else {
7879
+ match = options.find((option) => this._getOptionDisplayText(option).startsWith(this.typeaheadBuffer));
7880
+ }
7750
7881
 
7751
- // Select the new option in the menu
7752
- const newOption = letterOptions[index];
7753
- this.menu.updateActiveOption(newOption);
7882
+ if (match) {
7883
+ if (!this.dropdown.isPopoverVisible) {
7884
+ this.dropdown.show();
7885
+ }
7886
+ this.menu.updateActiveOption(match);
7754
7887
  }
7755
7888
  }
7756
7889
 
@@ -7864,6 +7997,11 @@ class AuroSelect extends AuroElement$1 {
7864
7997
  }
7865
7998
  }
7866
7999
 
8000
+ disconnectedCallback() {
8001
+ super.disconnectedCallback();
8002
+ this._clearTypeaheadBuffer();
8003
+ }
8004
+
7867
8005
  // lifecycle runs only after the element's DOM has been updated the first time
7868
8006
  firstUpdated() {
7869
8007
  // Add the tag name as an attribute if it is different than the component name
@@ -7876,7 +8014,7 @@ class AuroSelect extends AuroElement$1 {
7876
8014
 
7877
8015
  setMenuValue(value) {
7878
8016
  if (!this.menu) return;
7879
- this.menu.value = value;
8017
+ this.menu.selectByValue(value);
7880
8018
  }
7881
8019
 
7882
8020
  /**
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Returns the enabled (non-disabled) options for a menu, safely.
3
+ *
4
+ * Auro-menu's `options` getter returns `undefined` when the menu has no items
5
+ * (initItems sets `items` to undefined for empty menus). Callers that reach for
6
+ * `.find()` / `[...spread]` would otherwise crash; this helper normalizes the
7
+ * empty case to `[]` so array methods are always safe.
8
+ *
9
+ * @param {HTMLElement | null | undefined} menu - The auro-menu element.
10
+ * @returns {Array<HTMLElement>} Non-disabled options, empty array when none.
11
+ */
12
+ export function getEnabledOptions(menu: HTMLElement | null | undefined): Array<HTMLElement>;
13
+ /**
14
+ * Returns the active (selectable + visible) options for type-ahead navigation.
15
+ *
16
+ * Uses auro-menuoption's `isActive` getter, which excludes disabled, hidden,
17
+ * and static options (e.g. `static nomatch` placeholders) so the type-ahead
18
+ * cursor never lands on a non-actionable item. Same empty-safe handling as
19
+ * `getEnabledOptions`.
20
+ *
21
+ * @param {HTMLElement | null | undefined} menu - The auro-menu element.
22
+ * @returns {Array<HTMLElement>} Active options, empty array when none.
23
+ */
24
+ export function getActiveOptions(menu: HTMLElement | null | undefined): Array<HTMLElement>;