Skip to content

Commit

Permalink
refactor(dialog): migrate to signals spartan-ng#427
Browse files Browse the repository at this point in the history
  • Loading branch information
MerlinMoos committed Dec 2, 2024
1 parent 4e6ba40 commit 9230225
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ import type { BrnAlertDialogComponent } from './brn-alert-dialog.component';
export class BrnAlertDialogTriggerDirective extends BrnDialogTriggerDirective {
@Input()
public set brnAlertDialogTriggerFor(brnDialog: BrnAlertDialogComponent) {
super.brnDialogTriggerFor = brnDialog;
this.brnDialogTriggerForState().set(brnDialog);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation, forwardRef } from '@angular/core';
import { ChangeDetectionStrategy, Component, forwardRef, ViewEncapsulation } from '@angular/core';
import { BrnAlertDialogComponent, BrnAlertDialogOverlayComponent } from '@spartan-ng/ui-alertdialog-brain';
import { BrnDialogComponent } from '@spartan-ng/ui-dialog-brain';
import { HlmAlertDialogOverlayDirective } from './hlm-alert-dialog-overlay.directive';
Expand All @@ -24,6 +24,6 @@ import { HlmAlertDialogOverlayDirective } from './hlm-alert-dialog-overlay.direc
export class HlmAlertDialogComponent extends BrnAlertDialogComponent {
constructor() {
super();
this.closeDelay = 100;
this.closeDelayState().set(100);
}
}
13 changes: 4 additions & 9 deletions libs/ui/dialog/brain/src/lib/brn-dialog-close.directive.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type NumberInput, coerceNumberProperty } from '@angular/cdk/coercion';
import { Directive, Input, inject } from '@angular/core';
import { coerceNumberProperty } from '@angular/cdk/coercion';
import { Directive, inject, input } from '@angular/core';
import { BrnDialogRef } from './brn-dialog-ref';

@Directive({
Expand All @@ -12,14 +12,9 @@ import { BrnDialogRef } from './brn-dialog-ref';
export class BrnDialogCloseDirective {
private readonly _brnDialogRef = inject(BrnDialogRef);

private _delay: number | undefined;

@Input()
public set delay(value: NumberInput) {
this._delay = coerceNumberProperty(value);
}
public readonly delay = input<number | undefined, number>(undefined, { transform: coerceNumberProperty });

public close() {
this._brnDialogRef.close(undefined, this._delay);
this._brnDialogRef.close(undefined, this.delay());
}
}
18 changes: 10 additions & 8 deletions libs/ui/dialog/brain/src/lib/brn-dialog-content.directive.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Directive, Input, TemplateRef, computed, inject } from '@angular/core';
import { computed, Directive, effect, inject, input, TemplateRef } from '@angular/core';
import { provideExposesStateProviderExisting } from '@spartan-ng/ui-core';
import { BrnDialogRef } from './brn-dialog-ref';
import { BrnDialogComponent } from './brn-dialog.component';
Expand All @@ -14,17 +14,19 @@ export class BrnDialogContentDirective<T> {
private readonly _template = inject(TemplateRef);
public readonly state = computed(() => this._brnDialog?.state() ?? this._brnDialogRef?.state() ?? 'closed');

@Input()
public set class(newClass: string | null | undefined) {
public readonly className = input<string | null | undefined>(undefined, { alias: 'class' });
private readonly _classEffect = effect(() => {
if (!this._brnDialog) return;
const newClass = this.className();
this._brnDialog.setPanelClass(newClass);
}
});

@Input()
public set context(context: T) {
if (!this._brnDialog) return;
public readonly context = input<T | undefined>(undefined);
private readonly _contextEffect = effect(() => {
const context = this.context();
if (!this._brnDialog || !context) return;
this._brnDialog.setContext(context);
}
});

constructor() {
if (!this._brnDialog) return;
Expand Down
10 changes: 6 additions & 4 deletions libs/ui/dialog/brain/src/lib/brn-dialog-overlay.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation, inject } from '@angular/core';
import { ChangeDetectionStrategy, Component, effect, inject, input, ViewEncapsulation } from '@angular/core';
import { provideCustomClassSettableExisting } from '@spartan-ng/ui-core';
import { BrnDialogComponent } from './brn-dialog.component';

Expand All @@ -13,10 +13,12 @@ import { BrnDialogComponent } from './brn-dialog.component';
export class BrnDialogOverlayComponent {
private readonly _brnDialog = inject(BrnDialogComponent);

@Input()
public set class(newClass: string | null | undefined) {
public readonly className = input<string | null | undefined>(undefined, { alias: 'class' });
private readonly _classEffect = effect(() => {
if (!this._brnDialog) return;
const newClass = this.className();
this._brnDialog.setOverlayClass(newClass);
}
});

setClassToCustomElement(newClass: string) {
this._brnDialog.setOverlayClass(newClass);
Expand Down
14 changes: 10 additions & 4 deletions libs/ui/dialog/brain/src/lib/brn-dialog-trigger.directive.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Directive, Input, type Signal, inject, input, signal } from '@angular/core';
import { computed, Directive, effect, inject, input, type Signal, signal } from '@angular/core';
import { BrnDialogRef } from './brn-dialog-ref';
import type { BrnDialogState } from './brn-dialog-state';
import { BrnDialogComponent } from './brn-dialog.component';
Expand Down Expand Up @@ -27,10 +27,16 @@ export class BrnDialogTriggerDirective {
public readonly state: Signal<BrnDialogState> = this._brnDialogRef?.state ?? signal('closed');
public readonly dialogId = `brn-dialog-${this._brnDialogRef?.dialogId ?? idSequence++}`;

@Input()
public set brnDialogTriggerFor(brnDialog: BrnDialogComponent) {
public readonly brnDialogTriggerForInput = input<BrnDialogComponent | undefined>(undefined, {
alias: 'brnDialogTriggerFor',
});
public readonly brnDialogTriggerForState = computed(() => signal(this.brnDialogTriggerForInput()));
public readonly brnDialogTriggerFor = computed(() => this.brnDialogTriggerForState()());
private readonly _brnDialogTriggerForEffect = effect(() => {
const brnDialog = this.brnDialogTriggerFor();
if (!brnDialog) return;
this._brnDialog = brnDialog;
}
});

open() {
this._brnDialog?.open();
Expand Down
225 changes: 125 additions & 100 deletions libs/ui/dialog/brain/src/lib/brn-dialog.component.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
import type { AutoFocusTarget } from '@angular/cdk/dialog';
import {
type ConnectedPosition,
type FlexibleConnectedPositionStrategyOrigin,
OverlayPositionBuilder,
type PositionStrategy,
type ScrollStrategy,
ScrollStrategyOptions,
} from '@angular/cdk/overlay';
import { OverlayPositionBuilder, ScrollStrategyOptions } from '@angular/cdk/overlay';
import {
booleanAttribute,
ChangeDetectionStrategy,
Component,
type EffectRef,
type ElementRef,
EventEmitter,
Injector,
Input,
Output,
type TemplateRef,
ViewContainerRef,
ViewEncapsulation,
booleanAttribute,
computed,
effect,
type EffectRef,
inject,
Injector,
input,
numberAttribute,
output,
runInInjectionContext,
signal,
type TemplateRef,
ViewContainerRef,
ViewEncapsulation,
} from '@angular/core';
import { take } from 'rxjs';
import { type BrnDialogOptions, DEFAULT_BRN_DIALOG_OPTIONS } from './brn-dialog-options';
Expand Down Expand Up @@ -61,114 +51,149 @@ export class BrnDialogComponent {

public readonly state = computed(() => this._dialogRef()?.state() ?? 'closed');

@Output()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public readonly closed = new EventEmitter<any>();
public readonly closed = output<any>();

@Output()
public readonly stateChanged = new EventEmitter<BrnDialogState>();
public readonly stateChanged = output<BrnDialogState>();

// eslint-disable-next-line @angular-eslint/no-input-rename
@Input('state')
public set newState(state: BrnDialogState) {
public readonly newState = input<BrnDialogState | null>(null, { alias: 'state' });
private readonly _newStateEffect = effect(() => {
const state = this.newState();
if (state === 'open') {
this.open();
}
if (state === 'closed') {
this.close(this._options.closeDelay);
}
}

@Input()
public set role(role: 'dialog' | 'alertdialog') {
this._options.role = role;
}

@Input({ transform: booleanAttribute })
public set hasBackdrop(hasBackdrop: boolean) {
this._options.hasBackdrop = hasBackdrop;
}

@Input()
public set positionStrategy(positionStrategy: PositionStrategy) {
this._options.positionStrategy = positionStrategy;
}

@Input()
public set scrollStrategy(scrollStrategy: ScrollStrategy | 'close' | 'reposition') {
});

public readonly role = input<BrnDialogOptions['role']>('dialog');
private readonly _roleEffect = effect(() => {
this._options.role = this.role();
});

public readonly hasBackdropInput = input(true, { transform: booleanAttribute, alias: 'hasBackdrop' });
public readonly hasBackdropState = computed(() => signal(this.hasBackdropInput()));
public readonly hasBackdrop = computed(() => this.hasBackdropState()());
private readonly _hasBackdropEffect = effect(() => {
this._options.hasBackdrop = this.hasBackdrop();
});

public readonly positionStrategyInput = input<BrnDialogOptions['positionStrategy']>(null, {
alias: 'positionStrategy',
});
public readonly positionStrategyState = computed(() => signal(this.positionStrategyInput()));
public readonly positionStrategy = computed(() => this.positionStrategyState()());
private readonly _positionStrategyEffect = effect(() => {
this._options.positionStrategy = this.positionStrategy();
});

public readonly scrollStrategyInput = input<BrnDialogOptions['scrollStrategy'] | 'close' | 'reposition'>(null, {
alias: 'scrollStrategy',
});
public readonly scrollStrategyState = computed(() => signal(this.scrollStrategyInput()));
public readonly scrollStrategy = computed(() => this.scrollStrategyState()());
private readonly _scrollStrategyEffect = effect(() => {
const scrollStrategy = this.scrollStrategy();
if (scrollStrategy === 'close') {
this._options.scrollStrategy = this.ssos.close();
} else if (scrollStrategy === 'reposition') {
this._options.scrollStrategy = this.ssos.reposition();
} else {
this._options.scrollStrategy = scrollStrategy;
}
}
});

@Input()
public set restoreFocus(restoreFocus: boolean | string | ElementRef) {
this._options.restoreFocus = restoreFocus;
}

@Input({ transform: booleanAttribute })
public set closeOnOutsidePointerEvents(closeOnOutsidePointerEvents: boolean) {
this._options.closeOnOutsidePointerEvents = closeOnOutsidePointerEvents;
}

@Input({ transform: booleanAttribute })
public set closeOnBackdropClick(closeOnBackdropClick: boolean) {
this._options.closeOnBackdropClick = closeOnBackdropClick;
}

@Input()
public set attachTo(attachTo: FlexibleConnectedPositionStrategyOrigin | null | undefined) {
this._options.attachTo = attachTo;
}

@Input()
public set attachPositions(attachPositions: ConnectedPosition[]) {
this._options.attachPositions = attachPositions;
}

@Input()
public set autoFocus(autoFocus: AutoFocusTarget | string) {
this._options.autoFocus = autoFocus;
}
public readonly restoreFocus = input<BrnDialogOptions['restoreFocus']>(true);
private readonly _restoreFocusEffect = effect(() => {
this._options.restoreFocus = this.restoreFocus();
});

@Input({ transform: numberAttribute })
public set closeDelay(closeDelay: number) {
this._options.closeDelay = closeDelay;
}

@Input({ transform: booleanAttribute })
public set disableClose(disableClose: boolean) {
this._options.disableClose = disableClose;
}

/* eslint-disable-next-line @angular-eslint/no-input-rename */
@Input('aria-describedby')
public set ariaDescribedBy(ariaDescribedBy: string | null | undefined) {
public readonly closeOnOutsidePointerEventsInput = input(false, {
transform: booleanAttribute,
alias: 'closeOnOutsidePointerEvents',
});
public readonly closeOnOutsidePointerEventsState = computed(() => signal(this.closeOnOutsidePointerEventsInput()));
public readonly closeOnOutsidePointerEvents = computed(() => this.closeOnOutsidePointerEventsState()());
private readonly _closeOnOutsidePointerEventsEffect = effect(() => {
this._options.closeOnOutsidePointerEvents = this.closeOnOutsidePointerEvents();
});

public readonly closeOnBackdropClickInput = input(true, {
transform: booleanAttribute,
alias: 'closeOnBackdropClick',
});
private readonly _closeOnBackdropClickEffect = effect(() => {
this._options.closeOnBackdropClick = this.closeOnBackdropClickInput();
});

public readonly attachToInput = input<BrnDialogOptions['attachTo']>(null, { alias: 'attachTo' });
public readonly attachToState = computed(() => signal(this.attachToInput()));
public readonly attachTo = computed(() => this.attachToState()());
private readonly _attachToEffect = effect(() => {
this._options.attachTo = this.attachTo();
});

public readonly attachPositionsInput = input<BrnDialogOptions['attachPositions']>([], { alias: 'attachPositions' });
public readonly attachPositionsState = computed(() => signal(this.attachPositionsInput()));
public readonly attachPositions = computed(() => this.attachPositionsState()());
private readonly _attachPositionsEffect = effect(() => {
this._options.attachPositions = this.attachPositions();
});

public readonly autoFocusInput = input<BrnDialogOptions['autoFocus']>('first-tabbable', { alias: 'autoFocus' });
private readonly _autoFocusEffect = effect(() => {
this._options.autoFocus = this.autoFocusInput();
});

public readonly closeDelayInput = input(0, { alias: 'closeDelay', transform: numberAttribute });
public readonly closeDelayState = computed(() => signal(this.closeDelayInput()));
public readonly closeDelay = computed(() => this.closeDelayState()());
private readonly _closeDelayEffect = effect(() => {
this._options.closeDelay = this.closeDelay();
});

public readonly disableCloseInput = input(false, { transform: booleanAttribute, alias: 'disableClose' });
private readonly _disableCloseEffect = effect(() => {
this._options.disableClose = this.disableCloseInput();
});

public readonly ariaDescribedByInput = input<BrnDialogOptions['ariaDescribedBy']>(null, {
alias: 'aria-describedby',
});
public readonly ariaDescribedByState = computed(() => signal(this.ariaDescribedByInput()));
public readonly ariaDescribedBy = computed(() => this.ariaDescribedByState()());
private readonly _ariaDescribedByEffect = effect(() => {
const ariaDescribedBy = this.ariaDescribedBy();
this.setAriaDescribedBy(ariaDescribedBy);
}
});

/* eslint-disable-next-line @angular-eslint/no-input-rename */
@Input('aria-labelledby')
public set ariaLabelledBy(ariaLabelledBy: string | null | undefined) {
public readonly ariaLabelledByInput = input<BrnDialogOptions['ariaLabelledBy']>(null, { alias: 'aria-labelledby' });
public readonly ariaLabelledByState = computed(() => signal(this.ariaLabelledByInput()));
public readonly ariaLabelledBy = computed(() => this.ariaLabelledByState()());
private readonly _ariaLabelledByEffect = effect(() => {
const ariaLabelledBy = this.ariaLabelledBy();
this.setAriaLabelledBy(ariaLabelledBy);
}
});

@Input('aria-label')
public set ariaLabel(ariaLabel: string | null | undefined) {
public readonly ariaLabelInput = input<BrnDialogOptions['ariaLabel']>(null, { alias: 'aria-label' });
public readonly ariaLabelState = computed(() => signal(this.ariaLabelInput()));
public readonly ariaLabel = computed(() => this.ariaLabelState()());
private readonly _ariaLabelEffect = effect(() => {
const ariaLabel = this.ariaLabel();
this.setAriaLabel(ariaLabel);
}
});

@Input({
public readonly ariaModalInput = input(true, {
alias: 'aria-modal',
transform: booleanAttribute,
})
public set ariaModal(isModal: boolean) {
});
public readonly ariaModalState = computed(() => signal(this.ariaModalInput()));
public readonly ariaModal = computed(() => this.ariaModalState()());
private readonly _ariaModalEffect = effect(() => {
const isModal = this.ariaModal();
this.setAriaModal(isModal);
}
});

public open<DialogContext>() {
if (!this._contentTemplate || this._dialogRef()) return;
Expand Down
Loading

0 comments on commit 9230225

Please sign in to comment.