Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 26x 26x 44x 26x 20x 18x 18x 18x 18x 18x 26x 8x 8x 8x 8x 8x 8x 6x 26x 6x 6x 6x 3x 3x 3x 20x 20x 3x 1x 26x | // SPDX-License-Identifier: MIT
/**
* Dropdown state management
*/
import { setItemActiveState, setTabindexBatch } from './helpers.js';
export interface DropdownElements {
dropdownMenu: HTMLElement;
trigger: HTMLButtonElement;
dropdown: HTMLElement;
selectEl: HTMLSelectElement | null;
}
export interface DropdownState {
currentIndex: number;
menuItems: HTMLElement[];
}
export interface DropdownStateManager {
updateAriaExpanded: (expanded: boolean) => void;
focusMenuItem: (index: number) => void;
closeDropdown: (options?: { restoreFocus?: boolean }) => void;
toggleDropdown: (focusFirst?: boolean) => void;
}
/**
* Creates dropdown state management functions.
*/
export function createDropdownStateManager(
elements: DropdownElements,
state: DropdownState
): DropdownStateManager {
const { trigger, dropdown } = elements;
const updateAriaExpanded = (expanded: boolean): void => {
trigger.setAttribute('aria-expanded', String(expanded));
};
const focusMenuItem = (index: number): void => {
if (index < 0 || index >= state.menuItems.length) return;
const item = state.menuItems[index]!;
setTabindexBatch(state.menuItems, '-1');
item.setAttribute('tabindex', '0');
item.focus();
state.currentIndex = index;
};
const closeDropdown = (options: { restoreFocus?: boolean } = {}): void => {
const { restoreFocus = true } = options;
dropdown.classList.remove('is-active');
updateAriaExpanded(false);
setTabindexBatch(state.menuItems, '-1');
state.currentIndex = -1;
if (restoreFocus) {
trigger.focus();
}
};
const toggleDropdown = (focusFirst = false): void => {
const isActive = dropdown.classList.toggle('is-active');
updateAriaExpanded(isActive);
if (!isActive) {
state.currentIndex = -1;
setTabindexBatch(state.menuItems, '-1');
for (const menuItem of state.menuItems) {
const isActiveItem = menuItem.classList.contains('is-active');
setItemActiveState(menuItem, isActiveItem);
}
} else if (focusFirst && state.menuItems.length > 0) {
focusMenuItem(0);
}
};
return { updateAriaExpanded, focusMenuItem, closeDropdown, toggleDropdown };
}
|