-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(playground): add search for component list (#2939)
- Loading branch information
Uladzislau Sakalou
authored
Nov 22, 2021
1 parent
fca5cd1
commit 1d8e814
Showing
12 changed files
with
269 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,21 @@ | ||
.framework-options-bar { | ||
.toolbar { | ||
display: flex; | ||
align-items: center; | ||
flex-wrap: wrap; | ||
} | ||
|
||
::ng-deep { | ||
.options-bar { | ||
display: flex; | ||
align-items: center; | ||
} | ||
.options-show { | ||
margin-left: auto; | ||
} | ||
.options-show.fixed { | ||
.toolbar-toggle { | ||
margin: 0 1.25rem; | ||
|
||
&-fixed { | ||
position: fixed; | ||
right: 0; | ||
top: 0; | ||
left: 0; | ||
top: 0.5rem; | ||
} | ||
} | ||
|
||
.component-list-wrapper { | ||
padding: 2rem; | ||
flex: 0 0 100vw; | ||
min-height: 100vh; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { OnInit, ChangeDetectorRef, Directive, ElementRef, HostBinding, Input, OnDestroy } from '@angular/core'; | ||
import { Subject } from 'rxjs'; | ||
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; | ||
import { ComponentsListService } from './components-list.service'; | ||
|
||
@Directive({ | ||
selector: '[npgComponentLink]', | ||
}) | ||
export class ComponentLinkDirective implements OnInit, OnDestroy { | ||
private destroy$ = new Subject<void>(); | ||
|
||
@Input() npgComponentLink: string = ''; | ||
|
||
@HostBinding('class.selected') | ||
selected = false; | ||
|
||
constructor( | ||
private componentsListService: ComponentsListService, | ||
private cd: ChangeDetectorRef, | ||
private elementRef: ElementRef<Element>, | ||
) {} | ||
|
||
ngOnInit() { | ||
let isFirstEmission = true; | ||
this.componentsListService.selectedLink$ | ||
.pipe( | ||
map((selectedLink: string) => this.npgComponentLink === selectedLink), | ||
distinctUntilChanged(), | ||
takeUntil(this.destroy$), | ||
) | ||
.subscribe((isSelected) => { | ||
this.selected = isSelected; | ||
this.cd.markForCheck(); | ||
|
||
if (isFirstEmission) { | ||
isFirstEmission = false; | ||
} else { | ||
this.elementRef.nativeElement.scrollIntoView({ block: 'nearest' }); | ||
} | ||
}); | ||
} | ||
|
||
ngOnDestroy() { | ||
this.destroy$.next(); | ||
this.destroy$.complete(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; | ||
import { map, shareReplay, take } from 'rxjs/operators'; | ||
import { ComponentLink, PLAYGROUND_COMPONENTS } from './playground-components'; | ||
|
||
@Injectable({ | ||
providedIn: 'root', | ||
}) | ||
export class ComponentsListService { | ||
private readonly searchString$ = new BehaviorSubject<string>(''); | ||
private readonly selectedLinkIndex$ = new BehaviorSubject<number>(0); | ||
|
||
readonly components$: Observable<ComponentLink[]> = this.searchString$.pipe( | ||
map((searchString: string) => this.filter(searchString)), | ||
shareReplay(1), | ||
); | ||
|
||
private readonly componentLinks$ = this.components$.pipe( | ||
map((components: ComponentLink[]) => this.extractLinks(components)), | ||
shareReplay(1), | ||
); | ||
|
||
readonly selectedLink$: Observable<string> = combineLatest([this.componentLinks$, this.selectedLinkIndex$]).pipe( | ||
map(([filteredComponents, activeElementIndex]) => filteredComponents[activeElementIndex]), | ||
shareReplay(1), | ||
); | ||
|
||
updateSearch(searchString: string): void { | ||
this.selectedLinkIndex$.next(0); | ||
this.searchString$.next(searchString); | ||
} | ||
|
||
selectNextComponent(): void { | ||
this.moveSelection(1); | ||
} | ||
|
||
selectPreviousComponent(): void { | ||
this.moveSelection(-1); | ||
} | ||
|
||
private moveSelection(offset: 1 | -1): void { | ||
combineLatest([this.selectedLinkIndex$, this.componentLinks$]) | ||
.pipe( | ||
map(([selectedIndex, components]: [number, string[]]) => [selectedIndex, components.length]), | ||
take(1), | ||
) | ||
.subscribe(([selectedIndex, length]: number[]) => { | ||
let indexToSelect = selectedIndex + offset; | ||
const isOutOfBounds = indexToSelect < 0 || indexToSelect >= length; | ||
// If we went out of bounds when moving forward (offset === 1), we should select the first element. | ||
// Otherwise, we're moving backward, and after we pass the first element, | ||
// we move the selection to the last one (length - 1). | ||
if (isOutOfBounds && offset === 1) { | ||
indexToSelect = 0; | ||
} | ||
if (isOutOfBounds && offset === -1) { | ||
indexToSelect = length - 1; | ||
} | ||
this.selectedLinkIndex$.next(indexToSelect); | ||
}); | ||
} | ||
|
||
private extractLinks(componentLink: ComponentLink[]): string[] { | ||
return componentLink.reduce((acc: string[], item) => { | ||
if (item.link) { | ||
acc.push(item.link); | ||
} | ||
if (item.children) { | ||
acc = [...acc, ...this.extractLinks(item.children)]; | ||
} | ||
return acc; | ||
}, []); | ||
} | ||
|
||
private filter(searchString: string): ComponentLink[] { | ||
if (searchString === '') { | ||
return PLAYGROUND_COMPONENTS; | ||
} | ||
|
||
const filterBySearchString = (components: ComponentLink[], componentLink: ComponentLink) => { | ||
if (componentLink.name?.toLowerCase().includes(searchString)) { | ||
components.push(componentLink); | ||
return components; | ||
} | ||
if (componentLink.children) { | ||
const children = componentLink.children.reduce(filterBySearchString, []); | ||
if (children.length) { | ||
components.push({ ...componentLink, children }); | ||
} | ||
} | ||
return components; | ||
}; | ||
|
||
return PLAYGROUND_COMPONENTS.reduce(filterBySearchString, []); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.