Skip to content

Commit 8fd4393

Browse files
committed
feat(docs): username filter and search highlight (#DS-5132)
1 parent 804aa1e commit 8fd4393

5 files changed

Lines changed: 118 additions & 2 deletions

File tree

packages/components-dev/username/module.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { UsernameExamplesModule } from '../../docs-examples/components/username'
99
<username-playground-example />
1010
<username-custom-example />
1111
<username-as-link-example />
12+
<username-search-example />
1213
`,
1314
changeDetection: ChangeDetectionStrategy.OnPush
1415
})

packages/components/username/username.en.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,11 @@ To format the full name, use the `kbqUsernameCustom` pipe with a format string a
2121
The component can be conveniently used inside links. To visually match the link style, set the `inherit` style — this ensures that color and appearance are inherited from the parent element.
2222

2323
<!-- example(username-as-link) -->
24+
25+
### Search and highlight
26+
27+
To filter a list of users by the displayed value, inject `KbqUsernamePipe` as a service and call its `transform` method — it returns the same formatted string that `kbq-username` renders by default.
28+
29+
To highlight the matched substring, use `kbq-username-custom-view` together with the `kbqHighlightBackground` pipe.
30+
31+
<!-- example(username-search) -->

packages/components/username/username.ru.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,11 @@
1717
Компонент удобно использовать внутри ссылок. Чтобы он визуально соответствовал стилю ссылки, установите стиль `inherit` — в этом случае цвет и оформление будут унаследованы от родительского элемента.
1818

1919
<!-- example(username-as-link) -->
20+
21+
### Поиск и подсветка
22+
23+
Чтобы фильтровать список пользователей по отображаемому значению, используйте `KbqUsernamePipe` как сервис. Метод `transform` возвращает ту же строку, которую по умолчанию формирует `kbq-username`.
24+
25+
Для подсветки найденной подстроки используйте `kbq-username-custom-view` вместе с пайпом `kbqHighlightBackground`.
26+
27+
<!-- example(username-search) -->

packages/docs-examples/components/username/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,22 @@ import { UsernameAsLinkExample } from './username-as-link/username-as-link-examp
33
import { UsernameCustomExample } from './username-custom/username-custom-example';
44
import { UsernameOverviewExample } from './username-overview/username-overview-example';
55
import { UsernamePlaygroundExample } from './username-playground/username-playground-example';
6+
import { UsernameSearchExample } from './username-search/username-search-example';
67

7-
export { UsernameAsLinkExample, UsernameCustomExample, UsernameOverviewExample, UsernamePlaygroundExample };
8+
export {
9+
UsernameAsLinkExample,
10+
UsernameCustomExample,
11+
UsernameOverviewExample,
12+
UsernamePlaygroundExample,
13+
UsernameSearchExample
14+
};
815

916
const EXAMPLES = [
1017
UsernameCustomExample,
1118
UsernameOverviewExample,
1219
UsernamePlaygroundExample,
13-
UsernameAsLinkExample
20+
UsernameAsLinkExample,
21+
UsernameSearchExample
1422
];
1523

1624
@NgModule({
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
2+
import { toSignal } from '@angular/core/rxjs-interop';
3+
import { FormControl, ReactiveFormsModule } from '@angular/forms';
4+
import { KbqHighlightBackgroundPipe } from '@koobiq/components/core';
5+
import { KbqFormFieldModule } from '@koobiq/components/form-field';
6+
import { KbqIconModule } from '@koobiq/components/icon';
7+
import { KbqInputModule } from '@koobiq/components/input';
8+
import { KbqUserInfo, KbqUsernameModule, KbqUsernamePipe } from '@koobiq/components/username';
9+
import { startWith } from 'rxjs';
10+
11+
/**
12+
* @title Username search
13+
*/
14+
@Component({
15+
selector: 'username-search-example',
16+
imports: [
17+
ReactiveFormsModule,
18+
KbqFormFieldModule,
19+
KbqInputModule,
20+
KbqUsernameModule,
21+
KbqIconModule,
22+
KbqHighlightBackgroundPipe
23+
],
24+
template: `
25+
<kbq-form-field>
26+
<i kbqPrefix kbq-icon="kbq-magnifying-glass_16"></i>
27+
<input kbqInput type="text" placeholder="Search" autocomplete="off" [formControl]="searchControl" />
28+
<kbq-cleaner />
29+
</kbq-form-field>
30+
31+
<div class="example__users-list">
32+
@for (user of filteredUsers(); track user.login) {
33+
<kbq-username>
34+
<kbq-username-custom-view>
35+
@let fullName = user | kbqUsername;
36+
<span
37+
kbqUsernamePrimary
38+
[innerHTML]="fullName | kbqHighlightBackground: searchControl.value"
39+
></span>
40+
41+
@if (user.login) {
42+
<span
43+
kbqUsernameSecondary
44+
[innerHTML]="user.login | kbqHighlightBackground: searchControl.value"
45+
></span>
46+
}
47+
</kbq-username-custom-view>
48+
</kbq-username>
49+
} @empty {
50+
<span class="kbq-text-normal kbq-second">Nothing found</span>
51+
}
52+
</div>
53+
`,
54+
styles: `
55+
.example__users-list {
56+
display: flex;
57+
flex-direction: column;
58+
gap: var(--kbq-size-s);
59+
}
60+
`,
61+
changeDetection: ChangeDetectionStrategy.OnPush,
62+
host: {
63+
class: 'layout-column layout-gap-m layout-padding-m'
64+
}
65+
})
66+
export class UsernameSearchExample {
67+
private readonly usernamePipe = inject(KbqUsernamePipe);
68+
69+
protected readonly searchControl = new FormControl('');
70+
71+
private readonly searchText = toSignal(this.searchControl.valueChanges.pipe(startWith('')), { initialValue: '' });
72+
73+
protected readonly users: KbqUserInfo[] = [
74+
{ firstName: 'Maxwell', middleName: 'Alan', lastName: 'Root', login: 'mroot', site: 'corp' },
75+
{ firstName: 'Alice', middleName: 'Marie', lastName: 'Stone', login: 'astone' },
76+
{ firstName: 'Robert', lastName: 'Green', login: 'rgreen', site: 'dev' },
77+
{ firstName: 'Elena', middleName: 'Vera', lastName: 'Fox', login: 'efox' }
78+
];
79+
80+
protected readonly filteredUsers = computed(() => {
81+
const query = (this.searchText() ?? '').toLowerCase().trim();
82+
83+
if (!query) return this.users;
84+
85+
return this.users.filter((user) => {
86+
const formatted = this.usernamePipe.transform(user).toLowerCase();
87+
88+
return formatted.includes(query) || (user.login?.toLowerCase().includes(query) ?? false);
89+
});
90+
});
91+
}

0 commit comments

Comments
 (0)