From eae563970d9f16c72b594219a9b710c156da6dd8 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sun, 12 Apr 2026 10:34:31 +0200 Subject: [PATCH] fix(multiple): make more public APIs readonly Marks some more public APIs in `aria` as readonly. --- goldens/aria/combobox/index.api.md | 8 +- goldens/aria/listbox/index.api.md | 34 +-- goldens/aria/menu/index.api.md | 4 +- goldens/aria/private/index.api.md | 277 +++++++++--------- goldens/aria/toolbar/index.api.md | 2 +- src/aria/combobox/combobox-dialog.ts | 2 +- src/aria/combobox/combobox-input.ts | 2 +- src/aria/combobox/combobox.ts | 4 +- src/aria/listbox/listbox.ts | 24 +- src/aria/listbox/option.ts | 10 +- src/aria/menu/menu-trigger.ts | 4 +- src/aria/private/accordion/accordion.ts | 8 +- .../event-manager/click-event-manager.ts | 2 +- .../event-manager/keyboard-event-manager.ts | 2 +- .../event-manager/pointer-event-manager.ts | 2 +- .../behaviors/list-focus/list-focus.ts | 6 +- .../list-selection/list-selection.ts | 6 +- .../list-typeahead/list-typeahead.ts | 8 +- src/aria/private/behaviors/list/list.ts | 20 +- src/aria/private/behaviors/tree/tree.ts | 22 +- src/aria/private/combobox/combobox.ts | 56 ++-- src/aria/private/listbox/combobox-listbox.ts | 34 +-- src/aria/private/listbox/listbox.ts | 30 +- src/aria/private/listbox/option.ts | 22 +- src/aria/private/menu/menu.ts | 133 +++++---- src/aria/private/tree/combobox-tree.ts | 46 +-- src/aria/private/tree/tree.ts | 2 +- src/aria/toolbar/toolbar.ts | 2 +- 28 files changed, 390 insertions(+), 382 deletions(-) diff --git a/goldens/aria/combobox/index.api.md b/goldens/aria/combobox/index.api.md index 57dbe14c8fe1..0179350b6d19 100644 --- a/goldens/aria/combobox/index.api.md +++ b/goldens/aria/combobox/index.api.md @@ -16,14 +16,14 @@ export class Combobox { readonly disabled: _angular_core.InputSignalWithTransform; readonly element: HTMLElement; readonly expanded: _angular_core.Signal; - filterMode: _angular_core.InputSignal<"manual" | "auto-select" | "highlight">; + readonly filterMode: _angular_core.InputSignal<"manual" | "auto-select" | "highlight">; readonly firstMatch: _angular_core.InputSignal; readonly inputElement: _angular_core.Signal; open(): void; readonly _pattern: ComboboxPattern; readonly popup: _angular_core.Signal | undefined>; readonly readonly: _angular_core.InputSignalWithTransform; - protected textDirection: _angular_core.Signal<_angular_cdk_bidi.Direction>; + protected readonly textDirection: _angular_core.Signal<_angular_cdk_bidi.Direction>; // (undocumented) static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngCombobox]", ["ngCombobox"], { "filterMode": { "alias": "filterMode"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "firstMatch": { "alias": "firstMatch"; "required": false; "isSignal": true; }; "alwaysExpanded": { "alias": "alwaysExpanded"; "required": false; "isSignal": true; }; }, {}, ["popup"], never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>; // (undocumented) @@ -38,7 +38,7 @@ export class ComboboxDialog { readonly combobox: Combobox; readonly element: HTMLElement; // (undocumented) - _pattern: ComboboxDialogPattern; + readonly _pattern: ComboboxDialogPattern; // (undocumented) static ɵdir: _angular_core.ɵɵDirectiveDeclaration; // (undocumented) @@ -50,7 +50,7 @@ export class ComboboxInput { constructor(); readonly combobox: Combobox; readonly element: HTMLElement; - value: _angular_core.ModelSignal; + readonly value: _angular_core.ModelSignal; // (undocumented) static ɵdir: _angular_core.ɵɵDirectiveDeclaration; // (undocumented) diff --git a/goldens/aria/listbox/index.api.md b/goldens/aria/listbox/index.api.md index 30466756d1e9..9bab3e7021fd 100644 --- a/goldens/aria/listbox/index.api.md +++ b/goldens/aria/listbox/index.api.md @@ -10,24 +10,24 @@ import * as _angular_core from '@angular/core'; // @public export class Listbox { constructor(); - disabled: _angular_core.InputSignalWithTransform; + readonly disabled: _angular_core.InputSignalWithTransform; readonly element: HTMLElement; - focusMode: _angular_core.InputSignal<"roving" | "activedescendant">; + readonly focusMode: _angular_core.InputSignal<"roving" | "activedescendant">; gotoFirst(): void; readonly id: _angular_core.InputSignal; - protected items: _angular_core.Signal[]>; - multi: _angular_core.InputSignalWithTransform; - orientation: _angular_core.InputSignal<"vertical" | "horizontal">; + protected readonly items: _angular_core.Signal[]>; + readonly multi: _angular_core.InputSignalWithTransform; + readonly orientation: _angular_core.InputSignal<"vertical" | "horizontal">; readonly _pattern: ListboxPattern; - readonly: _angular_core.InputSignalWithTransform; + readonly readonly: _angular_core.InputSignalWithTransform; // (undocumented) scrollActiveItemIntoView(options?: ScrollIntoViewOptions): void; - selectionMode: _angular_core.InputSignal<"follow" | "explicit">; - softDisabled: _angular_core.InputSignalWithTransform; - protected textDirection: _angular_core.Signal<_angular_cdk_bidi.Direction>; - typeaheadDelay: _angular_core.InputSignal; - value: _angular_core.ModelSignal; - wrap: _angular_core.InputSignalWithTransform; + readonly selectionMode: _angular_core.InputSignal<"follow" | "explicit">; + readonly softDisabled: _angular_core.InputSignalWithTransform; + protected readonly textDirection: _angular_core.Signal<_angular_cdk_bidi.Direction>; + readonly typeaheadDelay: _angular_core.InputSignal; + readonly value: _angular_core.ModelSignal; + readonly wrap: _angular_core.InputSignalWithTransform; // (undocumented) static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngListbox]", ["ngListbox"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "multi": { "alias": "multi"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "focusMode": { "alias": "focusMode"; "required": false; "isSignal": true; }; "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "typeaheadDelay": { "alias": "typeaheadDelay"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, ["_options"], never, true, [{ directive: typeof ComboboxPopup; inputs: {}; outputs: {}; }]>; // (undocumented) @@ -36,15 +36,15 @@ export class Listbox { // @public class Option_2 { - active: _angular_core.Signal; - disabled: _angular_core.InputSignalWithTransform; + readonly active: _angular_core.Signal; + readonly disabled: _angular_core.InputSignalWithTransform; readonly element: HTMLElement; readonly id: _angular_core.InputSignal; - label: _angular_core.InputSignal; + readonly label: _angular_core.InputSignal; readonly _pattern: OptionPattern; - protected searchTerm: _angular_core.Signal; + protected readonly searchTerm: _angular_core.Signal; readonly selected: _angular_core.Signal; - value: _angular_core.InputSignal; + readonly value: _angular_core.InputSignal; // (undocumented) static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[ngOption]", ["ngOption"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>; // (undocumented) diff --git a/goldens/aria/menu/index.api.md b/goldens/aria/menu/index.api.md index 922ffd4376d6..5e0a364526e3 100644 --- a/goldens/aria/menu/index.api.md +++ b/goldens/aria/menu/index.api.md @@ -93,9 +93,9 @@ export class MenuTrigger { readonly element: HTMLElement; readonly expanded: _angular_core.Signal; readonly hasPopup: _angular_core.Signal; - menu: _angular_core.InputSignal | undefined>; + readonly menu: _angular_core.InputSignal | undefined>; open(): void; - _pattern: MenuTriggerPattern; + readonly _pattern: MenuTriggerPattern; readonly softDisabled: _angular_core.InputSignalWithTransform; readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; // (undocumented) diff --git a/goldens/aria/private/index.api.md b/goldens/aria/private/index.api.md index f484be549c6c..096a41c60b6b 100644 --- a/goldens/aria/private/index.api.md +++ b/goldens/aria/private/index.api.md @@ -21,14 +21,14 @@ export class AccordionGroupPattern { readonly focusBehavior: ListFocus; // (undocumented) readonly inputs: AccordionGroupInputs; - keydown: SignalLike>; + readonly keydown: SignalLike>; readonly navigationBehavior: ListNavigation; - nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; + readonly nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; onFocus(event: FocusEvent): void; onKeydown(event: KeyboardEvent): void; onPointerdown(event: PointerEvent): void; - pointerdown: SignalLike>; - prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; + readonly pointerdown: SignalLike>; + readonly prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; toggle(): void; } @@ -65,7 +65,7 @@ export class ComboboxDialogPattern { id: SignalLike; }); // (undocumented) - id: () => string; + readonly id: () => string; // (undocumented) readonly inputs: { combobox: ComboboxPattern; @@ -73,13 +73,13 @@ export class ComboboxDialogPattern { id: SignalLike; }; // (undocumented) - keydown: SignalLike>; + readonly keydown: SignalLike>; // (undocumented) onClick(event: MouseEvent): void; // (undocumented) onKeydown(event: KeyboardEvent): void; // (undocumented) - role: () => "dialog"; + readonly role: () => "dialog"; } // @public @@ -107,7 +107,7 @@ export interface ComboboxListboxControls, V> { getActiveItem: () => T | undefined; getItem: (e: PointerEvent) => T | undefined; getSelectedItems: () => T[]; - id: () => string; + readonly id: () => string; items: SignalLike; last: () => void; multi: SignalLike; @@ -128,63 +128,62 @@ export type ComboboxListboxInputs = ListboxInputs & { // @public (undocumented) export class ComboboxListboxPattern extends ListboxPattern implements ComboboxListboxControls, V> { constructor(inputs: ComboboxListboxInputs); - activeId: SignalLike; - clearSelection: () => void; - first: () => void; - focus: (item: OptionPattern, opts?: { + readonly activeId: SignalLike; + readonly clearSelection: () => void; + readonly first: () => void; + readonly focus: (item: OptionPattern, opts?: { focusElement?: boolean; }) => void; - getActiveItem: () => OptionPattern | undefined; - getItem: (e: PointerEvent) => OptionPattern | undefined; - getSelectedItems: () => OptionPattern[]; - id: SignalLike; + readonly getActiveItem: () => OptionPattern | undefined; + readonly getItem: (e: PointerEvent) => OptionPattern | undefined; + readonly getSelectedItems: () => OptionPattern[]; + readonly id: SignalLike; // (undocumented) readonly inputs: ComboboxListboxInputs; - items: SignalLike[]>; - last: () => void; + readonly items: SignalLike[]>; + readonly last: () => void; multi: SignalLike; - next: () => void; + readonly next: () => void; onClick(_: PointerEvent): void; onKeydown(_: KeyboardEvent): void; - prev: () => void; - role: SignalLike<"listbox">; - select: (item?: OptionPattern) => void; + readonly prev: () => void; + readonly role: SignalLike<"listbox">; + readonly select: (item?: OptionPattern) => void; setDefaultState(): void; - setValue: (value: V | undefined) => void; + readonly setValue: (value: V | undefined) => void; tabIndex: SignalLike<-1 | 0>; - toggle: (item?: OptionPattern) => void; - unfocus: () => void; + readonly toggle: (item?: OptionPattern) => void; + readonly unfocus: () => void; } // @public export class ComboboxPattern, V> { constructor(inputs: ComboboxInputs); - activeDescendant: SignalLike; - autocomplete: SignalLike<"both" | "list">; - click: SignalLike>; + readonly activeDescendant: SignalLike; + readonly autocomplete: SignalLike<"both" | "list">; + readonly click: SignalLike>; close(opts?: { reset: boolean; }): void; collapseItem(): void; - collapseKey: SignalLike<"ArrowLeft" | "ArrowRight">; + readonly collapseKey: SignalLike<"ArrowLeft" | "ArrowRight">; commit(): void; - disabled: () => boolean; - expanded: WritableSignalLike; + readonly disabled: () => boolean; + readonly expanded: WritableSignalLike; expandItem(): void; - expandKey: SignalLike<"ArrowLeft" | "ArrowRight">; + readonly expandKey: SignalLike<"ArrowLeft" | "ArrowRight">; first(): void; - firstMatch: SignalLike; - hasBeenInteracted: WritableSignalLike; - hasPopup: SignalLike<"listbox" | "tree" | "grid" | "dialog" | null>; + readonly firstMatch: SignalLike; + readonly hasBeenInteracted: WritableSignalLike; + readonly hasPopup: SignalLike<"listbox" | "tree" | "grid" | "dialog" | null>; highlight(): void; - highlightedItem: WritableSignalLike; + readonly highlightedItem: WritableSignalLike; // (undocumented) readonly inputs: ComboboxInputs; - isDeleting: boolean; - isFocused: WritableSignalLike; - keydown: SignalLike>; + readonly isFocused: WritableSignalLike; + readonly keydown: SignalLike>; last(): void; - listControls: () => ComboboxListboxControls | null | undefined; + readonly listControls: () => ComboboxListboxControls | null | undefined; next(): void; onClick(event: MouseEvent): void; onFilter(): void; @@ -197,15 +196,15 @@ export class ComboboxPattern, V> { last?: boolean; selected?: boolean; }): void; - popupId: SignalLike; + readonly popupId: SignalLike; prev(): void; - readonly: SignalLike; + readonly readonly: SignalLike; select(opts?: { item?: T; commit?: boolean; close?: boolean; }): void; - treeControls: () => ComboboxTreeControls | null; + readonly treeControls: () => ComboboxTreeControls | null; } // @public (undocumented) @@ -229,36 +228,36 @@ export type ComboboxTreeInputs = TreeInputs & { export class ComboboxTreePattern extends TreePattern implements ComboboxTreeControls, V> { constructor(inputs: ComboboxTreeInputs); // (undocumented) - activeId: SignalLike; - clearSelection: () => void; - collapseAll: () => void; - collapseItem: () => void; - expandAll: () => void; - expandItem: () => void; - first: () => void; - focus: (item: TreeItemPattern) => void; - getActiveItem: () => TreeItemPattern | undefined; - getItem: (e: PointerEvent) => TreeItemPattern | undefined; - getSelectedItems: () => TreeItemPattern[]; + readonly activeId: SignalLike; + readonly clearSelection: () => void; + readonly collapseAll: () => void; + readonly collapseItem: () => void; + readonly expandAll: () => void; + readonly expandItem: () => void; + readonly first: () => void; + readonly focus: (item: TreeItemPattern) => void; + readonly getActiveItem: () => TreeItemPattern | undefined; + readonly getItem: (e: PointerEvent) => TreeItemPattern | undefined; + readonly getSelectedItems: () => TreeItemPattern[]; // (undocumented) readonly inputs: ComboboxTreeInputs; - isItemCollapsible: () => boolean; + readonly isItemCollapsible: () => boolean; isItemExpandable(item?: TreeItemPattern | undefined): boolean; - isItemSelectable: (item?: TreeItemPattern | undefined) => boolean; + readonly isItemSelectable: (item?: TreeItemPattern | undefined) => boolean; items: SignalLike[]>; - last: () => void; - next: () => void; + readonly last: () => void; + readonly next: () => void; onKeydown(_: KeyboardEvent): void; onPointerdown(_: PointerEvent): void; - prev: () => void; - role: () => "tree"; - select: (item?: TreeItemPattern) => void; + readonly prev: () => void; + readonly role: () => "tree"; + readonly select: (item?: TreeItemPattern) => void; setDefaultState(): void; - setValue: (value: V | undefined) => void; - tabIndex: SignalLike<-1 | 0>; - toggle: (item?: TreeItemPattern) => void; - toggleExpansion: (item?: TreeItemPattern) => void; - unfocus: () => void; + readonly setValue: (value: V | undefined) => void; + readonly tabIndex: SignalLike<-1 | 0>; + readonly toggle: (item?: TreeItemPattern) => void; + readonly toggleExpansion: (item?: TreeItemPattern) => void; + readonly unfocus: () => void; } // @public (undocumented) @@ -449,36 +448,36 @@ export type ListboxInputs = ListInputs, V> & { // @public export class ListboxPattern { constructor(inputs: ListboxInputs); - activeDescendant: SignalLike; - clickManager: SignalLike>; - disabled: SignalLike; - dynamicSpaceKey: SignalLike<"" | " ">; - followFocus: SignalLike; + readonly activeDescendant: SignalLike; + readonly clickManager: SignalLike>; + readonly disabled: SignalLike; + readonly dynamicSpaceKey: SignalLike<"" | " ">; + readonly followFocus: SignalLike; // (undocumented) protected _getItem(e: PointerEvent): OptionPattern | undefined; readonly hasBeenInteracted: WritableSignalLike; // (undocumented) readonly inputs: ListboxInputs; - keydown: SignalLike>; + readonly keydown: SignalLike>; // (undocumented) - listBehavior: List, V>; + readonly listBehavior: List, V>; multi: SignalLike; - nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; + readonly nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">; // (undocumented) onClick(event: PointerEvent): void; // (undocumented) onFocusIn(): void; onKeydown(event: KeyboardEvent): void; - orientation: SignalLike<'vertical' | 'horizontal'>; - prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; - readonly: SignalLike; + readonly orientation: SignalLike<'vertical' | 'horizontal'>; + readonly prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; + readonly readonly: SignalLike; setDefaultState(): void; setDefaultStateEffect(): void; - setsize: SignalLike; - tabIndex: SignalLike<-1 | 0>; - typeaheadRegexp: RegExp; + readonly setsize: SignalLike; + readonly tabIndex: SignalLike<-1 | 0>; + readonly typeaheadRegexp: RegExp; validate(): string[]; - wrap: WritableSignalLike; + readonly wrap: WritableSignalLike; } // @public @@ -492,17 +491,17 @@ export interface MenuBarInputs extends ListInputs, V> { export class MenuBarPattern { constructor(inputs: MenuBarInputs); close(): void; - disabled: () => boolean; - dynamicSpaceKey: SignalLike<"" | " ">; + readonly disabled: () => boolean; + readonly dynamicSpaceKey: SignalLike<"" | " ">; goto(item: MenuItemPattern, opts?: { focusElement?: boolean; }): void; - hasBeenInteracted: WritableSignalLike; + readonly hasBeenInteracted: WritableSignalLike; // (undocumented) readonly inputs: MenuBarInputs; - isFocused: WritableSignalLike; - keydownManager: SignalLike>; - listBehavior: List, V>; + readonly isFocused: WritableSignalLike; + readonly keydownManager: SignalLike>; + readonly listBehavior: List, V>; next(): void; onClick(event: MouseEvent): void; onFocusIn(): void; @@ -512,8 +511,8 @@ export class MenuBarPattern { prev(): void; setDefaultState(): void; setDefaultStateEffect(): void; - tabIndex: () => 0 | -1; - typeaheadRegexp: RegExp; + readonly tabIndex: () => 0 | -1; + readonly typeaheadRegexp: RegExp; } // @public @@ -535,19 +534,19 @@ export interface MenuItemInputs extends Omit, 'index' | 'selectab // @public export class MenuItemPattern implements ListItem { constructor(inputs: MenuItemInputs); - active: SignalLike; + readonly active: SignalLike; close(opts?: { refocus?: boolean; }): void; - controls: WritableSignalLike; - disabled: () => boolean; - element: SignalLike; - expanded: SignalLike; - _expanded: WritableSignalLike; - hasBeenInteracted: WritableSignalLike; - hasPopup: SignalLike; - id: SignalLike; - index: SignalLike; + readonly controls: WritableSignalLike; + readonly disabled: () => boolean; + readonly element: SignalLike; + readonly expanded: SignalLike; + readonly _expanded: WritableSignalLike; + readonly hasBeenInteracted: WritableSignalLike; + readonly hasPopup: SignalLike; + readonly id: SignalLike; + readonly index: SignalLike; // (undocumented) readonly inputs: MenuItemInputs; onFocusIn(): void; @@ -555,12 +554,12 @@ export class MenuItemPattern implements ListItem { first?: boolean; last?: boolean; }): void; - role: () => string; - searchTerm: SignalLike; - selectable: SignalLike; - submenu: SignalLike | undefined>; - tabIndex: SignalLike<0 | -1>; - value: SignalLike; + readonly role: () => string; + readonly searchTerm: SignalLike; + readonly selectable: SignalLike; + readonly submenu: SignalLike | undefined>; + readonly tabIndex: SignalLike<0 | -1>; + readonly value: SignalLike; } // @public @@ -573,19 +572,19 @@ export class MenuPattern { closeAll(): void; _closeTimeout: any; collapse(): void; - disabled: () => boolean; - dynamicSpaceKey: SignalLike<"" | " ">; + readonly disabled: () => boolean; + readonly dynamicSpaceKey: SignalLike<"" | " ">; expand(): void; first(): void; - hasBeenHovered: WritableSignalLike; - hasBeenInteracted: WritableSignalLike; - id: SignalLike; + readonly hasBeenHovered: WritableSignalLike; + readonly hasBeenInteracted: WritableSignalLike; + readonly id: SignalLike; // (undocumented) readonly inputs: MenuInputs; - isFocused: WritableSignalLike; - keydownManager: SignalLike>; + readonly isFocused: WritableSignalLike; + readonly keydownManager: SignalLike>; last(): void; - listBehavior: List, V>; + readonly listBehavior: List, V>; next(): void; onClick(event: MouseEvent): void; onFocusIn(): void; @@ -595,16 +594,16 @@ export class MenuPattern { onMouseOver(event: MouseEvent): void; _openTimeout: any; prev(): void; - role: () => string; - root: SignalLike | MenuBarPattern | MenuPattern | undefined>; + readonly role: () => string; + readonly root: SignalLike | MenuBarPattern | MenuPattern | undefined>; setDefaultState(): void; setDefaultStateEffect(): void; - shouldFocus: SignalLike; + readonly shouldFocus: SignalLike; submit(item?: MenuItemPattern | undefined): void; - tabIndex: () => 0 | -1; + readonly tabIndex: () => 0 | -1; trigger(): void; - typeaheadRegexp: RegExp; - visible: SignalLike; + readonly typeaheadRegexp: RegExp; + readonly visible: SignalLike; } // @public @@ -621,14 +620,14 @@ export class MenuTriggerPattern { close(opts?: { refocus?: boolean; }): void; - disabled: () => boolean; - expanded: WritableSignalLike; - hasBeenInteracted: WritableSignalLike; - hasPopup: () => boolean; + readonly disabled: () => boolean; + readonly expanded: WritableSignalLike; + readonly hasBeenInteracted: WritableSignalLike; + readonly hasPopup: () => boolean; // (undocumented) readonly inputs: MenuTriggerInputs; - keydownManager: SignalLike>; - menu: SignalLike | undefined>; + readonly keydownManager: SignalLike>; + readonly menu: SignalLike | undefined>; onClick(): void; onFocusIn(): void; onFocusOut(event: FocusEvent): void; @@ -637,8 +636,8 @@ export class MenuTriggerPattern { first?: boolean; last?: boolean; }): void; - role: () => string; - tabIndex: SignalLike<-1 | 0>; + readonly role: () => string; + readonly tabIndex: SignalLike<-1 | 0>; } // @public @@ -650,17 +649,17 @@ export interface OptionInputs extends Omit, 'index' | 'selectable // @public export class OptionPattern { constructor(args: OptionInputs); - active: SignalLike; - disabled: SignalLike; - element: SignalLike; - id: SignalLike; - index: SignalLike; - listbox: SignalLike | undefined>; - searchTerm: SignalLike; - selectable: () => boolean; - selected: SignalLike; - tabIndex: SignalLike<0 | -1 | undefined>; - value: SignalLike; + readonly active: SignalLike; + readonly disabled: SignalLike; + readonly element: SignalLike; + readonly id: SignalLike; + readonly index: SignalLike; + readonly listbox: SignalLike | undefined>; + readonly searchTerm: SignalLike; + readonly selectable: () => boolean; + readonly selected: SignalLike; + readonly tabIndex: SignalLike<0 | -1 | undefined>; + readonly value: SignalLike; } // @public (undocumented) @@ -906,7 +905,7 @@ export class TreePattern implements TreeInputs { onKeydown(event: KeyboardEvent): void; onPointerdown(event: PointerEvent): void; readonly orientation: SignalLike<'vertical' | 'horizontal'>; - pointerdown: SignalLike>; + readonly pointerdown: SignalLike>; readonly prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">; readonly selectionMode: SignalLike<'follow' | 'explicit'>; setDefaultState(): void; diff --git a/goldens/aria/toolbar/index.api.md b/goldens/aria/toolbar/index.api.md index 2527a24a189c..d7437fc5d51f 100644 --- a/goldens/aria/toolbar/index.api.md +++ b/goldens/aria/toolbar/index.api.md @@ -19,7 +19,7 @@ export class Toolbar { readonly _pattern: ToolbarPattern; // (undocumented) _register(widget: ToolbarWidget): void; - softDisabled: _angular_core.InputSignalWithTransform; + readonly softDisabled: _angular_core.InputSignalWithTransform; readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>; // (undocumented) _unregister(widget: ToolbarWidget): void; diff --git a/src/aria/combobox/combobox-dialog.ts b/src/aria/combobox/combobox-dialog.ts index 903d3087d3c0..a54882e145c4 100644 --- a/src/aria/combobox/combobox-dialog.ts +++ b/src/aria/combobox/combobox-dialog.ts @@ -56,7 +56,7 @@ export class ComboboxDialog { optional: true, }); - _pattern: ComboboxDialogPattern; + readonly _pattern: ComboboxDialogPattern; constructor() { this._pattern = new ComboboxDialogPattern({ diff --git a/src/aria/combobox/combobox-input.ts b/src/aria/combobox/combobox-input.ts index 3a79ba895b77..ea12db5229b9 100644 --- a/src/aria/combobox/combobox-input.ts +++ b/src/aria/combobox/combobox-input.ts @@ -67,7 +67,7 @@ export class ComboboxInput { readonly combobox = inject(Combobox); /** The value of the input. */ - value = model(''); + readonly value = model(''); constructor() { (this.combobox._pattern.inputs.inputEl as WritableSignal).set( diff --git a/src/aria/combobox/combobox.ts b/src/aria/combobox/combobox.ts index e5aa15c5b54d..906042ffbc7b 100644 --- a/src/aria/combobox/combobox.ts +++ b/src/aria/combobox/combobox.ts @@ -78,7 +78,7 @@ import {ComboboxPopup} from './combobox-popup'; }) export class Combobox { /** A signal wrapper for directionality. */ - protected textDirection = inject(Directionality).valueSignal.asReadonly(); + protected readonly textDirection = inject(Directionality).valueSignal.asReadonly(); /** The element that the combobox is attached to. */ private readonly _elementRef = inject(ElementRef); @@ -98,7 +98,7 @@ export class Combobox { * - `auto-select`: The combobox automatically selects the first matching option. * - `highlight`: The combobox highlights matching text in the options without changing selection. */ - filterMode = input<'manual' | 'auto-select' | 'highlight'>('manual'); + readonly filterMode = input<'manual' | 'auto-select' | 'highlight'>('manual'); /** Whether the combobox is disabled. */ readonly disabled = input(false, {transform: booleanAttribute}); diff --git a/src/aria/listbox/listbox.ts b/src/aria/listbox/listbox.ts index aba47bbb95e5..c599ed8e9257 100644 --- a/src/aria/listbox/listbox.ts +++ b/src/aria/listbox/listbox.ts @@ -88,53 +88,53 @@ export class Listbox { private readonly _options = contentChildren(Option, {descendants: true}); /** A signal wrapper for directionality. */ - protected textDirection = inject(Directionality).valueSignal.asReadonly(); + protected readonly textDirection = inject(Directionality).valueSignal.asReadonly(); /** The Option UIPatterns of the child Options. */ - protected items = computed[]>(() => + protected readonly items = computed[]>(() => this._options().map(option => option._pattern), ); /** Whether the list is vertically or horizontally oriented. */ - orientation = input<'vertical' | 'horizontal'>('vertical'); + readonly orientation = input<'vertical' | 'horizontal'>('vertical'); /** Whether multiple items in the list can be selected at once. */ - multi = input(false, {transform: booleanAttribute}); + readonly multi = input(false, {transform: booleanAttribute}); /** Whether focus should wrap when navigating. */ - wrap = input(true, {transform: booleanAttribute}); + readonly wrap = input(true, {transform: booleanAttribute}); /** * Whether to allow disabled items to receive focus. When `true`, disabled items are * focusable but not interactive. When `false`, disabled items are skipped during navigation. */ - softDisabled = input(true, {transform: booleanAttribute}); + readonly softDisabled = input(true, {transform: booleanAttribute}); /** * The focus strategy used by the list. * - `roving`: Focus is moved to the active item using `tabindex`. * - `activedescendant`: Focus remains on the listbox container, and `aria-activedescendant` is used to indicate the active item. */ - focusMode = input<'roving' | 'activedescendant'>('roving'); + readonly focusMode = input<'roving' | 'activedescendant'>('roving'); /** * The selection strategy used by the list. * - `follow`: The focused item is automatically selected. * - `explicit`: Items are selected explicitly by the user (e.g., via click or spacebar). */ - selectionMode = input<'follow' | 'explicit'>('follow'); + readonly selectionMode = input<'follow' | 'explicit'>('follow'); /** The amount of time before the typeahead search is reset. */ - typeaheadDelay = input(500); // Picked arbitrarily. + readonly typeaheadDelay = input(500); // Picked arbitrarily. /** Whether the listbox is disabled. */ - disabled = input(false, {transform: booleanAttribute}); + readonly disabled = input(false, {transform: booleanAttribute}); /** Whether the listbox is readonly. */ - readonly = input(false, {transform: booleanAttribute}); + readonly readonly = input(false, {transform: booleanAttribute}); /** The values of the currently selected items. */ - value = model([]); + readonly value = model([]); /** The Listbox UIPattern. */ readonly _pattern: ListboxPattern; diff --git a/src/aria/listbox/option.ts b/src/aria/listbox/option.ts index b14205678fe9..9ace2b204dc5 100644 --- a/src/aria/listbox/option.ts +++ b/src/aria/listbox/option.ts @@ -48,7 +48,7 @@ export class Option { readonly element = inject(ElementRef).nativeElement as HTMLElement; /** Whether the option is currently active (focused). */ - active = computed(() => this._pattern.active()); + readonly active = computed(() => this._pattern.active()); /** The parent Listbox. */ private readonly _listbox = inject(LISTBOX); @@ -59,19 +59,19 @@ export class Option { // TODO(wagnermaciel): See if we want to change how we handle this since textContent is not // reactive. See https://github.com/angular/components/pull/30495#discussion_r1961260216. /** The text used by the typeahead search. */ - protected searchTerm = computed(() => this.label() ?? this.element.textContent); + protected readonly searchTerm = computed(() => this.label() ?? this.element.textContent); /** The parent Listbox UIPattern. */ private readonly _listboxPattern = computed(() => this._listbox._pattern); /** The value of the option. */ - value = input.required(); + readonly value = input.required(); /** Whether an item is disabled. */ - disabled = input(false, {transform: booleanAttribute}); + readonly disabled = input(false, {transform: booleanAttribute}); /** The text used by the typeahead search. */ - label = input(); + readonly label = input(); /** Whether the option is selected. */ readonly selected = computed(() => this._pattern.selected()); diff --git a/src/aria/menu/menu-trigger.ts b/src/aria/menu/menu-trigger.ts index bf0e7892c9b4..1baae2ac5940 100644 --- a/src/aria/menu/menu-trigger.ts +++ b/src/aria/menu/menu-trigger.ts @@ -67,7 +67,7 @@ export class MenuTrigger { readonly textDirection = inject(Directionality).valueSignal; /** The menu associated with the trigger. */ - menu = input | undefined>(undefined); + readonly menu = input | undefined>(undefined); /** Whether the menu is expanded. */ readonly expanded = computed(() => this._pattern.expanded()); @@ -82,7 +82,7 @@ export class MenuTrigger { readonly softDisabled = input(true, {transform: booleanAttribute}); /** The menu trigger ui pattern instance. */ - _pattern: MenuTriggerPattern = new MenuTriggerPattern({ + readonly _pattern: MenuTriggerPattern = new MenuTriggerPattern({ textDirection: this.textDirection, element: computed(() => this._elementRef.nativeElement), menu: computed(() => this.menu()?._pattern), diff --git a/src/aria/private/accordion/accordion.ts b/src/aria/private/accordion/accordion.ts index a43fe0b807d5..f579b69d19c0 100644 --- a/src/aria/private/accordion/accordion.ts +++ b/src/aria/private/accordion/accordion.ts @@ -53,7 +53,7 @@ export class AccordionGroupPattern { } /** The key used to navigate to the previous accordion trigger. */ - prevKey = computed(() => { + readonly prevKey = computed(() => { if (this.inputs.orientation() === 'vertical') { return 'ArrowUp'; } @@ -61,7 +61,7 @@ export class AccordionGroupPattern { }); /** The key used to navigate to the next accordion trigger. */ - nextKey = computed(() => { + readonly nextKey = computed(() => { if (this.inputs.orientation() === 'vertical') { return 'ArrowDown'; } @@ -69,7 +69,7 @@ export class AccordionGroupPattern { }); /** The keydown event manager for the accordion trigger. */ - keydown = computed(() => { + readonly keydown = computed(() => { return new KeyboardEventManager() .on(this.prevKey, () => this.navigationBehavior.prev(), {ignoreRepeat: false}) .on(this.nextKey, () => this.navigationBehavior.next(), {ignoreRepeat: false}) @@ -80,7 +80,7 @@ export class AccordionGroupPattern { }); /** The pointerdown event manager for the accordion trigger. */ - pointerdown = computed(() => { + readonly pointerdown = computed(() => { return new PointerEventManager().on(e => { const item = this._findTriggerPattern(e.target as Element); if (!item) return; diff --git a/src/aria/private/behaviors/event-manager/click-event-manager.ts b/src/aria/private/behaviors/event-manager/click-event-manager.ts index 03c6c2560008..3be9949a84e9 100644 --- a/src/aria/private/behaviors/event-manager/click-event-manager.ts +++ b/src/aria/private/behaviors/event-manager/click-event-manager.ts @@ -43,7 +43,7 @@ export function isProgrammaticClick(event: Event): boolean { * when handling keyboard activation explicitly via KeyboardEventManager. */ export class ClickEventManager extends EventManager { - options: EventHandlerOptions = { + readonly options: EventHandlerOptions = { preventDefault: false, stopPropagation: false, }; diff --git a/src/aria/private/behaviors/event-manager/keyboard-event-manager.ts b/src/aria/private/behaviors/event-manager/keyboard-event-manager.ts index 19f89782e91b..5b16dc33d4c2 100644 --- a/src/aria/private/behaviors/event-manager/keyboard-event-manager.ts +++ b/src/aria/private/behaviors/event-manager/keyboard-event-manager.ts @@ -29,7 +29,7 @@ type KeyCode = string | SignalLike | RegExp; * propagation and prevents default on all events it handles. */ export class KeyboardEventManager extends EventManager { - options: EventHandlerOptions = { + readonly options: EventHandlerOptions = { ignoreRepeat: true, preventDefault: true, stopPropagation: true, diff --git a/src/aria/private/behaviors/event-manager/pointer-event-manager.ts b/src/aria/private/behaviors/event-manager/pointer-event-manager.ts index 018cbcc2e92e..311bd2c815c0 100644 --- a/src/aria/private/behaviors/event-manager/pointer-event-manager.ts +++ b/src/aria/private/behaviors/event-manager/pointer-event-manager.ts @@ -26,7 +26,7 @@ export enum MouseButton { /** An event manager that is specialized for handling pointer events. */ export class PointerEventManager extends EventManager { - options: EventHandlerOptions = { + readonly options: EventHandlerOptions = { preventDefault: false, stopPropagation: false, }; diff --git a/src/aria/private/behaviors/list-focus/list-focus.ts b/src/aria/private/behaviors/list-focus/list-focus.ts index bfb96e1d3806..1aba209153d0 100644 --- a/src/aria/private/behaviors/list-focus/list-focus.ts +++ b/src/aria/private/behaviors/list-focus/list-focus.ts @@ -44,15 +44,15 @@ export interface ListFocusInputs { /** Controls focus for a list of items. */ export class ListFocus { /** The last item that was active. */ - prevActiveItem = signal(undefined); + readonly prevActiveItem = signal(undefined); /** The index of the last item that was active. */ - prevActiveIndex = computed(() => { + readonly prevActiveIndex = computed(() => { return this.prevActiveItem() ? this.inputs.items().indexOf(this.prevActiveItem()!) : -1; }); /** The current active index in the list. */ - activeIndex = computed(() => { + readonly activeIndex = computed(() => { return this.inputs.activeItem() ? this.inputs.items().indexOf(this.inputs.activeItem()!) : -1; }); diff --git a/src/aria/private/behaviors/list-selection/list-selection.ts b/src/aria/private/behaviors/list-selection/list-selection.ts index 61601f7f5fde..8b22b28110ac 100644 --- a/src/aria/private/behaviors/list-selection/list-selection.ts +++ b/src/aria/private/behaviors/list-selection/list-selection.ts @@ -33,13 +33,13 @@ export interface ListSelectionInputs, V> extends /** Controls selection for a list of items. */ export class ListSelection, V> { /** The start index to use for range selection. */ - rangeStartIndex = signal(0); + readonly rangeStartIndex = signal(0); /** The end index to use for range selection. */ - rangeEndIndex = signal(0); + readonly rangeEndIndex = signal(0); /** The currently selected items. */ - selectedItems = computed(() => + readonly selectedItems = computed(() => this.inputs.items().filter(item => this.inputs.value().includes(item.value())), ); diff --git a/src/aria/private/behaviors/list-typeahead/list-typeahead.ts b/src/aria/private/behaviors/list-typeahead/list-typeahead.ts index 048a2ea99d5b..7719dd0edfa1 100644 --- a/src/aria/private/behaviors/list-typeahead/list-typeahead.ts +++ b/src/aria/private/behaviors/list-typeahead/list-typeahead.ts @@ -33,16 +33,16 @@ export class ListTypeahead { timeout?: ReturnType | undefined; /** The focus controller of the parent list. */ - focusManager: ListFocus; + readonly focusManager: ListFocus; /** Whether the user is actively typing a typeahead search query. */ - isTyping = computed(() => this._query().length > 0); + readonly isTyping = computed(() => this._query().length > 0); /** Keeps track of the characters that typeahead search is being called with. */ - private _query = signal(''); + private readonly _query = signal(''); /** The index where that the typeahead search was initiated from. */ - private _startIndex = signal(undefined); + private readonly _startIndex = signal(undefined); constructor(readonly inputs: ListTypeaheadInputs & {focusManager: ListFocus}) { this.focusManager = inputs.focusManager; diff --git a/src/aria/private/behaviors/list/list.ts b/src/aria/private/behaviors/list/list.ts index 2fd702f481ff..e70e6e020a6e 100644 --- a/src/aria/private/behaviors/list/list.ts +++ b/src/aria/private/behaviors/list/list.ts @@ -50,28 +50,28 @@ export type ListInputs, V> = ListFocusInputs & /** Controls the state of a list. */ export class List, V> { /** Controls navigation for the list. */ - navigationBehavior: ListNavigation; + readonly navigationBehavior: ListNavigation; /** Controls selection for the list. */ - selectionBehavior: ListSelection; + readonly selectionBehavior: ListSelection; /** Controls typeahead for the list. */ - typeaheadBehavior: ListTypeahead; + readonly typeaheadBehavior: ListTypeahead; /** Controls focus for the list. */ - focusBehavior: ListFocus; + readonly focusBehavior: ListFocus; /** Whether the list is disabled. */ - disabled = computed(() => this.focusBehavior.isListDisabled()); + readonly disabled = computed(() => this.focusBehavior.isListDisabled()); /** The id of the current active item. */ - activeDescendant = computed(() => this.focusBehavior.getActiveDescendant()); + readonly activeDescendant = computed(() => this.focusBehavior.getActiveDescendant()); /** The tab index of the list. */ - tabIndex = computed(() => this.focusBehavior.getListTabIndex()); + readonly tabIndex = computed(() => this.focusBehavior.getListTabIndex()); /** The index of the currently active item in the list. */ - activeIndex = computed(() => this.focusBehavior.activeIndex()); + readonly activeIndex = computed(() => this.focusBehavior.activeIndex()); /** * The uncommitted index for selecting a range of options. @@ -85,10 +85,10 @@ export class List, V> { * In other words, "rangeStartIndex" is only set when a user commits to starting a range selection * while "anchorIndex" is set whenever a user indicates they may be starting a range selection. */ - private _anchorIndex = signal(0); + private readonly _anchorIndex = signal(0); /** Whether the list should wrap. Used to disable wrapping while range selecting. */ - private _wrap = signal(true); + private readonly _wrap = signal(true); constructor(readonly inputs: ListInputs) { this.focusBehavior = new ListFocus(inputs); diff --git a/src/aria/private/behaviors/tree/tree.ts b/src/aria/private/behaviors/tree/tree.ts index 7dd6040c2fd2..4ba301369d27 100644 --- a/src/aria/private/behaviors/tree/tree.ts +++ b/src/aria/private/behaviors/tree/tree.ts @@ -61,37 +61,37 @@ class TreeListFocus, V> extends ListFocus { /** Controls the state of a tree. */ export class Tree, V> { /** Controls navigation for the tree. */ - navigationBehavior: ListNavigation; + readonly navigationBehavior: ListNavigation; /** Controls selection for the tree. */ - selectionBehavior: ListSelection; + readonly selectionBehavior: ListSelection; /** Controls typeahead for the tree. */ - typeaheadBehavior: ListTypeahead; + readonly typeaheadBehavior: ListTypeahead; /** Controls focus for the tree. */ - focusBehavior: ListFocus; + readonly focusBehavior: ListFocus; /** Controls expansion for the tree. */ - expansionBehavior: ListExpansion; + readonly expansionBehavior: ListExpansion; /** Whether the tree is disabled. */ - disabled = computed(() => this.focusBehavior.isListDisabled()); + readonly disabled = computed(() => this.focusBehavior.isListDisabled()); /** The id of the current active item. */ - activeDescendant = computed(() => this.focusBehavior.getActiveDescendant()); + readonly activeDescendant = computed(() => this.focusBehavior.getActiveDescendant()); /** The tab index of the tree. */ - tabIndex = computed(() => this.focusBehavior.getListTabIndex()); + readonly tabIndex = computed(() => this.focusBehavior.getListTabIndex()); /** The index of the currently active item in the tree (within the flattened list). */ - activeIndex = computed(() => this.focusBehavior.activeIndex()); + readonly activeIndex = computed(() => this.focusBehavior.activeIndex()); /** The uncommitted index for selecting a range of options. */ - private _anchorIndex = signal(0); + private readonly _anchorIndex = signal(0); /** Whether the list should wrap. */ - private _wrap = signal(true); + private readonly _wrap = signal(true); constructor(readonly inputs: TreeInputs) { this.focusBehavior = new TreeListFocus(inputs); diff --git a/src/aria/private/combobox/combobox.ts b/src/aria/private/combobox/combobox.ts index 43cd6065faa8..5fa3e70117ae 100644 --- a/src/aria/private/combobox/combobox.ts +++ b/src/aria/private/combobox/combobox.ts @@ -53,7 +53,7 @@ export interface ComboboxInputs, V> { /** An interface that allows combobox popups to expose the necessary controls for the combobox. */ export interface ComboboxListboxControls, V> { /** A unique identifier for the popup. */ - id: () => string; + readonly id: () => string; /** The ARIA role for the popup. */ role: SignalLike<'listbox' | 'tree' | 'grid'>; @@ -141,13 +141,13 @@ export interface ComboboxTreeControls, V> extends Combobox /** Controls the state of a combobox. */ export class ComboboxPattern, V> { /** Whether the combobox is expanded. */ - expanded = signal(false); + readonly expanded = signal(false); /** Whether the combobox is disabled. */ - disabled = () => this.inputs.disabled(); + readonly disabled = () => this.inputs.disabled(); /** The ID of the active item in the combobox. */ - activeDescendant = computed(() => { + readonly activeDescendant = computed(() => { const popupControls = this.inputs.popupControls(); if (popupControls instanceof ComboboxDialogPattern) { return null; @@ -157,39 +157,43 @@ export class ComboboxPattern, V> { }); /** The currently highlighted item in the combobox. */ - highlightedItem = signal(undefined); + readonly highlightedItem = signal(undefined); /** Whether the most recent input event was a deletion. */ - isDeleting = false; + private _isDeleting = false; /** Whether the combobox is focused. */ - isFocused = signal(false); + readonly isFocused = signal(false); /** Whether the combobox has ever been focused. */ - hasBeenInteracted = signal(false); + readonly hasBeenInteracted = signal(false); /** The key used to navigate to the previous item in the list. */ - expandKey = computed(() => (this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight')); + readonly expandKey = computed(() => + this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight', + ); /** The key used to navigate to the next item in the list. */ - collapseKey = computed(() => + readonly collapseKey = computed(() => this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft', ); /** The ID of the popup associated with the combobox. */ - popupId = computed(() => this.inputs.popupControls()?.id() || null); + readonly popupId = computed(() => this.inputs.popupControls()?.id() || null); /** The autocomplete behavior of the combobox. */ - autocomplete = computed(() => (this.inputs.filterMode() === 'highlight' ? 'both' : 'list')); + readonly autocomplete = computed(() => + this.inputs.filterMode() === 'highlight' ? 'both' : 'list', + ); /** The ARIA role of the popup associated with the combobox. */ - hasPopup = computed(() => this.inputs.popupControls()?.role() || null); + readonly hasPopup = computed(() => this.inputs.popupControls()?.role() || null); /** Whether the combobox is read-only. */ - readonly = computed(() => this.inputs.readonly() || this.inputs.disabled() || null); + readonly readonly = computed(() => this.inputs.readonly() || this.inputs.disabled() || null); /** Returns the listbox controls for the combobox. */ - listControls = () => { + readonly listControls = () => { const popupControls = this.inputs.popupControls(); if (popupControls instanceof ComboboxDialogPattern) { @@ -200,7 +204,7 @@ export class ComboboxPattern, V> { }; /** Returns the tree controls for the combobox. */ - treeControls = () => { + readonly treeControls = () => { const popupControls = this.inputs.popupControls(); if (popupControls?.role() === 'tree') { @@ -211,7 +215,7 @@ export class ComboboxPattern, V> { }; /** The keydown event manager for the combobox. */ - keydown = computed(() => { + readonly keydown = computed(() => { const manager = new KeyboardEventManager(); const popupControls = this.inputs.popupControls(); @@ -289,7 +293,7 @@ export class ComboboxPattern, V> { }); /** The click event manager for the combobox. */ - click = computed(() => + readonly click = computed(() => new PointerEventManager().on(e => { if (e.target === this.inputs.inputEl()) { if (this.readonly()) { @@ -358,9 +362,9 @@ export class ComboboxPattern, V> { this.open(); this.inputs.inputValue?.set(inputEl.value); - this.isDeleting = event instanceof InputEvent && !!event.inputType.match(/^delete/); + this._isDeleting = event instanceof InputEvent && !!event.inputType.match(/^delete/); - if (this.inputs.filterMode() === 'highlight' && !this.isDeleting) { + if (this.inputs.filterMode() === 'highlight' && !this._isDeleting) { this.highlight(); } } @@ -420,7 +424,7 @@ export class ComboboxPattern, V> { } /** The first matching item in the combobox. */ - firstMatch = computed(() => { + readonly firstMatch = computed(() => { // TODO(wagnermaciel): Consider whether we should not provide this default behavior for the // listbox. Instead, we may want to allow users to have no match so that typing does not focus // any option. @@ -449,7 +453,7 @@ 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._isDeleting; if (isInitialRender) { return; @@ -479,7 +483,7 @@ export class ComboboxPattern, V> { this.select({item}); } - if (this.inputs.filterMode() === 'highlight' && !this.isDeleting) { + if (this.inputs.filterMode() === 'highlight' && !this._isDeleting) { this.highlight(); } } @@ -710,11 +714,11 @@ export class ComboboxPattern, V> { } export class ComboboxDialogPattern { - id = () => this.inputs.id(); + readonly id = () => this.inputs.id(); - role = () => 'dialog' as const; + readonly role = () => 'dialog' as const; - keydown = computed(() => { + readonly keydown = computed(() => { return new KeyboardEventManager().on('Escape', () => this.inputs.combobox.close()); }); diff --git a/src/aria/private/listbox/combobox-listbox.ts b/src/aria/private/listbox/combobox-listbox.ts index 9b78da330253..acbda822082a 100644 --- a/src/aria/private/listbox/combobox-listbox.ts +++ b/src/aria/private/listbox/combobox-listbox.ts @@ -21,16 +21,16 @@ export class ComboboxListboxPattern implements ComboboxListboxControls, V> { /** A unique identifier for the popup. */ - id = computed(() => this.inputs.id()); + readonly id = computed(() => this.inputs.id()); /** The ARIA role for the listbox. */ - role = computed(() => 'listbox' as const); + readonly role = computed(() => 'listbox' as const); /** The id of the active (focused) item in the listbox. */ - activeId = computed(() => this.listBehavior.activeDescendant()); + readonly activeId = computed(() => this.listBehavior.activeDescendant()); /** The list of options in the listbox. */ - items: SignalLike[]> = computed(() => this.inputs.items()); + readonly items: SignalLike[]> = computed(() => this.inputs.items()); /** The tab index for the listbox. Always -1 because the combobox handles focus. */ override tabIndex: SignalLike<-1 | 0> = () => -1; @@ -59,42 +59,42 @@ export class ComboboxListboxPattern override setDefaultState(): void {} /** Navigates to the specified item in the listbox. */ - focus = (item: OptionPattern, opts?: {focusElement?: boolean}) => { + readonly focus = (item: OptionPattern, opts?: {focusElement?: boolean}) => { this.listBehavior.goto(item, opts); }; /** Navigates to the previous focusable item in the listbox. */ - getActiveItem = () => this.inputs.activeItem(); + readonly getActiveItem = () => this.inputs.activeItem(); /** Navigates to the next focusable item in the listbox. */ - next = () => this.listBehavior.next(); + readonly next = () => this.listBehavior.next(); /** Navigates to the previous focusable item in the listbox. */ - prev = () => this.listBehavior.prev(); + readonly prev = () => this.listBehavior.prev(); /** Navigates to the last focusable item in the listbox. */ - last = () => this.listBehavior.last(); + readonly last = () => this.listBehavior.last(); /** Navigates to the first focusable item in the listbox. */ - first = () => this.listBehavior.first(); + readonly first = () => this.listBehavior.first(); /** Unfocuses the currently focused item in the listbox. */ - unfocus = () => this.listBehavior.unfocus(); + readonly unfocus = () => this.listBehavior.unfocus(); /** Selects the specified item in the listbox. */ - select = (item?: OptionPattern) => this.listBehavior.select(item); + readonly select = (item?: OptionPattern) => this.listBehavior.select(item); /** Toggles the selection state of the given item in the listbox. */ - toggle = (item?: OptionPattern) => this.listBehavior.toggle(item); + readonly toggle = (item?: OptionPattern) => this.listBehavior.toggle(item); /** Clears the selection in the listbox. */ - clearSelection = () => this.listBehavior.deselectAll(); + readonly clearSelection = () => this.listBehavior.deselectAll(); /** Retrieves the OptionPattern associated with a pointer event. */ - getItem = (e: PointerEvent) => this._getItem(e); + readonly getItem = (e: PointerEvent) => this._getItem(e); /** Retrieves the currently selected items in the listbox. */ - getSelectedItems = () => { + readonly getSelectedItems = () => { // 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()) { @@ -107,5 +107,5 @@ export class ComboboxListboxPattern }; /** Sets the value of the combobox listbox. */ - setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); + readonly setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); } diff --git a/src/aria/private/listbox/listbox.ts b/src/aria/private/listbox/listbox.ts index bf6897bce1ec..0bf38594a1f2 100644 --- a/src/aria/private/listbox/listbox.ts +++ b/src/aria/private/listbox/listbox.ts @@ -23,40 +23,40 @@ export type ListboxInputs = ListInputs, V> & { /** Controls the state of a listbox. */ export class ListboxPattern { - listBehavior: List, V>; + readonly listBehavior: List, V>; /** Whether the listbox has been interacted with. */ readonly hasBeenInteracted = signal(false); /** Whether the list is vertically or horizontally oriented. */ - orientation: SignalLike<'vertical' | 'horizontal'>; + readonly orientation: SignalLike<'vertical' | 'horizontal'>; /** Whether the listbox is disabled. */ - disabled = computed(() => this.listBehavior.disabled()); + readonly disabled = computed(() => this.listBehavior.disabled()); /** Whether the listbox is readonly. */ - readonly: SignalLike; + readonly readonly: SignalLike; /** The tab index of the listbox. */ - tabIndex: SignalLike<-1 | 0> = computed(() => this.listBehavior.tabIndex()); + readonly tabIndex: SignalLike<-1 | 0> = computed(() => this.listBehavior.tabIndex()); /** The id of the current active item. */ - activeDescendant = computed(() => this.listBehavior.activeDescendant()); + readonly activeDescendant = computed(() => this.listBehavior.activeDescendant()); /** Whether multiple items in the list can be selected at once. */ multi: SignalLike; /** The number of items in the listbox. */ - setsize = computed(() => this.inputs.items().length); + readonly setsize = computed(() => this.inputs.items().length); /** Whether the listbox selection follows focus. */ - followFocus = computed(() => this.inputs.selectionMode() === 'follow'); + readonly followFocus = computed(() => this.inputs.selectionMode() === 'follow'); /** Whether the listbox should wrap. Used to disable wrapping while range selecting. */ - wrap = signal(true); + readonly wrap = signal(true); /** The key used to navigate to the previous item in the list. */ - prevKey = computed(() => { + readonly prevKey = computed(() => { if (this.inputs.orientation() === 'vertical') { return 'ArrowUp'; } @@ -64,7 +64,7 @@ export class ListboxPattern { }); /** The key used to navigate to the next item in the list. */ - nextKey = computed(() => { + readonly nextKey = computed(() => { if (this.inputs.orientation() === 'vertical') { return 'ArrowDown'; } @@ -72,13 +72,13 @@ export class ListboxPattern { }); /** Represents the space key. Does nothing when the user is actively using typeahead. */ - dynamicSpaceKey = computed(() => (this.listBehavior.isTyping() ? '' : ' ')); + readonly dynamicSpaceKey = computed(() => (this.listBehavior.isTyping() ? '' : ' ')); /** The regexp used to decide if a key should trigger typeahead. */ - typeaheadRegexp = /^.$/; + readonly typeaheadRegexp = /^.$/; /** The keydown event manager for the listbox. */ - keydown = computed(() => { + readonly keydown = computed(() => { const manager = new KeyboardEventManager(); if (this.readonly()) { @@ -165,7 +165,7 @@ export class ListboxPattern { }); /** The click event manager for the listbox. */ - clickManager = computed(() => { + readonly clickManager = computed(() => { const manager = new ClickEventManager(); if (this.readonly()) { diff --git a/src/aria/private/listbox/option.ts b/src/aria/private/listbox/option.ts index c7daacf1bf45..0e8de02c2985 100644 --- a/src/aria/private/listbox/option.ts +++ b/src/aria/private/listbox/option.ts @@ -26,37 +26,37 @@ export interface OptionInputs extends Omit, 'index' | 'selectable /** Represents an option in a listbox. */ export class OptionPattern { /** A unique identifier for the option. */ - id: SignalLike; + readonly id: SignalLike; /** The value of the option. */ - value: SignalLike; + readonly value: SignalLike; /** The position of the option in the list. */ - index = computed(() => this.listbox()?.inputs.items().indexOf(this) ?? -1); + readonly index = computed(() => this.listbox()?.inputs.items().indexOf(this) ?? -1); /** Whether the option is active. */ - active = computed(() => this.listbox()?.inputs.activeItem() === this); + readonly active = computed(() => this.listbox()?.inputs.activeItem() === this); /** Whether the option is selected. */ - selected = computed(() => this.listbox()?.inputs.value().includes(this.value())); + readonly selected = computed(() => this.listbox()?.inputs.value().includes(this.value())); /** Whether the option is selectable. */ - selectable = () => true; + readonly selectable = () => true; /** Whether the option is disabled. */ - disabled: SignalLike; + readonly disabled: SignalLike; /** The text used by the typeahead search. */ - searchTerm: SignalLike; + readonly searchTerm: SignalLike; /** A reference to the parent listbox. */ - listbox: SignalLike | undefined>; + readonly listbox: SignalLike | undefined>; /** The tab index of the option. */ - tabIndex = computed(() => this.listbox()?.listBehavior.getItemTabindex(this)); + readonly tabIndex = computed(() => this.listbox()?.listBehavior.getItemTabindex(this)); /** The html element that should receive focus. */ - element: SignalLike; + readonly element: SignalLike; constructor(args: OptionInputs) { this.id = args.id; diff --git a/src/aria/private/menu/menu.ts b/src/aria/private/menu/menu.ts index d5fd07ca970e..c81962926071 100644 --- a/src/aria/private/menu/menu.ts +++ b/src/aria/private/menu/menu.ts @@ -70,28 +70,30 @@ export interface MenuItemInputs extends Omit, 'index' | 'selectab /** The menu ui pattern class. */ export class MenuPattern { /** The unique ID of the menu. */ - id: SignalLike; + readonly id: SignalLike; /** The role of the menu. */ - role = () => 'menu'; + readonly role = () => 'menu'; /** Whether the menu is disabled. */ - disabled = () => this.inputs.disabled(); + readonly disabled = () => this.inputs.disabled(); /** Whether the menu is visible. */ - visible = computed(() => (this.inputs.parent() ? !!this.inputs.parent()?.expanded() : true)); + readonly visible = computed(() => + this.inputs.parent() ? !!this.inputs.parent()?.expanded() : true, + ); /** Controls list behavior for the menu items. */ - listBehavior: List, V>; + readonly listBehavior: List, V>; /** Whether the menu or any of its child elements are currently focused. */ - isFocused = signal(false); + readonly isFocused = signal(false); /** Whether the menu has received interaction. */ - hasBeenInteracted = signal(false); + readonly hasBeenInteracted = signal(false); /** Whether the menu trigger has been hovered. */ - hasBeenHovered = signal(false); + readonly hasBeenHovered = signal(false); /** Timeout used to open sub-menus on hover. */ _openTimeout: any; @@ -100,10 +102,10 @@ export class MenuPattern { _closeTimeout: any; /** The tab index of the menu. */ - tabIndex = () => this.listBehavior.tabIndex(); + readonly tabIndex = () => this.listBehavior.tabIndex(); /** Whether the menu should be focused on mouse over. */ - shouldFocus = computed(() => { + readonly shouldFocus = computed(() => { const root = this.root(); if (root instanceof MenuTriggerPattern) { @@ -118,45 +120,46 @@ export class MenuPattern { }); /** The key used to expand sub-menus. */ - private _expandKey = computed(() => { + private readonly _expandKey = computed(() => { return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; }); /** The key used to collapse sub-menus. */ - private _collapseKey = computed(() => { + private readonly _collapseKey = computed(() => { return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; }); /** Represents the space key. Does nothing when the user is actively using typeahead. */ - dynamicSpaceKey = computed(() => (this.listBehavior.isTyping() ? '' : ' ')); + readonly dynamicSpaceKey = computed(() => (this.listBehavior.isTyping() ? '' : ' ')); /** The regexp used to decide if a key should trigger typeahead. */ - typeaheadRegexp = /^.$/; + readonly typeaheadRegexp = /^.$/; /** The root of the menu. */ - root: SignalLike | MenuBarPattern | MenuPattern | undefined> = - computed(() => { - const parent = this.inputs.parent(); + readonly root: SignalLike< + MenuTriggerPattern | MenuBarPattern | MenuPattern | undefined + > = computed(() => { + const parent = this.inputs.parent(); - if (!parent) { - return this; - } + if (!parent) { + return this; + } - if (parent instanceof MenuTriggerPattern) { - return parent; - } + if (parent instanceof MenuTriggerPattern) { + return parent; + } - const grandparent = parent.inputs.parent(); + const grandparent = parent.inputs.parent(); - if (grandparent instanceof MenuBarPattern) { - return grandparent; - } + if (grandparent instanceof MenuBarPattern) { + return grandparent; + } - return grandparent?.root(); - }); + return grandparent?.root(); + }); /** Handles keyboard events for the menu. */ - keydownManager = computed(() => { + readonly keydownManager = computed(() => { return new KeyboardEventManager() .on('ArrowDown', () => this.next(), {ignoreRepeat: false}) .on('ArrowUp', () => this.prev(), {ignoreRepeat: false}) @@ -460,38 +463,38 @@ export class MenuPattern { /** The menubar ui pattern class. */ export class MenuBarPattern { /** Controls list behavior for the menu items. */ - listBehavior: List, V>; + readonly listBehavior: List, V>; /** The tab index of the menu. */ - tabIndex = () => this.listBehavior.tabIndex(); + readonly tabIndex = () => this.listBehavior.tabIndex(); /** The key used to navigate to the next item. */ - private _nextKey = computed(() => { + private readonly _nextKey = computed(() => { return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; }); /** The key used to navigate to the previous item. */ - private _previousKey = computed(() => { + private readonly _previousKey = computed(() => { return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; }); /** Represents the space key. Does nothing when the user is actively using typeahead. */ - dynamicSpaceKey = computed(() => (this.listBehavior.isTyping() ? '' : ' ')); + readonly dynamicSpaceKey = computed(() => (this.listBehavior.isTyping() ? '' : ' ')); /** The regexp used to decide if a key should trigger typeahead. */ - typeaheadRegexp = /^.$/; + readonly typeaheadRegexp = /^.$/; /** Whether the menubar or any of its children are currently focused. */ - isFocused = signal(false); + readonly isFocused = signal(false); /** Whether the menubar has been interacted with. */ - hasBeenInteracted = signal(false); + readonly hasBeenInteracted = signal(false); /** Whether the menubar is disabled. */ - disabled = () => this.inputs.disabled(); + readonly disabled = () => this.inputs.disabled(); /** Handles keyboard events for the menu. */ - keydownManager = computed(() => { + readonly keydownManager = computed(() => { return new KeyboardEventManager() .on(this._nextKey, () => this.next(), {ignoreRepeat: false}) .on(this._previousKey, () => this.prev(), {ignoreRepeat: false}) @@ -617,28 +620,30 @@ export class MenuBarPattern { /** The menu trigger ui pattern class. */ export class MenuTriggerPattern { /** Whether the menu trigger is expanded. */ - expanded = signal(false); + readonly expanded = signal(false); /** Whether the menu trigger has received interaction. */ - hasBeenInteracted = signal(false); + readonly hasBeenInteracted = signal(false); /** The role of the menu trigger. */ - role = () => 'button'; + readonly role = () => 'button'; /** Whether the menu trigger has a popup. */ - hasPopup = () => true; + readonly hasPopup = () => true; /** The menu associated with the trigger. */ - menu: SignalLike | undefined>; + readonly menu: SignalLike | undefined>; /** The tab index of the menu trigger. */ - tabIndex = computed(() => (this.expanded() && this.menu()?.inputs.activeItem() ? -1 : 0)); + readonly tabIndex = computed(() => + this.expanded() && this.menu()?.inputs.activeItem() ? -1 : 0, + ); /** Whether the menu trigger is disabled. */ - disabled = () => this.inputs.disabled(); + readonly disabled = () => this.inputs.disabled(); /** Handles keyboard events for the menu trigger. */ - keydownManager = computed(() => { + readonly keydownManager = computed(() => { return new KeyboardEventManager() .on(' ', () => this.open({first: true})) .on('Enter', () => this.open({first: true})) @@ -719,28 +724,28 @@ export class MenuTriggerPattern { /** The menu item ui pattern class. */ export class MenuItemPattern implements ListItem { /** The value of the menu item. */ - value: SignalLike; + readonly value: SignalLike; /** The unique ID of the menu item. */ - id: SignalLike; + readonly id: SignalLike; /** Whether the menu item is disabled. */ - disabled = () => this.inputs.parent()?.disabled() || this.inputs.disabled(); + readonly disabled = () => this.inputs.parent()?.disabled() || this.inputs.disabled(); /** The search term for the menu item. */ - searchTerm: SignalLike; + readonly searchTerm: SignalLike; /** The element of the menu item. */ - element: SignalLike; + readonly element: SignalLike; /** Whether the menu item is active. */ - active = computed(() => this.inputs.parent()?.inputs.activeItem() === this); + readonly active = computed(() => this.inputs.parent()?.inputs.activeItem() === this); /** Whether the menu item has received interaction. */ - hasBeenInteracted = signal(false); + readonly hasBeenInteracted = signal(false); /** The tab index of the menu item. */ - tabIndex = computed(() => { + readonly tabIndex = computed(() => { if (this.submenu() && this.submenu()?.inputs.activeItem()) { return -1; } @@ -748,28 +753,28 @@ export class MenuItemPattern implements ListItem { }); /** The position of the menu item in the menu. */ - index = computed(() => this.inputs.parent()?.inputs.items().indexOf(this) ?? -1); + readonly index = computed(() => this.inputs.parent()?.inputs.items().indexOf(this) ?? -1); /** Whether the menu item is expanded. */ - expanded = computed(() => (this.submenu() ? this._expanded() : null)); + readonly expanded = computed(() => (this.submenu() ? this._expanded() : null)); /** Whether the menu item is expanded. */ - _expanded = signal(false); + readonly _expanded = signal(false); /** The ID of the menu that the menu item controls. */ - controls = signal(undefined); + readonly controls = signal(undefined); /** The role of the menu item. */ - role = () => 'menuitem'; + readonly role = () => 'menuitem'; /** Whether the menu item has a popup. */ - hasPopup = computed(() => !!this.submenu()); + readonly hasPopup = computed(() => !!this.submenu()); /** The submenu associated with the menu item. */ - submenu: SignalLike | undefined>; + readonly submenu: SignalLike | undefined>; /** Whether the menu item is selectable. */ - selectable: SignalLike; + readonly selectable: SignalLike; constructor(readonly inputs: MenuItemInputs) { this.id = inputs.id; diff --git a/src/aria/private/tree/combobox-tree.ts b/src/aria/private/tree/combobox-tree.ts index fc806021684e..7c83c6d8fe53 100644 --- a/src/aria/private/tree/combobox-tree.ts +++ b/src/aria/private/tree/combobox-tree.ts @@ -20,25 +20,25 @@ export class ComboboxTreePattern implements ComboboxTreeControls, V> { /** Toggles to expand or collapse a tree item. */ - toggleExpansion = (item?: TreeItemPattern) => this.treeBehavior.toggleExpansion(item); + readonly toggleExpansion = (item?: TreeItemPattern) => this.treeBehavior.toggleExpansion(item); /** Whether the currently focused item is collapsible. */ - isItemCollapsible = () => this.inputs.activeItem()?.parent() instanceof TreeItemPattern; + readonly isItemCollapsible = () => this.inputs.activeItem()?.parent() instanceof TreeItemPattern; /** The ARIA role for the tree. */ - role = () => 'tree' as const; + readonly role = () => 'tree' as const; /* The id of the active (focused) item in the tree. */ - activeId = computed(() => this.treeBehavior.activeDescendant()); + readonly activeId = computed(() => this.treeBehavior.activeDescendant()); /** Returns the currently active (focused) item in the tree. */ - getActiveItem = () => this.inputs.activeItem(); + readonly getActiveItem = () => this.inputs.activeItem(); /** The list of items in the tree. */ override items = computed(() => this.inputs.items()); /** The tab index for the tree. Always -1 because the combobox handles focus. */ - override tabIndex: SignalLike<-1 | 0> = () => -1; + override readonly tabIndex: SignalLike<-1 | 0> = () => -1; constructor(override readonly inputs: ComboboxTreeInputs) { if (inputs.combobox()) { @@ -60,47 +60,47 @@ export class ComboboxTreePattern override setDefaultState(): void {} /** Navigates to the specified item in the tree. */ - focus = (item: TreeItemPattern) => this.treeBehavior.goto(item); + readonly focus = (item: TreeItemPattern) => this.treeBehavior.goto(item); /** Navigates to the next focusable item in the tree. */ - next = () => this.treeBehavior.next(); + readonly next = () => this.treeBehavior.next(); /** Navigates to the previous focusable item in the tree. */ - prev = () => this.treeBehavior.prev(); + readonly prev = () => this.treeBehavior.prev(); /** Navigates to the last focusable item in the tree. */ - last = () => this.treeBehavior.last(); + readonly last = () => this.treeBehavior.last(); /** Navigates to the first focusable item in the tree. */ - first = () => this.treeBehavior.first(); + readonly first = () => this.treeBehavior.first(); /** Unfocuses the currently focused item in the tree. */ - unfocus = () => this.treeBehavior.unfocus(); + readonly unfocus = () => this.treeBehavior.unfocus(); // TODO: handle non-selectable parent nodes. /** Selects the specified item in the tree or the current active item if not provided. */ - select = (item?: TreeItemPattern) => this.treeBehavior.select(item); + readonly select = (item?: TreeItemPattern) => this.treeBehavior.select(item); /** Toggles the selection state of the given item in the tree or the current active item if not provided. */ - toggle = (item?: TreeItemPattern) => this.treeBehavior.toggle(item); + readonly toggle = (item?: TreeItemPattern) => this.treeBehavior.toggle(item); /** Clears the selection in the tree. */ - clearSelection = () => this.treeBehavior.deselectAll(); + readonly clearSelection = () => this.treeBehavior.deselectAll(); /** Retrieves the TreeItemPattern associated with a pointer event. */ - getItem = (e: PointerEvent) => this._getItem(e); + readonly getItem = (e: PointerEvent) => this._getItem(e); /** Retrieves the currently selected items in the tree */ - getSelectedItems = () => this.inputs.items().filter(item => item.selected()); + readonly getSelectedItems = () => this.inputs.items().filter(item => item.selected()); /** Sets the value of the combobox tree. */ - setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); + readonly setValue = (value: V | undefined) => this.inputs.value.set(value ? [value] : []); /** Expands the currently focused item if it is expandable, or navigates to the first child. */ - expandItem = () => this._expandOrFirstChild(); + readonly expandItem = () => this._expandOrFirstChild(); /** Collapses the currently focused item if it is expandable, or navigates to the parent. */ - collapseItem = () => this._collapseOrParent(); + readonly collapseItem = () => this._collapseOrParent(); /** Whether the specified item or the currently active item is expandable. */ isItemExpandable(item: TreeItemPattern | undefined = this.inputs.activeItem()) { @@ -108,13 +108,13 @@ export class ComboboxTreePattern } /** Expands all of the tree items. */ - expandAll = () => this.treeBehavior.expandAll(); + readonly expandAll = () => this.treeBehavior.expandAll(); /** Collapses all of the tree items. */ - collapseAll = () => this.treeBehavior.collapseAll(); + readonly collapseAll = () => this.treeBehavior.collapseAll(); /** Whether the currently active item is selectable. */ - isItemSelectable = (item: TreeItemPattern | undefined = this.inputs.activeItem()) => { + readonly isItemSelectable = (item: TreeItemPattern | undefined = this.inputs.activeItem()) => { return item ? item.selectable() : false; }; } diff --git a/src/aria/private/tree/tree.ts b/src/aria/private/tree/tree.ts index 300844a9919e..ad3383c3136c 100644 --- a/src/aria/private/tree/tree.ts +++ b/src/aria/private/tree/tree.ts @@ -288,7 +288,7 @@ export class TreePattern implements TreeInputs { }); /** The pointerdown event manager for the tree. */ - pointerdown = computed(() => { + readonly pointerdown = computed(() => { const manager = new PointerEventManager(); if (this.multi()) { diff --git a/src/aria/toolbar/toolbar.ts b/src/aria/toolbar/toolbar.ts index bbb877b58129..94b749bdfc4f 100644 --- a/src/aria/toolbar/toolbar.ts +++ b/src/aria/toolbar/toolbar.ts @@ -83,7 +83,7 @@ export class Toolbar { * Whether to allow disabled items to receive focus. When `true`, disabled items are * focusable but not interactive. When `false`, disabled items are skipped during navigation. */ - softDisabled = input(true, {transform: booleanAttribute}); + readonly softDisabled = input(true, {transform: booleanAttribute}); /** Whether the toolbar is disabled. */ readonly disabled = input(false, {transform: booleanAttribute});