Skip to content

Commit

Permalink
feat(design): implement DaffOpenable in the DaffModalComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
xelaint committed Jul 16, 2024
1 parent ac21361 commit 591fb30
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 25 deletions.
55 changes: 41 additions & 14 deletions libs/design/modal/src/modal/modal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ import {
import {
Component,
EventEmitter,
Input,
HostBinding,
ChangeDetectionStrategy,
ViewChild,
HostListener,
ElementRef,
AfterContentInit,
AfterViewInit,
Self,
} from '@angular/core';

import {
DaffOpenable,
DaffOpenableDirective,
} from '@daffodil/design';
import { daffFocusableElementsSelector } from '@daffodil/design';

import { daffFadeAnimations } from '../animations/modal-animation';
Expand All @@ -31,20 +33,19 @@ import { DaffModalService } from '../service/modal.service';
selector: 'daff-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.scss'],
hostDirectives: [{
directive: DaffOpenableDirective,
outputs: ['toggled'],
}],
animations: [daffFadeAnimations.fade],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DaffModalComponent implements AfterContentInit, AfterViewInit {
export class DaffModalComponent implements AfterContentInit, AfterViewInit, DaffOpenable {
/**
* HostBinding to set the default modal class on the host element.
*/
@HostBinding('class.daff-modal') modalClass = true;

/**
* Dictates whether or not a modal is open or closed.
*/
@Input() open = false;

/**
* The CDK Portal outlet used to portal content into the modal.
*/
Expand Down Expand Up @@ -75,18 +76,19 @@ export class DaffModalComponent implements AfterContentInit, AfterViewInit {
constructor(
private modalService: DaffModalService,
private _focusTrapFactory: ConfigurableFocusTrapFactory,
private _elementRef: ElementRef<HTMLElement>,
private elementRef: ElementRef<HTMLElement>,
private openDirective: DaffOpenableDirective,
) {
}

ngAfterContentInit() {
this._focusTrap = this._focusTrapFactory.create(
this._elementRef.nativeElement,
this.elementRef.nativeElement,
);
}

ngAfterViewInit() {
const focusableChild = (<HTMLElement>this._elementRef.nativeElement.querySelector(
const focusableChild = (<HTMLElement>this.elementRef.nativeElement.querySelector(
daffFocusableElementsSelector)
);

Expand All @@ -95,8 +97,8 @@ export class DaffModalComponent implements AfterContentInit, AfterViewInit {
} else {
// There's a timing condition when computing HostBindings afterContentInit
// so to allow the menu to be focused, we manually set the tabindex.
this._elementRef.nativeElement.tabIndex = 0;
(<HTMLElement>this._elementRef.nativeElement).focus();
this.elementRef.nativeElement.tabIndex = 0;
(<HTMLElement>this.elementRef.nativeElement).focus();
}
}

Expand All @@ -109,7 +111,7 @@ export class DaffModalComponent implements AfterContentInit, AfterViewInit {

/** Animation hook that controls the entrance and exit animations of the modal. */
@HostBinding('@fade') get fadeState(): string {
return getAnimationState(this.open);
return getAnimationState(this.openDirective.open);
}

/**
Expand All @@ -125,4 +127,29 @@ export class DaffModalComponent implements AfterContentInit, AfterViewInit {
this.closedAnimationCompleted.emit(e);
}
}

get open() {
return this.openDirective.open;
}

/**
* Reveals the modal
*/
reveal() {
this.openDirective.reveal();
}

/**
* Hides the modal
*/
hide() {
this.openDirective.hide();
}

/**
* Toggles the visibility of the modal
*/
toggle() {
this.openDirective.toggle();
}
}
4 changes: 2 additions & 2 deletions libs/design/modal/src/service/modal.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class DaffModalService {
}]}),
),
);
modal.instance.open = true;
modal.instance.reveal();
return modal;
}

Expand Down Expand Up @@ -96,7 +96,7 @@ export class DaffModalService {
}

close(component: DaffModalComponent): void {
component.open = false;
component.hide();
const modal = this._modals.get(component);

modal.overlay.detachBackdrop();
Expand Down
21 changes: 12 additions & 9 deletions libs/design/modal/src/specs/animations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,17 @@ describe('@daffodil/design/modal | DaffModalComponent', () => {
fixture.detectChanges();
});

describe('the entrance and exit animations', () => {
it('should change animation states depending on whether or not the modal is open or closed', () => {
wrapper.open = true;
fixture.detectChanges();
expect(modal.fadeState).toBe('open');
wrapper.open = false;
fixture.detectChanges();
expect(modal.fadeState).toBe('closed');
});
it('should change the animation state to open if modal is open', () => {
modal.reveal();
fixture.detectChanges();

expect(modal.fadeState).toBe('open');
});

it('should change the animation state to closed if modal is closed', () => {
modal.hide();
fixture.detectChanges();

expect(modal.fadeState).toBe('closed');
});
});

0 comments on commit 591fb30

Please sign in to comment.