mirror of
https://github.com/bitwarden/browser
synced 2026-02-03 10:13:31 +00:00
move animation done logic to service
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
||||
} from "@angular/cdk/dialog";
|
||||
import { ComponentType, ScrollStrategy } from "@angular/cdk/overlay";
|
||||
import { ComponentPortal, Portal } from "@angular/cdk/portal";
|
||||
import { Injectable, Injector, TemplateRef, inject } from "@angular/core";
|
||||
import { Injectable, Injector, TemplateRef, inject, signal } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { NavigationEnd, Router } from "@angular/router";
|
||||
import { filter, firstValueFrom, map, Observable, Subject, switchMap } from "rxjs";
|
||||
@@ -18,6 +18,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
|
||||
import { DrawerService } from "../drawer/drawer.service";
|
||||
|
||||
import { ANIMATION_IN_DURATION, ANIMATION_OUT_DURATION } from "./animations";
|
||||
import { SimpleConfigurableDialogComponent } from "./simple-dialog/simple-configurable-dialog/simple-configurable-dialog.component";
|
||||
import { SimpleDialogOptions } from "./simple-dialog/types";
|
||||
|
||||
@@ -132,6 +133,9 @@ export class DialogService {
|
||||
private defaultScrollStrategy = new CustomBlockScrollStrategy();
|
||||
private activeDrawer: DrawerDialogRef<any, any> | null = null;
|
||||
|
||||
/** Signal to control when focus trap auto-capture should be enabled after animation */
|
||||
readonly animationDone = signal(false);
|
||||
|
||||
constructor() {
|
||||
/**
|
||||
* TODO: This logic should exist outside of `libs/components`.
|
||||
@@ -177,6 +181,10 @@ export class DialogService {
|
||||
};
|
||||
|
||||
ref.cdkDialogRefBase = this.dialog.open<R, D, C>(componentOrTemplateRef, _config);
|
||||
|
||||
// Handle focus timing after animation completes
|
||||
this.setupFocusTiming();
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
@@ -198,6 +206,10 @@ export class DialogService {
|
||||
);
|
||||
this.activeDrawer.portal = portal;
|
||||
this.drawerService.open(portal);
|
||||
|
||||
// Handle focus timing after animation completes
|
||||
this.setupFocusTiming();
|
||||
|
||||
return this.activeDrawer;
|
||||
}
|
||||
|
||||
@@ -254,4 +266,20 @@ export class DialogService {
|
||||
parent: this.injector,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the focus timing for a dialog component after the animation completes.
|
||||
* This ensures the focus trap and autofocus only activate after the entrance animation finishes.
|
||||
*/
|
||||
private setupFocusTiming(): void {
|
||||
// Reset the signal to false for the new dialog
|
||||
this.animationDone.set(false);
|
||||
|
||||
const totalDuration = Math.max(ANIMATION_IN_DURATION, ANIMATION_OUT_DURATION);
|
||||
|
||||
// Set to true after animation completes
|
||||
setTimeout(() => {
|
||||
this.animationDone.set(true);
|
||||
}, totalDuration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
class="tw-flex tw-w-full tw-flex-col tw-self-center tw-overflow-hidden tw-border tw-border-solid tw-border-secondary-100 tw-bg-background tw-text-main"
|
||||
[ngClass]="[width, isDrawer ? 'tw-h-screen tw-border-t-0' : 'tw-rounded-xl tw-shadow-lg']"
|
||||
[@dialogAnimation]="isDrawer ? 'drawer' : 'dialog'"
|
||||
(@dialogAnimation.done)="onAnimationDone()"
|
||||
cdkTrapFocus
|
||||
[cdkTrapFocusAutoCapture]="animationDone()"
|
||||
>
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
input,
|
||||
booleanAttribute,
|
||||
ElementRef,
|
||||
signal,
|
||||
} from "@angular/core";
|
||||
import { toObservable } from "@angular/core/rxjs-interop";
|
||||
import { combineLatest, switchMap } from "rxjs";
|
||||
@@ -22,7 +21,7 @@ import { TypographyDirective } from "../../typography/typography.directive";
|
||||
import { hasScrollableContent$ } from "../../utils/";
|
||||
import { hasScrolledFrom } from "../../utils/has-scrolled-from";
|
||||
import { dialogAnimation } from "../animations";
|
||||
import { DialogRef } from "../dialog.service";
|
||||
import { DialogRef, DialogService } from "../dialog.service";
|
||||
import { DialogCloseDirective } from "../directives/dialog-close.directive";
|
||||
import { DialogTitleContainerDirective } from "../directives/dialog-title-container.directive";
|
||||
|
||||
@@ -52,8 +51,9 @@ export class DialogComponent {
|
||||
private readonly scrollBottom = viewChild.required<ElementRef<HTMLDivElement>>("scrollBottom");
|
||||
|
||||
protected dialogRef = inject(DialogRef, { optional: true });
|
||||
private dialogService = inject(DialogService);
|
||||
protected bodyHasScrolledFrom = hasScrolledFrom(this.scrollableBody);
|
||||
protected readonly animationDone = signal(false);
|
||||
protected readonly animationDone = this.dialogService.animationDone;
|
||||
|
||||
private scrollableBody$ = toObservable(this.scrollableBody);
|
||||
private scrollBottom$ = toObservable(this.scrollBottom);
|
||||
@@ -111,10 +111,6 @@ export class DialogComponent {
|
||||
}
|
||||
}
|
||||
|
||||
onAnimationDone() {
|
||||
this.animationDone.set(true);
|
||||
}
|
||||
|
||||
get width() {
|
||||
switch (this.dialogSize()) {
|
||||
case "small": {
|
||||
|
||||
9
libs/components/src/switch/switch.module.ts
Normal file
9
libs/components/src/switch/switch.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { SwitchComponent } from "./switch.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SwitchComponent],
|
||||
exports: [SwitchComponent],
|
||||
})
|
||||
export class SwitchModule {}
|
||||
Reference in New Issue
Block a user