From 032758dc134d9cfae97067e1a276772841154926 Mon Sep 17 00:00:00 2001 From: Andrey Dolgachev Date: Thu, 13 Nov 2025 17:16:02 -0800 Subject: [PATCH 1/8] refactor(aria/accordion): underscore pattern props only for internal usage --- src/aria/accordion/accordion.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/aria/accordion/accordion.ts b/src/aria/accordion/accordion.ts index 84f7f5a9d35a..3c873ffc95c1 100644 --- a/src/aria/accordion/accordion.ts +++ b/src/aria/accordion/accordion.ts @@ -79,14 +79,14 @@ export class AccordionPanel { readonly visible = computed(() => !this._pattern.hidden()); /** The parent accordion trigger pattern that controls this panel. This is set by AccordionGroup. */ - readonly accordionTrigger: WritableSignal = + readonly _accordionTriggerPattern: WritableSignal = signal(undefined); /** The UI pattern instance for this panel. */ readonly _pattern: AccordionPanelPattern = new AccordionPanelPattern({ id: this.id, panelId: this.panelId, - accordionTrigger: () => this.accordionTrigger(), + accordionTrigger: () => this._accordionTriggerPattern(), }); constructor() { @@ -98,17 +98,17 @@ export class AccordionPanel { /** Expands this item. */ expand() { - this.accordionTrigger()?.open(); + this._accordionTriggerPattern()?.open(); } /** Collapses this item. */ collapse() { - this.accordionTrigger()?.close(); + this._accordionTriggerPattern()?.close(); } /** Toggles the expansion state of this item. */ toggle() { - this.accordionTrigger()?.toggle(); + this._accordionTriggerPattern()?.toggle(); } } @@ -169,13 +169,14 @@ export class AccordionTrigger { readonly active = computed(() => this._pattern.active()); /** The accordion panel pattern controlled by this trigger. This is set by AccordionGroup. */ - readonly _accordionPanel: WritableSignal = signal(undefined); + readonly _accordionPanelPattern: WritableSignal = + signal(undefined); /** The UI pattern instance for this trigger. */ readonly _pattern: AccordionTriggerPattern = new AccordionTriggerPattern({ ...this, accordionGroup: computed(() => this._accordionGroup._pattern), - accordionPanel: this._accordionPanel, + accordionPanel: this._accordionPanelPattern, element: () => this.element, }); @@ -292,9 +293,9 @@ export class AccordionGroup { for (const trigger of triggers) { const panel = panels.find(p => p.panelId() === trigger.panelId()); - trigger._accordionPanel.set(panel?._pattern); + trigger._accordionPanelPattern.set(panel?._pattern); if (panel) { - panel.accordionTrigger.set(trigger._pattern); + panel._accordionTriggerPattern.set(trigger._pattern); } } }); From bde5b68156096971c01be074a50bfd3dc4daa06a Mon Sep 17 00:00:00 2001 From: Andrey Dolgachev Date: Thu, 13 Nov 2025 18:25:36 -0800 Subject: [PATCH 2/8] refactor(aria/combobox): underscore pattern props only for internal usage --- src/aria/combobox/combobox.ts | 8 ++++---- src/aria/listbox/listbox.ts | 2 +- src/aria/tree/tree.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/aria/combobox/combobox.ts b/src/aria/combobox/combobox.ts index a1cf79e0bde9..cad6898f65bc 100644 --- a/src/aria/combobox/combobox.ts +++ b/src/aria/combobox/combobox.ts @@ -138,7 +138,7 @@ export class Combobox { inputValue: signal(''), inputEl: signal(undefined), containerEl: () => this._elementRef.nativeElement, - popupControls: () => this.popup()?.controls(), + popupControls: () => this.popup()?._controls(), }); constructor() { @@ -231,7 +231,7 @@ export class ComboboxInput { ); this.combobox._pattern.inputs.inputValue = this.value; - const controls = this.combobox.popup()?.controls(); + const controls = this.combobox.popup()?._controls(); if (controls instanceof ComboboxDialogPattern) { return; } @@ -301,7 +301,7 @@ export class ComboboxPopup { readonly combobox = inject>(Combobox, {optional: true}); /** The popup controls exposed to the combobox. */ - readonly controls = signal< + readonly _controls = signal< | ComboboxListboxControls | ComboboxTreeControls | ComboboxDialogPattern @@ -359,7 +359,7 @@ export class ComboboxDialog { }); if (this._popup) { - this._popup.controls.set(this._pattern); + this._popup._controls.set(this._pattern); } afterRenderEffect(() => { diff --git a/src/aria/listbox/listbox.ts b/src/aria/listbox/listbox.ts index 31e56ed8a649..729881730d3b 100644 --- a/src/aria/listbox/listbox.ts +++ b/src/aria/listbox/listbox.ts @@ -154,7 +154,7 @@ export class Listbox { : new ListboxPattern(inputs); if (this._popup) { - this._popup.controls.set(this._pattern as ComboboxListboxPattern); + this._popup._controls.set(this._pattern as ComboboxListboxPattern); } afterRenderEffect(() => { diff --git a/src/aria/tree/tree.ts b/src/aria/tree/tree.ts index f3fa8232cc95..9c4d9506d7b5 100644 --- a/src/aria/tree/tree.ts +++ b/src/aria/tree/tree.ts @@ -190,7 +190,7 @@ export class Tree { : new TreePattern(inputs); if (this._popup?.combobox) { - this._popup?.controls?.set(this._pattern as ComboboxTreePattern); + this._popup?._controls?.set(this._pattern as ComboboxTreePattern); } afterRenderEffect(() => { From ed891f8da334e0f2541500bd8707464cc9d1d6ee Mon Sep 17 00:00:00 2001 From: Andrey Dolgachev Date: Thu, 13 Nov 2025 17:31:49 -0800 Subject: [PATCH 3/8] refactor(aria/grid): underscore pattern props only for internal usage --- src/aria/grid/grid.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/aria/grid/grid.ts b/src/aria/grid/grid.ts index 51b1c458cfbe..78bedc9ea35a 100644 --- a/src/aria/grid/grid.ts +++ b/src/aria/grid/grid.ts @@ -202,7 +202,7 @@ export class GridRow { private readonly _grid = inject(Grid); /** The parent grid UI pattern. */ - readonly grid = computed(() => this._grid._pattern); + readonly _gridPattern = computed(() => this._grid._pattern); /** The index of this row within the grid. */ readonly rowIndex = input(); @@ -211,6 +211,7 @@ export class GridRow { readonly _pattern = new GridRowPattern({ ...this, cells: this._cellPatterns, + grid: this._gridPattern, }); } @@ -318,7 +319,7 @@ export class GridCell { /** The UI pattern for the grid cell. */ readonly _pattern = new GridCellPattern({ ...this, - grid: this._row.grid, + grid: this._row._gridPattern, row: () => this._row._pattern, widgets: this._widgetPatterns, getWidget: e => this._getWidget(e), From 7801428c637622534fe93eec783cb32b5603a96a Mon Sep 17 00:00:00 2001 From: Andrey Dolgachev Date: Thu, 13 Nov 2025 18:30:16 -0800 Subject: [PATCH 4/8] refactor(aria/listbox): underscore pattern props only for internal usage --- src/aria/listbox/listbox.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aria/listbox/listbox.ts b/src/aria/listbox/listbox.ts index 729881730d3b..b35019118dc8 100644 --- a/src/aria/listbox/listbox.ts +++ b/src/aria/listbox/listbox.ts @@ -257,7 +257,7 @@ export class Option { protected searchTerm = computed(() => this.label() ?? this.element.textContent); /** The parent Listbox UIPattern. */ - protected listbox = computed(() => this._listbox._pattern); + private readonly _listboxPattern = computed(() => this._listbox._pattern); /** The value of the option. */ value = input.required(); @@ -276,7 +276,7 @@ export class Option { ...this, id: this.id, value: this.value, - listbox: this.listbox, + listbox: this._listboxPattern, element: () => this.element, searchTerm: () => this.searchTerm() ?? '', }); From e5a26a5181a6488b4b82c3675469a18f501e4c40 Mon Sep 17 00:00:00 2001 From: Andrey Dolgachev Date: Thu, 13 Nov 2025 17:40:13 -0800 Subject: [PATCH 5/8] refactor(aria/menu): underscore pattern props only for internal usage --- src/aria/menu/menu.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 4046446ddffb..4f1dfcb491a9 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -209,7 +209,7 @@ export class Menu { * sometimes the items array is empty. The bug can be reproduced by switching this to use a * computed and then quickly opening and closing menus in the dev app. */ - readonly items = () => this._items().map(i => i._pattern); + private readonly _itemPatterns = () => this._items().map(i => i._pattern); /** Whether the menu is visible. */ readonly visible = computed(() => this._pattern.visible()); @@ -227,6 +227,7 @@ export class Menu { this._pattern = new MenuPattern({ ...this, parent: computed(() => this.parent()?._pattern), + items: this._itemPatterns, multi: () => false, softDisabled: () => true, focusMode: () => 'roving', @@ -348,7 +349,7 @@ export class MenuBar { readonly _pattern: MenuBarPattern; /** The menu items as a writable signal. */ - readonly items = signal[]>([]); + private readonly _itemPatterns = signal[]>([]); /** A callback function triggered when a menu item is selected. */ onSelect = output(); @@ -356,6 +357,7 @@ export class MenuBar { constructor() { this._pattern = new MenuBarPattern({ ...this, + items: this._itemPatterns, multi: () => false, softDisabled: () => true, focusMode: () => 'roving', @@ -367,7 +369,7 @@ export class MenuBar { }); afterRenderEffect(() => { - this.items.set(this._items().map(i => i._pattern)); + this._itemPatterns.set(this._items().map(i => i._pattern)); }); afterRenderEffect(() => { From 58fb2ddb6892c5251030713fee64931f08ed9884 Mon Sep 17 00:00:00 2001 From: Andrey Dolgachev Date: Thu, 13 Nov 2025 17:26:58 -0800 Subject: [PATCH 6/8] refactor(aria/tabs): underscore pattern props only for internal usage --- src/aria/tabs/tabs.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/aria/tabs/tabs.ts b/src/aria/tabs/tabs.ts index 01de904e57d0..87d1a5b97cdf 100644 --- a/src/aria/tabs/tabs.ts +++ b/src/aria/tabs/tabs.ts @@ -307,10 +307,10 @@ export class Tab implements HasElement, OnInit, OnDestroy { readonly id = input(inject(_IdGenerator).getId('ng-tab-', true)); /** The parent TabList UIPattern. */ - readonly tablist = computed(() => this._tabList._pattern); + private readonly _tablistPattern = computed(() => this._tabList._pattern); /** The TabPanel UIPattern associated with the tab */ - readonly tabpanel = computed(() => + private readonly _tabpanelPattern = computed(() => this._tabs._unorderedTabpanelPatterns().find(tabpanel => tabpanel.value() === this.value()), ); @@ -329,8 +329,8 @@ export class Tab implements HasElement, OnInit, OnDestroy { /** The Tab UIPattern. */ readonly _pattern: TabPattern = new TabPattern({ ...this, - tablist: this.tablist, - tabpanel: this.tabpanel, + tablist: this._tablistPattern, + tabpanel: this._tabpanelPattern, expanded: signal(false), element: () => this.element, }); @@ -400,7 +400,7 @@ export class TabPanel implements OnInit, OnDestroy { readonly id = input(inject(_IdGenerator).getId('ng-tabpanel-', true)); /** The Tab UIPattern associated with the tabpanel */ - readonly tab = computed(() => + private readonly _tabPattern = computed(() => this._Tabs._tabPatterns()?.find(tab => tab.value() === this.value()), ); @@ -413,6 +413,7 @@ export class TabPanel implements OnInit, OnDestroy { /** The TabPanel UIPattern. */ readonly _pattern: TabPanelPattern = new TabPanelPattern({ ...this, + tab: this._tabPattern, }); constructor() { From e1978b50de157a60d8b2934bc49e46c5aad8740f Mon Sep 17 00:00:00 2001 From: Andrey Dolgachev Date: Thu, 13 Nov 2025 18:14:21 -0800 Subject: [PATCH 7/8] refactor(aria/toolbar): underscore pattern props only for internal usage --- src/aria/toolbar/toolbar.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/aria/toolbar/toolbar.ts b/src/aria/toolbar/toolbar.ts index e923c8daf1e8..005fd07353dd 100644 --- a/src/aria/toolbar/toolbar.ts +++ b/src/aria/toolbar/toolbar.ts @@ -89,7 +89,7 @@ export class Toolbar { readonly textDirection = inject(Directionality).valueSignal; /** Sorted UIPatterns of the child widgets */ - readonly items = computed(() => + readonly _itemPatterns = computed(() => [...this._widgets()].sort(sortDirectives).map(widget => widget._pattern), ); @@ -111,6 +111,7 @@ export class Toolbar { /** The toolbar UIPattern. */ readonly _pattern: ToolbarPattern = new ToolbarPattern({ ...this, + items: this._itemPatterns, activeItem: signal(undefined), textDirection: this.textDirection, element: () => this._elementRef.nativeElement, @@ -159,7 +160,7 @@ export class Toolbar { /** Finds the toolbar item associated with a given element. */ private _getItem(element: Element) { const widgetTarget = element.closest('[ngToolbarWidget]'); - return this.items().find(widget => widget.element() === widgetTarget); + return this._itemPatterns().find(widget => widget.element() === widgetTarget); } } @@ -204,7 +205,7 @@ export class ToolbarWidget implements OnInit, OnDestroy { readonly id = input(inject(_IdGenerator).getId('ng-toolbar-widget-', true)); /** The parent Toolbar UIPattern. */ - readonly toolbar = computed(() => this._toolbar._pattern); + readonly _toolbarPattern = computed(() => this._toolbar._pattern); /** Whether the widget is disabled. */ readonly disabled = input(false, {transform: booleanAttribute}); @@ -224,12 +225,15 @@ export class ToolbarWidget implements OnInit, OnDestroy { /** Whether the widget is selected (only relevant in a selection group). */ readonly selected = () => this._pattern.selected(); - readonly group: SignalLike, V> | undefined> = - () => this._group?._pattern; + private readonly _groupPattern: SignalLike< + ToolbarWidgetGroupPattern, V> | undefined + > = () => this._group?._pattern; /** The ToolbarWidget UIPattern. */ readonly _pattern = new ToolbarWidgetPattern({ ...this, + group: this._groupPattern, + toolbar: this._toolbarPattern, id: this.id, value: this.value, element: () => this.element, @@ -268,17 +272,21 @@ export class ToolbarWidgetGroup { private readonly _widgets = contentChildren(ToolbarWidget, {descendants: true}); /** The parent Toolbar UIPattern. */ - readonly toolbar = computed(() => this._toolbar?._pattern); + private readonly _toolbarPattern = computed(() => this._toolbar?._pattern); /** Whether the widget group is disabled. */ readonly disabled = input(false, {transform: booleanAttribute}); /** The list of toolbar items within the group. */ - readonly items = () => this._widgets().map(w => w._pattern); + private readonly _itemPatterns = () => this._widgets().map(w => w._pattern); /** Whether the group allows multiple widgets to be selected. */ readonly multi = input(false, {transform: booleanAttribute}); /** The ToolbarWidgetGroup UIPattern. */ - readonly _pattern = new ToolbarWidgetGroupPattern, V>(this); + readonly _pattern = new ToolbarWidgetGroupPattern, V>({ + ...this, + items: this._itemPatterns, + toolbar: this._toolbarPattern, + }); } From ccaad4be498ee2a7e15d6abf6a1abc8c6bc982cf Mon Sep 17 00:00:00 2001 From: Andrey Dolgachev Date: Thu, 13 Nov 2025 17:59:40 -0800 Subject: [PATCH 8/8] refactor(aria/tree): underscore pattern props only for internal usage --- src/aria/tree/tree.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aria/tree/tree.ts b/src/aria/tree/tree.ts index 9c4d9506d7b5..1607ad419aaf 100644 --- a/src/aria/tree/tree.ts +++ b/src/aria/tree/tree.ts @@ -363,7 +363,7 @@ export class TreeItem extends DeferredContentAware implements OnInit, OnDestr ...this, tree: treePattern, parent: parentPattern, - children: computed(() => this._group()?.children() ?? []), + children: computed(() => this._group()?._childPatterns() ?? []), hasChildren: computed(() => !!this._group()), element: () => this.element, searchTerm: () => this.searchTerm() ?? '', @@ -423,7 +423,7 @@ export class TreeItemGroup implements OnInit, OnDestroy { private readonly _unorderedItems = signal(new Set>()); /** Child items within this group. */ - readonly children = computed[]>(() => + readonly _childPatterns = computed[]>(() => [...this._unorderedItems()].sort(sortDirectives).map(c => c._pattern), );