@fluentui/web-components 3.0.0-rc.13 → 3.0.0-rc.15

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.
@@ -46,6 +46,11 @@ export declare class Accordion extends FASTElement {
46
46
  * @internal
47
47
  */
48
48
  slottedAccordionItemsChanged(oldValue: HTMLElement[], newValue: HTMLElement[]): void;
49
+ /**
50
+ * Guard flag to prevent re-entrant calls to setSingleExpandMode.
51
+ * @internal
52
+ */
53
+ private _isAdjusting;
49
54
  /**
50
55
  * Watch for changes to the slotted accordion items `disabled` and `expanded` attributes
51
56
  * @internal
@@ -818,14 +823,6 @@ export declare class BaseAccordionItem extends FASTElement {
818
823
  * HTML attribute: disabled
819
824
  */
820
825
  disabled: boolean;
821
- /**
822
- * The item ID
823
- *
824
- * @public
825
- * @remarks
826
- * HTML Attribute: id
827
- */
828
- id: string;
829
826
  /**
830
827
  * @internal
831
828
  */
@@ -2088,6 +2085,11 @@ export declare class BaseDropdown extends FASTElement {
2088
2085
  * @public
2089
2086
  */
2090
2087
  inputHandler(e: InputEvent): boolean | void;
2088
+ /**
2089
+ * Guard flag to prevent reentrant calls to `insertControl`.
2090
+ * @internal
2091
+ */
2092
+ private _insertingControl;
2091
2093
  /**
2092
2094
  * Inserts the control element based on the dropdown type.
2093
2095
  *
@@ -8653,19 +8655,28 @@ export declare class Menu extends FASTElement {
8653
8655
  * Holds the slotted menu list.
8654
8656
  * @public
8655
8657
  */
8656
- slottedMenuList: MenuList[];
8658
+ slottedMenuList: HTMLElement[];
8657
8659
  /**
8658
8660
  * Sets up the component when the slotted menu list changes.
8659
8661
  * @param prev - The previous items in the slotted menu list.
8660
8662
  * @param next - The new items in the slotted menu list.
8661
8663
  * @internal
8662
8664
  */
8663
- slottedMenuListChanged(prev: MenuList[] | undefined, next: MenuList[] | undefined): void;
8665
+ slottedMenuListChanged(prev: HTMLElement[] | undefined, next: HTMLElement[] | undefined): void;
8664
8666
  /**
8665
8667
  * Holds the slotted triggers.
8666
8668
  * @public
8667
8669
  */
8668
8670
  slottedTriggers: HTMLElement[];
8671
+ /**
8672
+ * Ensures the trigger is properly set up when the slotted triggers change.
8673
+ * This includes setting ARIA attributes and adding event listeners based on the current property values.
8674
+ *
8675
+ * @param prev - The previous items in the slotted triggers list.
8676
+ * @param next - The current items in the slotted triggers list.
8677
+ * @internal
8678
+ */
8679
+ slottedTriggersChanged(prev: HTMLElement[] | undefined, next: HTMLElement[] | undefined): void;
8669
8680
  /**
8670
8681
  * Holds the primary slot element.
8671
8682
  * @public
@@ -8686,6 +8697,14 @@ export declare class Menu extends FASTElement {
8686
8697
  * @internal
8687
8698
  */
8688
8699
  private _menuList?;
8700
+ /**
8701
+ * @internal
8702
+ */
8703
+ private _triggerAbortController?;
8704
+ /**
8705
+ * @internal
8706
+ */
8707
+ private _menuListAbortController?;
8689
8708
  /**
8690
8709
  * Called when the element is connected to the DOM.
8691
8710
  * Sets up the component.
@@ -8700,7 +8719,8 @@ export declare class Menu extends FASTElement {
8700
8719
  disconnectedCallback(): void;
8701
8720
  /**
8702
8721
  * Sets the component.
8703
- * Sets the trigger and menu list elements and adds event listeners.
8722
+ * @deprecated This method is no longer used. Trigger and menu-list listeners are now
8723
+ * managed by their respective slot-changed callbacks.
8704
8724
  * @public
8705
8725
  */
8706
8726
  setComponent(): void;
@@ -8770,23 +8790,15 @@ export declare class Menu extends FASTElement {
8770
8790
  */
8771
8791
  closeOnScrollChanged(oldValue: boolean, newValue: boolean): void;
8772
8792
  /**
8773
- * Adds event listeners.
8774
- * Adds click and keydown event listeners to the trigger.
8775
- * Adds a 'toggle' event listener to the menu list.
8776
- * If 'openOnHover' is true, adds a 'mouseover' event listener to the trigger.
8777
- * If 'openOnContext' is true, adds a 'contextmenu' event listener to the trigger and a document 'click' event listener.
8793
+ * Adds trigger-related event listeners.
8778
8794
  * @internal
8779
8795
  */
8780
- private addListeners;
8796
+ private addTriggerListeners;
8781
8797
  /**
8782
- * Removes event listeners.
8783
- * Removes click and keydown event listeners from the trigger.
8784
- * Also removes toggle event listener from the menu list.
8785
- * Also removes 'mouseover' event listeners from the trigger.
8786
- * Also removes 'contextmenu' event listeners from the trigger and document 'click' event listeners.
8798
+ * Adds menu-list event listeners.
8787
8799
  * @internal
8788
8800
  */
8789
- private removeListeners;
8801
+ private addMenuListListeners;
8790
8802
  /**
8791
8803
  * Handles keyboard interaction for the menu. Closes the menu and focuses on the trigger when the Escape key is
8792
8804
  * pressed. Closes the menu when the Tab key is pressed.
@@ -4302,7 +4302,6 @@ class BaseAccordionItem extends FASTElement {
4302
4302
  this.headinglevel = 2;
4303
4303
  this.expanded = false;
4304
4304
  this.disabled = false;
4305
- this.id = uniqueId$1("accordion-");
4306
4305
  }
4307
4306
  }
4308
4307
  __decorateClass$O([attr({
@@ -4316,7 +4315,7 @@ __decorateClass$O([attr({
4316
4315
  __decorateClass$O([attr({
4317
4316
  mode: "boolean"
4318
4317
  })], BaseAccordionItem.prototype, "disabled", 2);
4319
- __decorateClass$O([attr], BaseAccordionItem.prototype, "id", 2);
4318
+ __decorateClass$O([observable], BaseAccordionItem.prototype, "expandbutton", 2);
4320
4319
 
4321
4320
  var __defProp$N = Object.defineProperty;
4322
4321
  var __getOwnPropDesc$N = Object.getOwnPropertyDescriptor;
@@ -4621,7 +4620,7 @@ const chevronDown20Filled = html.partial(`<svg
4621
4620
  />
4622
4621
  </svg>`);
4623
4622
  function accordionItemTemplate(options = {}) {
4624
- return html`<div class="heading" part="heading" role="heading" aria-level="${x => x.headinglevel}"><button class="button" part="button" ${ref("expandbutton")} ?disabled="${x => x.disabled ? "true" : void 0}" aria-expanded="${x => x.expanded}" aria-controls="${x => x.id}-panel" id="${x => x.id}"><slot name="heading"></slot></button>${startSlotTemplate(options)}<slot name="marker-expanded">${staticallyCompose(options.expandedIcon)}</slot><slot name="marker-collapsed">${staticallyCompose(options.collapsedIcon)}</slot></div><div class="content" part="content" id="${x => x.id}-panel" role="region" aria-labelledby="${x => x.id}"><slot></slot></div>`;
4623
+ return html`<div class="heading" part="heading" role="heading" aria-level="${x => x.headinglevel}"><button class="button" part="button" id="control" aria-controls="panel" aria-expanded="${x => x.expanded}" ?disabled="${x => x.disabled}" ${ref("expandbutton")}><slot name="heading"></slot></button>${startSlotTemplate(options)}<slot name="marker-expanded">${staticallyCompose(options.expandedIcon)}</slot><slot name="marker-collapsed">${staticallyCompose(options.collapsedIcon)}</slot></div><div class="content" part="content" id="panel" role="region" aria-labelledby="control"><slot></slot></div>`;
4625
4624
  }
4626
4625
  const template$F = accordionItemTemplate({
4627
4626
  collapsedIcon: chevronRight20Filled,
@@ -4646,15 +4645,22 @@ function requestIdleCallback(callback, options) {
4646
4645
  didTimeout: options?.timeout ? Date.now() - start >= options.timeout : false,
4647
4646
  timeRemaining: () => 0
4648
4647
  });
4649
- }, 1);
4648
+ }, options?.timeout ?? 1);
4650
4649
  }
4651
4650
  function waitForConnectedDescendants(target, callback, options) {
4652
4651
  const shallow = options?.shallow ?? false;
4653
4652
  const timeout = options?.timeout ?? 50;
4653
+ const useIdleCallback = options?.idleCallback ?? false;
4654
4654
  const selector = `${shallow ? ":scope > " : ""}:not(:defined)`;
4655
4655
  const scheduleCheck = deadline => {
4656
4656
  if (target.querySelector(selector) === null || deadline && deadline.timeRemaining() <= 0) {
4657
- requestAnimationFrame(callback);
4657
+ if (useIdleCallback) {
4658
+ requestIdleCallback(callback, {
4659
+ timeout
4660
+ });
4661
+ } else {
4662
+ callback();
4663
+ }
4658
4664
  return;
4659
4665
  }
4660
4666
  requestIdleCallback(scheduleCheck, {
@@ -4684,6 +4690,11 @@ var __decorateClass$M = (decorators, target, key, kind) => {
4684
4690
  class Accordion extends FASTElement {
4685
4691
  constructor() {
4686
4692
  super(...arguments);
4693
+ /**
4694
+ * Guard flag to prevent re-entrant calls to setSingleExpandMode.
4695
+ * @internal
4696
+ */
4697
+ this._isAdjusting = false;
4687
4698
  this.activeItemIndex = 0;
4688
4699
  /**
4689
4700
  * Resets event listeners and sets the `accordionItems` property
@@ -4750,15 +4761,13 @@ class Accordion extends FASTElement {
4750
4761
  this.setSingleExpandMode(expandedItem);
4751
4762
  return;
4752
4763
  }
4753
- expandedItem?.expandbutton.removeAttribute("aria-disabled");
4764
+ expandedItem?.expandbutton?.removeAttribute("aria-disabled");
4754
4765
  }
4755
4766
  /**
4756
4767
  * @internal
4757
4768
  */
4758
4769
  slottedAccordionItemsChanged(oldValue, newValue) {
4759
- if (this.$fastController.isConnected) {
4760
- this.setItems();
4761
- }
4770
+ this.setItems();
4762
4771
  }
4763
4772
  /**
4764
4773
  * Watch for changes to the slotted accordion items `disabled` and `expanded` attributes
@@ -4768,8 +4777,10 @@ class Accordion extends FASTElement {
4768
4777
  if (propertyName === "disabled") {
4769
4778
  this.setItems();
4770
4779
  } else if (propertyName === "expanded") {
4771
- if (source.expanded && this.isSingleExpandMode()) {
4780
+ if (source.expanded && this.isSingleExpandMode() && !this._isAdjusting) {
4781
+ this._isAdjusting = true;
4772
4782
  this.setSingleExpandMode(source);
4783
+ this._isAdjusting = false;
4773
4784
  }
4774
4785
  }
4775
4786
  }
@@ -4796,33 +4807,29 @@ class Accordion extends FASTElement {
4796
4807
  * @returns {void}
4797
4808
  */
4798
4809
  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
- }
4810
+ if (this.accordionItems.length === 0) {
4811
+ return;
4812
+ }
4813
+ const currentItems = Array.from(this.accordionItems);
4814
+ this.activeItemIndex = currentItems.indexOf(expandedItem);
4815
+ currentItems.forEach((item, index) => {
4816
+ if (isAccordionItem(item)) {
4817
+ if (this.activeItemIndex === index) {
4818
+ item.expanded = true;
4819
+ item.expandbutton?.setAttribute("aria-disabled", "true");
4820
+ } else {
4821
+ item.expanded = false;
4822
+ if (!item.hasAttribute("disabled")) {
4823
+ item.expandbutton?.removeAttribute("aria-disabled");
4815
4824
  }
4816
4825
  }
4817
- });
4826
+ }
4818
4827
  });
4819
4828
  }
4820
4829
  connectedCallback() {
4821
4830
  super.connectedCallback();
4822
- requestAnimationFrame(() => {
4823
- this.expandmode = this.expandmode || AccordionExpandMode.multi;
4824
- this.setItems();
4825
- });
4831
+ this.expandmode = this.expandmode || AccordionExpandMode.multi;
4832
+ this.setItems();
4826
4833
  }
4827
4834
  }
4828
4835
  __decorateClass$M([attr({
@@ -7154,7 +7161,6 @@ class Drawer extends FASTElement {
7154
7161
  * Handles click events on the drawer.
7155
7162
  */
7156
7163
  clickHandler(event) {
7157
- event.preventDefault();
7158
7164
  if (this.dialog.open && event.target === this.dialog) {
7159
7165
  this.hide();
7160
7166
  }
@@ -7346,6 +7352,11 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7346
7352
  * @internal
7347
7353
  */
7348
7354
  this.elementInternals = this.attachInternals();
7355
+ /**
7356
+ * Guard flag to prevent reentrant calls to `insertControl`.
7357
+ * @internal
7358
+ */
7359
+ this._insertingControl = false;
7349
7360
  this.elementInternals.role = "presentation";
7350
7361
  }
7351
7362
  get activeDescendant() {
@@ -7440,7 +7451,7 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7440
7451
  const notifier = Observable.getNotifier(this);
7441
7452
  notifier.subscribe(next);
7442
7453
  notifier.notify("multiple");
7443
- Updates.enqueue(() => {
7454
+ waitForConnectedDescendants(next, () => {
7444
7455
  this.options.forEach(option => {
7445
7456
  option.disabled = option.disabledAttribute || this.disabled;
7446
7457
  option.name = this.name;
@@ -7449,6 +7460,8 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7449
7460
  x.selected = this.multiple || i === 0;
7450
7461
  });
7451
7462
  this.setValidity();
7463
+ }, {
7464
+ idleCallback: true
7452
7465
  });
7453
7466
  if (AnchorPositioningCSSSupported) {
7454
7467
  const anchorName = uniqueId("--dropdown-anchor-");
@@ -7792,12 +7805,17 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7792
7805
  * This method can be overridden in derived classes to provide custom control elements, though this is not recommended.
7793
7806
  */
7794
7807
  insertControl() {
7808
+ if (this._insertingControl) {
7809
+ return;
7810
+ }
7811
+ this._insertingControl = true;
7795
7812
  this.controlSlot?.assignedNodes().forEach(x => this.removeChild(x));
7796
7813
  if (this.type === DropdownType.combobox) {
7797
7814
  dropdownInputTemplate.render(this, this);
7798
7815
  return;
7799
7816
  }
7800
7817
  dropdownButtonTemplate.render(this, this);
7818
+ this._insertingControl = false;
7801
7819
  }
7802
7820
  /**
7803
7821
  * Handles the keydown events for the dropdown.
@@ -7896,7 +7914,9 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7896
7914
  */
7897
7915
  selectOption(index = this.selectedIndex, shouldEmit = false) {
7898
7916
  this.listbox.selectOption(index);
7899
- this.control.value = this.displayValue;
7917
+ if (this.control) {
7918
+ this.control.value = this.displayValue;
7919
+ }
7900
7920
  this.setValidity();
7901
7921
  this.updateFreeformOption();
7902
7922
  if (shouldEmit) {
@@ -7913,17 +7933,18 @@ const _BaseDropdown = class _BaseDropdown extends FASTElement {
7913
7933
  * @internal
7914
7934
  */
7915
7935
  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);
7936
+ if (!this.elementInternals) {
7937
+ return;
7926
7938
  }
7939
+ if (this.disabled || !this.required) {
7940
+ this.elementInternals.setValidity({});
7941
+ return;
7942
+ }
7943
+ const valueMissing = this.required && this.listbox.selectedOptions.length === 0;
7944
+ this.elementInternals.setValidity({
7945
+ valueMissing,
7946
+ ...flags
7947
+ }, message ?? this.validationMessage, anchor ?? this.control);
7927
7948
  }
7928
7949
  /**
7929
7950
  * Handles the `slotchange` event for the dropdown.
@@ -8085,7 +8106,7 @@ __decorateClass$w([attr], Dropdown.prototype, "size", 2);
8085
8106
  const styles$q = css`
8086
8107
  ${display("inline-flex")}
8087
8108
 
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}`;
8109
+ :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
8110
 
8090
8111
  const definition$r = Dropdown.compose({
8091
8112
  name: `${FluentDesignSystem.prefix}-dropdown`,
@@ -9276,7 +9297,33 @@ class Menu extends FASTElement {
9276
9297
  * @internal
9277
9298
  */
9278
9299
  slottedMenuListChanged(prev, next) {
9279
- this.setComponent();
9300
+ this._menuListAbortController?.abort();
9301
+ if (!next?.length) {
9302
+ return;
9303
+ }
9304
+ this._menuList = next[0];
9305
+ this._menuList.popover = this.openOnContext ? "manual" : "";
9306
+ this.addMenuListListeners();
9307
+ }
9308
+ /**
9309
+ * Ensures the trigger is properly set up when the slotted triggers change.
9310
+ * This includes setting ARIA attributes and adding event listeners based on the current property values.
9311
+ *
9312
+ * @param prev - The previous items in the slotted triggers list.
9313
+ * @param next - The current items in the slotted triggers list.
9314
+ * @internal
9315
+ */
9316
+ slottedTriggersChanged(prev, next) {
9317
+ this._triggerAbortController?.abort();
9318
+ if (next?.length) {
9319
+ const trigger = next[0];
9320
+ this._trigger = trigger;
9321
+ if (this._trigger?.isConnected) {
9322
+ this._trigger.setAttribute("aria-haspopup", "true");
9323
+ this._trigger.setAttribute("aria-expanded", `${this._open}`);
9324
+ this.addTriggerListeners();
9325
+ }
9326
+ }
9280
9327
  }
9281
9328
  /**
9282
9329
  * Called when the element is connected to the DOM.
@@ -9294,32 +9341,16 @@ class Menu extends FASTElement {
9294
9341
  */
9295
9342
  disconnectedCallback() {
9296
9343
  super.disconnectedCallback();
9297
- this.removeListeners();
9344
+ this._triggerAbortController?.abort();
9345
+ this._menuListAbortController?.abort();
9298
9346
  }
9299
9347
  /**
9300
9348
  * Sets the component.
9301
- * Sets the trigger and menu list elements and adds event listeners.
9349
+ * @deprecated This method is no longer used. Trigger and menu-list listeners are now
9350
+ * managed by their respective slot-changed callbacks.
9302
9351
  * @public
9303
9352
  */
9304
- setComponent() {
9305
- waitForConnectedDescendants(this, () => {
9306
- const trigger = this.slottedTriggers?.[0];
9307
- const menuList = this.slottedMenuList?.[0];
9308
- if (!trigger || !menuList) {
9309
- this.removeListeners();
9310
- return;
9311
- }
9312
- this._trigger = trigger;
9313
- this._menuList = menuList;
9314
- this._trigger.setAttribute("aria-haspopup", "true");
9315
- this._trigger.setAttribute("aria-expanded", `${this._open}`);
9316
- this._menuList.setAttribute("popover", this.openOnContext ? "manual" : "");
9317
- this.removeListeners();
9318
- this.addListeners();
9319
- }, {
9320
- shallow: true
9321
- });
9322
- }
9353
+ setComponent() {}
9323
9354
  /**
9324
9355
  * Focuses on the menu list.
9325
9356
  * @public
@@ -9347,10 +9378,9 @@ class Menu extends FASTElement {
9347
9378
  * @public
9348
9379
  */
9349
9380
  openOnHoverChanged(oldValue, newValue) {
9350
- if (newValue) {
9351
- this._trigger?.addEventListener("mouseover", this.openMenu);
9352
- } else {
9353
- this._trigger?.removeEventListener("mouseover", this.openMenu);
9381
+ if (this._trigger) {
9382
+ this._triggerAbortController?.abort();
9383
+ this.addTriggerListeners();
9354
9384
  }
9355
9385
  }
9356
9386
  /**
@@ -9361,10 +9391,9 @@ class Menu extends FASTElement {
9361
9391
  * @param newValue - The new value of 'persistOnItemClick'.
9362
9392
  */
9363
9393
  persistOnItemClickChanged(oldValue, newValue) {
9364
- if (!newValue) {
9365
- this._menuList?.addEventListener("change", this.closeMenu);
9366
- } else {
9367
- this._menuList?.removeEventListener("change", this.closeMenu);
9394
+ if (this._menuList) {
9395
+ this._menuListAbortController?.abort();
9396
+ this.addMenuListListeners();
9368
9397
  }
9369
9398
  }
9370
9399
  /**
@@ -9376,9 +9405,13 @@ class Menu extends FASTElement {
9376
9405
  */
9377
9406
  openOnContextChanged(oldValue, newValue) {
9378
9407
  if (newValue) {
9379
- this._trigger?.addEventListener("contextmenu", this.openMenu);
9408
+ this._menuList?.setAttribute("popover", "manual");
9380
9409
  } else {
9381
- this._trigger?.removeEventListener("contextmenu", this.openMenu);
9410
+ this._menuList?.setAttribute("popover", "");
9411
+ }
9412
+ if (this._trigger) {
9413
+ this._triggerAbortController?.abort();
9414
+ this.addTriggerListeners();
9382
9415
  }
9383
9416
  }
9384
9417
  /**
@@ -9396,50 +9429,50 @@ class Menu extends FASTElement {
9396
9429
  }
9397
9430
  }
9398
9431
  /**
9399
- * Adds event listeners.
9400
- * Adds click and keydown event listeners to the trigger.
9401
- * Adds a 'toggle' event listener to the menu list.
9402
- * If 'openOnHover' is true, adds a 'mouseover' event listener to the trigger.
9403
- * If 'openOnContext' is true, adds a 'contextmenu' event listener to the trigger and a document 'click' event listener.
9432
+ * Adds trigger-related event listeners.
9404
9433
  * @internal
9405
9434
  */
9406
- addListeners() {
9407
- this._menuList?.addEventListener("toggle", this.toggleHandler);
9408
- this._trigger?.addEventListener("keydown", this.triggerKeydownHandler);
9409
- if (!this.persistOnItemClick) {
9410
- this._menuList?.addEventListener("change", this.closeMenu);
9411
- }
9435
+ addTriggerListeners() {
9436
+ this._triggerAbortController = new AbortController();
9437
+ const {
9438
+ signal
9439
+ } = this._triggerAbortController;
9440
+ this._trigger?.addEventListener("keydown", this.triggerKeydownHandler, {
9441
+ signal
9442
+ });
9412
9443
  if (this.openOnHover) {
9413
- this._trigger?.addEventListener("mouseover", this.openMenu);
9444
+ this._trigger?.addEventListener("mouseover", this.openMenu, {
9445
+ signal
9446
+ });
9414
9447
  } else if (this.openOnContext) {
9415
- this._trigger?.addEventListener("contextmenu", this.openMenu);
9416
- document.addEventListener("click", this.documentClickHandler);
9448
+ this._trigger?.addEventListener("contextmenu", this.openMenu, {
9449
+ signal
9450
+ });
9451
+ document.addEventListener("click", this.documentClickHandler, {
9452
+ signal
9453
+ });
9417
9454
  } else {
9418
- this._trigger?.addEventListener("click", this.toggleMenu);
9455
+ this._trigger?.addEventListener("click", this.toggleMenu, {
9456
+ signal
9457
+ });
9419
9458
  }
9420
9459
  }
9421
9460
  /**
9422
- * Removes event listeners.
9423
- * Removes click and keydown event listeners from the trigger.
9424
- * Also removes toggle event listener from the menu list.
9425
- * Also removes 'mouseover' event listeners from the trigger.
9426
- * Also removes 'contextmenu' event listeners from the trigger and document 'click' event listeners.
9461
+ * Adds menu-list event listeners.
9427
9462
  * @internal
9428
9463
  */
9429
- removeListeners() {
9430
- this._menuList?.removeEventListener("toggle", this.toggleHandler);
9431
- this._trigger?.removeEventListener("keydown", this.triggerKeydownHandler);
9464
+ addMenuListListeners() {
9465
+ this._menuListAbortController = new AbortController();
9466
+ const {
9467
+ signal
9468
+ } = this._menuListAbortController;
9469
+ this._menuList?.addEventListener("toggle", this.toggleHandler, {
9470
+ signal
9471
+ });
9432
9472
  if (!this.persistOnItemClick) {
9433
- this._menuList?.removeEventListener("change", this.closeMenu);
9434
- }
9435
- if (this.openOnHover) {
9436
- this._trigger?.removeEventListener("mouseover", this.openMenu);
9437
- }
9438
- if (this.openOnContext) {
9439
- this._trigger?.removeEventListener("contextmenu", this.openMenu);
9440
- document.removeEventListener("click", this.documentClickHandler);
9441
- } else {
9442
- this._trigger?.removeEventListener("click", this.toggleMenu);
9473
+ this._menuList?.addEventListener("change", this.closeMenu, {
9474
+ signal
9475
+ });
9443
9476
  }
9444
9477
  }
9445
9478
  /**
@@ -11746,9 +11779,9 @@ class BaseTablist extends FASTElement {
11746
11779
  });
11747
11780
  }
11748
11781
  getTabIds() {
11749
- return this.tabs.map(tab => {
11782
+ return this.tabs?.map(tab => {
11750
11783
  return tab.getAttribute("id") ?? `tab-${uniqueId$1()}`;
11751
- });
11784
+ }) ?? [];
11752
11785
  }
11753
11786
  setComponent() {
11754
11787
  if (this.activeTabIndex !== this.prevActiveTabIndex) {
@@ -11793,6 +11826,8 @@ class BaseTablist extends FASTElement {
11793
11826
  waitForConnectedDescendants(this, () => {
11794
11827
  this.tabIds = this.getTabIds();
11795
11828
  this.setTabs();
11829
+ }, {
11830
+ shallow: true
11796
11831
  });
11797
11832
  }
11798
11833
  }