Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(select): decouple hlm from brn #253

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
18 changes: 9 additions & 9 deletions libs/ui/select/brain/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import { NgModule } from '@angular/core';
import { BrnSelectContentComponent } from './lib/brn-select-content.component';
import { BrnSelectContentDirective } from './lib/brn-select-content.directive';
import { BrnSelectGroupDirective } from './lib/brn-select-group.directive';
import { BrnSelectLabelDirective } from './lib/brn-select-label.directive';
import { BrnSelectOptionDirective } from './lib/brn-select-option.directive';
import { BrnSelectScrollDownDirective } from './lib/brn-select-scroll-down.directive';
import { BrnSelectScrollUpDirective } from './lib/brn-select-scroll-up.directive';
import { BrnSelectTriggerDirective } from './lib/brn-select-trigger.directive';
import { BrnSelectValueComponent } from './lib/brn-select-value.component';
import { BrnSelectComponent } from './lib/brn-select.component';
import { BrnSelectValueDirective } from './lib/brn-select-value.directive';
import { BrnSelectDirective } from './lib/brn-select.directive';

export * from './lib/brn-select-content.component';
export * from './lib/brn-select-content.directive';
export * from './lib/brn-select-group.directive';
export * from './lib/brn-select-label.directive';
export * from './lib/brn-select-option.directive';
export * from './lib/brn-select-scroll-down.directive';
export * from './lib/brn-select-scroll-up.directive';
export * from './lib/brn-select-trigger.directive';
export * from './lib/brn-select-value.component';
export * from './lib/brn-select.component';
export * from './lib/brn-select-value.directive';
export * from './lib/brn-select.directive';
export * from './lib/brn-select.service';

export const BrnSelectImports = [
BrnSelectComponent,
BrnSelectContentComponent,
BrnSelectDirective,
BrnSelectContentDirective,
BrnSelectTriggerDirective,
BrnSelectOptionDirective,
BrnSelectValueComponent,
BrnSelectValueDirective,
BrnSelectScrollDownDirective,
BrnSelectScrollUpDirective,
BrnSelectGroupDirective,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,101 +1,43 @@
import { CdkListbox, ListboxValueChangeEvent } from '@angular/cdk/listbox';
import { NgTemplateOutlet } from '@angular/common';
import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
ContentChild,
ContentChildren,
DestroyRef,
Directive,
ElementRef,
QueryList,
ViewChild,
effect,
inject,
signal,
} from '@angular/core';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { filter, firstValueFrom } from 'rxjs';
import { BrnSelectOptionDirective } from './brn-select-option.directive';
import { BrnSelectScrollDownDirective } from './brn-select-scroll-down.directive';
import { BrnSelectScrollUpDirective } from './brn-select-scroll-up.directive';
import { BrnSelectService } from './brn-select.service';

@Component({
selector: 'brn-select-content, hlm-select-content:not(noHlm)',
@Directive({
selector: '[brnSelectContent]',
standalone: true,
imports: [BrnSelectScrollUpDirective, BrnSelectScrollDownDirective, NgTemplateOutlet],
hostDirectives: [CdkListbox],
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
'[attr.aria-labelledBy]': 'labelledBy()',
'[attr.aria-controlledBy]': "id() +'--trigger'",
'[id]': "id() + '--content'",
'[attr.dir]': '_selectService.dir()',
},
styles: [
`
:host {
display: flex;
box-sizing: border-box;
flex-direction: column;
outline: none;
pointer-events: auto;
}

[data-brn-select-viewport] {
scrollbar-width: none;
-ms-overflow-style: none;
-webkit-overflow-scrolling: touch;
}

[data-brn-select-viewport]::-webkit-scrollbar {
display: none;
}
`,
],
template: `
<ng-template #scrollUp>
<ng-content select="hlm-select-scroll-up" />
<ng-content select="brnSelectScrollUp" />
</ng-template>
<ng-container *ngTemplateOutlet="canScrollUp() && scrollUpBtn ? scrollUp : null" />
<div
data-brn-select-viewport
#viewport
(scroll)="handleScroll()"
style="flex: 1 1 0%;
position: relative;
width:100%;
overflow:auto;
min-height: 36px;
padding-bottom: 2px;
margin-bottom: -2px;"
>
<ng-content />
</div>
<ng-template #scrollDown>
<ng-content select="brnSelectScrollDown" />
<ng-content select="hlm-select-scroll-down" />
</ng-template>
<ng-container *ngTemplateOutlet="canScrollDown() && scrollDownBtn ? scrollDown : null" />
`,
})
export class BrnSelectContentComponent implements AfterViewInit {
export class BrnSelectContentDirective implements AfterViewInit {
private readonly _el: ElementRef<HTMLElement> = inject(ElementRef);
private readonly _cdkListbox = inject(CdkListbox, { host: true });
private readonly destroyRef = inject(DestroyRef);
protected readonly _selectService = inject(BrnSelectService);

protected readonly labelledBy = this._selectService.labelId;
protected readonly id = this._selectService.id;
protected readonly canScrollUp = signal(false);
protected readonly canScrollDown = signal(false);
readonly labelledBy = this._selectService.labelId;
readonly id = this._selectService.id;
readonly canScrollUp = signal(false);
readonly canScrollDown = signal(false);
readonly viewport = signal<ElementRef<HTMLElement> | undefined>(undefined);
readonly viewport$ = toObservable(this.viewport);

protected initialSelectedOptions$ = toObservable(this._selectService.initialSelectedOptions);

@ViewChild('viewport')
protected viewport!: ElementRef<HTMLElement>;

@ContentChild(BrnSelectScrollUpDirective, { static: false })
protected scrollUpBtn!: BrnSelectScrollUpDirective;

Expand Down Expand Up @@ -140,10 +82,11 @@ export class BrnSelectContentComponent implements AfterViewInit {
});
}

public updateArrowDisplay(): void {
this.canScrollUp.set(this.viewport.nativeElement.scrollTop > 0);
const maxScroll = this.viewport.nativeElement.scrollHeight - this.viewport.nativeElement.clientHeight;
this.canScrollDown.set(Math.ceil(this.viewport.nativeElement.scrollTop) < maxScroll);
public async updateArrowDisplay() {
const viewport = await firstValueFrom(this.viewport$.pipe(filter(Boolean)));
this.canScrollUp.set(viewport.nativeElement.scrollTop > 0);
const maxScroll = viewport.nativeElement.scrollHeight - viewport.nativeElement.clientHeight;
this.canScrollDown.set(Math.ceil(viewport.nativeElement.scrollTop) < maxScroll);
}

public handleScroll() {
Expand All @@ -155,17 +98,19 @@ export class BrnSelectContentComponent implements AfterViewInit {
}

public moveFocusUp() {
this.viewport.nativeElement.scrollBy({ top: -100, behavior: 'smooth' });
if (this.viewport.nativeElement.scrollTop === 0) {
const viewport = this.viewport()!;
viewport.nativeElement.scrollBy({ top: -100, behavior: 'smooth' });
if (viewport.nativeElement.scrollTop === 0) {
this.scrollUpBtn.stopEmittingEvents();
}
}

public moveFocusDown() {
this.viewport.nativeElement.scrollBy({ top: 100, behavior: 'smooth' });
const viewport = this.viewport()!;
viewport.nativeElement.scrollBy({ top: 100, behavior: 'smooth' });
const viewportSize = this._el.nativeElement.scrollHeight;
const viewportScrollPosition = this.viewport.nativeElement.scrollTop;
if (viewportSize + viewportScrollPosition + 100 > this.viewport.nativeElement.scrollHeight + 50) {
const viewportScrollPosition = viewport.nativeElement.scrollTop;
if (viewportSize + viewportScrollPosition + 100 > viewport.nativeElement.scrollHeight + 50) {
this.scrollDownBtn.stopEmittingEvents();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { DestroyRef, Directive, ElementRef, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Subject, fromEvent, interval, takeUntil } from 'rxjs';
import { BrnSelectContentComponent } from './brn-select-content.component';
import { BrnSelectContentDirective } from './brn-select-content.directive';

@Directive({
selector: '[brnSelectScrollDown], brn-select-scroll-down, hlm-select-scroll-down:not(noHlm)',
selector: '[brnSelectScrollDown], brn-select-scroll-down',
standalone: true,
host: {
'aria-hidden': 'true',
Expand All @@ -13,7 +13,7 @@ import { BrnSelectContentComponent } from './brn-select-content.component';
})
export class BrnSelectScrollDownDirective {
private readonly _el = inject(ElementRef);
private readonly _selectContent = inject(BrnSelectContentComponent);
private readonly _selectContent = inject(BrnSelectContentDirective);

private readonly endReached = new Subject<boolean>();
private readonly _destroyRef = inject(DestroyRef);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { DestroyRef, Directive, ElementRef, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Subject, fromEvent, interval, takeUntil } from 'rxjs';
import { BrnSelectContentComponent } from './brn-select-content.component';
import { BrnSelectContentDirective } from './brn-select-content.directive';

@Directive({
selector: '[brnSelectScrollUp], brn-select-scroll-up, hlm-select-scroll-up:not(noHlm)',
selector: '[brnSelectScrollUp], brn-select-scroll-up',
standalone: true,
host: {
'aria-hidden': 'true',
Expand All @@ -13,7 +13,7 @@ import { BrnSelectContentComponent } from './brn-select-content.component';
})
export class BrnSelectScrollUpDirective {
private readonly _el = inject(ElementRef);
private readonly _selectContent = inject(BrnSelectContentComponent);
private readonly _selectContent = inject(BrnSelectContentDirective);

private readonly endReached = new Subject<boolean>();
private readonly _destroyRef = inject(DestroyRef);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
import { ChangeDetectionStrategy, Component, computed, inject, Input } from '@angular/core';
import { computed, Directive, inject, Input } from '@angular/core';
import { BrnSelectService } from './brn-select.service';

@Component({
selector: 'brn-select-value, hlm-select-value',
template: `
{{ value() || placeholder() }}
`,
host: {
'[id]': 'id()',
},
styles: [
`
:host {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
white-space: nowrap;
pointer-events: none;
}
`,
],
@Directive({
selector: '[brnSelectValue]',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BrnSelectValueComponent {
export class BrnSelectValueDirective {
private readonly _selectService = inject(BrnSelectService);

public readonly id = computed(() => `${this._selectService.id()}--value`);
Expand All @@ -43,6 +25,5 @@ export class BrnSelectValueComponent {
});

@Input()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
transformFn: (values: (string | undefined)[]) => any = (values) => (values ?? []).join(', ');
transformFn: (values: (string | undefined)[]) => string = (values) => (values ?? []).join(', ');
}
Loading
Loading