()
| 137 | readonly activeDescendant: Signal<string | undefined>; |
| 138 | |
| 139 | constructor() { |
| 140 | // Map directives to their patterns for the ListboxPattern |
| 141 | const orderedItemPatterns = computed(() => |
| 142 | this._collection.orderedItems().map(option => option._pattern), |
| 143 | ); |
| 144 | |
| 145 | const inputs = { |
| 146 | ...this, |
| 147 | id: this.id, |
| 148 | items: orderedItemPatterns, |
| 149 | activeItem: signal(undefined), |
| 150 | textDirection: this.textDirection, |
| 151 | element: () => this._elementRef.nativeElement, |
| 152 | }; |
| 153 | |
| 154 | this._pattern = new ListboxPattern<V>(inputs); |
| 155 | |
| 156 | this.activeDescendant = computed(() => this._pattern.activeDescendant()); |
| 157 | |
| 158 | afterNextRender(() => { |
| 159 | this._collection.startObserving(this.element); |
| 160 | }); |
| 161 | |
| 162 | // Check for any violations after the DOM has been updated. |
| 163 | if (typeof ngDevMode === 'undefined' || ngDevMode) { |
| 164 | afterRenderEffect({ |
| 165 | read: () => { |
| 166 | reportViolations(this._pattern.validate(), this.element); |
| 167 | }, |
| 168 | }); |
| 169 | } |
| 170 | |
| 171 | afterRenderEffect({write: () => this._pattern.setDefaultStateEffect()}); |
| 172 | |
| 173 | // Ensure that if the active item is removed from |
| 174 | // the list, the listbox updates it's focus state. |
| 175 | afterRenderEffect({ |
| 176 | write: () => { |
| 177 | const items = inputs.items(); |
| 178 | const activeItem = untracked(() => inputs.activeItem()); |
| 179 | |
| 180 | if (activeItem && !items.some(i => i === activeItem)) { |
| 181 | this._pattern.listBehavior.unfocus(); |
| 182 | this._pattern.setDefaultState(); |
| 183 | } |
| 184 | }, |
| 185 | }); |
| 186 | |
| 187 | // Ensure that the value is always in sync with the available options. |
| 188 | // This needs to be after the render for the value to always be available. |
| 189 | afterRenderEffect({ |
| 190 | write: () => { |
| 191 | const items = inputs.items(); |
| 192 | const value = untracked(() => this.value()); |
| 193 | |
| 194 | if (items && value.some(v => !items.some(i => i.value() === v))) { |
| 195 | this.value.set(value.filter(v => items.some(i => i.value() === v))); |
| 196 | } |
nothing calls this directly
no test coverage detected