Skip to content

Commit

Permalink
feat(kit): fix pr comments: add tuiToRegexp pipe, optimize highlights…
Browse files Browse the repository at this point in the history
… logic, fix intersected ranges
  • Loading branch information
MillerSvt committed Nov 8, 2023
1 parent 2254429 commit 1c507d0
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 42 deletions.
4 changes: 3 additions & 1 deletion projects/cdk/utils/miscellaneous/to-array.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export function tuiToArray<T>(value: T | readonly T[]): readonly T[] {
import {TuiArrayOrValue} from '@taiga-ui/cdk/types';

export function tuiToArray<T>(value: TuiArrayOrValue<T>): readonly T[] {
return Array.isArray(value) ? value : [value];
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<table
class="tui-space_top-4"
[tuiHighlight]="search"
[tuiHighlight]="search | tuiToRegexp"
[tuiHighlightColor]="'#228B22'"
[tuiHighlightMultiOccurrences]="true"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ export class TuiHighlightExample4 {
['Sir Robin', 'The Not-Quite-So-Brave-As-Sir-Lancelot', 'Killed'],
];

readonly search = ['Sir', 'Arrested'];
/* cspell:disable-next-line */
readonly search = ['Sir', 'Arrested', 'killed'];
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {FormsModule} from '@angular/forms';
import {RouterModule} from '@angular/router';
import {TuiAddonDocModule, tuiGenerateRoutes} from '@taiga-ui/addon-doc';
import {TuiTextfieldControllerModule} from '@taiga-ui/core';
import {TuiHighlightModule, TuiInputModule} from '@taiga-ui/kit';
import {TuiHighlightModule, TuiInputModule, TuiToRegexpModule} from '@taiga-ui/kit';

import {TuiHighlightExample1} from './examples/1';
import {TuiHighlightExample2} from './examples/2';
Expand All @@ -21,6 +21,7 @@ import {ExampleTuiHighlightComponent} from './highlight.component';
TuiAddonDocModule,
RouterModule.forChild(tuiGenerateRoutes(ExampleTuiHighlightComponent)),
TuiTextfieldControllerModule,
TuiToRegexpModule,
],
declarations: [
ExampleTuiHighlightComponent,
Expand Down
85 changes: 53 additions & 32 deletions projects/kit/directives/highlight/highlight.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import {
TuiArrayOrValue,
TuiDestroyService,
tuiIsNumber,
tuiIsString,
TuiResizeService,
tuiToArray,
} from '@taiga-ui/cdk';
import {TuiToRegexpPipe} from '@taiga-ui/kit/pipes';
import {Observable, Subject} from 'rxjs';
import {mergeAll, switchMap, takeUntil} from 'rxjs/operators';

Expand All @@ -36,7 +36,7 @@ interface TuiHighlightOccurrence {
'[style.position]': '"relative"',
'[style.zIndex]': '0',
},
providers: [TuiDestroyService, TuiResizeService],
providers: [TuiDestroyService, TuiResizeService, TuiToRegexpPipe],
})
export class TuiHighlightDirective implements OnChanges {
private readonly treeWalker = this.doc.createTreeWalker(
Expand All @@ -51,8 +51,7 @@ export class TuiHighlightDirective implements OnChanges {

private readonly cf: ComponentFactory<TuiHighlightComponent>;

@Input()
tuiHighlight: TuiArrayOrValue<RegExp | string> = '';
private _tuiHighlight: readonly RegExp[] = [];

/**
* @deprecated Use --tui-highlight-color instead. Remove in 4.0.
Expand All @@ -64,16 +63,14 @@ export class TuiHighlightDirective implements OnChanges {
@Input()
tuiHighlightMultiOccurrences = false;

@Input()
tuiHighlightCaseSensitive = false;

constructor(
@Inject(DOCUMENT) private readonly doc: Document,
@Inject(ElementRef) private readonly el: ElementRef<HTMLElement>,
@Inject(TuiResizeService) resize$: Observable<unknown>,
@Self() @Inject(TuiDestroyService) destroy$: Observable<void>,
@Inject(ViewContainerRef) private readonly vcr: ViewContainerRef,
@Inject(ComponentFactoryResolver) cfr: ComponentFactoryResolver,
@Inject(TuiToRegexpPipe) private readonly toRegexpPipe: TuiToRegexpPipe,
) {
resize$.subscribe(() => {
this.updateHighlights();
Expand All @@ -89,6 +86,26 @@ export class TuiHighlightDirective implements OnChanges {
this.cf = cfr.resolveComponentFactory(TuiHighlightComponent);
}

get tuiHighlight(): TuiArrayOrValue<RegExp | string> {
return this._tuiHighlight;
}

@Input()
set tuiHighlight(value: TuiArrayOrValue<RegExp | string>) {
this._tuiHighlight = tuiToArray(value).map(item => {
if (item instanceof RegExp) {
// Only global regexp's can be used in String.prototype.mathAll method
if (!item.global) {
return new RegExp(item.source, `${item.flags}g`);
}

return item;
}

return this.toRegexpPipe.transform(item, 'gi');
});
}

get match(): boolean {
const [occurrence] = this.getOccurrences(this.el.nativeElement.textContent);

Expand Down Expand Up @@ -141,35 +158,39 @@ export class TuiHighlightDirective implements OnChanges {
}

private *getOccurrences(source: string | null): Generator<TuiHighlightOccurrence> {
if (!source || !this.tuiHighlight) {
if (!source || !this._tuiHighlight.length) {
return;
}

for (const item of tuiToArray(this.tuiHighlight)) {
if (tuiIsString(item)) {
const itemValue = this.tuiHighlightCaseSensitive
? item
: item.toLowerCase();
const sourceValue = this.tuiHighlightCaseSensitive
? source
: source.toLowerCase();

for (
let index = sourceValue.indexOf(itemValue);
index >= 0;
index = sourceValue.indexOf(itemValue, index + 1)
) {
yield {
index,
length: itemValue.length,
};
}
} else {
for (const match of source.matchAll(item)) {
if (tuiIsNumber(match.index) && match.length) {
const range: boolean[] = [];

for (const item of this._tuiHighlight) {
for (const match of source.matchAll(item)) {
if (tuiIsNumber(match.index) && match[0].length) {
let length = 0;
let index = match.index;

for (let i = match.index; i < match.index + match[0].length; i++) {
if (range[i]) {
if (length > 0) {
yield {
index,
length,
};
}

index = i + 1;
length = 0;
} else {
range[i] = true;
length++;
}
}

if (length > 0) {
yield {
index: match.index,
length: match[0].length,
index,
length,
};
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Component} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {TuiHighlightModule} from '@taiga-ui/kit';
import {TuiHighlightModule, TuiToRegexpModule} from '@taiga-ui/kit';
import {configureTestSuite} from '@taiga-ui/testing';

describe(`TuiHighlight directive`, () => {
Expand Down Expand Up @@ -111,15 +111,13 @@ describe(`TuiHighlight directive`, () => {
template: `
<div
id="f"
tuiHighlight="ica"
[tuiHighlightCaseSensitive]="true"
[tuiHighlight]="'ica' | tuiToRegexp"
>
HAPICA
</div>
<div
id="s"
tuiHighlight="ICA"
[tuiHighlightCaseSensitive]="true"
[tuiHighlight]="'ICA' | tuiToRegexp"
>
HAPICA
</div>
Expand All @@ -129,7 +127,7 @@ describe(`TuiHighlight directive`, () => {

configureTestSuite(() => {
TestBed.configureTestingModule({
imports: [TuiHighlightModule],
imports: [TuiHighlightModule, TuiToRegexpModule],
declarations: [TestComponent],
});
});
Expand Down
1 change: 1 addition & 0 deletions projects/kit/pipes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from '@taiga-ui/kit/pipes/sort-countries';
export * from '@taiga-ui/kit/pipes/stringify';
export * from '@taiga-ui/kit/pipes/stringify-content';
export * from '@taiga-ui/kit/pipes/to-country-code';
export * from '@taiga-ui/kit/pipes/to-regexp';
export * from '@taiga-ui/kit/pipes/to-year';
2 changes: 2 additions & 0 deletions projects/kit/pipes/to-regexp/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './to-regexp.module';
export * from './to-regexp.pipe';
5 changes: 5 additions & 0 deletions projects/kit/pipes/to-regexp/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"lib": {
"entryFile": "index.ts"
}
}
9 changes: 9 additions & 0 deletions projects/kit/pipes/to-regexp/to-regexp.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {NgModule} from '@angular/core';

import {TuiToRegexpPipe} from './to-regexp.pipe';

@NgModule({
declarations: [TuiToRegexpPipe],
exports: [TuiToRegexpPipe],
})
export class TuiToRegexpModule {}
35 changes: 35 additions & 0 deletions projects/kit/pipes/to-regexp/to-regexp.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {Pipe, PipeTransform} from '@angular/core';
import {TuiArrayOrValue, tuiIsString, tuiToArray} from '@taiga-ui/cdk';

/**
* Transforms a string or an array of strings into RegExp instances.
*/
@Pipe({
name: `tuiToRegexp`,
})
export class TuiToRegexpPipe implements PipeTransform {
/**
* Transforms a string into a RegExp instance.
* @param {string} value - The string to transform into a RegExp.
* @param {string} [flags] - Optional flags to be applied to the RegExp.
* @returns {RegExp} The transformed RegExp instance.
*/
transform(value: string, flags?: string): RegExp;
/**
* Transforms an array of strings into an array of RegExp instances.
* @param {readonly string[]} value - The array of strings to transform into RegExp instances.
* @param {string} [flags] - Optional flags to be applied to the RegExp instances.
* @returns {readonly RegExp[]} The transformed array of RegExp instances.
*/
transform(value: readonly string[], flags?: string): readonly RegExp[];
transform(
value: TuiArrayOrValue<string>,
flags: string = ``,
): TuiArrayOrValue<RegExp> {
if (tuiIsString(value)) {
return new RegExp(value, flags);
}

return tuiToArray(value).map(item => new RegExp(item, flags));
}
}

0 comments on commit 1c507d0

Please sign in to comment.