Skip to content

Commit 1f6e59e

Browse files
committed
docs(cdk-experimental/combobox): combobox tree examples
1 parent 00261a9 commit 1f6e59e

File tree

12 files changed

+508
-4
lines changed

12 files changed

+508
-4
lines changed

src/components-examples/cdk-experimental/combobox/cdk-combobox-examples.css

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@
8080
visibility: visible;
8181
}
8282

83-
.example-option[inert] {
84-
height: 0;
85-
padding: 0 1rem;
83+
.example-option[inert],
84+
.example-tree-item[inert] {
85+
display: none;
8686
}
8787

8888
.example-combobox-container:focus-within .cdk-active {
@@ -101,3 +101,49 @@
101101
);
102102
color: var(--mat-sys-primary);
103103
}
104+
105+
.example-tree {
106+
padding: 10px;
107+
overflow-x: scroll;
108+
}
109+
110+
.example-tree-item {
111+
cursor: pointer;
112+
list-style: none;
113+
text-decoration: none;
114+
display: flex;
115+
align-items: center;
116+
gap: 1rem;
117+
padding: 0.3rem 1rem;
118+
}
119+
120+
li[aria-expanded='false'] + ul[role='group'] {
121+
display: none;
122+
}
123+
124+
li[inert] + ul[role='group'] {
125+
padding-inline-start: 0;
126+
}
127+
128+
.example-icon {
129+
margin: 0;
130+
width: 24px;
131+
}
132+
133+
.example-parent-icon {
134+
transition: transform 0.2s ease;
135+
}
136+
137+
.example-tree-item[aria-expanded='true'] .example-parent-icon {
138+
transform: rotate(90deg);
139+
}
140+
141+
.example-selected-icon {
142+
visibility: hidden;
143+
margin-left: auto;
144+
}
145+
146+
.example-tree-item[aria-current] .example-selected-icon,
147+
.example-tree-item[aria-selected='true'] .example-selected-icon {
148+
visibility: visible;
149+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<div #combobox="cdkCombobox" cdkCombobox class="example-combobox-container" filterMode="auto-select">
2+
<div class="example-combobox-input-container">
3+
<span class="material-symbols-outlined example-icon example-search-icon">search</span>
4+
<input cdkComboboxInput class="example-combobox-input" placeholder="Search..." />
5+
</div>
6+
7+
<div popover="manual" #popover class="example-popover">
8+
<ng-template cdkComboboxPopupContent>
9+
<ul cdkTree #tree="cdkTree" class="example-tree">
10+
<ng-template
11+
[ngTemplateOutlet]="treeNodes"
12+
[ngTemplateOutletContext]="{nodes: nodes, parent: tree}"
13+
/>
14+
</ul>
15+
</ng-template>
16+
</div>
17+
</div>
18+
19+
<ng-template #treeNodes let-nodes="nodes" let-parent="parent">
20+
@for (node of nodes; track node.name) {
21+
<li
22+
cdkTreeItem
23+
[parent]="parent"
24+
[value]="node.name"
25+
[label]="node.name"
26+
[disabled]="node.disabled"
27+
#treeItem="cdkTreeItem"
28+
class="example-tree-item example-selectable example-stateful"
29+
>
30+
<span
31+
aria-hidden="true"
32+
class="material-symbols-outlined example-parent-icon example-icon"
33+
>{{node.children ? 'chevron_right' : ''}}</span
34+
>
35+
{{ node.name }}
36+
<span aria-hidden="true" class="material-symbols-outlined example-selected-icon example-icon"
37+
>check</span
38+
>
39+
</li>
40+
41+
@if (node.children) {
42+
<ul cdkTreeItemGroup [ownedBy]="treeItem" #group="cdkTreeItemGroup">
43+
<ng-template cdkTreeItemGroupContent>
44+
<ng-template
45+
[ngTemplateOutlet]="treeNodes"
46+
[ngTemplateOutletContext]="{nodes: node.children, parent: group}"
47+
/>
48+
</ng-template>
49+
</ul>
50+
}
51+
}
52+
</ng-template>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* @license
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+
*/
8+
9+
import {
10+
CdkCombobox,
11+
CdkComboboxInput,
12+
CdkComboboxPopup,
13+
CdkComboboxPopupContent,
14+
} from '@angular/cdk-experimental/combobox';
15+
import {
16+
CdkTree,
17+
CdkTreeItem,
18+
CdkTreeItemGroup,
19+
CdkTreeItemGroupContent,
20+
} from '@angular/cdk-experimental/tree';
21+
import {
22+
afterRenderEffect,
23+
ChangeDetectionStrategy,
24+
Component,
25+
ElementRef,
26+
viewChild,
27+
} from '@angular/core';
28+
import {TREE_DATA, FoodNode} from '../data';
29+
import {NgTemplateOutlet} from '@angular/common';
30+
31+
/** @title Combobox with tree popup and auto-select filtering. */
32+
@Component({
33+
selector: 'cdk-combobox-tree-auto-select-example',
34+
templateUrl: 'cdk-combobox-tree-auto-select-example.html',
35+
styleUrl: '../cdk-combobox-examples.css',
36+
imports: [
37+
CdkCombobox,
38+
CdkComboboxInput,
39+
CdkComboboxPopup,
40+
CdkComboboxPopupContent,
41+
CdkTree,
42+
CdkTreeItem,
43+
CdkTreeItemGroup,
44+
CdkTreeItemGroupContent,
45+
NgTemplateOutlet,
46+
],
47+
changeDetection: ChangeDetectionStrategy.OnPush,
48+
})
49+
export class CdkComboboxTreeAutoSelectExample {
50+
popover = viewChild<ElementRef>('popover');
51+
tree = viewChild<CdkTree<FoodNode>>(CdkTree);
52+
combobox = viewChild<CdkCombobox<FoodNode>>(CdkCombobox);
53+
54+
nodes = TREE_DATA;
55+
56+
constructor() {
57+
afterRenderEffect(() => {
58+
const popover = this.popover()!;
59+
const combobox = this.combobox()!;
60+
combobox.pattern.expanded() ? this.showPopover() : popover.nativeElement.hidePopover();
61+
62+
// TODO(wagnermaciel): Make this easier for developers to do.
63+
this.tree()?.pattern.inputs.activeItem()?.element().scrollIntoView({block: 'nearest'});
64+
});
65+
}
66+
67+
showPopover() {
68+
const popover = this.popover()!;
69+
const combobox = this.combobox()!;
70+
71+
const comboboxRect = combobox.pattern.inputs.inputEl()?.getBoundingClientRect();
72+
const popoverEl = popover.nativeElement;
73+
74+
if (comboboxRect) {
75+
popoverEl.style.width = `${comboboxRect.width}px`;
76+
popoverEl.style.top = `${comboboxRect.bottom}px`;
77+
popoverEl.style.left = `${comboboxRect.left - 1}px`;
78+
}
79+
80+
popover.nativeElement.showPopover();
81+
}
82+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<div #combobox="cdkCombobox" cdkCombobox class="example-combobox-container" filterMode="highlight">
2+
<div class="example-combobox-input-container">
3+
<span class="material-symbols-outlined example-icon example-search-icon">search</span>
4+
<input cdkComboboxInput class="example-combobox-input" placeholder="Search..." />
5+
</div>
6+
7+
<div popover="manual" #popover class="example-popover">
8+
<ng-template cdkComboboxPopupContent>
9+
<ul cdkTree #tree="cdkTree" class="example-tree">
10+
<ng-template
11+
[ngTemplateOutlet]="treeNodes"
12+
[ngTemplateOutletContext]="{nodes: nodes, parent: tree}"
13+
/>
14+
</ul>
15+
</ng-template>
16+
</div>
17+
</div>
18+
19+
<ng-template #treeNodes let-nodes="nodes" let-parent="parent">
20+
@for (node of nodes; track node.name) {
21+
<li
22+
cdkTreeItem
23+
[parent]="parent"
24+
[value]="node.name"
25+
[label]="node.name"
26+
[disabled]="node.disabled"
27+
#treeItem="cdkTreeItem"
28+
class="example-tree-item example-selectable example-stateful"
29+
>
30+
<span
31+
aria-hidden="true"
32+
class="material-symbols-outlined example-parent-icon example-icon"
33+
>{{node.children ? 'chevron_right' : ''}}</span
34+
>
35+
{{ node.name }}
36+
<span aria-hidden="true" class="material-symbols-outlined example-selected-icon example-icon"
37+
>check</span
38+
>
39+
</li>
40+
41+
@if (node.children) {
42+
<ul cdkTreeItemGroup [ownedBy]="treeItem" #group="cdkTreeItemGroup">
43+
<ng-template cdkTreeItemGroupContent>
44+
<ng-template
45+
[ngTemplateOutlet]="treeNodes"
46+
[ngTemplateOutletContext]="{nodes: node.children, parent: group}"
47+
/>
48+
</ng-template>
49+
</ul>
50+
}
51+
}
52+
</ng-template>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* @license
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+
*/
8+
9+
import {
10+
CdkCombobox,
11+
CdkComboboxInput,
12+
CdkComboboxPopup,
13+
CdkComboboxPopupContent,
14+
} from '@angular/cdk-experimental/combobox';
15+
import {
16+
CdkTree,
17+
CdkTreeItem,
18+
CdkTreeItemGroup,
19+
CdkTreeItemGroupContent,
20+
} from '@angular/cdk-experimental/tree';
21+
import {
22+
afterRenderEffect,
23+
ChangeDetectionStrategy,
24+
Component,
25+
ElementRef,
26+
viewChild,
27+
} from '@angular/core';
28+
import {TREE_DATA, FoodNode} from '../data';
29+
import {NgTemplateOutlet} from '@angular/common';
30+
31+
/** @title Combobox with tree popup and highlight filtering. */
32+
@Component({
33+
selector: 'cdk-combobox-tree-highlight-example',
34+
templateUrl: 'cdk-combobox-tree-highlight-example.html',
35+
styleUrl: '../cdk-combobox-examples.css',
36+
imports: [
37+
CdkCombobox,
38+
CdkComboboxInput,
39+
CdkComboboxPopup,
40+
CdkComboboxPopupContent,
41+
CdkTree,
42+
CdkTreeItem,
43+
CdkTreeItemGroup,
44+
CdkTreeItemGroupContent,
45+
NgTemplateOutlet,
46+
],
47+
changeDetection: ChangeDetectionStrategy.OnPush,
48+
})
49+
export class CdkComboboxTreeHighlightExample {
50+
popover = viewChild<ElementRef>('popover');
51+
tree = viewChild<CdkTree<FoodNode>>(CdkTree);
52+
combobox = viewChild<CdkCombobox<FoodNode>>(CdkCombobox);
53+
54+
nodes = TREE_DATA;
55+
56+
constructor() {
57+
afterRenderEffect(() => {
58+
const popover = this.popover()!;
59+
const combobox = this.combobox()!;
60+
combobox.pattern.expanded() ? this.showPopover() : popover.nativeElement.hidePopover();
61+
62+
// TODO(wagnermaciel): Make this easier for developers to do.
63+
this.tree()?.pattern.inputs.activeItem()?.element().scrollIntoView({block: 'nearest'});
64+
});
65+
}
66+
67+
showPopover() {
68+
const popover = this.popover()!;
69+
const combobox = this.combobox()!;
70+
71+
const comboboxRect = combobox.pattern.inputs.inputEl()?.getBoundingClientRect();
72+
const popoverEl = popover.nativeElement;
73+
74+
if (comboboxRect) {
75+
popoverEl.style.width = `${comboboxRect.width}px`;
76+
popoverEl.style.top = `${comboboxRect.bottom}px`;
77+
popoverEl.style.left = `${comboboxRect.left - 1}px`;
78+
}
79+
80+
popover.nativeElement.showPopover();
81+
}
82+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<div #combobox="cdkCombobox" cdkCombobox class="example-combobox-container" filterMode="manual">
2+
<div class="example-combobox-input-container">
3+
<span class="material-symbols-outlined example-icon example-search-icon">search</span>
4+
<input cdkComboboxInput class="example-combobox-input" placeholder="Search..." />
5+
</div>
6+
7+
<div popover="manual" #popover class="example-popover">
8+
<ng-template cdkComboboxPopupContent>
9+
<ul cdkTree #tree="cdkTree" class="example-tree">
10+
<ng-template
11+
[ngTemplateOutlet]="treeNodes"
12+
[ngTemplateOutletContext]="{nodes: nodes, parent: tree}"
13+
/>
14+
</ul>
15+
</ng-template>
16+
</div>
17+
</div>
18+
19+
<ng-template #treeNodes let-nodes="nodes" let-parent="parent">
20+
@for (node of nodes; track node.name) {
21+
<li
22+
cdkTreeItem
23+
[parent]="parent"
24+
[value]="node.name"
25+
[label]="node.name"
26+
[disabled]="node.disabled"
27+
#treeItem="cdkTreeItem"
28+
class="example-tree-item example-selectable example-stateful"
29+
>
30+
<span
31+
aria-hidden="true"
32+
class="material-symbols-outlined example-parent-icon example-icon"
33+
>{{node.children ? 'chevron_right' : ''}}</span
34+
>
35+
{{ node.name }}
36+
<span aria-hidden="true" class="material-symbols-outlined example-selected-icon example-icon"
37+
>check</span
38+
>
39+
</li>
40+
41+
@if (node.children) {
42+
<ul cdkTreeItemGroup [ownedBy]="treeItem" #group="cdkTreeItemGroup">
43+
<ng-template cdkTreeItemGroupContent>
44+
<ng-template
45+
[ngTemplateOutlet]="treeNodes"
46+
[ngTemplateOutletContext]="{nodes: node.children, parent: group}"
47+
/>
48+
</ng-template>
49+
</ul>
50+
}
51+
}
52+
</ng-template>

0 commit comments

Comments
 (0)