@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
@@ -1234,6 +1234,57 @@ class IconUtil {
1234
1234
  * SPDX-License-Identifier: BSD-3-Clause
1235
1235
  */let e$1 = class e extends i{constructor(i){if(super(i),this.it=A$2,i.type!==t.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(r){if(r===A$2||null==r)return this._t=void 0,this.it=r;if(r===E)return r;if("string"!=typeof r)throw Error(this.constructor.directiveName+"() called with a non-string value");if(r===this.it)return this._t;this.it=r;const s=[r];return s.raw=s,this._t={_$litType$:this.constructor.resultType,strings:s,values:[]}}};e$1.directiveName="unsafeHTML",e$1.resultType=1;
1236
1236
 
1237
+ /**
1238
+ * Computes display state once per keydown event.
1239
+ * Centralizes null-safety checks and makes the shared/modal/popover branching explicit.
1240
+ *
1241
+ * @param {HTMLElement} component - The component with a dropdown reference.
1242
+ * @param {Object} [options] - Optional config.
1243
+ * @param {HTMLElement} [options.dropdown] - Explicit dropdown reference. Falls back to component.dropdown.
1244
+ * @param {Function} [options.inputResolver] - Called with (component, ctx) to resolve the active input element.
1245
+ * @returns {{isExpanded: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}}
1246
+ * isModal and isPopover reflect the display mode (fullscreen vs not) regardless of expanded state.
1247
+ */
1248
+ function createDisplayContext$1(component, options = {}) {
1249
+ const dd = options.dropdown || component.dropdown;
1250
+ // isPopoverVisible reflects as the `open` attribute.
1251
+ // It reports whether the bib is open in any mode (popover or modal).
1252
+ const isExpanded = Boolean(dd && dd.isPopoverVisible);
1253
+ const isFullscreen = Boolean(dd && dd.isBibFullscreen);
1254
+
1255
+ const ctx = {
1256
+ isExpanded,
1257
+ isModal: isFullscreen,
1258
+ isPopover: !isFullscreen,
1259
+ activeInput: null,
1260
+ };
1261
+
1262
+ if (options.inputResolver) {
1263
+ const resolvedInput = options.inputResolver(component, ctx);
1264
+ // Guard against resolvers returning undefined or non-HTMLElement values.
1265
+ ctx.activeInput = resolvedInput instanceof HTMLElement ? resolvedInput : null;
1266
+ }
1267
+
1268
+ return ctx;
1269
+ }
1270
+
1271
+ /**
1272
+ * Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
1273
+ * Handles both sync and async handlers.
1274
+ * @param {HTMLElement} component - The component to attach the listener to.
1275
+ * @param {Object} strategy - Map of key names to handler functions.
1276
+ * @param {Object} [options] - Optional config passed to createDisplayContext.
1277
+ */
1278
+ function applyKeyboardStrategy$1(component, strategy, options = {}) {
1279
+ component.addEventListener('keydown', async (evt) => {
1280
+ const handler = strategy[evt.key] || strategy.default;
1281
+ if (typeof handler === 'function') {
1282
+ const ctx = createDisplayContext$1(component, options);
1283
+ await handler(component, evt, ctx);
1284
+ }
1285
+ });
1286
+ }
1287
+
1237
1288
  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>"};
1238
1289
 
1239
1290
  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>"};
@@ -1470,7 +1521,30 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
1470
1521
  }
1471
1522
  };
1472
1523
 
1473
- var formkitVersion$1 = '202603310527';
1524
+ var formkitVersion$1 = '202604031704';
1525
+
1526
+ // Copyright (c) 2026 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1527
+ // See LICENSE in the project root for license information.
1528
+
1529
+ const keyboardStrategy = {
1530
+ ArrowUp(component, _evt) {
1531
+ if (component.disabled) {
1532
+ return;
1533
+ }
1534
+
1535
+ _evt.preventDefault();
1536
+ component.increment();
1537
+ },
1538
+
1539
+ ArrowDown(component, _evt) {
1540
+ if (component.disabled) {
1541
+ return;
1542
+ }
1543
+
1544
+ _evt.preventDefault();
1545
+ component.decrement();
1546
+ }
1547
+ };
1474
1548
 
1475
1549
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1476
1550
  // See LICENSE in the project root for license information.
@@ -1544,14 +1618,36 @@ class AuroCounter extends i$2 {
1544
1618
 
1545
1619
  connectedCallback() {
1546
1620
  super.connectedCallback();
1547
- this.addEventListener('keydown', this.handleKeyDown);
1621
+ applyKeyboardStrategy$1(this, keyboardStrategy);
1548
1622
  }
1549
1623
 
1550
1624
  disconnectedCallback() {
1551
- this.removeEventListener('keydown', this.handleKeyDown);
1552
1625
  super.disconnectedCallback();
1553
1626
  }
1554
1627
 
1628
+ /**
1629
+ * Gets the current value of the counter.
1630
+ * @returns {number|undefined} The current value of the counter, or undefined if the value is not set or invalid.
1631
+ */
1632
+ get value() {
1633
+ return this._value;
1634
+ }
1635
+
1636
+ /**
1637
+ * 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.
1638
+ * @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.
1639
+ */
1640
+ set value(val) {
1641
+ const old = this._value;
1642
+ if (val === undefined || val === null) {
1643
+ this._value = undefined;
1644
+ } else {
1645
+ const num = Number(val);
1646
+ this._value = Number.isNaN(num) ? undefined : num;
1647
+ }
1648
+ this.requestUpdate('value', old);
1649
+ }
1650
+
1555
1651
  /**
1556
1652
  * Defines reactive properties for the component.
1557
1653
  * @returns {Object} Property configuration.
@@ -1736,29 +1832,6 @@ class AuroCounter extends i$2 {
1736
1832
  this.validation.validate(this, force);
1737
1833
  }
1738
1834
 
1739
- /**
1740
- * Handles the keydown event for the counter component.
1741
- * @param {KeyboardEvent} event - The keyboard event object.
1742
- * @returns {void}
1743
- * @private
1744
- */
1745
- handleKeyDown(event) {
1746
- if (this.disabled) {
1747
- return;
1748
- }
1749
-
1750
- switch (event.key) {
1751
- case 'ArrowUp':
1752
- event.preventDefault();
1753
- this.increment();
1754
- break;
1755
- case 'ArrowDown':
1756
- event.preventDefault();
1757
- this.decrement();
1758
- break;
1759
- }
1760
- }
1761
-
1762
1835
  firstUpdated() {
1763
1836
  this.initValue();
1764
1837
  this.setTagAttribute("auro-counter");
@@ -3719,6 +3792,11 @@ class AuroFloatingUI {
3719
3792
  this.clickHandler = null;
3720
3793
  this.keyDownHandler = null;
3721
3794
 
3795
+ /**
3796
+ * @private
3797
+ */
3798
+ this.enableKeyboardHandling = true;
3799
+
3722
3800
  /**
3723
3801
  * @private
3724
3802
  */
@@ -3979,11 +4057,10 @@ class AuroFloatingUI {
3979
4057
  return;
3980
4058
  }
3981
4059
 
3982
- const { activeElement } = document;
3983
4060
  // if focus is still inside of trigger or bib, do not close
3984
4061
  if (
3985
- this.element.contains(activeElement) ||
3986
- this.element.bib?.contains(activeElement)
4062
+ this.element.matches(":focus") ||
4063
+ this.element.matches(":focus-within")
3987
4064
  ) {
3988
4065
  return;
3989
4066
  }
@@ -4054,7 +4131,9 @@ class AuroFloatingUI {
4054
4131
  document.addEventListener("focusin", this.focusHandler);
4055
4132
  }
4056
4133
 
4057
- document.addEventListener("keydown", this.keyDownHandler);
4134
+ if (this.enableKeyboardHandling) {
4135
+ document.addEventListener("keydown", this.keyDownHandler);
4136
+ }
4058
4137
 
4059
4138
  // send this task to the end of queue to prevent conflicting
4060
4139
  // it conflicts if showBib gets call from a button that's not this.element.trigger
@@ -4310,8 +4389,9 @@ class AuroFloatingUI {
4310
4389
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
4311
4390
  }
4312
4391
 
4313
- configure(elem, eventPrefix) {
4392
+ configure(elem, eventPrefix, enableKeyboardHandling = true) {
4314
4393
  AuroFloatingUI.setupMousePressChecker();
4394
+ this.enableKeyboardHandling = enableKeyboardHandling;
4315
4395
 
4316
4396
  this.eventPrefix = eventPrefix;
4317
4397
  if (this.element !== elem) {
@@ -4344,7 +4424,9 @@ class AuroFloatingUI {
4344
4424
 
4345
4425
  this.handleEvent = this.handleEvent.bind(this);
4346
4426
  if (this.element.trigger) {
4347
- this.element.trigger.addEventListener("keydown", this.handleEvent);
4427
+ if (this.enableKeyboardHandling) {
4428
+ this.element.trigger.addEventListener("keydown", this.handleEvent);
4429
+ }
4348
4430
  this.element.trigger.addEventListener("click", this.handleEvent);
4349
4431
  this.element.trigger.addEventListener("mouseenter", this.handleEvent);
4350
4432
  this.element.trigger.addEventListener("mouseleave", this.handleEvent);
@@ -4822,12 +4904,83 @@ let p$2 = class p{registerComponent(t,a){customElements.get(t)||customElements.d
4822
4904
 
4823
4905
  var iconVersion$1 = '9.1.2';
4824
4906
 
4907
+ /**
4908
+ * Computes display state once per keydown event.
4909
+ * Centralizes null-safety checks and makes the shared/modal/popover branching explicit.
4910
+ *
4911
+ * @param {HTMLElement} component - The component with a dropdown reference.
4912
+ * @param {Object} [options] - Optional config.
4913
+ * @param {HTMLElement} [options.dropdown] - Explicit dropdown reference. Falls back to component.dropdown.
4914
+ * @param {Function} [options.inputResolver] - Called with (component, ctx) to resolve the active input element.
4915
+ * @returns {{isExpanded: boolean, isModal: boolean, isPopover: boolean, activeInput: HTMLElement|null}}
4916
+ * isModal and isPopover reflect the display mode (fullscreen vs not) regardless of expanded state.
4917
+ */
4918
+ function createDisplayContext(component, options = {}) {
4919
+ const dd = options.dropdown || component.dropdown;
4920
+ // isPopoverVisible reflects as the `open` attribute.
4921
+ // It reports whether the bib is open in any mode (popover or modal).
4922
+ const isExpanded = Boolean(dd && dd.isPopoverVisible);
4923
+ const isFullscreen = Boolean(dd && dd.isBibFullscreen);
4924
+
4925
+ const ctx = {
4926
+ isExpanded,
4927
+ isModal: isFullscreen,
4928
+ isPopover: !isFullscreen,
4929
+ activeInput: null,
4930
+ };
4931
+
4932
+ if (options.inputResolver) {
4933
+ const resolvedInput = options.inputResolver(component, ctx);
4934
+ // Guard against resolvers returning undefined or non-HTMLElement values.
4935
+ ctx.activeInput = resolvedInput instanceof HTMLElement ? resolvedInput : null;
4936
+ }
4937
+
4938
+ return ctx;
4939
+ }
4940
+
4941
+ /**
4942
+ * Wires up a keydown listener that dispatches to strategy[evt.key] or strategy.default.
4943
+ * Handles both sync and async handlers.
4944
+ * @param {HTMLElement} component - The component to attach the listener to.
4945
+ * @param {Object} strategy - Map of key names to handler functions.
4946
+ * @param {Object} [options] - Optional config passed to createDisplayContext.
4947
+ */
4948
+ function applyKeyboardStrategy(component, strategy, options = {}) {
4949
+ component.addEventListener('keydown', async (evt) => {
4950
+ const handler = strategy[evt.key] || strategy.default;
4951
+ if (typeof handler === 'function') {
4952
+ const ctx = createDisplayContext(component, options);
4953
+ await handler(component, evt, ctx);
4954
+ }
4955
+ });
4956
+ }
4957
+
4825
4958
  var styleCss$2 = i$5`: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}`;
4826
4959
 
4827
4960
  var colorCss$2 = i$5`.container{background-color:var(--ds-auro-dropdownbib-container-color);box-shadow:var(--ds-auro-dropdownbib-boxshadow-color);color:var(--ds-auro-dropdownbib-text-color)}`;
4828
4961
 
4829
4962
  var tokensCss$1 = i$5`: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)}`;
4830
4963
 
4964
+ /**
4965
+ * Creates a keyboard strategy for dialog-specific key handling.
4966
+ * All other keydown behavior is left to the browser's native bubbling path.
4967
+ * @param {HTMLElement} bib - The dropdown bib element.
4968
+ * @returns {Object} Keyboard handlers keyed by `event.key`.
4969
+ */
4970
+ // eslint-disable-next-line no-unused-vars
4971
+ function createDropdownBibKeyboardStrategy(bib) {
4972
+ return {
4973
+ // eslint-disable-next-line no-unused-vars
4974
+ Enter(_dialog, event) {
4975
+ // Floating UI handles Enter key to open the dropdown
4976
+ },
4977
+ // eslint-disable-next-line no-unused-vars
4978
+ Escape(_dialog, event) {
4979
+ // Floating UI handles Escape key to close the dropdown
4980
+ }
4981
+ };
4982
+ }
4983
+
4831
4984
  // Copyright (c) 2020 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
4832
4985
  // See LICENSE in the project root for license information.
4833
4986
  /* eslint-disable max-lines */
@@ -4952,11 +5105,7 @@ class AuroDropdownBib extends i$2 {
4952
5105
  },
4953
5106
 
4954
5107
  /**
4955
- * Set by auro-dropdown when a menu option is highlighted via
4956
- * aria-activedescendant. The dialog keyboard bridge checks this
4957
- * flag so that Enter selects the highlighted option instead of
4958
- * activating the focused interactive element (e.g. the trigger
4959
- * button, or the bibtemplate close button in fullscreen).
5108
+ * Tracks whether a menu option is currently highlighted.
4960
5109
  * @private
4961
5110
  */
4962
5111
  hasActiveDescendant: {
@@ -5030,7 +5179,7 @@ class AuroDropdownBib extends i$2 {
5030
5179
 
5031
5180
  const dialog = this.shadowRoot.querySelector('dialog');
5032
5181
  this._setupCancelHandler(dialog);
5033
- this._setupKeyboardBridge(dialog);
5182
+ applyKeyboardStrategy(dialog, createDropdownBibKeyboardStrategy());
5034
5183
 
5035
5184
  this.dispatchEvent(new CustomEvent('auro-dropdownbib-connected', {
5036
5185
  bubbles: true,
@@ -5057,92 +5206,6 @@ class AuroDropdownBib extends i$2 {
5057
5206
  });
5058
5207
  }
5059
5208
 
5060
- /**
5061
- * showModal() creates a closed focus scope — keyboard events inside
5062
- * the dialog's shadow DOM do NOT bubble out to the combobox/select
5063
- * keydown handlers in the parent shadow DOM. This handler bridges
5064
- * that gap by re-dispatching navigation keys so they cross the
5065
- * shadow boundary and reach the menu navigation logic in the parent
5066
- * component.
5067
- *
5068
- * The trade-off: intercepting these keys means native keyboard
5069
- * behaviors that would normally "just work" must be manually
5070
- * re-implemented here:
5071
- *
5072
- * - Enter on buttons: Custom elements (auro-button) don't get the
5073
- * native Enter→click that <button> provides, so we call .click()
5074
- * directly when Enter is pressed on a button-like element.
5075
- *
5076
- * - Tab: Intercepted and re-dispatched so parent components
5077
- * (select/combobox) can select the active option and close the
5078
- * dialog. The <dialog> provides containment and isolation
5079
- * (inert background, VoiceOver focus trapping, top layer), while
5080
- * the content inside is a role="listbox" navigated via
5081
- * aria-activedescendant (options are not focusable). Tab keyboard
5082
- * behavior follows listbox conventions (select + close) because
5083
- * the dialog's native Tab trap only cycles between the close
5084
- * button and browser chrome.
5085
- *
5086
- * - Escape: The native <dialog> fires a `cancel` event on ESC
5087
- * (handled by _setupCancelHandler), so the re-dispatched Escape
5088
- * is a secondary path for parent components that also listen for
5089
- * Escape keydown.
5090
- *
5091
- * @param {HTMLDialogElement} dialog - The dialog element to attach the keyboard bridge to.
5092
- * @private
5093
- */
5094
- _setupKeyboardBridge(dialog) {
5095
- const navKeys = new Set([
5096
- 'ArrowUp',
5097
- 'ArrowDown',
5098
- 'Enter',
5099
- 'Escape',
5100
- 'Tab'
5101
- ]);
5102
-
5103
- dialog.addEventListener('keydown', (event) => {
5104
- if (!navKeys.has(event.key)) {
5105
- return;
5106
- }
5107
-
5108
- // Custom elements (auro-button) don't get the native Enter→click
5109
- // behavior that <button> has. Find the button in the composed path
5110
- // and click it directly — but only when no menu option is
5111
- // highlighted. In fullscreen mode focus stays on the close button
5112
- // while arrow keys move the active-descendant highlight through
5113
- // the listbox. If the user presses Enter with an option
5114
- // highlighted, the intent is to select that option, not to click
5115
- // the close button. In that case we fall through and bridge the
5116
- // Enter key to the parent component's keyboard strategy.
5117
- if (event.key === 'Enter') {
5118
- if (!this.hasActiveDescendant) {
5119
- const buttonSelector = 'button, [role="button"], auro-button, [auro-button]';
5120
- const btn = event.composedPath().find((el) => el.matches && el.matches(buttonSelector));
5121
- if (btn) {
5122
- event.preventDefault();
5123
- event.stopPropagation();
5124
- btn.click();
5125
- return;
5126
- }
5127
- }
5128
- }
5129
-
5130
- event.preventDefault();
5131
- event.stopPropagation();
5132
- const newEvent = new KeyboardEvent('keydown', {
5133
- key: event.key,
5134
- code: event.code,
5135
- shiftKey: event.shiftKey,
5136
- altKey: event.altKey,
5137
- ctrlKey: event.ctrlKey,
5138
- metaKey: event.metaKey,
5139
- bubbles: true,
5140
- composed: true,
5141
- cancelable: true
5142
- });
5143
- this.dispatchEvent(newEvent);
5144
- });
5145
- }
5146
5209
 
5147
5210
  /**
5148
5211
  * Blocks touch-driven page scroll while a fullscreen modal dialog is open.
@@ -5517,7 +5580,7 @@ class AuroHelpText extends i$2 {
5517
5580
  }
5518
5581
  }
5519
5582
 
5520
- var formkitVersion = '202603310527';
5583
+ var formkitVersion = '202604031704';
5521
5584
 
5522
5585
  let AuroElement$1 = class AuroElement extends i$2 {
5523
5586
  static get properties() {
@@ -5698,7 +5761,7 @@ class AuroDropdown extends AuroElement$1 {
5698
5761
  this.appearance = 'default';
5699
5762
  this.chevron = false;
5700
5763
  this.disabled = false;
5701
- this.disableFocusTrap = false;
5764
+ this.disableKeyboardHandling = false;
5702
5765
  this.error = false;
5703
5766
  this.tabIndex = 0;
5704
5767
  this.noToggle = false;
@@ -5796,9 +5859,8 @@ class AuroDropdown extends AuroElement$1 {
5796
5859
  // showModal() fires asynchronously via Lit's update cycle, which
5797
5860
  // falls outside the user activation window and causes iOS to
5798
5861
  // dismiss the keyboard.
5799
- if (this.isBibFullscreen && this.bibElement && this.bibElement.value) {
5800
- const useModal = !this.disableFocusTrap;
5801
- this.bibElement.value.open(useModal);
5862
+ if (this.bibElement && this.bibElement.value) {
5863
+ this.bibElement.value.open(this.isBibFullscreen);
5802
5864
  }
5803
5865
  }
5804
5866
 
@@ -5912,9 +5974,9 @@ class AuroDropdown extends AuroElement$1 {
5912
5974
  },
5913
5975
 
5914
5976
  /**
5915
- * If declared, the focus trap inside of bib will be turned off.
5977
+ * If declared, the dropdown will not handle keyboard events and will require the consumer to manage this behavior.
5916
5978
  */
5917
- disableFocusTrap: {
5979
+ disableKeyboardHandling: {
5918
5980
  type: Boolean,
5919
5981
  reflect: true
5920
5982
  },
@@ -6192,7 +6254,7 @@ class AuroDropdown extends AuroElement$1 {
6192
6254
  if (this.isPopoverVisible) {
6193
6255
  // Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
6194
6256
  // Desktop: use show() for Floating UI positioning + FocusTrap for focus management
6195
- const useModal = this.isBibFullscreen && !this.disableFocusTrap;
6257
+ const useModal = this.isBibFullscreen;
6196
6258
  this.bibElement.value.open(useModal);
6197
6259
  } else {
6198
6260
  this.bibElement.value.close();
@@ -6202,7 +6264,7 @@ class AuroDropdown extends AuroElement$1 {
6202
6264
  // When fullscreen strategy changes while open, re-open dialog with correct mode
6203
6265
  // (e.g. resizing from desktop → mobile while dropdown is open)
6204
6266
  if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
6205
- const useModal = this.isBibFullscreen && !this.disableFocusTrap;
6267
+ const useModal = this.isBibFullscreen;
6206
6268
  this.bibElement.value.close();
6207
6269
  this.bibElement.value.open(useModal);
6208
6270
  }
@@ -6224,7 +6286,7 @@ class AuroDropdown extends AuroElement$1 {
6224
6286
 
6225
6287
  firstUpdated() {
6226
6288
  // Configure the floater to, this will generate the ID for the bib
6227
- this.floater.configure(this, 'auroDropdown');
6289
+ this.floater.configure(this, 'auroDropdown', !this.disableKeyboardHandling);
6228
6290
 
6229
6291
  // Prevent `contain: layout` on the dropdown host. Layout containment
6230
6292
  // creates a containing block for position:fixed descendants (the bib),
@@ -6314,7 +6376,7 @@ class AuroDropdown extends AuroElement$1 {
6314
6376
  * @private
6315
6377
  */
6316
6378
  updateFocusTrap() {
6317
- if (this.isPopoverVisible && !this.disableFocusTrap) {
6379
+ if (this.isPopoverVisible) {
6318
6380
  if (!this.isBibFullscreen) {
6319
6381
  // Desktop: show() doesn't trap focus, so use FocusTrap
6320
6382
  this.focusTrap = new FocusTrap(this.bibContent);
@@ -6532,6 +6594,7 @@ class AuroDropdown extends AuroElement$1 {
6532
6594
  aria-expanded="${o$2(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
6533
6595
  aria-controls="${o$2(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.dropdownId)}"
6534
6596
  aria-labelledby="${o$2(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
6597
+ aria-disabled="${o$2(this.disabled ? 'true' : undefined)}"
6535
6598
  @focusin="${this.handleFocusin}"
6536
6599
  @blur="${this.handleFocusOut}">
6537
6600
  <div class="triggerContentWrapper" id="triggerLabel">
@@ -7514,6 +7577,7 @@ class AuroCounterGroup extends AuroElement {
7514
7577
  counter.addEventListener("input", this.updateValue);
7515
7578
  counter.addEventListener("auroFormElement-validated", this.updateValidity);
7516
7579
  });
7580
+ this.updateValue();
7517
7581
  }
7518
7582
 
7519
7583
  /**
@@ -7644,6 +7708,8 @@ class AuroCounterGroup extends AuroElement {
7644
7708
  counter.addEventListener("auroFormElement-validated", this.updateValidity);
7645
7709
  });
7646
7710
 
7711
+ this.updateValue();
7712
+
7647
7713
  if (this.isDropdown) {
7648
7714
  this.configureBibtemplate();
7649
7715
  }
@@ -7669,15 +7735,6 @@ class AuroCounterGroup extends AuroElement {
7669
7735
  });
7670
7736
  }
7671
7737
  });
7672
-
7673
- // Tab closes the fullscreen dialog
7674
- // The dialog event bridge intercepts Tab and re-dispatches it as a
7675
- // composed keydown; this listener catches the re-dispatched event.
7676
- this.addEventListener('keydown', (evt) => {
7677
- if (evt.key === 'Tab' && this.dropdown.isPopoverVisible && this.dropdown.isBibFullscreen) {
7678
- this.dropdown.hide();
7679
- }
7680
- });
7681
7738
  }
7682
7739
 
7683
7740
  /**
@@ -7867,8 +7924,7 @@ class AuroCounterGroup extends AuroElement {
7867
7924
  */
7868
7925
  renderCounterDropdown() {
7869
7926
  return u$5`
7870
- <${this.dropdownTag}
7871
- noHideOnThisFocusLoss
7927
+ <${this.dropdownTag}
7872
7928
  chevron
7873
7929
  part="dropdown"
7874
7930
  appearance="${this.onDark ? 'inverse' : this.appearance}"
@@ -40,7 +40,16 @@ export class AuroCounter extends LitElement {
40
40
  min: number;
41
41
  onDark: boolean;
42
42
  validity: any;
43
- value: number;
43
+ /**
44
+ * 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.
45
+ * @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.
46
+ */
47
+ set value(val: number | string | undefined | null);
48
+ /**
49
+ * Gets the current value of the counter.
50
+ * @returns {number|undefined} The current value of the counter, or undefined if the value is not set or invalid.
51
+ */
52
+ get value(): number | undefined;
44
53
  /**
45
54
  * @private
46
55
  */
@@ -59,6 +68,7 @@ export class AuroCounter extends LitElement {
59
68
  * @private
60
69
  */
61
70
  private runtimeUtils;
71
+ _value: number;
62
72
  /**
63
73
  * Increments the counter value by 1. If a value is provided, it increments by that amount.
64
74
  * @method increment
@@ -92,13 +102,6 @@ export class AuroCounter extends LitElement {
92
102
  * @param {boolean} [force=false] - Whether to force validation.
93
103
  */
94
104
  validate(force?: boolean): void;
95
- /**
96
- * Handles the keydown event for the counter component.
97
- * @param {KeyboardEvent} event - The keyboard event object.
98
- * @returns {void}
99
- * @private
100
- */
101
- private handleKeyDown;
102
105
  firstUpdated(): void;
103
106
  /**
104
107
  * Sets an attribute that matches the default tag name if the tag name is not the default.