@aurodesignsystem-dev/auro-formkit 0.0.0-pr1408.15 → 0.0.0-pr1408.17

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 (58) hide show
  1. package/components/checkbox/demo/api.min.js +1 -1
  2. package/components/checkbox/demo/index.min.js +1 -1
  3. package/components/checkbox/demo/keyboardBehavior.md +0 -0
  4. package/components/checkbox/dist/index.js +1 -1
  5. package/components/checkbox/dist/registered.js +1 -1
  6. package/components/combobox/demo/api.min.js +320 -282
  7. package/components/combobox/demo/index.min.js +320 -282
  8. package/components/combobox/demo/keyboardBehavior.md +9 -36
  9. package/components/combobox/dist/auro-combobox.d.ts +17 -0
  10. package/components/combobox/dist/comboboxKeyboardStrategy.d.ts +6 -3
  11. package/components/combobox/dist/index.js +286 -255
  12. package/components/combobox/dist/registered.js +286 -255
  13. package/components/counter/demo/api.md +1 -1
  14. package/components/counter/demo/api.min.js +202 -146
  15. package/components/counter/demo/index.min.js +202 -146
  16. package/components/counter/dist/auro-counter.d.ts +11 -8
  17. package/components/counter/dist/index.js +202 -146
  18. package/components/counter/dist/keyboardStrategy.d.ts +4 -0
  19. package/components/counter/dist/registered.js +202 -146
  20. package/components/datepicker/demo/api.min.js +148 -137
  21. package/components/datepicker/demo/index.min.js +148 -137
  22. package/components/datepicker/dist/index.js +143 -132
  23. package/components/datepicker/dist/registered.js +143 -132
  24. package/components/dropdown/demo/api.md +29 -29
  25. package/components/dropdown/demo/api.min.js +117 -121
  26. package/components/dropdown/demo/index.min.js +117 -121
  27. package/components/dropdown/dist/auro-dropdown.d.ts +3 -3
  28. package/components/dropdown/dist/auro-dropdownBib.d.ts +1 -40
  29. package/components/dropdown/dist/dropdownBibKeyboardStrategy.d.ts +7 -0
  30. package/components/dropdown/dist/index.js +101 -109
  31. package/components/dropdown/dist/registered.js +101 -109
  32. package/components/form/demo/api.min.js +958 -788
  33. package/components/form/demo/index.min.js +958 -788
  34. package/components/form/demo/keyboardBehavior.md +0 -0
  35. package/components/input/demo/api.min.js +102 -77
  36. package/components/input/demo/index.min.js +102 -77
  37. package/components/input/demo/keyboardBehavior.md +0 -0
  38. package/components/input/dist/auro-input.d.ts +11 -0
  39. package/components/input/dist/base-input.d.ts +1 -0
  40. package/components/input/dist/index.js +32 -18
  41. package/components/input/dist/registered.js +32 -18
  42. package/components/menu/demo/api.min.js +34 -27
  43. package/components/menu/demo/index.min.js +34 -27
  44. package/components/menu/dist/auro-menu.d.ts +0 -6
  45. package/components/menu/dist/index.js +34 -27
  46. package/components/menu/dist/registered.js +34 -27
  47. package/components/radio/demo/api.min.js +1 -1
  48. package/components/radio/demo/index.min.js +1 -1
  49. package/components/radio/dist/index.js +1 -1
  50. package/components/radio/dist/registered.js +1 -1
  51. package/components/select/demo/api.min.js +225 -166
  52. package/components/select/demo/index.min.js +225 -166
  53. package/components/select/demo/keyboardBehavior.md +3 -3
  54. package/components/select/dist/index.js +191 -139
  55. package/components/select/dist/registered.js +191 -139
  56. package/components/select/dist/selectKeyboardStrategy.d.ts +5 -2
  57. package/custom-elements.json +1547 -1466
  58. package/package.json +8 -6
@@ -1184,6 +1184,57 @@ class IconUtil {
1184
1184
  }
1185
1185
  }
1186
1186
 
1187
+ /**
1188
+ * Computes display state once per keydown event.
1189
+ * Centralizes null-safety checks and makes the shared/modal/popover branching explicit.
1190
+ *
1191
+ * @param {HTMLElement} component - The component with a dropdown reference.
1192
+ * @param {Object} [options] - Optional config.
1193
+ * @param {HTMLElement} [options.dropdown] - Explicit dropdown reference. Falls back to component.dropdown.
1194
+ * @param {Function} [options.inputResolver] - Called with (component, ctx) to resolve the active input element.
1195
+ * @returns {{isExpanded: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}}
1196
+ * isModal and isPopover reflect the display mode (fullscreen vs not) regardless of expanded state.
1197
+ */
1198
+ function createDisplayContext$1(component, options = {}) {
1199
+ const dd = options.dropdown || component.dropdown;
1200
+ // isPopoverVisible reflects as the `open` attribute.
1201
+ // It reports whether the bib is open in any mode (popover or modal).
1202
+ const isExpanded = Boolean(dd && dd.isPopoverVisible);
1203
+ const isFullscreen = Boolean(dd && dd.isBibFullscreen);
1204
+
1205
+ const ctx = {
1206
+ isExpanded,
1207
+ isModal: isFullscreen,
1208
+ isPopover: !isFullscreen,
1209
+ activeInput: null,
1210
+ };
1211
+
1212
+ if (options.inputResolver) {
1213
+ const resolvedInput = options.inputResolver(component, ctx);
1214
+ // Guard against resolvers returning undefined or non-HTMLElement values.
1215
+ ctx.activeInput = resolvedInput instanceof HTMLElement ? resolvedInput : null;
1216
+ }
1217
+
1218
+ return ctx;
1219
+ }
1220
+
1221
+ /**
1222
+ * Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
1223
+ * Handles both sync and async handlers.
1224
+ * @param {HTMLElement} component - The component to attach the listener to.
1225
+ * @param {Object} strategy - Map of key names to handler functions.
1226
+ * @param {Object} [options] - Optional config passed to createDisplayContext.
1227
+ */
1228
+ function applyKeyboardStrategy$1(component, strategy, options = {}) {
1229
+ component.addEventListener('keydown', async (evt) => {
1230
+ const handler = strategy[evt.key] || strategy.default;
1231
+ if (typeof handler === 'function') {
1232
+ const ctx = createDisplayContext$1(component, options);
1233
+ await handler(component, evt, ctx);
1234
+ }
1235
+ });
1236
+ }
1237
+
1187
1238
  var plusIcon = {"role":"img","color":"currentColor","title":"","desc":"","width":"var(--auro-size-lg, var(--ds-size-300, 1.5rem))","height":"var(--auro-size-lg, var(--ds-size-300, 1.5rem))","xmlns":"http://www.w3.org/2000/svg","xmlns_xlink":"http://www.w3.org/1999/xlink","viewBox":"0 0 24 24","path":"/icons","style":"ico_squareLarge","type":"icon","name":"plus-lg","category":"interface","svg":"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" aria-hidden=\"true\" class=\"ico_squareLarge\" role=\"img\" style=\"min-width:var(--auro-size-lg, var(--ds-size-300, 1.5rem));height:var(--auro-size-lg, var(--ds-size-300, 1.5rem));fill:currentColor\" viewBox=\"0 0 24 24\" part=\"svg\"><title/><path d=\"M11.898 5.007 12 5a.75.75 0 0 1 .743.648l.007.102v5.5h5.5a.75.75 0 0 1 .743.648L19 12a.75.75 0 0 1-.648.743l-.102.007h-5.501l.001 5.5a.75.75 0 0 1-.648.743L12 19a.75.75 0 0 1-.743-.648l-.007-.102-.001-5.5H5.75a.75.75 0 0 1-.743-.648L5 12a.75.75 0 0 1 .648-.743l.102-.007h5.5v-5.5a.75.75 0 0 1 .648-.743L12 5z\"/></svg>"};
1188
1239
 
1189
1240
  var minusIcon = {"role":"img","color":"currentColor","title":"","desc":"","width":"var(--auro-size-lg, var(--ds-size-300, 1.5rem))","height":"var(--auro-size-lg, var(--ds-size-300, 1.5rem))","xmlns":"http://www.w3.org/2000/svg","xmlns_xlink":"http://www.w3.org/1999/xlink","viewBox":"0 0 24 24","path":"/icons","style":"ico_squareLarge","type":"icon","name":"minus-lg","category":"interface","deprecated":true,"svg":"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" aria-hidden=\"true\" class=\"ico_squareLarge\" data-deprecated=\"true\" role=\"img\" style=\"min-width:var(--auro-size-lg, var(--ds-size-300, 1.5rem));height:var(--auro-size-lg, var(--ds-size-300, 1.5rem));fill:currentColor\" viewBox=\"0 0 24 24\" part=\"svg\"><title/><path d=\"M5.75 12.75h12.5a.75.75 0 1 0 0-1.5H5.75a.75.75 0 1 0 0 1.5\"/></svg>"};
@@ -1420,7 +1471,30 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
1420
1471
  }
1421
1472
  };
1422
1473
 
1423
- var formkitVersion$1 = '202603310527';
1474
+ var formkitVersion$1 = '202604031704';
1475
+
1476
+ // Copyright (c) 2026 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1477
+ // See LICENSE in the project root for license information.
1478
+
1479
+ const keyboardStrategy = {
1480
+ ArrowUp(component, _evt) {
1481
+ if (component.disabled) {
1482
+ return;
1483
+ }
1484
+
1485
+ _evt.preventDefault();
1486
+ component.increment();
1487
+ },
1488
+
1489
+ ArrowDown(component, _evt) {
1490
+ if (component.disabled) {
1491
+ return;
1492
+ }
1493
+
1494
+ _evt.preventDefault();
1495
+ component.decrement();
1496
+ }
1497
+ };
1424
1498
 
1425
1499
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1426
1500
  // See LICENSE in the project root for license information.
@@ -1494,14 +1568,36 @@ class AuroCounter extends LitElement {
1494
1568
 
1495
1569
  connectedCallback() {
1496
1570
  super.connectedCallback();
1497
- this.addEventListener('keydown', this.handleKeyDown);
1571
+ applyKeyboardStrategy$1(this, keyboardStrategy);
1498
1572
  }
1499
1573
 
1500
1574
  disconnectedCallback() {
1501
- this.removeEventListener('keydown', this.handleKeyDown);
1502
1575
  super.disconnectedCallback();
1503
1576
  }
1504
1577
 
1578
+ /**
1579
+ * Gets the current value of the counter.
1580
+ * @returns {number|undefined} The current value of the counter, or undefined if the value is not set or invalid.
1581
+ */
1582
+ get value() {
1583
+ return this._value;
1584
+ }
1585
+
1586
+ /**
1587
+ * Sets the value of the counter. If the provided value is undefined, null, or cannot be converted to a number, the internal value will be set to undefined.
1588
+ * @param {number|string|undefined|null} val - The value to set for the counter. Can be a number, a string that can be converted to a number, undefined, or null.
1589
+ */
1590
+ set value(val) {
1591
+ const old = this._value;
1592
+ if (val === undefined || val === null) {
1593
+ this._value = undefined;
1594
+ } else {
1595
+ const num = Number(val);
1596
+ this._value = Number.isNaN(num) ? undefined : num;
1597
+ }
1598
+ this.requestUpdate('value', old);
1599
+ }
1600
+
1505
1601
  /**
1506
1602
  * Defines reactive properties for the component.
1507
1603
  * @returns {Object} Property configuration.
@@ -1686,29 +1782,6 @@ class AuroCounter extends LitElement {
1686
1782
  this.validation.validate(this, force);
1687
1783
  }
1688
1784
 
1689
- /**
1690
- * Handles the keydown event for the counter component.
1691
- * @param {KeyboardEvent} event - The keyboard event object.
1692
- * @returns {void}
1693
- * @private
1694
- */
1695
- handleKeyDown(event) {
1696
- if (this.disabled) {
1697
- return;
1698
- }
1699
-
1700
- switch (event.key) {
1701
- case 'ArrowUp':
1702
- event.preventDefault();
1703
- this.increment();
1704
- break;
1705
- case 'ArrowDown':
1706
- event.preventDefault();
1707
- this.decrement();
1708
- break;
1709
- }
1710
- }
1711
-
1712
1785
  firstUpdated() {
1713
1786
  this.initValue();
1714
1787
  this.setTagAttribute("auro-counter");
@@ -3651,6 +3724,11 @@ class AuroFloatingUI {
3651
3724
  this.clickHandler = null;
3652
3725
  this.keyDownHandler = null;
3653
3726
 
3727
+ /**
3728
+ * @private
3729
+ */
3730
+ this.enableKeyboardHandling = true;
3731
+
3654
3732
  /**
3655
3733
  * @private
3656
3734
  */
@@ -3911,11 +3989,10 @@ class AuroFloatingUI {
3911
3989
  return;
3912
3990
  }
3913
3991
 
3914
- const { activeElement } = document;
3915
3992
  // if focus is still inside of trigger or bib, do not close
3916
3993
  if (
3917
- this.element.contains(activeElement) ||
3918
- this.element.bib?.contains(activeElement)
3994
+ this.element.matches(":focus") ||
3995
+ this.element.matches(":focus-within")
3919
3996
  ) {
3920
3997
  return;
3921
3998
  }
@@ -3986,7 +4063,9 @@ class AuroFloatingUI {
3986
4063
  document.addEventListener("focusin", this.focusHandler);
3987
4064
  }
3988
4065
 
3989
- document.addEventListener("keydown", this.keyDownHandler);
4066
+ if (this.enableKeyboardHandling) {
4067
+ document.addEventListener("keydown", this.keyDownHandler);
4068
+ }
3990
4069
 
3991
4070
  // send this task to the end of queue to prevent conflicting
3992
4071
  // it conflicts if showBib gets call from a button that's not this.element.trigger
@@ -4242,8 +4321,9 @@ class AuroFloatingUI {
4242
4321
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
4243
4322
  }
4244
4323
 
4245
- configure(elem, eventPrefix) {
4324
+ configure(elem, eventPrefix, enableKeyboardHandling = true) {
4246
4325
  AuroFloatingUI.setupMousePressChecker();
4326
+ this.enableKeyboardHandling = enableKeyboardHandling;
4247
4327
 
4248
4328
  this.eventPrefix = eventPrefix;
4249
4329
  if (this.element !== elem) {
@@ -4276,7 +4356,9 @@ class AuroFloatingUI {
4276
4356
 
4277
4357
  this.handleEvent = this.handleEvent.bind(this);
4278
4358
  if (this.element.trigger) {
4279
- this.element.trigger.addEventListener("keydown", this.handleEvent);
4359
+ if (this.enableKeyboardHandling) {
4360
+ this.element.trigger.addEventListener("keydown", this.handleEvent);
4361
+ }
4280
4362
  this.element.trigger.addEventListener("click", this.handleEvent);
4281
4363
  this.element.trigger.addEventListener("mouseenter", this.handleEvent);
4282
4364
  this.element.trigger.addEventListener("mouseleave", this.handleEvent);
@@ -4754,12 +4836,83 @@ let p$2 = class p{registerComponent(t,a){customElements.get(t)||customElements.d
4754
4836
 
4755
4837
  var iconVersion$1 = '9.1.2';
4756
4838
 
4839
+ /**
4840
+ * Computes display state once per keydown event.
4841
+ * Centralizes null-safety checks and makes the shared/modal/popover branching explicit.
4842
+ *
4843
+ * @param {HTMLElement} component - The component with a dropdown reference.
4844
+ * @param {Object} [options] - Optional config.
4845
+ * @param {HTMLElement} [options.dropdown] - Explicit dropdown reference. Falls back to component.dropdown.
4846
+ * @param {Function} [options.inputResolver] - Called with (component, ctx) to resolve the active input element.
4847
+ * @returns {{isExpanded: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}}
4848
+ * isModal and isPopover reflect the display mode (fullscreen vs not) regardless of expanded state.
4849
+ */
4850
+ function createDisplayContext(component, options = {}) {
4851
+ const dd = options.dropdown || component.dropdown;
4852
+ // isPopoverVisible reflects as the `open` attribute.
4853
+ // It reports whether the bib is open in any mode (popover or modal).
4854
+ const isExpanded = Boolean(dd && dd.isPopoverVisible);
4855
+ const isFullscreen = Boolean(dd && dd.isBibFullscreen);
4856
+
4857
+ const ctx = {
4858
+ isExpanded,
4859
+ isModal: isFullscreen,
4860
+ isPopover: !isFullscreen,
4861
+ activeInput: null,
4862
+ };
4863
+
4864
+ if (options.inputResolver) {
4865
+ const resolvedInput = options.inputResolver(component, ctx);
4866
+ // Guard against resolvers returning undefined or non-HTMLElement values.
4867
+ ctx.activeInput = resolvedInput instanceof HTMLElement ? resolvedInput : null;
4868
+ }
4869
+
4870
+ return ctx;
4871
+ }
4872
+
4873
+ /**
4874
+ * Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
4875
+ * Handles both sync and async handlers.
4876
+ * @param {HTMLElement} component - The component to attach the listener to.
4877
+ * @param {Object} strategy - Map of key names to handler functions.
4878
+ * @param {Object} [options] - Optional config passed to createDisplayContext.
4879
+ */
4880
+ function applyKeyboardStrategy(component, strategy, options = {}) {
4881
+ component.addEventListener('keydown', async (evt) => {
4882
+ const handler = strategy[evt.key] || strategy.default;
4883
+ if (typeof handler === 'function') {
4884
+ const ctx = createDisplayContext(component, options);
4885
+ await handler(component, evt, ctx);
4886
+ }
4887
+ });
4888
+ }
4889
+
4757
4890
  var styleCss$2 = css`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host(:popover-open){position:fixed;overflow:visible;padding:0;border:none;margin:0;background:transparent;inset:unset;outline:none}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
4758
4891
 
4759
4892
  var colorCss$2 = css`.container{background-color:var(--ds-auro-dropdownbib-container-color);box-shadow:var(--ds-auro-dropdownbib-boxshadow-color);color:var(--ds-auro-dropdownbib-text-color)}`;
4760
4893
 
4761
4894
  var tokensCss$1 = css`:host(:not([ondark])),:host(:not([appearance=inverse])){--ds-auro-dropdown-label-text-color: var(--ds-basic-color-texticon-muted, #676767);--ds-auro-dropdown-trigger-background-color: var(--ds-basic-color-surface-default, #ffffff);--ds-auro-dropdown-trigger-hover-background-color: var(--ds-basic-color-surface-default, #ffffff);--ds-auro-dropdown-trigger-container-color: var(--ds-basic-color-surface-default, #ffffff);--ds-auro-dropdown-trigger-border-color: var(--ds-basic-color-border-bold, #585e67);--ds-auro-dropdown-trigger-outline-color: transparent;--ds-auro-dropdown-trigger-text-color: var(--ds-basic-color-texticon-default, #2a2a2a);--ds-auro-dropdownbib-boxshadow-color: var(--ds-elevation-200, 0px 0px 10px rgba(0, 0, 0, 0.15));--ds-auro-dropdownbib-background-color: var(--ds-basic-color-surface-default, #ffffff);--ds-auro-dropdownbib-container-color: var(--ds-basic-color-surface-default, #ffffff);--ds-auro-dropdownbib-text-color: var(--ds-basic-color-texticon-default, #2a2a2a)}:host([ondark]),:host([appearance=inverse]){--ds-auro-dropdown-label-text-color: var(--ds-basic-color-texticon-inverse-muted, #ccd2db);--ds-auro-dropdown-trigger-background-color: var(--ds-advanced-color-shared-background-inverse, rgba(255, 255, 255, 0.15));--ds-auro-dropdown-trigger-hover-background-color: var(--ds-advanced-color-shared-background-inverse, rgba(255, 255, 255, 0.15));--ds-auro-dropdown-trigger-container-color: var(--ds-advanced-color-shared-background-inverse, rgba(255, 255, 255, 0.15));--ds-auro-dropdown-trigger-border-color: var(--ds-basic-color-border-inverse, #ffffff);--ds-auro-dropdown-trigger-outline-color: transparent;--ds-auro-dropdown-trigger-text-color: var(--ds-basic-color-texticon-inverse, #ffffff);--ds-auro-dropdownbib-boxshadow-color: var(--ds-elevation-200, 0px 0px 10px rgba(0, 0, 0, 0.15));--ds-auro-dropdownbib-background-color: var(--ds-advanced-color-shared-background-inverse, rgba(255, 255, 255, 0.15));--ds-auro-dropdownbib-container-color: var(--ds-advanced-color-shared-background-inverse, rgba(255, 255, 255, 0.15));--ds-auro-dropdownbib-text-color: var(--ds-basic-color-texticon-inverse, #ffffff)}`;
4762
4895
 
4896
+ /**
4897
+ * Creates a keyboard strategy for dialog-specific key handling.
4898
+ * All other keydown behavior is left to the browser's native bubbling path.
4899
+ * @param {HTMLElement} bib - The dropdown bib element.
4900
+ * @returns {Object} Keyboard handlers keyed by `event.key`.
4901
+ */
4902
+ // eslint-disable-next-line no-unused-vars
4903
+ function createDropdownBibKeyboardStrategy(bib) {
4904
+ return {
4905
+ // eslint-disable-next-line no-unused-vars
4906
+ Enter(_dialog, event) {
4907
+ // Floating UI handles Enter key to open the dropdown
4908
+ },
4909
+ // eslint-disable-next-line no-unused-vars
4910
+ Escape(_dialog, event) {
4911
+ // Floating UI handles Escape key to close the dropdown
4912
+ }
4913
+ };
4914
+ }
4915
+
4763
4916
  // Copyright (c) 2020 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
4764
4917
  // See LICENSE in the project root for license information.
4765
4918
  /* eslint-disable max-lines */
@@ -4884,11 +5037,7 @@ class AuroDropdownBib extends LitElement {
4884
5037
  },
4885
5038
 
4886
5039
  /**
4887
- * Set by auro-dropdown when a menu option is highlighted via
4888
- * aria-activedescendant. The dialog keyboard bridge checks this
4889
- * flag so that Enter selects the highlighted option instead of
4890
- * activating the focused interactive element (e.g. the trigger
4891
- * button, or the bibtemplate close button in fullscreen).
5040
+ * Tracks whether a menu option is currently highlighted.
4892
5041
  * @private
4893
5042
  */
4894
5043
  hasActiveDescendant: {
@@ -4962,7 +5111,7 @@ class AuroDropdownBib extends LitElement {
4962
5111
 
4963
5112
  const dialog = this.shadowRoot.querySelector('dialog');
4964
5113
  this._setupCancelHandler(dialog);
4965
- this._setupKeyboardBridge(dialog);
5114
+ applyKeyboardStrategy(dialog, createDropdownBibKeyboardStrategy());
4966
5115
 
4967
5116
  this.dispatchEvent(new CustomEvent('auro-dropdownbib-connected', {
4968
5117
  bubbles: true,
@@ -4989,92 +5138,6 @@ class AuroDropdownBib extends LitElement {
4989
5138
  });
4990
5139
  }
4991
5140
 
4992
- /**
4993
- * showModal() creates a closed focus scope — keyboard events inside
4994
- * the dialog's shadow DOM do NOT bubble out to the combobox/select
4995
- * keydown handlers in the parent shadow DOM. This handler bridges
4996
- * that gap by re-dispatching navigation keys so they cross the
4997
- * shadow boundary and reach the menu navigation logic in the parent
4998
- * component.
4999
- *
5000
- * The trade-off: intercepting these keys means native keyboard
5001
- * behaviors that would normally "just work" must be manually
5002
- * re-implemented here:
5003
- *
5004
- * - Enter on buttons: Custom elements (auro-button) don't get the
5005
- * native Enter→click that <button> provides, so we call .click()
5006
- * directly when Enter is pressed on a button-like element.
5007
- *
5008
- * - Tab: Intercepted and re-dispatched so parent components
5009
- * (select/combobox) can select the active option and close the
5010
- * dialog. The <dialog> provides containment and isolation
5011
- * (inert background, VoiceOver focus trapping, top layer), while
5012
- * the content inside is a role="listbox" navigated via
5013
- * aria-activedescendant (options are not focusable). Tab keyboard
5014
- * behavior follows listbox conventions (select + close) because
5015
- * the dialog's native Tab trap only cycles between the close
5016
- * button and browser chrome.
5017
- *
5018
- * - Escape: The native <dialog> fires a `cancel` event on ESC
5019
- * (handled by _setupCancelHandler), so the re-dispatched Escape
5020
- * is a secondary path for parent components that also listen for
5021
- * Escape keydown.
5022
- *
5023
- * @param {HTMLDialogElement} dialog - The dialog element to attach the keyboard bridge to.
5024
- * @private
5025
- */
5026
- _setupKeyboardBridge(dialog) {
5027
- const navKeys = new Set([
5028
- 'ArrowUp',
5029
- 'ArrowDown',
5030
- 'Enter',
5031
- 'Escape',
5032
- 'Tab'
5033
- ]);
5034
-
5035
- dialog.addEventListener('keydown', (event) => {
5036
- if (!navKeys.has(event.key)) {
5037
- return;
5038
- }
5039
-
5040
- // Custom elements (auro-button) don't get the native Enter→click
5041
- // behavior that <button> has. Find the button in the composed path
5042
- // and click it directly — but only when no menu option is
5043
- // highlighted. In fullscreen mode focus stays on the close button
5044
- // while arrow keys move the active-descendant highlight through
5045
- // the listbox. If the user presses Enter with an option
5046
- // highlighted, the intent is to select that option, not to click
5047
- // the close button. In that case we fall through and bridge the
5048
- // Enter key to the parent component's keyboard strategy.
5049
- if (event.key === 'Enter') {
5050
- if (!this.hasActiveDescendant) {
5051
- const buttonSelector = 'button, [role="button"], auro-button, [auro-button]';
5052
- const btn = event.composedPath().find((el) => el.matches && el.matches(buttonSelector));
5053
- if (btn) {
5054
- event.preventDefault();
5055
- event.stopPropagation();
5056
- btn.click();
5057
- return;
5058
- }
5059
- }
5060
- }
5061
-
5062
- event.preventDefault();
5063
- event.stopPropagation();
5064
- const newEvent = new KeyboardEvent('keydown', {
5065
- key: event.key,
5066
- code: event.code,
5067
- shiftKey: event.shiftKey,
5068
- altKey: event.altKey,
5069
- ctrlKey: event.ctrlKey,
5070
- metaKey: event.metaKey,
5071
- bubbles: true,
5072
- composed: true,
5073
- cancelable: true
5074
- });
5075
- this.dispatchEvent(newEvent);
5076
- });
5077
- }
5078
5141
 
5079
5142
  /**
5080
5143
  * Blocks touch-driven page scroll while a fullscreen modal dialog is open.
@@ -5449,7 +5512,7 @@ class AuroHelpText extends LitElement {
5449
5512
  }
5450
5513
  }
5451
5514
 
5452
- var formkitVersion = '202603310527';
5515
+ var formkitVersion = '202604031704';
5453
5516
 
5454
5517
  let AuroElement$1 = class AuroElement extends LitElement {
5455
5518
  static get properties() {
@@ -5630,7 +5693,7 @@ class AuroDropdown extends AuroElement$1 {
5630
5693
  this.appearance = 'default';
5631
5694
  this.chevron = false;
5632
5695
  this.disabled = false;
5633
- this.disableFocusTrap = false;
5696
+ this.disableKeyboardHandling = false;
5634
5697
  this.error = false;
5635
5698
  this.tabIndex = 0;
5636
5699
  this.noToggle = false;
@@ -5728,9 +5791,8 @@ class AuroDropdown extends AuroElement$1 {
5728
5791
  // showModal() fires asynchronously via Lit's update cycle, which
5729
5792
  // falls outside the user activation window and causes iOS to
5730
5793
  // dismiss the keyboard.
5731
- if (this.isBibFullscreen && this.bibElement && this.bibElement.value) {
5732
- const useModal = !this.disableFocusTrap;
5733
- this.bibElement.value.open(useModal);
5794
+ if (this.bibElement && this.bibElement.value) {
5795
+ this.bibElement.value.open(this.isBibFullscreen);
5734
5796
  }
5735
5797
  }
5736
5798
 
@@ -5844,9 +5906,9 @@ class AuroDropdown extends AuroElement$1 {
5844
5906
  },
5845
5907
 
5846
5908
  /**
5847
- * If declared, the focus trap inside of bib will be turned off.
5909
+ * If declared, the dropdown will not handle keyboard events and will require the consumer to manage this behavior.
5848
5910
  */
5849
- disableFocusTrap: {
5911
+ disableKeyboardHandling: {
5850
5912
  type: Boolean,
5851
5913
  reflect: true
5852
5914
  },
@@ -6124,7 +6186,7 @@ class AuroDropdown extends AuroElement$1 {
6124
6186
  if (this.isPopoverVisible) {
6125
6187
  // Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
6126
6188
  // Desktop: use show() for Floating UI positioning + FocusTrap for focus management
6127
- const useModal = this.isBibFullscreen && !this.disableFocusTrap;
6189
+ const useModal = this.isBibFullscreen;
6128
6190
  this.bibElement.value.open(useModal);
6129
6191
  } else {
6130
6192
  this.bibElement.value.close();
@@ -6134,7 +6196,7 @@ class AuroDropdown extends AuroElement$1 {
6134
6196
  // When fullscreen strategy changes while open, re-open dialog with correct mode
6135
6197
  // (e.g. resizing from desktop → mobile while dropdown is open)
6136
6198
  if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
6137
- const useModal = this.isBibFullscreen && !this.disableFocusTrap;
6199
+ const useModal = this.isBibFullscreen;
6138
6200
  this.bibElement.value.close();
6139
6201
  this.bibElement.value.open(useModal);
6140
6202
  }
@@ -6156,7 +6218,7 @@ class AuroDropdown extends AuroElement$1 {
6156
6218
 
6157
6219
  firstUpdated() {
6158
6220
  // Configure the floater to, this will generate the ID for the bib
6159
- this.floater.configure(this, 'auroDropdown');
6221
+ this.floater.configure(this, 'auroDropdown', !this.disableKeyboardHandling);
6160
6222
 
6161
6223
  // Prevent `contain: layout` on the dropdown host. Layout containment
6162
6224
  // creates a containing block for position:fixed descendants (the bib),
@@ -6246,7 +6308,7 @@ class AuroDropdown extends AuroElement$1 {
6246
6308
  * @private
6247
6309
  */
6248
6310
  updateFocusTrap() {
6249
- if (this.isPopoverVisible && !this.disableFocusTrap) {
6311
+ if (this.isPopoverVisible) {
6250
6312
  if (!this.isBibFullscreen) {
6251
6313
  // Desktop: show() doesn't trap focus, so use FocusTrap
6252
6314
  this.focusTrap = new FocusTrap(this.bibContent);
@@ -6464,6 +6526,7 @@ class AuroDropdown extends AuroElement$1 {
6464
6526
  aria-expanded="${ifDefined(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
6465
6527
  aria-controls="${ifDefined(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.dropdownId)}"
6466
6528
  aria-labelledby="${ifDefined(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
6529
+ aria-disabled="${ifDefined(this.disabled ? 'true' : undefined)}"
6467
6530
  @focusin="${this.handleFocusin}"
6468
6531
  @blur="${this.handleFocusOut}">
6469
6532
  <div class="triggerContentWrapper" id="triggerLabel">
@@ -7446,6 +7509,7 @@ class AuroCounterGroup extends AuroElement {
7446
7509
  counter.addEventListener("input", this.updateValue);
7447
7510
  counter.addEventListener("auroFormElement-validated", this.updateValidity);
7448
7511
  });
7512
+ this.updateValue();
7449
7513
  }
7450
7514
 
7451
7515
  /**
@@ -7576,6 +7640,8 @@ class AuroCounterGroup extends AuroElement {
7576
7640
  counter.addEventListener("auroFormElement-validated", this.updateValidity);
7577
7641
  });
7578
7642
 
7643
+ this.updateValue();
7644
+
7579
7645
  if (this.isDropdown) {
7580
7646
  this.configureBibtemplate();
7581
7647
  }
@@ -7601,15 +7667,6 @@ class AuroCounterGroup extends AuroElement {
7601
7667
  });
7602
7668
  }
7603
7669
  });
7604
-
7605
- // Tab closes the fullscreen dialog
7606
- // The dialog event bridge intercepts Tab and re-dispatches it as a
7607
- // composed keydown; this listener catches the re-dispatched event.
7608
- this.addEventListener('keydown', (evt) => {
7609
- if (evt.key === 'Tab' && this.dropdown.isPopoverVisible && this.dropdown.isBibFullscreen) {
7610
- this.dropdown.hide();
7611
- }
7612
- });
7613
7670
  }
7614
7671
 
7615
7672
  /**
@@ -7799,8 +7856,7 @@ class AuroCounterGroup extends AuroElement {
7799
7856
  */
7800
7857
  renderCounterDropdown() {
7801
7858
  return html`
7802
- <${this.dropdownTag}
7803
- noHideOnThisFocusLoss
7859
+ <${this.dropdownTag}
7804
7860
  chevron
7805
7861
  part="dropdown"
7806
7862
  appearance="${this.onDark ? 'inverse' : this.appearance}"
@@ -0,0 +1,4 @@
1
+ export namespace keyboardStrategy {
2
+ function ArrowUp(component: any, _evt: any): void;
3
+ function ArrowDown(component: any, _evt: any): void;
4
+ }