Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/components-dev/username/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { UsernameExamplesModule } from '../../docs-examples/components/username'
<username-playground-example />
<username-custom-example />
<username-as-link-example />
<username-search-example />
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
Expand Down
8 changes: 8 additions & 0 deletions packages/components/username/username.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@ To format the full name, use the `kbqUsernameCustom` pipe with a format string a
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.

<!-- example(username-as-link) -->

### Search and highlight

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.

To highlight the matched substring, use `kbq-username-custom-view` together with the `kbqHighlightBackground` pipe.

<!-- example(username-search) -->
8 changes: 8 additions & 0 deletions packages/components/username/username.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@
Компонент удобно использовать внутри ссылок. Чтобы он визуально соответствовал стилю ссылки, установите стиль `inherit` — в этом случае цвет и оформление будут унаследованы от родительского элемента.

<!-- example(username-as-link) -->

### Поиск и подсветка

Чтобы фильтровать список пользователей по отображаемому значению, используйте `KbqUsernamePipe` как сервис. Метод `transform` возвращает ту же строку, которую по умолчанию формирует `kbq-username`.

Для подсветки найденной подстроки используйте `kbq-username-custom-view` вместе с пайпом `kbqHighlightBackground`.

<!-- example(username-search) -->
12 changes: 10 additions & 2 deletions packages/docs-examples/components/username/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,22 @@ import { UsernameAsLinkExample } from './username-as-link/username-as-link-examp
import { UsernameCustomExample } from './username-custom/username-custom-example';
import { UsernameOverviewExample } from './username-overview/username-overview-example';
import { UsernamePlaygroundExample } from './username-playground/username-playground-example';
import { UsernameSearchExample } from './username-search/username-search-example';

export { UsernameAsLinkExample, UsernameCustomExample, UsernameOverviewExample, UsernamePlaygroundExample };
export {
UsernameAsLinkExample,
UsernameCustomExample,
UsernameOverviewExample,
UsernamePlaygroundExample,
UsernameSearchExample
};

const EXAMPLES = [
UsernameCustomExample,
UsernameOverviewExample,
UsernamePlaygroundExample,
UsernameAsLinkExample
UsernameAsLinkExample,
UsernameSearchExample
];

@NgModule({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { KbqHighlightBackgroundPipe } from '@koobiq/components/core';
import { KbqFormFieldModule } from '@koobiq/components/form-field';
import { KbqIconModule } from '@koobiq/components/icon';
import { KbqInputModule } from '@koobiq/components/input';
import { KbqUserInfo, KbqUsernameModule, KbqUsernamePipe } from '@koobiq/components/username';
import { startWith } from 'rxjs';

/**
* @title Username search
*/
@Component({
selector: 'username-search-example',
imports: [
ReactiveFormsModule,
KbqFormFieldModule,
KbqInputModule,
KbqUsernameModule,
KbqIconModule,
KbqHighlightBackgroundPipe
],
template: `
<kbq-form-field>
<i kbqPrefix kbq-icon="kbq-magnifying-glass_16"></i>
<input kbqInput type="text" placeholder="Search" autocomplete="off" [formControl]="searchControl" />
<kbq-cleaner />
</kbq-form-field>

<div class="example__users-list">
@for (user of filteredUsers(); track user) {
<kbq-username>
<kbq-username-custom-view>
@let fullName = user | kbqUsername;
<span
kbqUsernamePrimary
[innerHTML]="fullName | kbqHighlightBackground: searchControl.value.trim()"
></span>

@if (user.login) {
<span
kbqUsernameSecondary
[innerHTML]="user.login | kbqHighlightBackground: searchControl.value.trim()"
></span>
}
</kbq-username-custom-view>
</kbq-username>
} @empty {
<span class="kbq-text-normal kbq-second">Nothing found</span>
}
</div>
`,
styles: `
.example__users-list {
display: flex;
flex-direction: column;
gap: var(--kbq-size-s);
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
class: 'layout-column layout-gap-m layout-padding-m'
}
})
export class UsernameSearchExample {
private readonly usernamePipe = inject(KbqUsernamePipe);

protected readonly searchControl = new FormControl('', { nonNullable: true });

private readonly searchText = toSignal(this.searchControl.valueChanges.pipe(startWith('')), { initialValue: '' });

protected readonly users: KbqUserInfo[] = [
{ firstName: 'Maxwell', middleName: 'Alan', lastName: 'Root', login: 'mroot', site: 'corp' },
{ firstName: 'Alice', middleName: 'Marie', lastName: 'Stone', login: 'astone' },
{ firstName: 'Robert', lastName: 'Green', login: 'rgreen', site: 'dev' },
{ firstName: 'Elena', middleName: 'Vera', lastName: 'Fox', login: 'efox' }
];

protected readonly filteredUsers = computed(() => {
const query = (this.searchText() ?? '').toLowerCase().trim();

if (!query) return this.users;

return this.users.filter((user) => {
const formatted = this.usernamePipe.transform(user).toLowerCase();

return formatted.includes(query) || (user.login?.toLowerCase().includes(query) ?? false);
});
});
}
Loading