| 58 | }, |
| 59 | }) |
| 60 | export class Toolbar<V> implements OnDestroy { |
| 61 | /** A reference to the host element. */ |
| 62 | private readonly _elementRef = inject(ElementRef); |
| 63 | |
| 64 | /** A reference to the host element. */ |
| 65 | readonly element = this._elementRef.nativeElement as HTMLElement; |
| 66 | |
| 67 | /** The collection of widgets in the toolbar. */ |
| 68 | readonly _collection = new SortedCollection<ToolbarWidget<V>>(); |
| 69 | |
| 70 | /** Text direction. */ |
| 71 | readonly textDirection = inject(Directionality).valueSignal; |
| 72 | |
| 73 | /** Sorted UIPatterns of the child widgets */ |
| 74 | readonly _itemPatterns = computed<ToolbarWidgetPattern<V>[]>(() => |
| 75 | this._collection.orderedItems().map(widget => widget._pattern), |
| 76 | ); |
| 77 | |
| 78 | /** Whether the toolbar is vertically or horizontally oriented. */ |
| 79 | readonly orientation = input<'vertical' | 'horizontal'>('horizontal'); |
| 80 | |
| 81 | /** |
| 82 | * Whether to allow disabled items to receive focus. When `true`, disabled items are |
| 83 | * focusable but not interactive. When `false`, disabled items are skipped during navigation. |
| 84 | */ |
| 85 | readonly softDisabled = input(true, {transform: booleanAttribute}); |
| 86 | |
| 87 | /** Whether the toolbar is disabled. */ |
| 88 | readonly disabled = input(false, {transform: booleanAttribute}); |
| 89 | |
| 90 | /** Whether focus should wrap when navigating. */ |
| 91 | readonly wrap = input(true, {transform: booleanAttribute}); |
| 92 | |
| 93 | /** The values of the selected widgets within the toolbar. */ |
| 94 | readonly value = model<V[]>([]); |
| 95 | |
| 96 | /** The toolbar UIPattern. */ |
| 97 | readonly _pattern: ToolbarPattern<V> = new ToolbarPattern<V>({ |
| 98 | ...this, |
| 99 | items: this._itemPatterns, |
| 100 | activeItem: signal(undefined), |
| 101 | textDirection: this.textDirection, |
| 102 | element: () => this._elementRef.nativeElement, |
| 103 | getItem: e => this._getItem(e), |
| 104 | value: this.value, |
| 105 | }); |
| 106 | |
| 107 | constructor() { |
| 108 | afterRenderEffect({write: () => this._pattern.setDefaultStateEffect()}); |
| 109 | |
| 110 | // Check for any violations after the DOM has been updated. |
| 111 | if (typeof ngDevMode === 'undefined' || ngDevMode) { |
| 112 | afterRenderEffect({ |
| 113 | read: () => { |
| 114 | reportViolations(this._pattern.validate(), this.element); |
| 115 | }, |
| 116 | }); |
| 117 | } |