diff --git a/src/aria/combobox/combobox.ts b/src/aria/combobox/combobox.ts index 8601227cbf8f..a690f69aa6d7 100644 --- a/src/aria/combobox/combobox.ts +++ b/src/aria/combobox/combobox.ts @@ -117,14 +117,14 @@ export class Combobox { afterRenderEffect(() => { if ( !this._deferredContentAware?.contentVisible() && - (this._pattern.isFocused() || this.alwaysExpanded()) + (this._pattern.focused() || this.alwaysExpanded()) ) { this._deferredContentAware?.contentVisible.set(true); } }); afterRenderEffect(() => { - if (!this._hasBeenFocused() && this._pattern.isFocused()) { + if (!this._hasBeenFocused() && this._pattern.focused()) { this._hasBeenFocused.set(true); } }); diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index c56aa3abab3a..5e00523ece7b 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -110,7 +110,7 @@ export class MenuTrigger { 'role': 'menu', 'class': 'ng-menu', '[attr.id]': '_pattern.id()', - '[attr.data-visible]': '_pattern.isVisible()', + '[attr.data-visible]': '_pattern.visible()', '(keydown)': '_pattern.onKeydown($event)', '(mouseover)': '_pattern.onMouseOver($event)', '(mouseout)': '_pattern.onMouseOut($event)', @@ -171,7 +171,7 @@ export class Menu { readonly items = () => this._items().map(i => i._pattern); /** Whether the menu is visible. */ - isVisible = computed(() => this._pattern.isVisible()); + visible = computed(() => this._pattern.visible()); /** A callback function triggered when a menu item is selected. */ onSelect = output(); @@ -199,7 +199,7 @@ export class Menu { this._deferredContentAware?.contentVisible.set(true); } else { this._deferredContentAware?.contentVisible.set( - this._pattern.isVisible() || !!this.parent()?.hasBeenFocused(), + this._pattern.visible() || !!this.parent()?.hasBeenFocused(), ); } }); @@ -209,7 +209,7 @@ export class Menu { // update the display property. The result is focus() being called on an element that is not // focusable. This simply retries focusing the element after render. afterRenderEffect(() => { - if (this._pattern.isVisible()) { + if (this._pattern.visible()) { const activeItem = untracked(() => this._pattern.inputs.activeItem()); this._pattern.listBehavior.goto(activeItem!); } @@ -335,7 +335,7 @@ export class MenuBar { 'class': 'ng-menu-item', '(focusin)': 'onFocusIn()', '[attr.tabindex]': '_pattern.tabIndex()', - '[attr.data-active]': '_pattern.isActive()', + '[attr.data-active]': '_pattern.active()', '[attr.aria-haspopup]': '_pattern.hasPopup()', '[attr.aria-expanded]': '_pattern.expanded()', '[attr.aria-disabled]': '_pattern.disabled()', diff --git a/src/aria/private/combobox/combobox.spec.ts b/src/aria/private/combobox/combobox.spec.ts index d97876882b38..d9c80d8206f0 100644 --- a/src/aria/private/combobox/combobox.spec.ts +++ b/src/aria/private/combobox/combobox.spec.ts @@ -376,7 +376,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickOption(listbox.inputs.items(), 0)); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[0]); expect(listbox.inputs.value()).toEqual(['Apple']); expect(inputEl.value).toBe('Apple'); }); @@ -384,7 +384,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select and commit to input on Enter', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[0]); expect(listbox.inputs.value()).toEqual(['Apple']); expect(inputEl.value).toBe('Apple'); }); @@ -392,7 +392,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select on focusout if the input text exactly matches an item', () => { type('Apple'); combobox.onFocusOut(new FocusEvent('focusout')); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[0]); expect(listbox.inputs.value()).toEqual(['Apple']); }); @@ -409,20 +409,20 @@ describe('Combobox with Listbox Pattern', () => { it('should not select on navigation', () => { combobox.onKeydown(down()); - expect(listbox.getSelectedItems().length).toBe(0); + expect(listbox.selectedItems().length).toBe(0); expect(listbox.inputs.value()).toEqual([]); }); it('should not select on input', () => { type('A'); - expect(listbox.getSelectedItems().length).toBe(0); + expect(listbox.selectedItems().length).toBe(0); expect(listbox.inputs.value()).toEqual([]); }); it('should not select on focusout if the input text does not match an item', () => { type('Appl'); combobox.onFocusOut(new FocusEvent('focusout')); - expect(listbox.getSelectedItems().length).toBe(0); + expect(listbox.selectedItems().length).toBe(0); expect(listbox.inputs.value()).toEqual([]); expect(inputEl.value).toBe('Appl'); }); @@ -437,7 +437,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickOption(listbox.inputs.items(), 3)); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[3]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[3]); expect(listbox.inputs.value()).toEqual(['Blackberry']); expect(inputEl.value).toBe('Blackberry'); }); @@ -447,20 +447,20 @@ describe('Combobox with Listbox Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[2]); expect(listbox.inputs.value()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[0]); expect(listbox.inputs.value()).toEqual(['Apple']); }); it('should select the last item on arrow up when collapsed', () => { combobox.onKeydown(up()); - expect(listbox.getSelectedItems()[0]).toBe( + expect(listbox.selectedItems()[0]).toBe( listbox.inputs.items()[listbox.inputs.items().length - 1], ); expect(listbox.inputs.value()).toEqual(['Cranberry']); @@ -469,7 +469,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[1]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[1]); expect(listbox.inputs.value()).toEqual(['Apricot']); }); @@ -498,7 +498,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickOption(listbox.inputs.items(), 3)); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[3]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[3]); expect(listbox.inputs.value()).toEqual(['Blackberry']); expect(inputEl.value).toBe('Blackberry'); }); @@ -508,20 +508,20 @@ describe('Combobox with Listbox Pattern', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[2]); expect(listbox.inputs.value()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[0]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[0]); expect(listbox.inputs.value()).toEqual(['Apple']); }); it('should select the last item on arrow up when collapsed', () => { combobox.onKeydown(up()); - expect(listbox.getSelectedItems()[0]).toBe( + expect(listbox.selectedItems()[0]).toBe( listbox.inputs.items()[listbox.inputs.items().length - 1], ); expect(listbox.inputs.value()).toEqual(['Cranberry']); @@ -530,7 +530,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select on navigation', () => { combobox.onKeydown(down()); combobox.onKeydown(down()); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[1]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[1]); expect(listbox.inputs.value()).toEqual(['Apricot']); }); @@ -585,7 +585,7 @@ describe('Combobox with Listbox Pattern', () => { it('should select and close on selection', () => { const {combobox, listbox, inputEl} = getPatterns({readonly: true}); combobox.onPointerup(clickOption(listbox.inputs.items(), 2)); - expect(listbox.getSelectedItems()[0]).toBe(listbox.inputs.items()[2]); + expect(listbox.selectedItems()[0]).toBe(listbox.inputs.items()[2]); expect(listbox.inputs.value()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); expect(combobox.expanded()).toBe(false); @@ -748,7 +748,7 @@ describe('Combobox with Tree Pattern', () => { it('should select and commit to input on Enter', () => { combobox.onKeydown(down()); combobox.onKeydown(enter()); - expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); + expect(tree.selectedItems()[0]).toBe(tree.inputs.allItems()[0]); expect(tree.inputs.value()).toEqual(['Fruit']); expect(inputEl.value).toBe('Fruit'); }); @@ -773,20 +773,20 @@ describe('Combobox with Tree Pattern', () => { it('should not select on navigation', () => { combobox.onKeydown(down()); - expect(tree.getSelectedItems().length).toBe(0); + expect(tree.selectedItems().length).toBe(0); expect(tree.inputs.value()).toEqual([]); }); it('should not select on input', () => { type('A'); - expect(tree.getSelectedItems().length).toBe(0); + expect(tree.selectedItems().length).toBe(0); expect(tree.inputs.value()).toEqual([]); }); it('should not select on focusout if the input text does not match an item', () => { type('Appl'); combobox.onFocusOut(new FocusEvent('focusout')); - expect(tree.getSelectedItems().length).toBe(0); + expect(tree.selectedItems().length).toBe(0); expect(tree.inputs.value()).toEqual([]); expect(inputEl.value).toBe('Appl'); }); @@ -801,7 +801,7 @@ describe('Combobox with Tree Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 2)); - expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[2]); + expect(tree.selectedItems()[0]).toBe(tree.inputs.allItems()[2]); expect(tree.inputs.value()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); @@ -817,7 +817,7 @@ describe('Combobox with Tree Pattern', () => { it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); - expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); + expect(tree.selectedItems()[0]).toBe(tree.inputs.allItems()[0]); expect(tree.inputs.value()).toEqual(['Fruit']); }); @@ -858,7 +858,7 @@ describe('Combobox with Tree Pattern', () => { it('should select and commit on click', () => { combobox.onPointerup(clickTreeItem(tree.inputs.allItems(), 2)); - expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[2]); + expect(tree.selectedItems()[0]).toBe(tree.inputs.allItems()[2]); expect(tree.inputs.value()).toEqual(['Banana']); expect(inputEl.value).toBe('Banana'); }); @@ -874,7 +874,7 @@ describe('Combobox with Tree Pattern', () => { it('should select the first item on arrow down when collapsed', () => { combobox.onKeydown(down()); - expect(tree.getSelectedItems()[0]).toBe(tree.inputs.allItems()[0]); + expect(tree.selectedItems()[0]).toBe(tree.inputs.allItems()[0]); expect(tree.inputs.value()).toEqual(['Fruit']); }); diff --git a/src/aria/private/combobox/combobox.ts b/src/aria/private/combobox/combobox.ts index 2dfd672ec352..56b2ffec71a3 100644 --- a/src/aria/private/combobox/combobox.ts +++ b/src/aria/private/combobox/combobox.ts @@ -93,13 +93,13 @@ export interface ComboboxListboxControls, V> { unfocus: () => void; /** Returns the item corresponding to the given event. */ - getItem: (e: PointerEvent) => T | undefined; + item: (e: PointerEvent) => T | undefined; /** Returns the currently active (focused) item in the popup. */ - getActiveItem: () => T | undefined; + activeItem: () => T | undefined; /** Returns the currently selected items in the popup. */ - getSelectedItems: () => T[]; + selectedItems: () => T[]; /** Sets the value of the combobox based on the selected item. */ setValue: (value: V | undefined) => void; // For re-setting the value if the popup was destroyed. @@ -108,7 +108,7 @@ export interface ComboboxListboxControls, V> { export interface ComboboxTreeControls, V> extends ComboboxListboxControls { /** Whether the currently active item in the popup is collapsible. */ - isItemCollapsible: () => boolean; + collapsible: () => boolean; /** Expands the currently active item in the popup. */ expandItem: () => void; @@ -116,8 +116,8 @@ export interface ComboboxTreeControls, V> /** Collapses the currently active item in the popup. */ collapseItem: () => void; - /** Checks if the currently active item in the popup is expandable. */ - isItemExpandable: (item?: T) => boolean; + /** Whether the specified item or the currently active item is expandable. */ + expandable: (item?: T) => boolean; /** Expands all nodes in the tree. */ expandAll: () => void; @@ -129,7 +129,7 @@ export interface ComboboxTreeControls, V> toggleExpansion: (item?: T) => void; /** Whether the current active item is selectable. */ - isItemSelectable: (item?: T) => boolean; + selectable: (item?: T) => boolean; } /** Controls the state of a combobox. */ @@ -151,10 +151,10 @@ export class ComboboxPattern, V> { highlightedItem = signal(undefined); /** Whether the most recent input event was a deletion. */ - isDeleting = false; + deleting = false; /** Whether the combobox is focused. */ - isFocused = signal(false); + focused = signal(false); /** Whether the combobox has ever been focused. */ hasBeenFocused = signal(false); @@ -258,21 +258,21 @@ export class ComboboxPattern, V> { const treeControls = this.treeControls(); - if (treeControls?.isItemSelectable()) { + if (treeControls?.selectable()) { manager.on('Enter', () => this.select({commit: true, close: true})); } - if (treeControls?.isItemExpandable()) { + if (treeControls?.expandable()) { manager .on(this.expandKey(), () => this.expandItem()) .on(this.collapseKey(), () => this.collapseItem()); - if (!treeControls.isItemSelectable()) { + if (!treeControls.selectable()) { manager.on('Enter', () => this.expandItem()); } } - if (treeControls?.isItemCollapsible()) { + if (treeControls?.collapsible()) { manager.on(this.collapseKey(), () => this.collapseItem()); } @@ -294,13 +294,13 @@ export class ComboboxPattern, V> { return; } - const item = controls?.getItem(e); + const item = controls?.item(e); if (item) { if (controls?.role() === 'tree') { const treeControls = controls as ComboboxTreeControls; - if (treeControls.isItemExpandable(item) && !treeControls.isItemSelectable(item)) { + if (treeControls.expandable(item) && !treeControls.selectable(item)) { treeControls.toggleExpansion(item); this.inputs.inputEl()?.focus(); return; @@ -349,9 +349,9 @@ export class ComboboxPattern, V> { this.open(); this.inputs.inputValue?.set(inputEl.value); - this.isDeleting = event instanceof InputEvent && !!event.inputType.match(/^delete/); + this.deleting = event instanceof InputEvent && !!event.inputType.match(/^delete/); - if (this.inputs.filterMode() === 'highlight' && !this.isDeleting) { + if (this.inputs.filterMode() === 'highlight' && !this.deleting) { this.highlight(); } } @@ -359,11 +359,11 @@ export class ComboboxPattern, V> { /** Handles focus in events for the combobox. */ onFocusIn() { if (this.inputs.alwaysExpanded() && !this.hasBeenFocused()) { - const firstSelectedItem = this.listControls()?.getSelectedItems()[0]; + const firstSelectedItem = this.listControls()?.selectedItems()[0]; firstSelectedItem ? this.listControls()?.focus(firstSelectedItem) : this.first(); } - this.isFocused.set(true); + this.focused.set(true); this.hasBeenFocused.set(true); } @@ -383,7 +383,7 @@ export class ComboboxPattern, V> { !(event.relatedTarget instanceof HTMLElement) || !this.inputs.containerEl()?.contains(event.relatedTarget) ) { - this.isFocused.set(false); + this.focused.set(false); if (this.readonly()) { this.close(); @@ -436,14 +436,14 @@ export class ComboboxPattern, V> { // When the user first interacts with the combobox, the popup will lazily render for the first // time. This is a simple way to detect this and avoid auto-focus & selection logic, but this // should probably be moved to the component layer instead. - const isInitialRender = !this.inputs.inputValue?.().length && !this.isDeleting; + const isInitialRender = !this.inputs.inputValue?.().length && !this.deleting; if (isInitialRender) { return; } // Avoid refocusing the input if a filter event occurs after focus has left the combobox. - if (!this.isFocused()) { + if (!this.focused()) { return; } @@ -466,7 +466,7 @@ export class ComboboxPattern, V> { this.select({item}); } - if (this.inputs.filterMode() === 'highlight' && !this.isDeleting) { + if (this.inputs.filterMode() === 'highlight' && !this.deleting) { this.highlight(); } } @@ -474,7 +474,7 @@ export class ComboboxPattern, V> { /** Highlights the currently selected item in the combobox. */ highlight() { const inputEl = this.inputs.inputEl(); - const selectedItems = this.listControls()?.getSelectedItems(); + const selectedItems = this.listControls()?.selectedItems(); const item = selectedItems?.[0]; if (!inputEl || !item) { @@ -535,7 +535,7 @@ export class ComboboxPattern, V> { } else if (this.expanded()) { this.close(); - const selectedItem = popupControls?.getSelectedItems()?.[0]; + const selectedItem = popupControls?.selectedItems()?.[0]; if (selectedItem?.searchTerm() !== this.inputs.inputValue!()) { popupControls?.clearSelection(); @@ -577,7 +577,7 @@ export class ComboboxPattern, V> { if (nav?.selected) { const selectedItem = popupControls ?.items() - .find(i => popupControls?.getSelectedItems().includes(i)); + .find(i => popupControls?.selectedItems().includes(i)); selectedItem ? popupControls?.focus(selectedItem) : this.first(); } } @@ -635,7 +635,7 @@ export class ComboboxPattern, V> { /** Updates the value of the input based on the currently selected item. */ commit() { const inputEl = this.inputs.inputEl(); - const selectedItems = this.listControls()?.getSelectedItems(); + const selectedItems = this.listControls()?.selectedItems(); if (!inputEl) { return; @@ -661,7 +661,7 @@ export class ComboboxPattern, V> { if (this.inputs.filterMode() === 'highlight') { // This is to handle when the user navigates back to the originally highlighted item. // E.g. User types "Al", highlights "Alice", then navigates down and back up to "Alice". - const selectedItem = this.listControls()?.getSelectedItems()[0]; + const selectedItem = this.listControls()?.selectedItems()[0]; if (!selectedItem) { return; diff --git a/src/aria/private/listbox/combobox-listbox.ts b/src/aria/private/listbox/combobox-listbox.ts index 02735c6c4aa6..2f14d62e4b46 100644 --- a/src/aria/private/listbox/combobox-listbox.ts +++ b/src/aria/private/listbox/combobox-listbox.ts @@ -65,7 +65,7 @@ export class ComboboxListboxPattern }; /** Navigates to the previous focusable item in the listbox. */ - getActiveItem = () => this.inputs.activeItem(); + activeItem = () => this.inputs.activeItem(); /** Navigates to the next focusable item in the listbox. */ next = () => this.listBehavior.next(); @@ -92,10 +92,10 @@ export class ComboboxListboxPattern clearSelection = () => this.listBehavior.deselectAll(); /** Retrieves the OptionPattern associated with a pointer event. */ - getItem = (e: PointerEvent) => this._getItem(e); + item = (e: PointerEvent) => this._getItem(e); /** Retrieves the currently selected items in the listbox. */ - getSelectedItems = () => { + selectedItems = () => { // NOTE: We need to do this funky for loop to preserve the order of the selected values. const items = []; for (const value of this.inputs.value()) { diff --git a/src/aria/private/menu/menu.spec.ts b/src/aria/private/menu/menu.spec.ts index d38d2f30e504..497e14e12ac6 100644 --- a/src/aria/private/menu/menu.spec.ts +++ b/src/aria/private/menu/menu.spec.ts @@ -292,130 +292,130 @@ describe('Standalone Menu Pattern', () => { describe('Expansion and Collapse', () => { it('should be expanded by default', () => { - expect(menu.isVisible()).toBe(true); - expect(submenu.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu.visible()).toBe(false); }); it('should expand submenu on click', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should open submenu on arrow right', () => { menu.onKeydown(right()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should close submenu on arrow left', () => { menu.onKeydown(right()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(left()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close submenu on click outside', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onFocusOut(new FocusEvent('focusout', {relatedTarget: null})); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should expand submenu on enter', () => { menu.onKeydown(enter()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should expand submenu on space', () => { menu.onKeydown(space()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should close submenu on escape', () => { menu.onKeydown(right()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(escape()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close submenu on arrow left', () => { menu.onKeydown(right()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(left()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should open submenu on mouseover', async () => { const menuItem = menu.inputs.items()[0]; menu.onMouseOver({target: menuItem.element()} as unknown as MouseEvent); await new Promise(resolve => setTimeout(resolve, 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should close on selecting an item on click', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onClick(clickMenuItem(submenu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close on selecting an item on enter', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(enter()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close on selecting an item on space', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(space()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close on focus out from the menu', () => { menu.onClick(clickMenuItem(menu.inputs.items(), 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onFocusOut(new FocusEvent('focusout', {relatedTarget: null})); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close a submenu on focus out', async () => { const parentMenuItem = menu.inputs.items()[0]; menu.onMouseOver({target: parentMenuItem.element()} as unknown as MouseEvent); await new Promise(resolve => setTimeout(resolve, 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); expect(submenu.isFocused()).toBe(false); submenu.onFocusOut(new FocusEvent('focusout', {relatedTarget: document.body})); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should close an unfocused submenu on mouse out', async () => { menu.onMouseOver({target: menu.inputs.items()[0].element()} as unknown as MouseEvent); await new Promise(resolve => setTimeout(resolve, 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onMouseOut({relatedTarget: document.body} as unknown as MouseEvent); await new Promise(resolve => setTimeout(resolve, 0)); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); it('should not close an unfocused submenu on mouse out if the parent menu is hovered', async () => { const parentMenuItem = menu.inputs.items()[0]; menu.onMouseOver({target: parentMenuItem.element()} as unknown as MouseEvent); await new Promise(resolve => setTimeout(resolve, 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onMouseOut({relatedTarget: parentMenuItem.element()} as unknown as MouseEvent); await new Promise(resolve => setTimeout(resolve, 0)); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); }); @@ -428,15 +428,15 @@ describe('Standalone Menu Pattern', () => { it('should open submenu on arrow left', () => { menu.onKeydown(left()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); }); it('should close submenu on arrow right', () => { menu.onKeydown(left()); - expect(submenu.isVisible()).toBe(true); + expect(submenu.visible()).toBe(true); submenu.onKeydown(right()); - expect(submenu.isVisible()).toBe(false); + expect(submenu.visible()).toBe(false); }); }); }); @@ -482,118 +482,118 @@ describe('Menu Trigger Pattern', () => { describe('Expansion and Collapse', () => { it('should be closed by default', () => { expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); it('should open on click', () => { trigger.onClick(); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should close on second click', () => { trigger.onClick(); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); + expect(menu.visible()).toBe(true); trigger.onClick(); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); }); it('should open on arrow down', () => { trigger.onKeydown(down()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should open on arrow up', () => { trigger.onKeydown(up()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should open on space', () => { trigger.onKeydown(space()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should open on enter', () => { trigger.onKeydown(enter()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); }); it('should close on escape', () => { trigger.onKeydown(down()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); + expect(menu.visible()).toBe(true); menu.onKeydown(escape()); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); }); it('should close on selecting an item on click', () => { trigger.onClick(); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); menu.onClick(clickMenuItem(menu.inputs.items(), 0)); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(true); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(true); submenu?.onClick(clickMenuItem(submenu.inputs.items(), 0)); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); it('should close on selecting an item on enter', () => { trigger.onKeydown(down()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); menu.onKeydown(right()); - expect(submenu?.isVisible()).toBe(true); + expect(submenu?.visible()).toBe(true); submenu?.onKeydown(enter()); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); it('should close on selecting an item on space', () => { trigger.onKeydown(down()); expect(trigger.expanded()).toBe(true); - expect(menu.isVisible()).toBe(true); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(true); + expect(submenu?.visible()).toBe(false); menu.onKeydown(right()); - expect(submenu?.isVisible()).toBe(true); + expect(submenu?.visible()).toBe(true); submenu?.onKeydown(space()); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); it('should close the trigger on focus out from the menu', () => { trigger.onKeydown(down()); menu.onFocusOut(new FocusEvent('focusout', {relatedTarget: null})); expect(trigger.expanded()).toBe(false); - expect(menu.isVisible()).toBe(false); - expect(submenu?.isVisible()).toBe(false); + expect(menu.visible()).toBe(false); + expect(submenu?.visible()).toBe(false); }); }); }); @@ -617,7 +617,7 @@ describe('Menu Bar Pattern', () => { menubar.inputs.activeItem.set(menubarItems[0]); menubar.onKeydown(down()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[0]); }); @@ -626,7 +626,7 @@ describe('Menu Bar Pattern', () => { menubar.inputs.activeItem.set(menubarItems[0]); menubar.onKeydown(up()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[1]); }); @@ -635,7 +635,7 @@ describe('Menu Bar Pattern', () => { menubar.inputs.activeItem.set(menubarItems[0]); menubar.onKeydown(enter()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[0]); }); @@ -644,45 +644,45 @@ describe('Menu Bar Pattern', () => { menubar.inputs.activeItem.set(menubarItems[0]); menubar.onKeydown(space()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[0]); }); it('should navigate to a menubar item on mouse over', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); - expect(menuB.isVisible()).toBe(false); + expect(menuA.visible()).toBe(true); + expect(menuB.visible()).toBe(false); const mouseOverEvent = {target: menubarItems[1].element()} as unknown as MouseEvent; menubar.onMouseOver(mouseOverEvent); - expect(menuA.isVisible()).toBe(false); - expect(menuB.isVisible()).toBe(true); + expect(menuA.visible()).toBe(false); + expect(menuB.visible()).toBe(true); expect(menubar.inputs.activeItem()).toBe(menubarItems[1]); }); it('should focus the first item of the next menubar item on arrow right', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); // open menuA - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(right()); - expect(menuA.isVisible()).toBe(false); - expect(menuB.isVisible()).toBe(true); + expect(menuA.visible()).toBe(false); + expect(menuB.visible()).toBe(true); expect(menuB.inputs.activeItem()).toBe(menuB.inputs.items()[0]); }); it('should focus the first item of the previous menubar item on arrow left', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 1)); // open menuB - expect(menuB.isVisible()).toBe(true); + expect(menuB.visible()).toBe(true); menuB.onKeydown(left()); - expect(menuB.isVisible()).toBe(false); - expect(menuA.isVisible()).toBe(true); + expect(menuB.visible()).toBe(false); + expect(menuA.visible()).toBe(true); expect(menuA.inputs.activeItem()).toBe(menuA.inputs.items()[0]); }); }); @@ -694,9 +694,9 @@ describe('Menu Bar Pattern', () => { expect(menubarItems[1].expanded()).toBe(false); expect(menubarItems[2].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); - expect(menuB.isVisible()).toBe(false); - expect(menuC.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); + expect(menuB.visible()).toBe(false); + expect(menuC.visible()).toBe(false); }); it('should expand on click', () => { @@ -707,9 +707,9 @@ describe('Menu Bar Pattern', () => { expect(menubarItems[1].expanded()).toBe(false); expect(menubarItems[2].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(true); - expect(menuB.isVisible()).toBe(false); - expect(menuC.isVisible()).toBe(false); + expect(menuA.visible()).toBe(true); + expect(menuB.visible()).toBe(false); + expect(menuC.visible()).toBe(false); }); it('should collapse on second click', () => { @@ -717,12 +717,12 @@ describe('Menu Bar Pattern', () => { menubar.onClick(clickMenuItem(menubarItems, 0)); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menubar.onClick(clickMenuItem(menubarItems, 0)); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should expand on arrow down', () => { @@ -731,7 +731,7 @@ describe('Menu Bar Pattern', () => { menubar.onKeydown(down()); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); }); it('should expand on arrow up', () => { @@ -740,7 +740,7 @@ describe('Menu Bar Pattern', () => { menubar.onKeydown(up()); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); }); it('should expand on space', () => { @@ -749,7 +749,7 @@ describe('Menu Bar Pattern', () => { menubar.onKeydown(space()); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); }); it('should expand on enter', () => { @@ -758,84 +758,84 @@ describe('Menu Bar Pattern', () => { menubar.onKeydown(enter()); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); }); it('should close on escape', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); expect(menubarItems[0].expanded()).toBe(true); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(escape()); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on selecting an item on click', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onClick(clickMenuItem(menuA.inputs.items(), 0)); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on selecting an item on enter', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(enter()); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on selecting an item on space', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(space()); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on focus out from the menu', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onFocusOut(new FocusEvent('focusout', {relatedTarget: null})); expect(menubarItems[0].expanded()).toBe(false); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); }); it('should close on arrow right on a leaf menu item', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(right()); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); expect(menubarItems[0].expanded()).toBe(false); }); it('should close on arrow left on a root menu item', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 1)); - expect(menuB.isVisible()).toBe(true); + expect(menuB.visible()).toBe(true); menuB.onKeydown(left()); - expect(menuB.isVisible()).toBe(false); + expect(menuB.visible()).toBe(false); expect(menubarItems[1].expanded()).toBe(false); }); @@ -845,7 +845,7 @@ describe('Menu Bar Pattern', () => { menuA.onKeydown(right()); - expect(menuB.isVisible()).toBe(true); + expect(menuB.visible()).toBe(true); expect(menubarItems[1].expanded()).toBe(true); expect(menubar.inputs.activeItem()).toBe(menubarItems[1]); }); @@ -856,7 +856,7 @@ describe('Menu Bar Pattern', () => { menuB.onKeydown(left()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menubarItems[0].expanded()).toBe(true); expect(menubar.inputs.activeItem()).toBe(menubarItems[0]); }); @@ -873,22 +873,22 @@ describe('Menu Bar Pattern', () => { it('should close on arrow left on a leaf menu item', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 0)); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); menuA.onKeydown(left()); - expect(menuA.isVisible()).toBe(false); + expect(menuA.visible()).toBe(false); expect(menubarItems[0].expanded()).toBe(false); }); it('should close on arrow right on a root menu item', () => { const menubarItems = menubar.inputs.items(); menubar.onClick(clickMenuItem(menubarItems, 1)); - expect(menuB.isVisible()).toBe(true); + expect(menuB.visible()).toBe(true); menuB.onKeydown(right()); - expect(menuB.isVisible()).toBe(false); + expect(menuB.visible()).toBe(false); expect(menubarItems[1].expanded()).toBe(false); }); @@ -898,7 +898,7 @@ describe('Menu Bar Pattern', () => { menuA.onKeydown(left()); - expect(menuB.isVisible()).toBe(true); + expect(menuB.visible()).toBe(true); expect(menubarItems[1].expanded()).toBe(true); expect(menubar.inputs.activeItem()).toBe(menubarItems[1]); }); @@ -909,7 +909,7 @@ describe('Menu Bar Pattern', () => { menuB.onKeydown(right()); - expect(menuA.isVisible()).toBe(true); + expect(menuA.visible()).toBe(true); expect(menubarItems[0].expanded()).toBe(true); expect(menubar.inputs.activeItem()).toBe(menubarItems[0]); }); diff --git a/src/aria/private/menu/menu.ts b/src/aria/private/menu/menu.ts index f9b4cec3c921..575ef41dfdbc 100644 --- a/src/aria/private/menu/menu.ts +++ b/src/aria/private/menu/menu.ts @@ -75,7 +75,7 @@ export class MenuPattern { role = () => 'menu'; /** Whether the menu is visible. */ - isVisible = computed(() => (this.inputs.parent() ? !!this.inputs.parent()?.expanded() : true)); + visible = computed(() => (this.inputs.parent() ? !!this.inputs.parent()?.expanded() : true)); /** Controls list behavior for the menu items. */ listBehavior: List, V>; @@ -184,7 +184,7 @@ export class MenuPattern { /** Handles mouseover events for the menu. */ onMouseOver(event: MouseEvent) { - if (!this.isVisible()) { + if (!this.visible()) { return; } @@ -306,7 +306,7 @@ export class MenuPattern { } if ( - this.isVisible() && + this.visible() && !parentEl?.contains(relatedTarget) && !this.inputs.element()?.contains(relatedTarget) ) { @@ -677,7 +677,7 @@ export class MenuItemPattern implements ListItem { element: SignalLike; /** Whether the menu item is active. */ - isActive = computed(() => this.inputs.parent()?.inputs.activeItem() === this); + active = computed(() => this.inputs.parent()?.inputs.activeItem() === this); /** The tab index of the menu item. */ tabIndex = computed(() => { diff --git a/src/aria/private/tree/combobox-tree.ts b/src/aria/private/tree/combobox-tree.ts index 3f64ae752938..7b8299d78c30 100644 --- a/src/aria/private/tree/combobox-tree.ts +++ b/src/aria/private/tree/combobox-tree.ts @@ -21,7 +21,7 @@ export class ComboboxTreePattern implements ComboboxTreeControls, V> { /** Whether the currently focused item is collapsible. */ - isItemCollapsible = () => this.inputs.activeItem()?.parent() instanceof TreeItemPattern; + collapsible = () => this.inputs.activeItem()?.parent() instanceof TreeItemPattern; /** The ARIA role for the tree. */ role = () => 'tree' as const; @@ -29,9 +29,6 @@ export class ComboboxTreePattern /* The id of the active (focused) item in the tree. */ activeId = computed(() => this.listBehavior.activeDescendant()); - /** Returns the currently active (focused) item in the tree. */ - getActiveItem = () => this.inputs.activeItem(); - /** The list of items in the tree. */ items = computed(() => this.inputs.allItems()); @@ -86,10 +83,10 @@ export class ComboboxTreePattern clearSelection = () => this.listBehavior.deselectAll(); /** Retrieves the TreeItemPattern associated with a pointer event. */ - getItem = (e: PointerEvent) => this._getItem(e); + item = (e: PointerEvent) => this._getItem(e); /** Retrieves the currently selected items in the tree */ - getSelectedItems = () => this.inputs.allItems().filter(item => item.selected()); + selectedItems = () => this.inputs.allItems().filter(item => item.selected()); /** Sets the value of the combobox tree. */ setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); @@ -101,7 +98,7 @@ export class ComboboxTreePattern collapseItem = () => this.collapse(); /** Whether the specified item or the currently active item is expandable. */ - isItemExpandable(item: TreeItemPattern | undefined = this.inputs.activeItem()) { + expandable(item: TreeItemPattern | undefined = this.inputs.activeItem()) { return item ? item.expandable() : false; } @@ -112,7 +109,7 @@ export class ComboboxTreePattern collapseAll = () => this.items().forEach(item => item.expansion.close()); /** Whether the currently active item is selectable. */ - isItemSelectable = (item: TreeItemPattern | undefined = this.inputs.activeItem()) => { + selectable = (item: TreeItemPattern | undefined = this.inputs.activeItem()) => { return item ? item.selectable() : false; }; } diff --git a/src/components-examples/aria/menu/simple-menu.ts b/src/components-examples/aria/menu/simple-menu.ts index 98930a997a5d..d2ccb75927c5 100644 --- a/src/components-examples/aria/menu/simple-menu.ts +++ b/src/components-examples/aria/menu/simple-menu.ts @@ -15,7 +15,7 @@ export class SimpleMenu { constructor() { afterRenderEffect(() => { - this.menu.isVisible() ? this.menu.element.showPopover() : this.menu.element.hidePopover(); + this.menu.visible() ? this.menu.element.showPopover() : this.menu.element.hidePopover(); }); }