@nectary/components 5.37.7 → 5.37.8

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.
package/bundle.js CHANGED
@@ -7378,12 +7378,80 @@ class Popover extends NectaryElement {
7378
7378
  };
7379
7379
  }
7380
7380
  defineCustomElement("sinch-popover", Popover);
7381
+ const isActivationKey = (key) => key === "Enter" || key === " ";
7382
+ function createKeyboardNavigation() {
7383
+ return {
7384
+ navigateToNextOption(enabledOptions, forward) {
7385
+ const optionsLength = enabledOptions.length;
7386
+ if (optionsLength === 0) {
7387
+ return;
7388
+ }
7389
+ const currentIndex = enabledOptions.findIndex((option) => option === getDeepActiveElement());
7390
+ let nextIndex;
7391
+ if (currentIndex !== -1) {
7392
+ if (forward) {
7393
+ nextIndex = (currentIndex + 1) % optionsLength;
7394
+ } else {
7395
+ nextIndex = currentIndex === 0 ? optionsLength - 1 : currentIndex - 1;
7396
+ }
7397
+ } else {
7398
+ nextIndex = forward ? 0 : optionsLength - 1;
7399
+ }
7400
+ this.navigateToOption(enabledOptions, nextIndex);
7401
+ },
7402
+ navigateToOption(enabledOptions, index) {
7403
+ const optionsLength = enabledOptions.length;
7404
+ if (enabledOptions.length === 0 || index < 0 || index >= optionsLength) {
7405
+ return;
7406
+ }
7407
+ const option = enabledOptions[index];
7408
+ option.focus();
7409
+ },
7410
+ handleKeyboardNavigation(e, enabledOptions) {
7411
+ switch (e.code) {
7412
+ case "Space":
7413
+ case "Enter": {
7414
+ e.preventDefault();
7415
+ const target = getTargetByAttribute(e, "value");
7416
+ if (target !== null) {
7417
+ target.click();
7418
+ }
7419
+ break;
7420
+ }
7421
+ case "ArrowLeft": {
7422
+ e.preventDefault();
7423
+ this.navigateToNextOption(enabledOptions, false);
7424
+ break;
7425
+ }
7426
+ case "ArrowRight": {
7427
+ e.preventDefault();
7428
+ this.navigateToNextOption(enabledOptions, true);
7429
+ break;
7430
+ }
7431
+ case "Home": {
7432
+ e.preventDefault();
7433
+ this.navigateToOption(enabledOptions, 0);
7434
+ break;
7435
+ }
7436
+ case "End": {
7437
+ e.preventDefault();
7438
+ this.navigateToOption(enabledOptions, enabledOptions.length - 1);
7439
+ break;
7440
+ }
7441
+ }
7442
+ }
7443
+ };
7444
+ }
7381
7445
  const templateHTML$P = '<style>:host{display:block}#wrapper{display:flex;width:100%;height:40px;border-bottom:1px solid var(--sinch-comp-tab-color-default-border-initial);box-sizing:border-box}</style><div id="wrapper"><slot></slot></div>';
7382
7446
  const template$P = document.createElement("template");
7383
7447
  template$P.innerHTML = templateHTML$P;
7384
7448
  class Tabs extends NectaryElement {
7385
7449
  #$slot;
7386
7450
  #controller = null;
7451
+ #enabledOptions = [];
7452
+ #keyboardNav = createKeyboardNavigation();
7453
+ #observer = null;
7454
+ #rovingValue = null;
7387
7455
  constructor() {
7388
7456
  super();
7389
7457
  const shadowRoot = this.attachShadow();
@@ -7393,14 +7461,28 @@ class Tabs extends NectaryElement {
7393
7461
  connectedCallback() {
7394
7462
  this.#controller = new AbortController();
7395
7463
  const { signal } = this.#controller;
7464
+ const options = { signal };
7396
7465
  this.setAttribute("role", "tablist");
7397
- this.#$slot.addEventListener("option-change", this.#onOptionChange, { signal });
7398
- this.#$slot.addEventListener("slotchange", this.#onSlotChange, { signal });
7399
- this.addEventListener("-change", this.#onChangeReactHandler, { signal });
7466
+ this.setAttribute("aria-orientation", "horizontal");
7467
+ this.#$slot.addEventListener("option-change", this.#onOptionChange, options);
7468
+ this.#$slot.addEventListener("slotchange", this.#onSlotChange, options);
7469
+ this.#$slot.addEventListener("focusin", this.#onOptionFocusIn, options);
7470
+ this.#$slot.addEventListener("keydown", this.#onOptionKeydown, options);
7471
+ this.addEventListener("-change", this.#onChangeReactHandler, options);
7472
+ this.#observer = new MutationObserver(this.#onOptionMutation);
7473
+ this.#observer.observe(this, {
7474
+ attributes: true,
7475
+ attributeFilter: ["disabled", "value"],
7476
+ childList: true,
7477
+ subtree: true
7478
+ });
7479
+ this.#syncOptions();
7400
7480
  }
7401
7481
  disconnectedCallback() {
7402
7482
  this.#controller.abort();
7403
7483
  this.#controller = null;
7484
+ this.#observer?.disconnect();
7485
+ this.#observer = null;
7404
7486
  }
7405
7487
  static get observedAttributes() {
7406
7488
  return ["value"];
@@ -7426,19 +7508,91 @@ class Tabs extends NectaryElement {
7426
7508
  }
7427
7509
  return null;
7428
7510
  }
7511
+ #getOptions() {
7512
+ return this.#$slot.assignedElements();
7513
+ }
7514
+ #updateEnabledOptions(options = this.#getOptions()) {
7515
+ this.#enabledOptions = options.filter((option) => !getBooleanAttribute(option, "disabled"));
7516
+ }
7517
+ #getFocusableOption() {
7518
+ if (this.#enabledOptions.length === 0) {
7519
+ return null;
7520
+ }
7521
+ if (this.#rovingValue !== null) {
7522
+ const rovingOption = this.#enabledOptions.find(
7523
+ (option) => getAttribute(option, "value", "") === this.#rovingValue
7524
+ );
7525
+ if (rovingOption != null) {
7526
+ return rovingOption;
7527
+ }
7528
+ }
7529
+ const selectedOption = this.#enabledOptions.find(
7530
+ (option) => getAttribute(option, "value", "") === this.value
7531
+ );
7532
+ return selectedOption ?? this.#enabledOptions[0];
7533
+ }
7534
+ #syncOptions() {
7535
+ const options = this.#getOptions();
7536
+ this.#updateEnabledOptions(options);
7537
+ const focusableOption = this.#getFocusableOption();
7538
+ this.#rovingValue = focusableOption == null ? null : getAttribute(focusableOption, "value", "");
7539
+ for (const $option of options) {
7540
+ const isDisabled = getBooleanAttribute($option, "disabled");
7541
+ const isChecked = !isDisabled && this.value === getAttribute($option, "value", "");
7542
+ updateBooleanAttribute($option, "data-checked", isChecked);
7543
+ $option.tabIndex = !isDisabled && $option === focusableOption ? 0 : -1;
7544
+ }
7545
+ }
7429
7546
  #onSlotChange = () => {
7430
- this.#onValueChange(this.value);
7547
+ this.#syncOptions();
7431
7548
  };
7432
7549
  #onOptionChange = (e) => {
7433
7550
  e.stopPropagation();
7434
- this.#dispatchChangeEvent(e.detail);
7551
+ const value = e.detail;
7552
+ this.#rovingValue = value;
7553
+ this.#dispatchChangeEvent(value);
7435
7554
  };
7436
7555
  #onValueChange(value) {
7437
- for (const $option of this.#$slot.assignedElements()) {
7438
- const isChecked = !getBooleanAttribute($option, "disabled") && value === getAttribute($option, "value", "");
7439
- updateBooleanAttribute($option, "data-checked", isChecked);
7440
- }
7556
+ this.#rovingValue = value;
7557
+ this.#syncOptions();
7441
7558
  }
7559
+ #onOptionFocusIn = (e) => {
7560
+ const target = getTargetByAttribute(e, "value");
7561
+ if (target === null || getBooleanAttribute(target, "disabled")) {
7562
+ return;
7563
+ }
7564
+ this.#rovingValue = getAttribute(target, "value", "");
7565
+ this.#syncOptions();
7566
+ };
7567
+ #onOptionKeydown = (e) => {
7568
+ switch (e.code) {
7569
+ case "ArrowLeft": {
7570
+ e.preventDefault();
7571
+ this.#keyboardNav.navigateToNextOption(this.#enabledOptions, false);
7572
+ break;
7573
+ }
7574
+ case "ArrowRight": {
7575
+ e.preventDefault();
7576
+ this.#keyboardNav.navigateToNextOption(this.#enabledOptions, true);
7577
+ break;
7578
+ }
7579
+ case "Home": {
7580
+ e.preventDefault();
7581
+ this.#keyboardNav.navigateToOption(this.#enabledOptions, 0);
7582
+ break;
7583
+ }
7584
+ case "End": {
7585
+ e.preventDefault();
7586
+ this.#keyboardNav.navigateToOption(this.#enabledOptions, this.#enabledOptions.length - 1);
7587
+ break;
7588
+ }
7589
+ }
7590
+ };
7591
+ #onOptionMutation = (mutations) => {
7592
+ if (mutations.some((mutation) => mutation.target !== this)) {
7593
+ this.#syncOptions();
7594
+ }
7595
+ };
7442
7596
  #dispatchChangeEvent(value) {
7443
7597
  this.dispatchEvent(
7444
7598
  new CustomEvent("-change", { detail: value })
@@ -7450,25 +7604,26 @@ class Tabs extends NectaryElement {
7450
7604
  };
7451
7605
  }
7452
7606
  defineCustomElement("sinch-tabs", Tabs);
7453
- const templateHTML$O = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}#button:hover{background-color:var(--sinch-comp-tab-color-default-background-hover)}#button:focus-visible::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#button:disabled{cursor:unset;pointer-events:none;--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}::slotted(*){display:block}</style><sinch-tooltip id="tooltip"><button id="button" tabindex="0"><slot name="icon"></slot></button></sinch-tooltip>';
7607
+ const templateHTML$O = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}:host([disabled]) #button{cursor:unset;pointer-events:none;--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}:host(:hover:not([disabled])) #button{background-color:var(--sinch-comp-tab-color-default-background-hover)}:host(:focus-visible) #button::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}::slotted(*){display:block;pointer-events:none}</style><sinch-tooltip id="tooltip"><div id="button"><slot name="icon"></slot></div></sinch-tooltip>';
7454
7608
  const template$O = document.createElement("template");
7455
7609
  template$O.innerHTML = templateHTML$O;
7456
7610
  class TabsIconOption extends NectaryElement {
7457
- #$button;
7458
7611
  #$tooltip;
7459
7612
  constructor() {
7460
7613
  super();
7461
- const shadowRoot = this.attachShadow({ delegatesFocus: true });
7614
+ const shadowRoot = this.attachShadow();
7462
7615
  shadowRoot.appendChild(template$O.content.cloneNode(true));
7463
- this.#$button = shadowRoot.querySelector("#button");
7464
7616
  this.#$tooltip = shadowRoot.querySelector("#tooltip");
7465
7617
  }
7466
7618
  connectedCallback() {
7467
7619
  this.setAttribute("role", "tab");
7468
- this.#$button.addEventListener("click", this.#onClick);
7620
+ this.addEventListener("click", this.#onClick);
7621
+ this.addEventListener("keydown", this.#onKeyDown);
7622
+ this.#updateTabIndex();
7469
7623
  }
7470
7624
  disconnectedCallback() {
7471
- this.#$button.removeEventListener("click", this.#onClick);
7625
+ this.removeEventListener("click", this.#onClick);
7626
+ this.removeEventListener("keydown", this.#onKeyDown);
7472
7627
  }
7473
7628
  static get observedAttributes() {
7474
7629
  return ["data-checked", "disabled", "aria-label"];
@@ -7496,7 +7651,8 @@ class TabsIconOption extends NectaryElement {
7496
7651
  }
7497
7652
  case "disabled": {
7498
7653
  const isDisabled = isAttrTrue(newVal);
7499
- this.#$button.disabled = isDisabled;
7654
+ this.#updateTabIndex();
7655
+ updateExplicitBooleanAttribute(this, "aria-disabled", isDisabled);
7500
7656
  updateBooleanAttribute(this, name, isDisabled);
7501
7657
  break;
7502
7658
  }
@@ -7510,17 +7666,32 @@ class TabsIconOption extends NectaryElement {
7510
7666
  return true;
7511
7667
  }
7512
7668
  focus() {
7513
- this.#$button.focus();
7669
+ HTMLElement.prototype.focus.call(this);
7514
7670
  }
7515
7671
  blur() {
7516
- this.#$button.blur();
7672
+ HTMLElement.prototype.blur.call(this);
7673
+ }
7674
+ #updateTabIndex() {
7675
+ if (this.disabled) {
7676
+ this.tabIndex = -1;
7677
+ }
7517
7678
  }
7518
7679
  #onClick = (e) => {
7680
+ if (this.disabled) {
7681
+ return;
7682
+ }
7519
7683
  e.stopPropagation();
7520
7684
  this.dispatchEvent(
7521
7685
  new CustomEvent("option-change", { bubbles: true, detail: this.value })
7522
7686
  );
7523
7687
  };
7688
+ #onKeyDown = (e) => {
7689
+ if (this.disabled || !isActivationKey(e.key)) {
7690
+ return;
7691
+ }
7692
+ e.preventDefault();
7693
+ this.#onClick(e);
7694
+ };
7524
7695
  }
7525
7696
  defineCustomElement("sinch-tabs-icon-option", TabsIconOption);
7526
7697
  const createDebounce = (delayFn, cancelFn) => (cb) => {
@@ -13058,65 +13229,6 @@ class SegmentedControlOption extends NectaryElement {
13058
13229
  };
13059
13230
  }
13060
13231
  defineCustomElement("sinch-segmented-control-option", SegmentedControlOption);
13061
- function createKeyboardNavigation() {
13062
- return {
13063
- navigateToNextOption(enabledOptions, forward) {
13064
- const optionsLength = enabledOptions.length;
13065
- if (optionsLength === 0) {
13066
- return;
13067
- }
13068
- const currentIndex = enabledOptions.findIndex((option) => option === getDeepActiveElement());
13069
- let nextIndex;
13070
- if (currentIndex !== -1) {
13071
- if (forward) {
13072
- nextIndex = (currentIndex + 1) % optionsLength;
13073
- } else {
13074
- nextIndex = currentIndex === 0 ? optionsLength - 1 : currentIndex - 1;
13075
- }
13076
- } else {
13077
- nextIndex = forward ? 0 : optionsLength - 1;
13078
- }
13079
- this.navigateToOption(enabledOptions, nextIndex);
13080
- },
13081
- navigateToOption(enabledOptions, index) {
13082
- const optionsLength = enabledOptions.length;
13083
- if (enabledOptions.length === 0 || index < 0 || index >= optionsLength) {
13084
- return;
13085
- }
13086
- const option = enabledOptions[index];
13087
- option.focus();
13088
- },
13089
- handleKeyboardNavigation(e, enabledOptions) {
13090
- switch (e.code) {
13091
- case "Space":
13092
- case "Enter": {
13093
- e.preventDefault();
13094
- const target = getTargetByAttribute(e, "value");
13095
- if (target !== null) {
13096
- target.click();
13097
- }
13098
- break;
13099
- }
13100
- case "ArrowLeft":
13101
- case "ArrowRight": {
13102
- e.preventDefault();
13103
- this.navigateToNextOption(enabledOptions, e.code === "ArrowRight");
13104
- break;
13105
- }
13106
- case "Home": {
13107
- e.preventDefault();
13108
- this.navigateToOption(enabledOptions, 0);
13109
- break;
13110
- }
13111
- case "End": {
13112
- e.preventDefault();
13113
- this.navigateToOption(enabledOptions, enabledOptions.length - 1);
13114
- break;
13115
- }
13116
- }
13117
- }
13118
- };
13119
- }
13120
13232
  const templateHTML$m = '<style>:host{display:block;outline:0}#wrapper{display:flex;flex-direction:row;width:100%;box-sizing:border-box;position:relative;z-index:0}</style><div id="wrapper"><slot></slot></div>';
13121
13233
  const template$m = document.createElement("template");
13122
13234
  template$m.innerHTML = templateHTML$m;
@@ -14695,25 +14807,26 @@ class Table extends NectaryElement {
14695
14807
  }
14696
14808
  }
14697
14809
  defineCustomElement("sinch-table", Table);
14698
- const templateHTML$6 = '<style>:host{display:block}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}#button:hover{background-color:var(--sinch-comp-tab-color-default-background-hover)}#button:focus-visible::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#button:disabled{cursor:unset;pointer-events:none;--sinch-global-color-text:var(--sinch-comp-tab-color-disabled-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-text:var(--sinch-comp-tab-color-checked-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}#text{flex-shrink:1;flex-basis:auto;min-width:0;--sinch-comp-text-font:var(--sinch-comp-tab-font-label)}::slotted(*){display:block}</style><button id="button" tabindex="0"><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text></button>';
14810
+ const templateHTML$6 = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}:host([disabled]) #button{cursor:unset;pointer-events:none;--sinch-global-color-text:var(--sinch-comp-tab-color-disabled-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-text:var(--sinch-comp-tab-color-checked-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}:host(:hover:not([disabled])) #button{background-color:var(--sinch-comp-tab-color-default-background-hover)}:host(:focus-visible) #button::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#text{flex-shrink:1;flex-basis:auto;min-width:0;--sinch-comp-text-font:var(--sinch-comp-tab-font-label)}::slotted(*){display:block;pointer-events:none}</style><div id="button"><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text></div>';
14699
14811
  const template$6 = document.createElement("template");
14700
14812
  template$6.innerHTML = templateHTML$6;
14701
14813
  class TabsOption extends NectaryElement {
14702
- #$button;
14703
14814
  #$text;
14704
14815
  constructor() {
14705
14816
  super();
14706
- const shadowRoot = this.attachShadow({ delegatesFocus: true });
14817
+ const shadowRoot = this.attachShadow();
14707
14818
  shadowRoot.appendChild(template$6.content.cloneNode(true));
14708
- this.#$button = shadowRoot.querySelector("#button");
14709
14819
  this.#$text = shadowRoot.querySelector("#text");
14710
14820
  }
14711
14821
  connectedCallback() {
14712
14822
  this.setAttribute("role", "tab");
14713
14823
  this.addEventListener("click", this.#onClick);
14824
+ this.addEventListener("keydown", this.#onKeyDown);
14825
+ this.#updateTabIndex();
14714
14826
  }
14715
14827
  disconnectedCallback() {
14716
14828
  this.removeEventListener("click", this.#onClick);
14829
+ this.removeEventListener("keydown", this.#onKeyDown);
14717
14830
  }
14718
14831
  static get observedAttributes() {
14719
14832
  return ["data-checked", "disabled", "text"];
@@ -14733,7 +14846,8 @@ class TabsOption extends NectaryElement {
14733
14846
  }
14734
14847
  case "disabled": {
14735
14848
  const isDisabled = isAttrTrue(newVal);
14736
- this.#$button.disabled = isDisabled;
14849
+ this.#updateTabIndex();
14850
+ updateExplicitBooleanAttribute(this, "aria-disabled", isDisabled);
14737
14851
  updateBooleanAttribute(this, name, isDisabled);
14738
14852
  break;
14739
14853
  }
@@ -14761,17 +14875,32 @@ class TabsOption extends NectaryElement {
14761
14875
  return true;
14762
14876
  }
14763
14877
  focus() {
14764
- this.#$button.focus();
14878
+ HTMLElement.prototype.focus.call(this);
14765
14879
  }
14766
14880
  blur() {
14767
- this.#$button.blur();
14881
+ HTMLElement.prototype.blur.call(this);
14882
+ }
14883
+ #updateTabIndex() {
14884
+ if (this.disabled) {
14885
+ this.tabIndex = -1;
14886
+ }
14768
14887
  }
14769
14888
  #onClick = (e) => {
14889
+ if (this.disabled) {
14890
+ return;
14891
+ }
14770
14892
  e.stopPropagation();
14771
14893
  this.dispatchEvent(
14772
14894
  new CustomEvent("option-change", { bubbles: true, detail: this.value })
14773
14895
  );
14774
14896
  };
14897
+ #onKeyDown = (e) => {
14898
+ if (this.disabled || !isActivationKey(e.key)) {
14899
+ return;
14900
+ }
14901
+ e.preventDefault();
14902
+ this.#onClick(e);
14903
+ };
14775
14904
  }
14776
14905
  defineCustomElement("sinch-tabs-option", TabsOption);
14777
14906
  const templateHTML$5 = '<style>:host{display:inline-block;vertical-align:middle;outline:0}:host([ellipsis]){display:inline}#wrapper{display:flex;flex-direction:row;align-items:center;gap:4px;width:100%;height:var(--sinch-comp-tag-size-container-m);padding:0 9px;border:1px solid var(--sinch-comp-tag-border);border-radius:var(--sinch-comp-tag-shape-radius);background-color:var(--sinch-comp-tag-color-default-background);box-sizing:border-box;user-select:none;--sinch-global-color-text:var(--sinch-comp-tag-color-default-foreground);--sinch-global-color-icon:var(--sinch-comp-tag-color-default-foreground);--sinch-global-size-icon:var(--sinch-comp-tag-size-icon-m)}:host([small]) #wrapper{height:var(--sinch-comp-tag-size-container-s);padding:0 8px;--sinch-global-size-icon:var(--sinch-comp-tag-size-icon-s)}#text{flex:1;--sinch-comp-text-font:var(--sinch-comp-tag-font-size-m-label)}:host([small]) #text{--sinch-comp-text-font:var(--sinch-comp-tag-font-size-s-label)}::slotted(*){margin-left:-4px}</style><sinch-tooltip id="tooltip" type="fast"><div id="wrapper"><slot name="icon"></slot><sinch-text id="text" type="s" ellipsis></sinch-text></div></sinch-tooltip>';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectary/components",
3
- "version": "5.37.7",
3
+ "version": "5.37.8",
4
4
  "files": [
5
5
  "**/*/*.css",
6
6
  "**/*/*.json",
package/tabs/index.js CHANGED
@@ -2,12 +2,18 @@ import { updateAttribute, getAttribute, getBooleanAttribute, updateBooleanAttrib
2
2
  import { defineCustomElement, NectaryElement } from "../utils/element.js";
3
3
  import { getRect } from "../utils/rect.js";
4
4
  import { getReactEventHandler } from "../utils/get-react-event-handler.js";
5
+ import { getTargetByAttribute } from "../utils/event-target.js";
6
+ import { createKeyboardNavigation } from "../utils/control-keyboard-navigation.js";
5
7
  const templateHTML = '<style>:host{display:block}#wrapper{display:flex;width:100%;height:40px;border-bottom:1px solid var(--sinch-comp-tab-color-default-border-initial);box-sizing:border-box}</style><div id="wrapper"><slot></slot></div>';
6
8
  const template = document.createElement("template");
7
9
  template.innerHTML = templateHTML;
8
10
  class Tabs extends NectaryElement {
9
11
  #$slot;
10
12
  #controller = null;
13
+ #enabledOptions = [];
14
+ #keyboardNav = createKeyboardNavigation();
15
+ #observer = null;
16
+ #rovingValue = null;
11
17
  constructor() {
12
18
  super();
13
19
  const shadowRoot = this.attachShadow();
@@ -17,14 +23,28 @@ class Tabs extends NectaryElement {
17
23
  connectedCallback() {
18
24
  this.#controller = new AbortController();
19
25
  const { signal } = this.#controller;
26
+ const options = { signal };
20
27
  this.setAttribute("role", "tablist");
21
- this.#$slot.addEventListener("option-change", this.#onOptionChange, { signal });
22
- this.#$slot.addEventListener("slotchange", this.#onSlotChange, { signal });
23
- this.addEventListener("-change", this.#onChangeReactHandler, { signal });
28
+ this.setAttribute("aria-orientation", "horizontal");
29
+ this.#$slot.addEventListener("option-change", this.#onOptionChange, options);
30
+ this.#$slot.addEventListener("slotchange", this.#onSlotChange, options);
31
+ this.#$slot.addEventListener("focusin", this.#onOptionFocusIn, options);
32
+ this.#$slot.addEventListener("keydown", this.#onOptionKeydown, options);
33
+ this.addEventListener("-change", this.#onChangeReactHandler, options);
34
+ this.#observer = new MutationObserver(this.#onOptionMutation);
35
+ this.#observer.observe(this, {
36
+ attributes: true,
37
+ attributeFilter: ["disabled", "value"],
38
+ childList: true,
39
+ subtree: true
40
+ });
41
+ this.#syncOptions();
24
42
  }
25
43
  disconnectedCallback() {
26
44
  this.#controller.abort();
27
45
  this.#controller = null;
46
+ this.#observer?.disconnect();
47
+ this.#observer = null;
28
48
  }
29
49
  static get observedAttributes() {
30
50
  return ["value"];
@@ -50,19 +70,91 @@ class Tabs extends NectaryElement {
50
70
  }
51
71
  return null;
52
72
  }
73
+ #getOptions() {
74
+ return this.#$slot.assignedElements();
75
+ }
76
+ #updateEnabledOptions(options = this.#getOptions()) {
77
+ this.#enabledOptions = options.filter((option) => !getBooleanAttribute(option, "disabled"));
78
+ }
79
+ #getFocusableOption() {
80
+ if (this.#enabledOptions.length === 0) {
81
+ return null;
82
+ }
83
+ if (this.#rovingValue !== null) {
84
+ const rovingOption = this.#enabledOptions.find(
85
+ (option) => getAttribute(option, "value", "") === this.#rovingValue
86
+ );
87
+ if (rovingOption != null) {
88
+ return rovingOption;
89
+ }
90
+ }
91
+ const selectedOption = this.#enabledOptions.find(
92
+ (option) => getAttribute(option, "value", "") === this.value
93
+ );
94
+ return selectedOption ?? this.#enabledOptions[0];
95
+ }
96
+ #syncOptions() {
97
+ const options = this.#getOptions();
98
+ this.#updateEnabledOptions(options);
99
+ const focusableOption = this.#getFocusableOption();
100
+ this.#rovingValue = focusableOption == null ? null : getAttribute(focusableOption, "value", "");
101
+ for (const $option of options) {
102
+ const isDisabled = getBooleanAttribute($option, "disabled");
103
+ const isChecked = !isDisabled && this.value === getAttribute($option, "value", "");
104
+ updateBooleanAttribute($option, "data-checked", isChecked);
105
+ $option.tabIndex = !isDisabled && $option === focusableOption ? 0 : -1;
106
+ }
107
+ }
53
108
  #onSlotChange = () => {
54
- this.#onValueChange(this.value);
109
+ this.#syncOptions();
55
110
  };
56
111
  #onOptionChange = (e) => {
57
112
  e.stopPropagation();
58
- this.#dispatchChangeEvent(e.detail);
113
+ const value = e.detail;
114
+ this.#rovingValue = value;
115
+ this.#dispatchChangeEvent(value);
59
116
  };
60
117
  #onValueChange(value) {
61
- for (const $option of this.#$slot.assignedElements()) {
62
- const isChecked = !getBooleanAttribute($option, "disabled") && value === getAttribute($option, "value", "");
63
- updateBooleanAttribute($option, "data-checked", isChecked);
64
- }
118
+ this.#rovingValue = value;
119
+ this.#syncOptions();
65
120
  }
121
+ #onOptionFocusIn = (e) => {
122
+ const target = getTargetByAttribute(e, "value");
123
+ if (target === null || getBooleanAttribute(target, "disabled")) {
124
+ return;
125
+ }
126
+ this.#rovingValue = getAttribute(target, "value", "");
127
+ this.#syncOptions();
128
+ };
129
+ #onOptionKeydown = (e) => {
130
+ switch (e.code) {
131
+ case "ArrowLeft": {
132
+ e.preventDefault();
133
+ this.#keyboardNav.navigateToNextOption(this.#enabledOptions, false);
134
+ break;
135
+ }
136
+ case "ArrowRight": {
137
+ e.preventDefault();
138
+ this.#keyboardNav.navigateToNextOption(this.#enabledOptions, true);
139
+ break;
140
+ }
141
+ case "Home": {
142
+ e.preventDefault();
143
+ this.#keyboardNav.navigateToOption(this.#enabledOptions, 0);
144
+ break;
145
+ }
146
+ case "End": {
147
+ e.preventDefault();
148
+ this.#keyboardNav.navigateToOption(this.#enabledOptions, this.#enabledOptions.length - 1);
149
+ break;
150
+ }
151
+ }
152
+ };
153
+ #onOptionMutation = (mutations) => {
154
+ if (mutations.some((mutation) => mutation.target !== this)) {
155
+ this.#syncOptions();
156
+ }
157
+ };
66
158
  #dispatchChangeEvent(value) {
67
159
  this.dispatchEvent(
68
160
  new CustomEvent("-change", { detail: value })
@@ -1,24 +1,26 @@
1
- import { updateAttribute, getAttribute, updateBooleanAttribute, getBooleanAttribute, isAttrEqual, isAttrTrue, updateExplicitBooleanAttribute } from "../utils/dom.js";
1
+ import { updateAttribute, getAttribute, updateBooleanAttribute, getBooleanAttribute, isAttrEqual, updateExplicitBooleanAttribute, isAttrTrue } from "../utils/dom.js";
2
2
  import { defineCustomElement, NectaryElement } from "../utils/element.js";
3
- const templateHTML = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}#button:hover{background-color:var(--sinch-comp-tab-color-default-background-hover)}#button:focus-visible::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#button:disabled{cursor:unset;pointer-events:none;--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}::slotted(*){display:block}</style><sinch-tooltip id="tooltip"><button id="button" tabindex="0"><slot name="icon"></slot></button></sinch-tooltip>';
3
+ import { isActivationKey } from "../utils/control-keyboard-navigation.js";
4
+ const templateHTML = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;flex-direction:column;padding:12px 16px 0;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}:host([disabled]) #button{cursor:unset;pointer-events:none;--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}:host(:hover:not([disabled])) #button{background-color:var(--sinch-comp-tab-color-default-background-hover)}:host(:focus-visible) #button::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}::slotted(*){display:block;pointer-events:none}</style><sinch-tooltip id="tooltip"><div id="button"><slot name="icon"></slot></div></sinch-tooltip>';
4
5
  const template = document.createElement("template");
5
6
  template.innerHTML = templateHTML;
6
7
  class TabsIconOption extends NectaryElement {
7
- #$button;
8
8
  #$tooltip;
9
9
  constructor() {
10
10
  super();
11
- const shadowRoot = this.attachShadow({ delegatesFocus: true });
11
+ const shadowRoot = this.attachShadow();
12
12
  shadowRoot.appendChild(template.content.cloneNode(true));
13
- this.#$button = shadowRoot.querySelector("#button");
14
13
  this.#$tooltip = shadowRoot.querySelector("#tooltip");
15
14
  }
16
15
  connectedCallback() {
17
16
  this.setAttribute("role", "tab");
18
- this.#$button.addEventListener("click", this.#onClick);
17
+ this.addEventListener("click", this.#onClick);
18
+ this.addEventListener("keydown", this.#onKeyDown);
19
+ this.#updateTabIndex();
19
20
  }
20
21
  disconnectedCallback() {
21
- this.#$button.removeEventListener("click", this.#onClick);
22
+ this.removeEventListener("click", this.#onClick);
23
+ this.removeEventListener("keydown", this.#onKeyDown);
22
24
  }
23
25
  static get observedAttributes() {
24
26
  return ["data-checked", "disabled", "aria-label"];
@@ -46,7 +48,8 @@ class TabsIconOption extends NectaryElement {
46
48
  }
47
49
  case "disabled": {
48
50
  const isDisabled = isAttrTrue(newVal);
49
- this.#$button.disabled = isDisabled;
51
+ this.#updateTabIndex();
52
+ updateExplicitBooleanAttribute(this, "aria-disabled", isDisabled);
50
53
  updateBooleanAttribute(this, name, isDisabled);
51
54
  break;
52
55
  }
@@ -60,17 +63,32 @@ class TabsIconOption extends NectaryElement {
60
63
  return true;
61
64
  }
62
65
  focus() {
63
- this.#$button.focus();
66
+ HTMLElement.prototype.focus.call(this);
64
67
  }
65
68
  blur() {
66
- this.#$button.blur();
69
+ HTMLElement.prototype.blur.call(this);
70
+ }
71
+ #updateTabIndex() {
72
+ if (this.disabled) {
73
+ this.tabIndex = -1;
74
+ }
67
75
  }
68
76
  #onClick = (e) => {
77
+ if (this.disabled) {
78
+ return;
79
+ }
69
80
  e.stopPropagation();
70
81
  this.dispatchEvent(
71
82
  new CustomEvent("option-change", { bubbles: true, detail: this.value })
72
83
  );
73
84
  };
85
+ #onKeyDown = (e) => {
86
+ if (this.disabled || !isActivationKey(e.key)) {
87
+ return;
88
+ }
89
+ e.preventDefault();
90
+ this.#onClick(e);
91
+ };
74
92
  }
75
93
  defineCustomElement("sinch-tabs-icon-option", TabsIconOption);
76
94
  export {
@@ -1,25 +1,27 @@
1
1
  import "../text/index.js";
2
- import { isAttrEqual, isAttrTrue, updateBooleanAttribute, updateExplicitBooleanAttribute, updateAttribute, getAttribute, getBooleanAttribute } from "../utils/dom.js";
2
+ import { isAttrEqual, updateExplicitBooleanAttribute, updateBooleanAttribute, isAttrTrue, updateAttribute, getAttribute, getBooleanAttribute } from "../utils/dom.js";
3
3
  import { defineCustomElement, NectaryElement } from "../utils/element.js";
4
- const templateHTML = '<style>:host{display:block}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}#button:hover{background-color:var(--sinch-comp-tab-color-default-background-hover)}#button:focus-visible::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#button:disabled{cursor:unset;pointer-events:none;--sinch-global-color-text:var(--sinch-comp-tab-color-disabled-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-text:var(--sinch-comp-tab-color-checked-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}#text{flex-shrink:1;flex-basis:auto;min-width:0;--sinch-comp-text-font:var(--sinch-comp-tab-font-label)}::slotted(*){display:block}</style><button id="button" tabindex="0"><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text></button>';
4
+ import { isActivationKey } from "../utils/control-keyboard-navigation.js";
5
+ const templateHTML = '<style>:host{display:block;outline:0}#button{all:initial;position:relative;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 16px;box-sizing:border-box;cursor:pointer;background-color:var(--sinch-comp-tab-color-default-background-initial);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);height:39px;--sinch-global-color-text:var(--sinch-comp-tab-color-default-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-default-icon-initial);--sinch-global-size-icon:var(--sinch-comp-tab-size-icon)}:host([disabled]) #button{cursor:unset;pointer-events:none;--sinch-global-color-text:var(--sinch-comp-tab-color-disabled-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-disabled-icon-initial)}:host([data-checked]) #button{--sinch-global-color-text:var(--sinch-comp-tab-color-checked-text-initial);--sinch-global-color-icon:var(--sinch-comp-tab-color-checked-icon-initial)}:host([data-checked]) #button::before{content:"";position:absolute;left:0;right:0;bottom:-1px;pointer-events:none;border-top:2px solid var(--sinch-comp-tab-color-checked-border-initial)}:host(:hover:not([disabled])) #button{background-color:var(--sinch-comp-tab-color-default-background-hover)}:host(:focus-visible) #button::after{content:"";position:absolute;inset:0;bottom:-3px;border:2px solid var(--sinch-comp-tab-color-default-outline-focus);border-top-left-radius:var(--sinch-comp-tab-shape-radius);border-top-right-radius:var(--sinch-comp-tab-shape-radius);pointer-events:none}#text{flex-shrink:1;flex-basis:auto;min-width:0;--sinch-comp-text-font:var(--sinch-comp-tab-font-label)}::slotted(*){display:block;pointer-events:none}</style><div id="button"><slot name="icon"></slot><sinch-text id="text" type="m" ellipsis></sinch-text></div>';
5
6
  const template = document.createElement("template");
6
7
  template.innerHTML = templateHTML;
7
8
  class TabsOption extends NectaryElement {
8
- #$button;
9
9
  #$text;
10
10
  constructor() {
11
11
  super();
12
- const shadowRoot = this.attachShadow({ delegatesFocus: true });
12
+ const shadowRoot = this.attachShadow();
13
13
  shadowRoot.appendChild(template.content.cloneNode(true));
14
- this.#$button = shadowRoot.querySelector("#button");
15
14
  this.#$text = shadowRoot.querySelector("#text");
16
15
  }
17
16
  connectedCallback() {
18
17
  this.setAttribute("role", "tab");
19
18
  this.addEventListener("click", this.#onClick);
19
+ this.addEventListener("keydown", this.#onKeyDown);
20
+ this.#updateTabIndex();
20
21
  }
21
22
  disconnectedCallback() {
22
23
  this.removeEventListener("click", this.#onClick);
24
+ this.removeEventListener("keydown", this.#onKeyDown);
23
25
  }
24
26
  static get observedAttributes() {
25
27
  return ["data-checked", "disabled", "text"];
@@ -39,7 +41,8 @@ class TabsOption extends NectaryElement {
39
41
  }
40
42
  case "disabled": {
41
43
  const isDisabled = isAttrTrue(newVal);
42
- this.#$button.disabled = isDisabled;
44
+ this.#updateTabIndex();
45
+ updateExplicitBooleanAttribute(this, "aria-disabled", isDisabled);
43
46
  updateBooleanAttribute(this, name, isDisabled);
44
47
  break;
45
48
  }
@@ -67,17 +70,32 @@ class TabsOption extends NectaryElement {
67
70
  return true;
68
71
  }
69
72
  focus() {
70
- this.#$button.focus();
73
+ HTMLElement.prototype.focus.call(this);
71
74
  }
72
75
  blur() {
73
- this.#$button.blur();
76
+ HTMLElement.prototype.blur.call(this);
77
+ }
78
+ #updateTabIndex() {
79
+ if (this.disabled) {
80
+ this.tabIndex = -1;
81
+ }
74
82
  }
75
83
  #onClick = (e) => {
84
+ if (this.disabled) {
85
+ return;
86
+ }
76
87
  e.stopPropagation();
77
88
  this.dispatchEvent(
78
89
  new CustomEvent("option-change", { bubbles: true, detail: this.value })
79
90
  );
80
91
  };
92
+ #onKeyDown = (e) => {
93
+ if (this.disabled || !isActivationKey(e.key)) {
94
+ return;
95
+ }
96
+ e.preventDefault();
97
+ this.#onClick(e);
98
+ };
81
99
  }
82
100
  defineCustomElement("sinch-tabs-option", TabsOption);
83
101
  export {
@@ -1,3 +1,4 @@
1
+ export declare const isActivationKey: (key: string) => key is " " | "Enter";
1
2
  export declare function createKeyboardNavigation(): {
2
3
  navigateToNextOption(enabledOptions: Element[], forward: boolean): void;
3
4
  navigateToOption(enabledOptions: Element[], index: number): void;
@@ -1,5 +1,6 @@
1
1
  import { getDeepActiveElement } from "./dom.js";
2
2
  import { getTargetByAttribute } from "./event-target.js";
3
+ const isActivationKey = (key) => key === "Enter" || key === " ";
3
4
  function createKeyboardNavigation() {
4
5
  return {
5
6
  navigateToNextOption(enabledOptions, forward) {
@@ -39,10 +40,14 @@ function createKeyboardNavigation() {
39
40
  }
40
41
  break;
41
42
  }
42
- case "ArrowLeft":
43
+ case "ArrowLeft": {
44
+ e.preventDefault();
45
+ this.navigateToNextOption(enabledOptions, false);
46
+ break;
47
+ }
43
48
  case "ArrowRight": {
44
49
  e.preventDefault();
45
- this.navigateToNextOption(enabledOptions, e.code === "ArrowRight");
50
+ this.navigateToNextOption(enabledOptions, true);
46
51
  break;
47
52
  }
48
53
  case "Home": {
@@ -60,5 +65,6 @@ function createKeyboardNavigation() {
60
65
  };
61
66
  }
62
67
  export {
63
- createKeyboardNavigation
68
+ createKeyboardNavigation,
69
+ isActivationKey
64
70
  };
package/utils/index.d.ts CHANGED
@@ -9,4 +9,5 @@ export * from './debounce';
9
9
  export * from './get-react-event-handler';
10
10
  export * from './markdown';
11
11
  export * from './event-target';
12
+ export { isActivationKey } from './control-keyboard-navigation';
12
13
  export * from './uid';
package/utils/index.js CHANGED
@@ -9,6 +9,7 @@ import { debounceAnimationFrame, debounceTimeout } from "./debounce.js";
9
9
  import { getReactEventHandler } from "./get-react-event-handler.js";
10
10
  import { isEmojiString, parseMarkdown } from "./markdown.js";
11
11
  import { getTargetAttribute, getTargetByAttribute, getTargetIndexInParent, isTargetEqual } from "./event-target.js";
12
+ import { isActivationKey } from "./control-keyboard-navigation.js";
12
13
  import { getUid } from "./uid.js";
13
14
  export {
14
15
  CSV_DELIMITER,
@@ -42,6 +43,7 @@ export {
42
43
  getTransformedAncestor,
43
44
  getUid,
44
45
  hasClass,
46
+ isActivationKey,
45
47
  isAttrEqual,
46
48
  isAttrTrue,
47
49
  isElementFocused,