@fluentui/web-components 3.0.0-rc.12 → 3.0.0-rc.14

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 (43) hide show
  1. package/CHANGELOG.md +20 -2
  2. package/custom-elements.json +968 -164
  3. package/dist/esm/accordion/accordion.d.ts +5 -0
  4. package/dist/esm/accordion/accordion.js +28 -27
  5. package/dist/esm/accordion/accordion.js.map +1 -1
  6. package/dist/esm/dropdown/dropdown.base.d.ts +5 -0
  7. package/dist/esm/dropdown/dropdown.base.js +23 -10
  8. package/dist/esm/dropdown/dropdown.base.js.map +1 -1
  9. package/dist/esm/dropdown/dropdown.styles.js +1 -0
  10. package/dist/esm/dropdown/dropdown.styles.js.map +1 -1
  11. package/dist/esm/index.d.ts +2 -2
  12. package/dist/esm/index.js +2 -2
  13. package/dist/esm/index.js.map +1 -1
  14. package/dist/esm/menu/menu.d.ts +25 -16
  15. package/dist/esm/menu/menu.js +61 -67
  16. package/dist/esm/menu/menu.js.map +1 -1
  17. package/dist/esm/menu-list/index.d.ts +1 -0
  18. package/dist/esm/menu-list/index.js +1 -0
  19. package/dist/esm/menu-list/index.js.map +1 -1
  20. package/dist/esm/menu-list/menu-list.base.d.ts +76 -0
  21. package/dist/esm/menu-list/menu-list.base.js +251 -0
  22. package/dist/esm/menu-list/menu-list.base.js.map +1 -0
  23. package/dist/esm/menu-list/menu-list.d.ts +3 -70
  24. package/dist/esm/menu-list/menu-list.js +3 -244
  25. package/dist/esm/menu-list/menu-list.js.map +1 -1
  26. package/dist/esm/radio-group/index.d.ts +1 -0
  27. package/dist/esm/radio-group/index.js +1 -0
  28. package/dist/esm/radio-group/index.js.map +1 -1
  29. package/dist/esm/radio-group/radio-group.base.d.ts +285 -0
  30. package/dist/esm/radio-group/radio-group.base.js +497 -0
  31. package/dist/esm/radio-group/radio-group.base.js.map +1 -0
  32. package/dist/esm/radio-group/radio-group.d.ts +4 -280
  33. package/dist/esm/radio-group/radio-group.js +4 -491
  34. package/dist/esm/radio-group/radio-group.js.map +1 -1
  35. package/dist/esm/tablist/tablist.base.js +3 -3
  36. package/dist/esm/tablist/tablist.base.js.map +1 -1
  37. package/dist/esm/utils/request-idle-callback.d.ts +15 -0
  38. package/dist/esm/utils/request-idle-callback.js +8 -2
  39. package/dist/esm/utils/request-idle-callback.js.map +1 -1
  40. package/dist/web-components.d.ts +1970 -1932
  41. package/dist/web-components.js +165 -124
  42. package/dist/web-components.min.js +114 -114
  43. package/package.json +1 -1
@@ -4646,15 +4646,22 @@ function requestIdleCallback(callback, options) {
4646
4646
  didTimeout: options?.timeout ? Date.now() - start >= options.timeout : false,
4647
4647
  timeRemaining: () => 0
4648
4648
  });
4649
- }, 1);
4649
+ }, options?.timeout ?? 1);
4650
4650
  }
4651
4651
  function waitForConnectedDescendants(target, callback, options) {
4652
4652
  const shallow = options?.shallow ?? false;
4653
4653
  const timeout = options?.timeout ?? 50;
4654
+ const useIdleCallback = options?.idleCallback ?? false;
4654
4655
  const selector = `${shallow ? ":scope > " : ""}:not(:defined)`;
4655
4656
  const scheduleCheck = deadline => {
4656
4657
  if (target.querySelector(selector) === null || deadline && deadline.timeRemaining() <= 0) {
4657
- requestAnimationFrame(callback);
4658
+ if (useIdleCallback) {
4659
+ requestIdleCallback(callback, {
4660
+ timeout
4661
+ });
4662
+ } else {
4663
+ callback();
4664
+ }
4658
4665
  return;
4659
4666
  }
4660
4667
  requestIdleCallback(scheduleCheck, {
@@ -4684,6 +4691,11 @@ var __decorateClass$M = (decorators, target, key, kind) => {
4684
4691
  class Accordion extends FASTElement {
4685
4692
  constructor() {
4686
4693
  super(...arguments);
4694
+ /**
4695
+ * Guard flag to prevent re-entrant calls to setSingleExpandMode.
4696
+ * @internal
4697
+ */
4698
+ this._isAdjusting = false;
4687
4699
  this.activeItemIndex = 0;
4688
4700
  /**
4689
4701
  * Resets event listeners and sets the `accordionItems` property
@@ -4750,15 +4762,13 @@ class Accordion extends FASTElement {
4750
4762
  this.setSingleExpandMode(expandedItem);
4751
4763
  return;
4752
4764
  }
4753
- expandedItem?.expandbutton.removeAttribute("aria-disabled");
4765
+ expandedItem?.expandbutton?.removeAttribute("aria-disabled");
4754
4766
  }
4755
4767
  /**
4756
4768
  * @internal
4757
4769
  */
4758
4770
  slottedAccordionItemsChanged(oldValue, newValue) {
4759
- if (this.$fastController.isConnected) {
4760
- this.setItems();
4761
- }
4771
+ this.setItems();
4762
4772
  }
4763
4773
  /**
4764
4774
  * Watch for changes to the slotted accordion items `disabled` and `expanded` attributes
@@ -4768,8 +4778,10 @@ class Accordion extends FASTElement {
4768
4778
  if (propertyName === "disabled") {
4769
4779
  this.setItems();
4770
4780
  } else if (propertyName === "expanded") {
4771
- if (source.expanded && this.isSingleExpandMode()) {
4781
+ if (source.expanded && this.isSingleExpandMode() && !this._isAdjusting) {
4782
+ this._isAdjusting = true;
4772
4783
  this.setSingleExpandMode(source);
4784
+ this._isAdjusting = false;
4773
4785
  }
4774
4786
  }
4775
4787
  }
@@ -4796,33 +4808,29 @@ class Accordion extends FASTElement {
4796
4808
  * @returns {void}
4797
4809
  */
4798
4810
  setSingleExpandMode(expandedItem) {
4799
- requestAnimationFrame(() => {
4800
- if (this.accordionItems.length === 0) {
4801
- return;
4802
- }
4803
- const currentItems = Array.from(this.accordionItems);
4804
- this.activeItemIndex = currentItems.indexOf(expandedItem);
4805
- currentItems.forEach((item, index) => {
4806
- if (isAccordionItem(item)) {
4807
- if (this.activeItemIndex === index) {
4808
- item.expanded = true;
4809
- item.expandbutton.setAttribute("aria-disabled", "true");
4810
- } else {
4811
- item.expanded = false;
4812
- if (!item.hasAttribute("disabled")) {
4813
- item.expandbutton.removeAttribute("aria-disabled");
4814
- }
4811
+ if (this.accordionItems.length === 0) {
4812
+ return;
4813
+ }
4814
+ const currentItems = Array.from(this.accordionItems);
4815
+ this.activeItemIndex = currentItems.indexOf(expandedItem);
4816
+ currentItems.forEach((item, index) => {
4817
+ if (isAccordionItem(item)) {
4818
+ if (this.activeItemIndex === index) {
4819
+ item.expanded = true;
4820
+ item.expandbutton?.setAttribute("aria-disabled", "true");
4821
+ } else {
4822
+ item.expanded = false;
4823
+ if (!item.hasAttribute("disabled")) {
4824
+ item.expandbutton?.removeAttribute("aria-disabled");
4815
4825
  }
4816
4826
  }
4817
- });
4827
+ }
4818
4828
  });
4819
4829
  }
4820
4830
  connectedCallback() {
4821
4831
  super.connectedCallback();
4822
- requestAnimationFrame(() => {
4823
- this.expandmode = this.expandmode || AccordionExpandMode.multi;
4824
- this.setItems();
4825
- });
4832
+ this.expandmode = this.expandmode || AccordionExpandMode.multi;
4833
+ this.setItems();
4826
4834
  }
4827
4835
  }
4828
4836
  __decorateClass$M([attr({
@@ -7346,6 +7354,11 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7346
7354
  * @internal
7347
7355
  */
7348
7356
  this.elementInternals = this.attachInternals();
7357
+ /**
7358
+ * Guard flag to prevent reentrant calls to `insertControl`.
7359
+ * @internal
7360
+ */
7361
+ this._insertingControl = false;
7349
7362
  this.elementInternals.role = "presentation";
7350
7363
  }
7351
7364
  get activeDescendant() {
@@ -7440,7 +7453,7 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7440
7453
  const notifier = Observable.getNotifier(this);
7441
7454
  notifier.subscribe(next);
7442
7455
  notifier.notify("multiple");
7443
- Updates.enqueue(() => {
7456
+ waitForConnectedDescendants(next, () => {
7444
7457
  this.options.forEach(option => {
7445
7458
  option.disabled = option.disabledAttribute || this.disabled;
7446
7459
  option.name = this.name;
@@ -7449,6 +7462,8 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7449
7462
  x.selected = this.multiple || i === 0;
7450
7463
  });
7451
7464
  this.setValidity();
7465
+ }, {
7466
+ idleCallback: true
7452
7467
  });
7453
7468
  if (AnchorPositioningCSSSupported) {
7454
7469
  const anchorName = uniqueId("--dropdown-anchor-");
@@ -7792,12 +7807,17 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7792
7807
  * This method can be overridden in derived classes to provide custom control elements, though this is not recommended.
7793
7808
  */
7794
7809
  insertControl() {
7810
+ if (this._insertingControl) {
7811
+ return;
7812
+ }
7813
+ this._insertingControl = true;
7795
7814
  this.controlSlot?.assignedNodes().forEach(x => this.removeChild(x));
7796
7815
  if (this.type === DropdownType.combobox) {
7797
7816
  dropdownInputTemplate.render(this, this);
7798
7817
  return;
7799
7818
  }
7800
7819
  dropdownButtonTemplate.render(this, this);
7820
+ this._insertingControl = false;
7801
7821
  }
7802
7822
  /**
7803
7823
  * Handles the keydown events for the dropdown.
@@ -7896,7 +7916,9 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7896
7916
  */
7897
7917
  selectOption(index = this.selectedIndex, shouldEmit = false) {
7898
7918
  this.listbox.selectOption(index);
7899
- this.control.value = this.displayValue;
7919
+ if (this.control) {
7920
+ this.control.value = this.displayValue;
7921
+ }
7900
7922
  this.setValidity();
7901
7923
  this.updateFreeformOption();
7902
7924
  if (shouldEmit) {
@@ -7913,17 +7935,18 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7913
7935
  * @internal
7914
7936
  */
7915
7937
  setValidity(flags, message, anchor) {
7916
- if (this.$fastController.isConnected) {
7917
- if (this.disabled || !this.required) {
7918
- this.elementInternals.setValidity({});
7919
- return;
7920
- }
7921
- const valueMissing = this.required && this.listbox.selectedOptions.length === 0;
7922
- this.elementInternals.setValidity({
7923
- valueMissing,
7924
- ...flags
7925
- }, message ?? this.validationMessage, anchor ?? this.control);
7938
+ if (!this.elementInternals) {
7939
+ return;
7926
7940
  }
7941
+ if (this.disabled || !this.required) {
7942
+ this.elementInternals.setValidity({});
7943
+ return;
7944
+ }
7945
+ const valueMissing = this.required && this.listbox.selectedOptions.length === 0;
7946
+ this.elementInternals.setValidity({
7947
+ valueMissing,
7948
+ ...flags
7949
+ }, message ?? this.validationMessage, anchor ?? this.control);
7927
7950
  }
7928
7951
  /**
7929
7952
  * Handles the `slotchange` event for the dropdown.
@@ -8085,7 +8108,7 @@ __decorateClass$w([attr], Dropdown.prototype, "size", 2);
8085
8108
  const styles$q = css`
8086
8109
  ${display("inline-flex")}
8087
8110
 
8088
- :host{anchor-name:--dropdown-trigger;box-sizing:border-box;color:${colorNeutralForeground1};cursor:pointer}:host(${placeholderShownState}){color:${colorNeutralForeground4}}.control{appearance:none;background-color:${colorNeutralBackground1};border-radius:${borderRadiusMedium};border:${strokeWidthThin} solid ${colorTransparentStroke};box-shadow:inset 0 0 0 ${strokeWidthThin} var(--control-border-color);box-sizing:border-box;color:inherit;column-gap:${spacingHorizontalXXS};display:inline-flex;justify-content:space-between;min-width:160px;overflow:hidden;padding:${spacingVerticalSNudge} ${spacingHorizontalMNudge};position:relative;text-align:start;width:100%;z-index:1;${typographyBody1Styles}}:host([size='small']) .control{column-gap:${spacingHorizontalXXS};padding:${spacingVerticalXS} ${spacingHorizontalSNudge};${typographyCaption1Styles}}:host([size='large']) .control{column-gap:${spacingHorizontalS};padding:${spacingVerticalS} ${spacingHorizontalM};${typographyBody2Styles}}::slotted(:is(input,button)){all:unset;flex:1 1 auto}::slotted(button){cursor:pointer}::slotted(input){cursor:text}:where(slot[name='indicator'] > *,::slotted([slot='indicator'])){all:unset;align-items:center;appearance:none;aspect-ratio:1;color:${colorNeutralForeground3};display:inline-flex;justify-content:center;width:20px}:host([size='small']) :where(slot[name='indicator'] > *,::slotted([slot='indicator'])){width:16px}:host([size='large']) :where(slot[name='indicator'] > *,::slotted([slot='indicator'])){width:24px}.control::after,.control::before{content:'' / '';inset:auto 0 0;pointer-events:none;position:absolute}.control::before{height:${strokeWidthThin}}.control::after{background-color:${colorCompoundBrandStroke};height:${strokeWidthThick};scale:0 1;transition:scale ${durationUltraFast} ${curveDecelerateMid}}:host(:where(:focus-within)) .control{border-radius:${borderRadiusMedium};box-shadow:inset 0 0 0 1px ${colorStrokeFocus1};outline:${strokeWidthThick} solid ${colorStrokeFocus2}}:host(:where(${openState},:focus-within)) .control::after{scale:1 1;transition-duration:${durationNormal};transition-timing-function:${curveAccelerateMid}}:host(:where([appearance='outline'],[appearance='transparent'])) .control::before{background-color:${colorNeutralStrokeAccessible}}:host([appearance='transparent']) .control{--control-border-color:${colorTransparentStrokeInteractive};background-color:${colorTransparentBackground};border-radius:${borderRadiusNone}}:host([appearance='outline']) .control{--control-border-color:${colorNeutralStroke1}}:host([appearance='outline']) .control:hover{--control-border-color:${colorNeutralStroke1Hover}}:host(:where([appearance='outline'],[appearance='transparent'])) .control:hover::before{background-color:${colorNeutralStrokeAccessibleHover}}:host([appearance='outline']) .control:hover::after{background-color:${colorCompoundBrandBackgroundHover}}:host([appearance='outline']) .control:active{--control-border-color:${colorNeutralStroke1Pressed}}:host(:where([appearance='outline'],[appearance='transparent'])) .control:active::before{background-color:${colorNeutralStrokeAccessiblePressed}}:host(:where([appearance='outline'],[appearance='transparent'])) .control:active::after{background-color:${colorCompoundBrandBackgroundPressed}}:host([appearance='filled-darker']) .control{background-color:${colorNeutralBackground3}}:host(:where([appearance='filled-lighter'],[appearance='filled-darker'])) .control{--control-border-color:${colorTransparentStroke}}:host(:disabled),:host(:disabled) ::slotted(:where(button,input)){cursor:not-allowed}:host(:disabled) .control::before,:host(:disabled) .control::after{content:none}:host(:disabled) .control:is(*,:active,:hover),:host(:disabled) :where(slot[name='indicator'] > *,::slotted([slot='indicator'])){--control-border-color:${colorNeutralStrokeDisabled};background-color:${colorNeutralBackgroundDisabled};color:${colorNeutralForegroundDisabled}}::slotted([popover]:not(:popover-open)){display:none}@supports not (anchor-name:--anchor){:host{--listbox-max-height:50vh;--margin-offset:calc(${lineHeightBase300} + (${spacingVerticalSNudge} * 2) + ${strokeWidthThin})}:host([size='small']){--margin-offset:calc(${lineHeightBase200} + (${spacingVerticalXS} * 2) + ${strokeWidthThin})}:host([size='large']){--margin-offset:calc(${lineHeightBase400} + (${spacingVerticalS} * 2) + ${strokeWidthThin})}}@media (forced-colors:active){:host(:disabled) .control{border-color:GrayText}:host(:disabled) :where(slot[name='indicator'] > *,::slotted([slot='indicator'])){color:GrayText}`;
8111
+ :host{anchor-name:--dropdown-trigger;box-sizing:border-box;color:${colorNeutralForeground1};cursor:pointer}:host(${placeholderShownState}){color:${colorNeutralForeground4}}.control{appearance:none;background-color:${colorNeutralBackground1};border-radius:${borderRadiusMedium};border:${strokeWidthThin} solid ${colorTransparentStroke};box-shadow:inset 0 0 0 ${strokeWidthThin} var(--control-border-color);box-sizing:border-box;color:inherit;column-gap:${spacingHorizontalXXS};display:inline-flex;justify-content:space-between;min-width:160px;overflow:hidden;padding:${spacingVerticalSNudge} ${spacingHorizontalMNudge};position:relative;text-align:start;width:100%;z-index:1;${typographyBody1Styles}}:host([size='small']) .control{column-gap:${spacingHorizontalXXS};padding:${spacingVerticalXS} ${spacingHorizontalSNudge};${typographyCaption1Styles}}:host([size='large']) .control{column-gap:${spacingHorizontalS};padding:${spacingVerticalS} ${spacingHorizontalM};${typographyBody2Styles}}::slotted(:is(input,button)){all:unset;flex:1 1 auto}::slotted(button){cursor:pointer}::slotted(input){cursor:text}:where(slot[name='indicator'] > *,::slotted([slot='indicator'])){all:unset;align-items:center;appearance:none;aspect-ratio:1;color:${colorNeutralForeground3};display:inline-flex;justify-content:center;width:20px}:host([size='small']) :where(slot[name='indicator'] > *,::slotted([slot='indicator'])){width:16px}:host([size='large']) :where(slot[name='indicator'] > *,::slotted([slot='indicator'])){width:24px}.control::after,.control::before{content:'' / '';inset:auto 0 0;pointer-events:none;position:absolute}.control::before{height:${strokeWidthThin}}.control::after{background-color:${colorCompoundBrandStroke};height:${strokeWidthThick};scale:0 1;transition:scale ${durationUltraFast} ${curveDecelerateMid}}:host(:where(:focus-within)) .control{border-radius:${borderRadiusMedium};box-shadow:inset 0 0 0 1px ${colorStrokeFocus1};outline:${strokeWidthThick} solid ${colorStrokeFocus2}}:host(:where(${openState},:focus-within)) .control::after{scale:1 1;transition-duration:${durationNormal};transition-timing-function:${curveAccelerateMid}}:host(:where([appearance='outline'],[appearance='transparent'])) .control::before{background-color:${colorNeutralStrokeAccessible}}:host([appearance='transparent']) .control{--control-border-color:${colorTransparentStrokeInteractive};background-color:${colorTransparentBackground};border-radius:${borderRadiusNone}}:host([appearance='outline']) .control{--control-border-color:${colorNeutralStroke1}}:host([appearance='outline']) .control:hover{--control-border-color:${colorNeutralStroke1Hover}}:host(:where([appearance='outline'],[appearance='transparent'])) .control:hover::before{background-color:${colorNeutralStrokeAccessibleHover}}:host([appearance='outline']) .control:hover::after{background-color:${colorCompoundBrandBackgroundHover}}:host([appearance='outline']) .control:active{--control-border-color:${colorNeutralStroke1Pressed}}:host(:where([appearance='outline'],[appearance='transparent'])) .control:active::before{background-color:${colorNeutralStrokeAccessiblePressed}}:host(:where([appearance='outline'],[appearance='transparent'])) .control:active::after{background-color:${colorCompoundBrandBackgroundPressed}}:host([appearance='filled-darker']) .control{background-color:${colorNeutralBackground3}}:host(:where([appearance='filled-lighter'],[appearance='filled-darker'])) .control{--control-border-color:${colorTransparentStroke}}:host(:disabled),:host(:disabled) ::slotted(:where(button,input)){cursor:not-allowed}:host(:disabled) .control::before,:host(:disabled) .control::after{content:none}:host(:disabled) .control:is(*,:active,:hover),:host(:disabled) :where(slot[name='indicator'] > *,::slotted([slot='indicator'])){--control-border-color:${colorNeutralStrokeDisabled};background-color:${colorNeutralBackgroundDisabled};color:${colorNeutralForegroundDisabled}}::slotted(:not([slot]):not([popover])),::slotted([popover]:not(:popover-open)){display:none}@supports not (anchor-name:--anchor){:host{--listbox-max-height:50vh;--margin-offset:calc(${lineHeightBase300} + (${spacingVerticalSNudge} * 2) + ${strokeWidthThin})}:host([size='small']){--margin-offset:calc(${lineHeightBase200} + (${spacingVerticalXS} * 2) + ${strokeWidthThin})}:host([size='large']){--margin-offset:calc(${lineHeightBase400} + (${spacingVerticalS} * 2) + ${strokeWidthThin})}}@media (forced-colors:active){:host(:disabled) .control{border-color:GrayText}:host(:disabled) :where(slot[name='indicator'] > *,::slotted([slot='indicator'])){color:GrayText}`;
8089
8112
 
8090
8113
  const definition$r = Dropdown.compose({
8091
8114
  name: `${FluentDesignSystem.prefix}-dropdown`,
@@ -8937,7 +8960,7 @@ var __decorateClass$o = (decorators, target, key, kind) => {
8937
8960
  if (kind && result) __defProp$o(target, key, result);
8938
8961
  return result;
8939
8962
  };
8940
- const _MenuList = class _MenuList extends FASTElement {
8963
+ const _BaseMenuList = class _BaseMenuList extends FASTElement {
8941
8964
  constructor() {
8942
8965
  super();
8943
8966
  /**
@@ -9017,7 +9040,7 @@ const _MenuList = class _MenuList extends FASTElement {
9017
9040
  * check if the item is a menu item
9018
9041
  */
9019
9042
  this.isMenuItemElement = el => {
9020
- return isMenuItem(el) || isHTMLElement(el) && !!el.role && el.role in _MenuList.focusableElementRoles;
9043
+ return isMenuItem(el) || isHTMLElement(el) && !!el.role && el.role in _BaseMenuList.focusableElementRoles;
9021
9044
  };
9022
9045
  /**
9023
9046
  * check if the item is focusable
@@ -9113,7 +9136,7 @@ const _MenuList = class _MenuList extends FASTElement {
9113
9136
  });
9114
9137
  const filteredMenuListItems = this.menuItems?.filter(this.isMenuItemElement);
9115
9138
  const indent = filteredMenuListItems?.reduce((accum, current) => {
9116
- const elementValue = _MenuList.elementIndent(current);
9139
+ const elementValue = _BaseMenuList.elementIndent(current);
9117
9140
  return Math.max(accum, elementValue);
9118
9141
  }, 0);
9119
9142
  filteredMenuListItems?.forEach(item => {
@@ -9147,9 +9170,11 @@ const _MenuList = class _MenuList extends FASTElement {
9147
9170
  }
9148
9171
  }
9149
9172
  };
9150
- _MenuList.focusableElementRoles = MenuItemRole;
9151
- __decorateClass$o([observable], _MenuList.prototype, "items", 2);
9152
- let MenuList = _MenuList;
9173
+ _BaseMenuList.focusableElementRoles = MenuItemRole;
9174
+ __decorateClass$o([observable], _BaseMenuList.prototype, "items", 2);
9175
+ let BaseMenuList = _BaseMenuList;
9176
+
9177
+ class MenuList extends BaseMenuList {}
9153
9178
 
9154
9179
  const styles$j = css`
9155
9180
  ${display("flex")}
@@ -9274,7 +9299,33 @@ class Menu extends FASTElement {
9274
9299
  * @internal
9275
9300
  */
9276
9301
  slottedMenuListChanged(prev, next) {
9277
- this.setComponent();
9302
+ this._menuListAbortController?.abort();
9303
+ if (!next?.length) {
9304
+ return;
9305
+ }
9306
+ this._menuList = next[0];
9307
+ this._menuList.popover = this.openOnContext ? "manual" : "";
9308
+ this.addMenuListListeners();
9309
+ }
9310
+ /**
9311
+ * Ensures the trigger is properly set up when the slotted triggers change.
9312
+ * This includes setting ARIA attributes and adding event listeners based on the current property values.
9313
+ *
9314
+ * @param prev - The previous items in the slotted triggers list.
9315
+ * @param next - The current items in the slotted triggers list.
9316
+ * @internal
9317
+ */
9318
+ slottedTriggersChanged(prev, next) {
9319
+ this._triggerAbortController?.abort();
9320
+ if (next?.length) {
9321
+ const trigger = next[0];
9322
+ this._trigger = trigger;
9323
+ if (this._trigger?.isConnected) {
9324
+ this._trigger.setAttribute("aria-haspopup", "true");
9325
+ this._trigger.setAttribute("aria-expanded", `${this._open}`);
9326
+ this.addTriggerListeners();
9327
+ }
9328
+ }
9278
9329
  }
9279
9330
  /**
9280
9331
  * Called when the element is connected to the DOM.
@@ -9292,32 +9343,16 @@ class Menu extends FASTElement {
9292
9343
  */
9293
9344
  disconnectedCallback() {
9294
9345
  super.disconnectedCallback();
9295
- this.removeListeners();
9346
+ this._triggerAbortController?.abort();
9347
+ this._menuListAbortController?.abort();
9296
9348
  }
9297
9349
  /**
9298
9350
  * Sets the component.
9299
- * Sets the trigger and menu list elements and adds event listeners.
9351
+ * @deprecated This method is no longer used. Trigger and menu-list listeners are now
9352
+ * managed by their respective slot-changed callbacks.
9300
9353
  * @public
9301
9354
  */
9302
- setComponent() {
9303
- waitForConnectedDescendants(this, () => {
9304
- const trigger = this.slottedTriggers?.[0];
9305
- const menuList = this.slottedMenuList?.[0];
9306
- if (!trigger || !menuList) {
9307
- this.removeListeners();
9308
- return;
9309
- }
9310
- this._trigger = trigger;
9311
- this._menuList = menuList;
9312
- this._trigger.setAttribute("aria-haspopup", "true");
9313
- this._trigger.setAttribute("aria-expanded", `${this._open}`);
9314
- this._menuList.setAttribute("popover", this.openOnContext ? "manual" : "");
9315
- this.removeListeners();
9316
- this.addListeners();
9317
- }, {
9318
- shallow: true
9319
- });
9320
- }
9355
+ setComponent() {}
9321
9356
  /**
9322
9357
  * Focuses on the menu list.
9323
9358
  * @public
@@ -9345,10 +9380,9 @@ class Menu extends FASTElement {
9345
9380
  * @public
9346
9381
  */
9347
9382
  openOnHoverChanged(oldValue, newValue) {
9348
- if (newValue) {
9349
- this._trigger?.addEventListener("mouseover", this.openMenu);
9350
- } else {
9351
- this._trigger?.removeEventListener("mouseover", this.openMenu);
9383
+ if (this._trigger) {
9384
+ this._triggerAbortController?.abort();
9385
+ this.addTriggerListeners();
9352
9386
  }
9353
9387
  }
9354
9388
  /**
@@ -9359,10 +9393,9 @@ class Menu extends FASTElement {
9359
9393
  * @param newValue - The new value of 'persistOnItemClick'.
9360
9394
  */
9361
9395
  persistOnItemClickChanged(oldValue, newValue) {
9362
- if (!newValue) {
9363
- this._menuList?.addEventListener("change", this.closeMenu);
9364
- } else {
9365
- this._menuList?.removeEventListener("change", this.closeMenu);
9396
+ if (this._menuList) {
9397
+ this._menuListAbortController?.abort();
9398
+ this.addMenuListListeners();
9366
9399
  }
9367
9400
  }
9368
9401
  /**
@@ -9374,9 +9407,13 @@ class Menu extends FASTElement {
9374
9407
  */
9375
9408
  openOnContextChanged(oldValue, newValue) {
9376
9409
  if (newValue) {
9377
- this._trigger?.addEventListener("contextmenu", this.openMenu);
9410
+ this._menuList?.setAttribute("popover", "manual");
9378
9411
  } else {
9379
- this._trigger?.removeEventListener("contextmenu", this.openMenu);
9412
+ this._menuList?.setAttribute("popover", "");
9413
+ }
9414
+ if (this._trigger) {
9415
+ this._triggerAbortController?.abort();
9416
+ this.addTriggerListeners();
9380
9417
  }
9381
9418
  }
9382
9419
  /**
@@ -9394,50 +9431,50 @@ class Menu extends FASTElement {
9394
9431
  }
9395
9432
  }
9396
9433
  /**
9397
- * Adds event listeners.
9398
- * Adds click and keydown event listeners to the trigger.
9399
- * Adds a 'toggle' event listener to the menu list.
9400
- * If 'openOnHover' is true, adds a 'mouseover' event listener to the trigger.
9401
- * If 'openOnContext' is true, adds a 'contextmenu' event listener to the trigger and a document 'click' event listener.
9434
+ * Adds trigger-related event listeners.
9402
9435
  * @internal
9403
9436
  */
9404
- addListeners() {
9405
- this._menuList?.addEventListener("toggle", this.toggleHandler);
9406
- this._trigger?.addEventListener("keydown", this.triggerKeydownHandler);
9407
- if (!this.persistOnItemClick) {
9408
- this._menuList?.addEventListener("change", this.closeMenu);
9409
- }
9437
+ addTriggerListeners() {
9438
+ this._triggerAbortController = new AbortController();
9439
+ const {
9440
+ signal
9441
+ } = this._triggerAbortController;
9442
+ this._trigger?.addEventListener("keydown", this.triggerKeydownHandler, {
9443
+ signal
9444
+ });
9410
9445
  if (this.openOnHover) {
9411
- this._trigger?.addEventListener("mouseover", this.openMenu);
9446
+ this._trigger?.addEventListener("mouseover", this.openMenu, {
9447
+ signal
9448
+ });
9412
9449
  } else if (this.openOnContext) {
9413
- this._trigger?.addEventListener("contextmenu", this.openMenu);
9414
- document.addEventListener("click", this.documentClickHandler);
9450
+ this._trigger?.addEventListener("contextmenu", this.openMenu, {
9451
+ signal
9452
+ });
9453
+ document.addEventListener("click", this.documentClickHandler, {
9454
+ signal
9455
+ });
9415
9456
  } else {
9416
- this._trigger?.addEventListener("click", this.toggleMenu);
9457
+ this._trigger?.addEventListener("click", this.toggleMenu, {
9458
+ signal
9459
+ });
9417
9460
  }
9418
9461
  }
9419
9462
  /**
9420
- * Removes event listeners.
9421
- * Removes click and keydown event listeners from the trigger.
9422
- * Also removes toggle event listener from the menu list.
9423
- * Also removes 'mouseover' event listeners from the trigger.
9424
- * Also removes 'contextmenu' event listeners from the trigger and document 'click' event listeners.
9463
+ * Adds menu-list event listeners.
9425
9464
  * @internal
9426
9465
  */
9427
- removeListeners() {
9428
- this._menuList?.removeEventListener("toggle", this.toggleHandler);
9429
- this._trigger?.removeEventListener("keydown", this.triggerKeydownHandler);
9466
+ addMenuListListeners() {
9467
+ this._menuListAbortController = new AbortController();
9468
+ const {
9469
+ signal
9470
+ } = this._menuListAbortController;
9471
+ this._menuList?.addEventListener("toggle", this.toggleHandler, {
9472
+ signal
9473
+ });
9430
9474
  if (!this.persistOnItemClick) {
9431
- this._menuList?.removeEventListener("change", this.closeMenu);
9432
- }
9433
- if (this.openOnHover) {
9434
- this._trigger?.removeEventListener("mouseover", this.openMenu);
9435
- }
9436
- if (this.openOnContext) {
9437
- this._trigger?.removeEventListener("contextmenu", this.openMenu);
9438
- document.removeEventListener("click", this.documentClickHandler);
9439
- } else {
9440
- this._trigger?.removeEventListener("click", this.toggleMenu);
9475
+ this._menuList?.addEventListener("change", this.closeMenu, {
9476
+ signal
9477
+ });
9441
9478
  }
9442
9479
  }
9443
9480
  /**
@@ -10032,7 +10069,7 @@ var __decorateClass$i = (decorators, target, key, kind) => {
10032
10069
  if (kind && result) __defProp$i(target, key, result);
10033
10070
  return result;
10034
10071
  };
10035
- class RadioGroup extends FASTElement {
10072
+ class BaseRadioGroup extends FASTElement {
10036
10073
  constructor() {
10037
10074
  super();
10038
10075
  /**
@@ -10488,23 +10525,25 @@ class RadioGroup extends FASTElement {
10488
10525
  *
10489
10526
  * @public
10490
10527
  */
10491
- RadioGroup.formAssociated = true;
10492
- __decorateClass$i([observable], RadioGroup.prototype, "checkedIndex", 2);
10528
+ BaseRadioGroup.formAssociated = true;
10529
+ __decorateClass$i([observable], BaseRadioGroup.prototype, "checkedIndex", 2);
10493
10530
  __decorateClass$i([attr({
10494
10531
  attribute: "disabled",
10495
10532
  mode: "boolean"
10496
- })], RadioGroup.prototype, "disabled", 2);
10533
+ })], BaseRadioGroup.prototype, "disabled", 2);
10497
10534
  __decorateClass$i([attr({
10498
10535
  attribute: "value",
10499
10536
  mode: "fromView"
10500
- })], RadioGroup.prototype, "initialValue", 2);
10501
- __decorateClass$i([attr], RadioGroup.prototype, "name", 2);
10502
- __decorateClass$i([attr], RadioGroup.prototype, "orientation", 2);
10503
- __decorateClass$i([observable], RadioGroup.prototype, "radios", 2);
10537
+ })], BaseRadioGroup.prototype, "initialValue", 2);
10538
+ __decorateClass$i([attr], BaseRadioGroup.prototype, "name", 2);
10539
+ __decorateClass$i([attr], BaseRadioGroup.prototype, "orientation", 2);
10540
+ __decorateClass$i([observable], BaseRadioGroup.prototype, "radios", 2);
10504
10541
  __decorateClass$i([attr({
10505
10542
  mode: "boolean"
10506
- })], RadioGroup.prototype, "required", 2);
10507
- __decorateClass$i([observable], RadioGroup.prototype, "slottedRadios", 2);
10543
+ })], BaseRadioGroup.prototype, "required", 2);
10544
+ __decorateClass$i([observable], BaseRadioGroup.prototype, "slottedRadios", 2);
10545
+
10546
+ class RadioGroup extends BaseRadioGroup {}
10508
10547
 
10509
10548
  const styles$e = css`
10510
10549
  ${display("flex")}
@@ -11742,9 +11781,9 @@ class BaseTablist extends FASTElement {
11742
11781
  });
11743
11782
  }
11744
11783
  getTabIds() {
11745
- return this.tabs.map(tab => {
11784
+ return this.tabs?.map(tab => {
11746
11785
  return tab.getAttribute("id") ?? `tab-${uniqueId$1()}`;
11747
- });
11786
+ }) ?? [];
11748
11787
  }
11749
11788
  setComponent() {
11750
11789
  if (this.activeTabIndex !== this.prevActiveTabIndex) {
@@ -11789,6 +11828,8 @@ class BaseTablist extends FASTElement {
11789
11828
  waitForConnectedDescendants(this, () => {
11790
11829
  this.tabIds = this.getTabIds();
11791
11830
  this.setTabs();
11831
+ }, {
11832
+ shallow: true
11792
11833
  });
11793
11834
  }
11794
11835
  }