Skip to content

Commit abff73b

Browse files
committed
main - 0ca47b4 feat(aria/combobox): migrate simple-combobox directly into primary entrypoints (#33206)
1 parent 79bd6be commit abff73b

28 files changed

Lines changed: 2324 additions & 9 deletions
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-combobox-container&quot;</span>&gt;</span>
2+
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> #<span class="hljs-attr">origin</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-autocomplete&quot;</span>&gt;</span>
3+
<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-search-icon material-symbols-outlined&quot;</span> <span class="hljs-attr">translate</span>=<span class="hljs-string">&quot;no&quot;</span>&gt;</span>search<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
4+
<span class="hljs-tag">&lt;<span class="hljs-name">input</span>
5+
<span class="hljs-attr">ngCombobox</span>
6+
#<span class="hljs-attr">combobox</span>=<span class="hljs-string">&quot;ngCombobox&quot;</span>
7+
<span class="hljs-attr">aria-label</span>=<span class="hljs-string">&quot;Label dropdown&quot;</span>
8+
<span class="hljs-attr">placeholder</span>=<span class="hljs-string">&quot;Select a country&quot;</span>
9+
[(<span class="hljs-attr">value</span>)]=<span class="hljs-string">&quot;searchString&quot;</span>
10+
[(<span class="hljs-attr">expanded</span>)]=<span class="hljs-string">&quot;popupExpanded&quot;</span>
11+
(<span class="hljs-attr">click</span>)=<span class="hljs-string">&quot;popupExpanded.set(true)&quot;</span>
12+
/&gt;</span>
13+
<span class="hljs-tag">&lt;<span class="hljs-name">button</span>
14+
<span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-clear-button&quot;</span>
15+
<span class="hljs-attr">aria-label</span>=<span class="hljs-string">&quot;Clear&quot;</span>
16+
(<span class="hljs-attr">keydown</span>)=<span class="hljs-string">&quot;onKeydown($event)&quot;</span>
17+
(<span class="hljs-attr">click</span>)=<span class="hljs-string">&quot;clear()&quot;</span>
18+
&gt;</span>
19+
<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">&quot;true&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-clear-icon material-symbols-outlined&quot;</span>&gt;</span>close<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
20+
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
21+
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
22+
23+
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">&quot;polite&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;cdk-visually-hidden&quot;</span>&gt;</span>
24+
{{countries().length === 0 ? &#x27;No results found for &#x27; + query() : &#x27;&#x27;}}
25+
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
26+
27+
<span class="hljs-tag">&lt;<span class="hljs-name">ng-template</span> [<span class="hljs-attr">cdkConnectedOverlay</span>]=<span class="hljs-string">&quot;{origin, usePopover: &#x27;inline&#x27;, matchWidth: true}&quot;</span> [<span class="hljs-attr">cdkConnectedOverlayOpen</span>]=<span class="hljs-string">&quot;popupExpanded()&quot;</span>&gt;</span>
28+
<span class="hljs-tag">&lt;<span class="hljs-name">ng-template</span> <span class="hljs-attr">ngComboboxPopup</span> [<span class="hljs-attr">combobox</span>]=<span class="hljs-string">&quot;combobox&quot;</span>&gt;</span>
29+
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-popup&quot;</span>&gt;</span>
30+
@if (countries().length === 0) {
31+
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-no-results&quot;</span>&gt;</span>No results found<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
32+
}
33+
34+
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ngListbox</span> <span class="hljs-attr">ngComboboxWidget</span> <span class="hljs-attr">focusMode</span>=<span class="hljs-string">&quot;activedescendant&quot;</span> [<span class="hljs-attr">tabindex</span>]=<span class="hljs-string">&quot;-1&quot;</span> [(<span class="hljs-attr">value</span>)]=<span class="hljs-string">&quot;selectedOption&quot;</span>
35+
(<span class="hljs-attr">click</span>)=<span class="hljs-string">&quot;onCommit()&quot;</span> (<span class="hljs-attr">keydown.enter</span>)=<span class="hljs-string">&quot;onCommit()&quot;</span>&gt;</span>
36+
@for (country of countries(); track country) {
37+
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ngOption</span> [<span class="hljs-attr">value</span>]=<span class="hljs-string">&quot;country&quot;</span> [<span class="hljs-attr">label</span>]=<span class="hljs-string">&quot;country&quot;</span> [<span class="hljs-attr">disabled</span>]=<span class="hljs-string">&quot;country === &#x27;Brazil&#x27;&quot;</span>&gt;</span>
38+
<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-option-label&quot;</span>&gt;</span>{{country}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
39+
<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;example-check-icon material-symbols-outlined&quot;</span> <span class="hljs-attr">translate</span>=<span class="hljs-string">&quot;no&quot;</span>&gt;</span>check<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
40+
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
41+
}
42+
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
43+
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
44+
<span class="hljs-tag">&lt;/<span class="hljs-name">ng-template</span>&gt;</span>
45+
<span class="hljs-tag">&lt;/<span class="hljs-name">ng-template</span>&gt;</span>
46+
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<span class="hljs-comment">/**
2+
* <span class="hljs-doctag">@license</span>
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/</span>
8+
9+
<span class="hljs-keyword">import</span> {<span class="hljs-title class_">Combobox</span>, <span class="hljs-title class_">ComboboxPopup</span>, <span class="hljs-title class_">ComboboxWidget</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;@angular/aria/combobox&#x27;</span>;
10+
<span class="hljs-keyword">import</span> {<span class="hljs-title class_">Listbox</span>, <span class="hljs-title class_">Option</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;@angular/aria/listbox&#x27;</span>;
11+
<span class="hljs-keyword">import</span> {
12+
afterRenderEffect,
13+
<span class="hljs-title class_">ChangeDetectionStrategy</span>,
14+
<span class="hljs-title class_">Component</span>,
15+
computed,
16+
signal,
17+
viewChild,
18+
} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;@angular/core&#x27;</span>;
19+
<span class="hljs-keyword">import</span> {<span class="hljs-variable constant_">COUNTRIES</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;../countries&#x27;</span>;
20+
<span class="hljs-keyword">import</span> {<span class="hljs-title class_">OverlayModule</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;@angular/cdk/overlay&#x27;</span>;
21+
<span class="hljs-keyword">import</span> {<span class="hljs-title class_">FormsModule</span>} <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;@angular/forms&#x27;</span>;
22+
23+
<span class="hljs-comment">/** <span class="hljs-doctag">@title</span> Autocomplete with auto-select filtering. */</span>
24+
<span class="hljs-meta">@Component</span>({
25+
<span class="hljs-attr">selector</span>: <span class="hljs-string">&#x27;autocomplete-auto-select-example&#x27;</span>,
26+
<span class="hljs-attr">templateUrl</span>: <span class="hljs-string">&#x27;autocomplete-auto-select-example.html&#x27;</span>,
27+
<span class="hljs-attr">styleUrl</span>: <span class="hljs-string">&#x27;../autocomplete.css&#x27;</span>,
28+
<span class="hljs-attr">imports</span>: [<span class="hljs-title class_">Combobox</span>, <span class="hljs-title class_">ComboboxPopup</span>, <span class="hljs-title class_">ComboboxWidget</span>, <span class="hljs-title class_">Listbox</span>, <span class="hljs-title class_">Option</span>, <span class="hljs-title class_">OverlayModule</span>, <span class="hljs-title class_">FormsModule</span>],
29+
<span class="hljs-attr">changeDetection</span>: <span class="hljs-title class_">ChangeDetectionStrategy</span>.<span class="hljs-property">OnPush</span>,
30+
})
31+
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">AutocompleteAutoSelectExample</span> {
32+
<span class="hljs-comment">/** The selected value of the combobox. */</span>
33+
<span class="hljs-keyword">readonly</span> listbox = <span class="hljs-title function_">viewChild</span>(<span class="hljs-title class_">Listbox</span>);
34+
<span class="hljs-keyword">readonly</span> combobox = <span class="hljs-title function_">viewChild</span>(<span class="hljs-title class_">Combobox</span>);
35+
36+
popupExpanded = <span class="hljs-title function_">signal</span>(<span class="hljs-literal">false</span>);
37+
searchString = <span class="hljs-title function_">signal</span>(<span class="hljs-string">&#x27;&#x27;</span>);
38+
selectedOption = signal&lt;<span class="hljs-built_in">string</span>[]&gt;([]);
39+
40+
<span class="hljs-comment">/** The query string used to filter the list of countries. */</span>
41+
query = <span class="hljs-title function_">computed</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">searchString</span>());
42+
43+
<span class="hljs-comment">/** The list of countries filtered by the query. */</span>
44+
countries = <span class="hljs-title function_">computed</span>(<span class="hljs-function">() =&gt;</span>
45+
<span class="hljs-variable constant_">COUNTRIES</span>.<span class="hljs-title function_">filter</span>(<span class="hljs-function"><span class="hljs-params">country</span> =&gt;</span> country.<span class="hljs-title function_">toLowerCase</span>().<span class="hljs-title function_">startsWith</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">query</span>().<span class="hljs-title function_">toLowerCase</span>())),
46+
);
47+
48+
<span class="hljs-title function_">constructor</span>(<span class="hljs-params"></span>) {
49+
<span class="hljs-title function_">afterRenderEffect</span>(<span class="hljs-function">() =&gt;</span> {
50+
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">listbox</span>()?.<span class="hljs-title function_">scrollActiveItemIntoView</span>();
51+
});
52+
}
53+
54+
<span class="hljs-comment">/** Clears the query and the listbox value. */</span>
55+
<span class="hljs-title function_">clear</span>(): <span class="hljs-built_in">void</span> {
56+
<span class="hljs-variable language_">this</span>.<span class="hljs-property">searchString</span>.<span class="hljs-title function_">set</span>(<span class="hljs-string">&#x27;&#x27;</span>);
57+
<span class="hljs-variable language_">this</span>.<span class="hljs-property">selectedOption</span>.<span class="hljs-title function_">set</span>([]);
58+
}
59+
60+
<span class="hljs-title function_">onCommit</span>(<span class="hljs-params"></span>) {
61+
<span class="hljs-keyword">const</span> selectedOption = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">selectedOption</span>();
62+
<span class="hljs-keyword">if</span> (selectedOption.<span class="hljs-property">length</span> &gt; <span class="hljs-number">0</span>) {
63+
<span class="hljs-variable language_">this</span>.<span class="hljs-property">searchString</span>.<span class="hljs-title function_">set</span>(selectedOption[<span class="hljs-number">0</span>]);
64+
}
65+
<span class="hljs-variable language_">this</span>.<span class="hljs-property">popupExpanded</span>.<span class="hljs-title function_">set</span>(<span class="hljs-literal">false</span>);
66+
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">combobox</span>()?.<span class="hljs-property">element</span>.<span class="hljs-title function_">focus</span>();
67+
}
68+
69+
<span class="hljs-comment">/** Handles keydown events on the clear button. */</span>
70+
<span class="hljs-title function_">onKeydown</span>(<span class="hljs-attr">event</span>: <span class="hljs-title class_">KeyboardEvent</span>): <span class="hljs-built_in">void</span> {
71+
<span class="hljs-keyword">if</span> (event.<span class="hljs-property">key</span> === <span class="hljs-string">&#x27;Enter&#x27;</span>) {
72+
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">clear</span>();
73+
<span class="hljs-variable language_">this</span>.<span class="hljs-property">popupExpanded</span>.<span class="hljs-title function_">set</span>(<span class="hljs-literal">false</span>);
74+
event.<span class="hljs-title function_">stopPropagation</span>();
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)