Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<i [kbq-icon]="icon.cssClass"></i>
<span
class="docs-icons-viewer__table-cell-name"
[innerHtml]="icon.name | mcHighlight: searchControl.value"
[innerHtml]="icon.name | kbqHighlightBackground: searchControl.value"
[kbqTooltip]="icon.name"
></span>
</div>
Expand Down
16 changes: 12 additions & 4 deletions packages/components-dev/form-field/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@
kbqTreeNodeToggle
[style.transform]="treeControl.isExpanded(node) ? '' : 'rotate(-90deg)'"
></i>
<span [innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"></span>
<span
[innerHTML]="treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value"
></span>
</kbq-tree-option>
</kbq-tree-selection>

Expand All @@ -109,7 +111,9 @@
kbqTreeNodeToggle
[style.transform]="treeControl.isExpanded(node) ? '' : 'rotate(-90deg)'"
></i>
<span [innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"></span>
<span
[innerHTML]="treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value"
></span>
</kbq-tree-option>
</kbq-tree-selection>

Expand All @@ -136,7 +140,9 @@
kbqTreeNodeToggle
[style.transform]="treeControl.isExpanded(node) ? '' : 'rotate(-90deg)'"
></i>
<span [innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"></span>
<span
[innerHTML]="treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value"
></span>
</kbq-tree-option>
</kbq-tree-selection>

Expand All @@ -163,7 +169,9 @@
kbqTreeNodeToggle
[style.transform]="treeControl.isExpanded(node) ? '' : 'rotate(-90deg)'"
></i>
<span [innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"></span>
<span
[innerHTML]="treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value"
></span>
</kbq-tree-option>
</kbq-tree-selection>

Expand Down
10 changes: 5 additions & 5 deletions packages/components-dev/select/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

<!-- @for (option of filteredOptions | async; track option) {-->
<!-- <kbq-option [value]="option">-->
<!-- <span [innerHTML]="option | mcHighlight: searchCtrl.value"></span>-->
<!-- <span [innerHTML]="option | kbqHighlightBackground: searchCtrl.value"></span>-->
<!-- </kbq-option>-->
<!-- }-->

Expand Down Expand Up @@ -59,7 +59,7 @@

<!-- @for (option of filteredOptions | async; track option) {-->
<!-- <kbq-option [value]="option">-->
<!-- <span [innerHTML]="option | mcHighlight: searchCtrl.value"></span>-->
<!-- <span [innerHTML]="option | kbqHighlightBackground: searchCtrl.value"></span>-->
<!-- </kbq-option>-->
<!-- }-->
<!-- </kbq-select>-->
Expand All @@ -72,7 +72,7 @@
<!-- *cdkVirtualFor="let option of filteredOptions | async; templateCacheSize: 0"-->
<!-- [value]="option"-->
<!-- >-->
<!-- <span [innerHTML]="option | mcHighlight: searchCtrl.value"></span>-->
<!-- <span [innerHTML]="option | kbqHighlightBackground: searchCtrl.value"></span>-->
<!-- </kbq-option>-->
<!-- </cdk-virtual-scroll-viewport>-->

Expand Down Expand Up @@ -140,7 +140,7 @@

<!-- @for (option of filteredOptions | async; track option) {-->
<!-- <kbq-option [value]="option">-->
<!-- <span [innerHTML]="option | mcHighlight: searchCtrl.value"></span>-->
<!-- <span [innerHTML]="option | kbqHighlightBackground: searchCtrl.value"></span>-->
<!-- </kbq-option>-->
<!-- }-->
<!-- </kbq-select>-->
Expand All @@ -166,7 +166,7 @@

<!-- @for (option of filteredMultipleOptions | async; track option) {-->
<!-- <kbq-option [showCheckbox]="false" [value]="option">-->
<!-- <span [innerHTML]="option | mcHighlight: multipleSearchCtrl.value"></span>-->
<!-- <span [innerHTML]="option | kbqHighlightBackground: multipleSearchCtrl.value"></span>-->
<!-- </kbq-option>-->
<!-- }-->
<!-- </kbq-select>-->
Expand Down
46 changes: 34 additions & 12 deletions packages/components-dev/tree-select/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ <h2 class="kbq-subheading">Custom footer</h2>
<kbq-tree-selection [dataSource]="dataSource" [treeControl]="treeControl">
<kbq-tree-option *kbqTreeNodeDef="let node" kbqTreeNodePadding [checkboxThirdState]="true">
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>

Expand All @@ -39,7 +41,9 @@ <h2 class="kbq-subheading">Custom footer</h2>
>
<kbq-tree-node-toggle [node]="node" />
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>
</kbq-tree-selection>
Expand Down Expand Up @@ -79,7 +83,9 @@ <h2 class="kbq-subheading">Default footer</h2>
<kbq-tree-selection [dataSource]="dataSource" [treeControl]="treeControl">
<kbq-tree-option *kbqTreeNodeDef="let node" kbqTreeNodePadding [checkboxThirdState]="true">
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>

Expand All @@ -94,7 +100,9 @@ <h2 class="kbq-subheading">Default footer</h2>
[style.transform]="treeControl.isExpanded(node) ? '' : 'rotate(-90deg)'"
></i>
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>
</kbq-tree-selection>
Expand Down Expand Up @@ -128,7 +136,9 @@ <h2 class="kbq-subheading">Default footer</h2>
<kbq-tree-selection [dataSource]="dataSource" [treeControl]="treeControl">
<kbq-tree-option *kbqTreeNodeDef="let node" kbqTreeNodePadding [checkboxThirdState]="true">
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>

Expand All @@ -143,7 +153,9 @@ <h2 class="kbq-subheading">Default footer</h2>
[style.transform]="treeControl.isExpanded(node) ? '' : 'rotate(-90deg)'"
></i>
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>
</kbq-tree-selection>
Expand Down Expand Up @@ -177,7 +189,9 @@ <h2 class="kbq-subheading">Default footer</h2>
<kbq-tree-selection [dataSource]="dataSource" [treeControl]="treeControl">
<kbq-tree-option *kbqTreeNodeDef="let node" kbqTreeNodePadding [checkboxThirdState]="true">
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>

Expand All @@ -192,7 +206,9 @@ <h2 class="kbq-subheading">Default footer</h2>
[style.transform]="treeControl.isExpanded(node) ? '' : 'rotate(-90deg)'"
></i>
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>
</kbq-tree-selection>
Expand Down Expand Up @@ -230,7 +246,9 @@ <h2 class="kbq-subheading">Default footer with icon button</h2>
<kbq-tree-selection [dataSource]="dataSource" [treeControl]="treeControl">
<kbq-tree-option *kbqTreeNodeDef="let node" kbqTreeNodePadding [checkboxThirdState]="true">
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>

Expand All @@ -245,7 +263,9 @@ <h2 class="kbq-subheading">Default footer with icon button</h2>
[style.transform]="treeControl.isExpanded(node) ? '' : 'rotate(-90deg)'"
></i>
<span
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="
treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>
</kbq-tree-selection>
Expand Down Expand Up @@ -294,7 +314,8 @@ <h2 class="kbq-subheading">Default footer with icon button</h2>
<kbq-tree-option *kbqTreeNodeDef="let node" kbqTreeNodePadding [checkboxThirdState]="true">
<span
[innerHTML]="
treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value
treeControl.getViewValue(node)
| kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>
Expand All @@ -311,7 +332,8 @@ <h2 class="kbq-subheading">Default footer with icon button</h2>
></i>
<span
[innerHTML]="
treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value
treeControl.getViewValue(node)
| kbqHighlightBackground: treeControl.filterValue.value
"
></span>
</kbq-tree-option>
Expand Down
14 changes: 10 additions & 4 deletions packages/components-dev/tree/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@
>
<kbq-tree-option *kbqTreeNodeDef="let node" kbqTreeNodePadding>
<i kbq-icon="kbq-circle-info_16"></i>
<span [innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"></span>
<span
[innerHTML]="treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value"
></span>
</kbq-tree-option>

<kbq-tree-option
Expand All @@ -70,7 +72,9 @@

<kbq-tree-node-toggle [node]="node" />

<span [innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"></span>
<span
[innerHTML]="treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value"
></span>

<kbq-option-action
[kbqDropdownTriggerFor]="dropdown"
Expand All @@ -93,7 +97,7 @@
<i kbq-icon="kbq-circle-info_16"></i>
<span
#kbqTitleText
[innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"
[innerHTML]="treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value"
></span>
</kbq-tree-option>

Expand All @@ -106,7 +110,9 @@

<kbq-tree-node-toggle [node]="node" />

<span [innerHTML]="treeControl.getViewValue(node) | mcHighlight: treeControl.filterValue.value"></span>
<span
[innerHTML]="treeControl.getViewValue(node) | kbqHighlightBackground: treeControl.filterValue.value"
></span>

<kbq-option-action
[kbqDropdownTriggerFor]="dropdown"
Expand Down
7 changes: 6 additions & 1 deletion packages/components/app-switcher/app-switcher.html
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,12 @@
}

@for (app of site.apps; track app) {
<a href="{{ app.link }}" kbq-app-switcher-list-item [app]="app"></a>
<a
href="{{ app.link }}"
kbq-app-switcher-list-item
[app]="app"
[highlightText]="searchControl.getRawValue() ?? ''"
></a>
}
} @empty {
<div class="kbq-app-switcher__empty-search-result">{{ localeData.searchEmptyResult }}</div>
Expand Down
28 changes: 28 additions & 0 deletions packages/components/app-switcher/app-switcher.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,34 @@ describe('KbqAppSwitcher', () => {

expect(searchResult).toBeTruthy();
}));

it('highlights only the matched fragment of the app name in search results', fakeAsync(() => {
trigger.show();
tick();
fixture.detectChanges();

const popup = trigger['instance'] as KbqAppSwitcherComponent;

popup.searchControl.setValue('pp 1');
tick();
fixture.detectChanges();

const marks = overlayContainerElement.querySelectorAll<HTMLElement>(
'.kbq-app-switcher__search-result mark.kbq-highlight-background'
);

expect(marks).toHaveLength(1);
expect(marks[0].textContent).toBe('pp 1');
expect(marks[0].closest('.kbq-app-switcher-list-item__name')!.textContent).toBe('App 1');
}));

it('does not highlight anything while the search query is empty', fakeAsync(() => {
trigger.show();
tick();
fixture.detectChanges();

expect(overlayContainerElement.querySelectorAll('mark.kbq-highlight-background')).toHaveLength(0);
}));
});
});

Expand Down
12 changes: 9 additions & 3 deletions packages/components/app-switcher/kbq-app-switcher-list-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ViewEncapsulation
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { KBQ_TITLE_TEXT_REF } from '@koobiq/components/core';
import { KBQ_TITLE_TEXT_REF, KbqHighlightBackgroundPipe } from '@koobiq/components/core';
import { KbqDropdownItem } from '@koobiq/components/dropdown';
import { KbqIconModule } from '@koobiq/components/icon';
import { KbqAppSwitcherApp } from './app-switcher';
Expand All @@ -19,7 +19,8 @@ import { KbqAppSwitcherApp } from './app-switcher';
selector: '[kbq-app-switcher-list-item]',
imports: [
KbqIconModule,
NgOptimizedImage
NgOptimizedImage,
KbqHighlightBackgroundPipe
],
template: `
@if (app.icon) {
Expand All @@ -31,7 +32,10 @@ import { KbqAppSwitcherApp } from './app-switcher';
}

<div class="kbq-app-switcher-list-item__container">
<div class="kbq-app-switcher-list-item__name">{{ app.name }}</div>
<div
class="kbq-app-switcher-list-item__name"
[innerHTML]="app.name | kbqHighlightBackground: highlightText()"
></div>
@if (app.caption) {
<div class="kbq-app-switcher-list-item__caption">{{ app.caption }}</div>
}
Expand Down Expand Up @@ -65,6 +69,8 @@ export class KbqAppSwitcherListItem extends KbqDropdownItem {
// and migrating would break narrowing currently.
@Input() app: KbqAppSwitcherApp;
readonly toggle = input(false, { transform: booleanAttribute });
/** Search query to highlight within the app name. */
readonly highlightText = input<string>('');
// TODO: Skipped for migration because:
// Your application code writes to the input. This prevents migration.
@Input({ transform: booleanAttribute }) collapsed: boolean = false;
Expand Down
22 changes: 14 additions & 8 deletions packages/components/core/highlight/highlight.en.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
mcHighlight is a pipe for highlighting text matches. Highlighting matches helps users quickly understand why a result is relevant and speeds up navigation through lists. Depending on the context, two styles are used.
Highlighting matches helps users quickly understand why a result is relevant and speeds up navigation through lists. Depending on the context, one of two styles is used.

The pipe takes a string and a search argument, wrapping the found matches in a <mark class="kbq-highlight"> tag.
Koobiq provides two pipes for highlighting text matches — `kbqHighlightBackground` and `mcHighlight`. Both take a string and a search argument, wrapping the found matches in a `<mark>` tag — `kbq-highlight-background` for the background-color style and `kbq-highlight` for the bold style.

#### Bold
#### Background color

Used in selects with search and homogeneous lists (for example, choosing a department or a name). This style is unobtrusive and ideal for quickly scanning familiar data: the user immediately sees that the searched word is in the row but is not distracted from the main choice.
Used in selects and other dropdown pickers with filtering, and to highlight matches in complex content: descriptions, messages, and articles. The solid background remains legible in hover and active states within overlays and makes matches noticeable even in long texts.

<!-- example(highlight-select) -->

#### Background color

Used in search results over complex content — descriptions, messages, articles. Highlighting also draws attention even inside long texts.
Matches in text:

<!-- example(highlight-background) -->

Matches in search results with a complex layout
Matches in search results with a complex layout:

<!-- example(highlight-background-complex) -->

Matches in a table:

<!-- example(highlight-background-table) -->

#### Bold

This style is unobtrusive and ideal for quickly scanning familiar data: the user immediately sees that the searched word is in the row but is not distracted from the main choice.

```html
<span [innerHTML]="item | mcHighlight: searchQuery"></span>
```
Loading