diff --git a/goldens/aria/accordion/index.api.md b/goldens/aria/accordion/index.api.md index 8fa6f80b9a57..5e74cb835bb6 100644 --- a/goldens/aria/accordion/index.api.md +++ b/goldens/aria/accordion/index.api.md @@ -6,10 +6,14 @@ import * as _angular_cdk_bidi from '@angular/cdk/bidi'; import * as _angular_core from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; import { Signal } from '@angular/core'; +// @public +export const ACCORDION_GROUP: InjectionToken; + // @public export class AccordionContent { // (undocumented) diff --git a/goldens/aria/combobox/index.api.md b/goldens/aria/combobox/index.api.md index 9091f9477eed..d4edcd91e5b8 100644 --- a/goldens/aria/combobox/index.api.md +++ b/goldens/aria/combobox/index.api.md @@ -9,6 +9,7 @@ import { ComboboxPattern } from '@angular/aria/private'; import { ComboboxPopupPattern } from '@angular/aria/private'; import { DeferredContentAware } from '@angular/aria/private'; import * as i1 from '@angular/aria/private'; +import { InjectionToken } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; @@ -36,6 +37,9 @@ export class Combobox extends DeferredContentAware implements OnInit { static ɵfac: _angular_core.ɵɵFactoryDeclaration; } +// @public +export const COMBOBOX_POPUP: InjectionToken; + // @public export class ComboboxPopup implements OnInit, OnDestroy { readonly activeDescendant: _angular_core.Signal; diff --git a/goldens/aria/grid/index.api.md b/goldens/aria/grid/index.api.md index 3d7839b9a1de..46fdbe3f841e 100644 --- a/goldens/aria/grid/index.api.md +++ b/goldens/aria/grid/index.api.md @@ -7,10 +7,14 @@ import * as _angular_cdk_bidi from '@angular/cdk/bidi'; import * as _angular_core from '@angular/core'; import { ElementRef } from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; import { Signal } from '@angular/core'; +// @public +export const GRID: InjectionToken; + // @public export class Grid implements OnDestroy { constructor(); @@ -37,6 +41,12 @@ export class Grid implements OnDestroy { static ɵfac: _angular_core.ɵɵFactoryDeclaration; } +// @public +export const GRID_CELL: InjectionToken; + +// @public +export const GRID_ROW: InjectionToken; + // @public export class GridCell implements OnInit, OnDestroy { constructor(); diff --git a/goldens/aria/listbox/index.api.md b/goldens/aria/listbox/index.api.md index 54232cffaefe..7bb1076dc422 100644 --- a/goldens/aria/listbox/index.api.md +++ b/goldens/aria/listbox/index.api.md @@ -6,10 +6,14 @@ import * as _angular_cdk_bidi from '@angular/cdk/bidi'; import * as _angular_core from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; import { Signal } from '@angular/core'; +// @public (undocumented) +export const LISTBOX: InjectionToken>; + // @public export class Listbox implements OnDestroy { constructor(); diff --git a/goldens/aria/menu/index.api.md b/goldens/aria/menu/index.api.md index 79630b052dba..a126bde37b01 100644 --- a/goldens/aria/menu/index.api.md +++ b/goldens/aria/menu/index.api.md @@ -6,6 +6,7 @@ import * as _angular_cdk_bidi from '@angular/cdk/bidi'; import * as _angular_core from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; import { Signal } from '@angular/core'; @@ -37,6 +38,9 @@ export class Menu implements OnDestroy { static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; } +// @public +export const MENU_COMPONENT: InjectionToken | MenuBar>; + // @public export class MenuBar implements OnDestroy { constructor(); diff --git a/goldens/aria/tabs/index.api.md b/goldens/aria/tabs/index.api.md index fdb9b12b2f05..25ff29133c75 100644 --- a/goldens/aria/tabs/index.api.md +++ b/goldens/aria/tabs/index.api.md @@ -6,6 +6,7 @@ import * as _angular_cdk_bidi from '@angular/cdk/bidi'; import * as _angular_core from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; import { Signal } from '@angular/core'; @@ -32,6 +33,9 @@ export class Tab implements HasElement, OnInit, OnDestroy { static ɵfac: _angular_core.ɵɵFactoryDeclaration; } +// @public +export const TAB_LIST: InjectionToken; + // @public export class TabContent { // (undocumented) @@ -87,6 +91,9 @@ export class TabPanel implements OnInit, OnDestroy { static ɵfac: _angular_core.ɵɵFactoryDeclaration; } +// @public +export const TABS: InjectionToken; + // @public export class Tabs implements OnDestroy { constructor(); diff --git a/goldens/aria/toolbar/index.api.md b/goldens/aria/toolbar/index.api.md index 2d833a5cf11a..73f492dfdb47 100644 --- a/goldens/aria/toolbar/index.api.md +++ b/goldens/aria/toolbar/index.api.md @@ -6,6 +6,7 @@ import * as _angular_cdk_bidi from '@angular/cdk/bidi'; import * as _angular_core from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { OnDestroy } from '@angular/core'; import { OnInit } from '@angular/core'; import { Signal } from '@angular/core'; @@ -31,6 +32,9 @@ export class Toolbar implements OnDestroy { static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; } +// @public +export const TOOLBAR_WIDGET_GROUP: InjectionToken>; + // @public export class ToolbarWidget implements OnInit, OnDestroy { readonly active: _angular_core.Signal; diff --git a/src/aria/accordion/public-api.ts b/src/aria/accordion/public-api.ts index 73d592f44124..b50f605e06fd 100644 --- a/src/aria/accordion/public-api.ts +++ b/src/aria/accordion/public-api.ts @@ -10,6 +10,7 @@ export {AccordionPanel} from './accordion-panel'; export {AccordionGroup} from './accordion-group'; export {AccordionTrigger} from './accordion-trigger'; export {AccordionContent} from './accordion-content'; +export {ACCORDION_GROUP} from './accordion-tokens'; // This needs to be re-exported, because it's used by the accordion components. // See: https://github.com/angular/components/issues/30663. diff --git a/src/aria/combobox/public-api.ts b/src/aria/combobox/public-api.ts index 997e18d45952..6cc707670a62 100644 --- a/src/aria/combobox/public-api.ts +++ b/src/aria/combobox/public-api.ts @@ -9,6 +9,7 @@ export {Combobox} from './combobox'; export {ComboboxPopup} from './combobox-popup'; export {ComboboxWidget} from './combobox-widget'; +export {COMBOBOX_POPUP} from './combobox-tokens'; // This needs to be re-exported, because it's used by the combobox components. // See: https://github.com/angular/components/issues/30663. diff --git a/src/aria/grid/grid.spec.ts b/src/aria/grid/grid.spec.ts index 03fb5170b582..4041ca97d2ae 100644 --- a/src/aria/grid/grid.spec.ts +++ b/src/aria/grid/grid.spec.ts @@ -5,6 +5,7 @@ import {Grid} from './grid'; import {GridRow} from './grid-row'; import {GridCell} from './grid-cell'; import {GridCellWidget} from './grid-cell-widget'; +import {GRID_ROW, GRID_CELL} from './grid-tokens'; import {waitForMicrotasks} from '../private/testing/test-helpers'; interface ModifierKeys { @@ -1174,6 +1175,23 @@ describe('Grid directives', () => { expect(consoleSpy).toHaveBeenCalledWith('ngGridRow must contain at least one ngGridCell.'); }); }); + + describe('subclassing and custom providers', () => { + it('should support subclassing GridRow and GridCell using exported injection tokens', async () => { + TestBed.resetTestingModule(); + TestBed.configureTestingModule({ + imports: [SubclassGridTestComponent], + }); + const subclassFixture = TestBed.createComponent(SubclassGridTestComponent); + subclassFixture.detectChanges(); + await subclassFixture.whenStable(); + + const cells = subclassFixture.debugElement.queryAll(By.directive(MyCustomCell)); + expect(cells.length).toBe(2); + expect(cells[0].nativeElement.getAttribute('role')).toBe('gridcell'); + expect(cells[1].nativeElement.getAttribute('role')).toBe('gridcell'); + }); + }); }); @Component({ @@ -1261,3 +1279,31 @@ class GridTestComponent { changeDetection: ChangeDetectionStrategy.Eager, }) class GridRowWithoutCells {} + +@Component({ + selector: 'my-custom-cell', + template: ``, + providers: [{provide: GRID_CELL, useExisting: MyCustomCell}], +}) +class MyCustomCell extends GridCell {} + +@Component({ + selector: 'my-custom-row', + template: ``, + providers: [{provide: GRID_ROW, useExisting: MyCustomRow}], +}) +class MyCustomRow extends GridRow {} + +@Component({ + template: ` + + + Cell 1 + Cell 2 + +
+ `, + imports: [Grid, MyCustomRow, MyCustomCell], + changeDetection: ChangeDetectionStrategy.Eager, +}) +class SubclassGridTestComponent {} diff --git a/src/aria/grid/public-api.ts b/src/aria/grid/public-api.ts index 05e171a92d47..b8c416da44f2 100644 --- a/src/aria/grid/public-api.ts +++ b/src/aria/grid/public-api.ts @@ -10,3 +10,4 @@ export {Grid} from './grid'; export {GridCell} from './grid-cell'; export {GridRow} from './grid-row'; export {GridCellWidget} from './grid-cell-widget'; +export {GRID, GRID_ROW, GRID_CELL} from './grid-tokens'; diff --git a/src/aria/listbox/public-api.ts b/src/aria/listbox/public-api.ts index d601e9cbfe33..b5e5b713694f 100644 --- a/src/aria/listbox/public-api.ts +++ b/src/aria/listbox/public-api.ts @@ -8,3 +8,4 @@ export {Listbox} from './listbox'; export {Option} from './option'; +export {LISTBOX} from './tokens'; diff --git a/src/aria/menu/public-api.ts b/src/aria/menu/public-api.ts index 98239182ce61..824788eede52 100644 --- a/src/aria/menu/public-api.ts +++ b/src/aria/menu/public-api.ts @@ -11,6 +11,7 @@ export {Menu} from './menu'; export {MenuBar} from './menu-bar'; export {MenuItem} from './menu-item'; export {MenuContent} from './menu-content'; +export {MENU_COMPONENT} from './menu-tokens'; // This needs to be re-exported, because it's used by the menu components. // See: https://github.com/angular/components/issues/30663. diff --git a/src/aria/tabs/public-api.ts b/src/aria/tabs/public-api.ts index 301245ea153e..af800b96299a 100644 --- a/src/aria/tabs/public-api.ts +++ b/src/aria/tabs/public-api.ts @@ -11,6 +11,7 @@ export {TabList} from './tab-list'; export {Tab} from './tab'; export {TabPanel} from './tab-panel'; export {TabContent} from './tab-content'; +export {TABS, TAB_LIST} from './tab-tokens'; // This needs to be re-exported, because it's used by the tab components. // See: https://github.com/angular/components/issues/30663. diff --git a/src/aria/toolbar/public-api.ts b/src/aria/toolbar/public-api.ts index 50f6e9f89f84..0d2e755a31dc 100644 --- a/src/aria/toolbar/public-api.ts +++ b/src/aria/toolbar/public-api.ts @@ -9,3 +9,4 @@ export {Toolbar} from './toolbar'; export {ToolbarWidget} from './toolbar-widget'; export {ToolbarWidgetGroup} from './toolbar-widget-group'; +export {TOOLBAR_WIDGET_GROUP} from './toolbar-tokens';