libs/ui/popover/src/lib/popover/popover.component.ts
A popover component that supports rich HTML
<ts-popover
#myPopper
(onHidden)="myFunction($event)"
(onUpdate)="myFunction($event)"
(popoverHidden)="myFunction($event)"
(popoverShown)="myFunction($event)"
>
My popover content
</ts-popover>
<example-url>https://getterminus.github.io/ui-demos-release/components/popover</example-url>
changeDetection | ChangeDetectionStrategy.OnPush |
encapsulation | ViewEncapsulation.None |
exportAs | tsPopoverComponent |
host | { |
selector | ts-popover |
styleUrls | ./popover.component.scss |
templateUrl | ./popover.component.html |
Properties |
|
Methods |
|
Outputs |
constructor(CDR: ChangeDetectorRef)
|
||||||
Parameters :
|
onHidden | |
Type : EventEmitter
|
|
Event emitted when the popover is hidden |
onUpdate | |
Type : EventEmitter
|
|
Event emitted when the popover is updated |
popoverHidden | |
Type : EventEmitter
|
|
Event emitted when the popover is hidden |
popoverShown | |
Type : EventEmitter
|
|
Event emitted when the popover is shown |
Public hide |
hide()
|
When popover is hidden, destroy the instance, toggle visibility to false and emit onHidden event.
Returns :
void
|
Public scheduleUpdate |
scheduleUpdate()
|
When popover is scheduled to be updated, call popper.js update
Returns :
void
|
Public show | ||||||||
show(options: TsPopoverOptions)
|
||||||||
When popover is shown, instantiate popper instance, does update and toggle visibility.
Parameters :
Returns :
void
|
Public toggleVisibility | ||||||||
toggleVisibility(visibility: boolean)
|
||||||||
Based on visibility, adjust visual settings
Parameters :
Returns :
void
|
Public ariaHidden |
Type : string
|
Default value : 'true'
|
aria hidden attribute - it requires a string value. |
Public displayType |
Type : string
|
Default value : 'none'
|
The display type of the popover element |
Public id |
Type : string
|
Default value : ''
|
ID set by trigger and pass to popover element |
Public opacity |
Type : number
|
Default value : 0
|
The opacity of popover element |
Public popoverInstance |
Type : Popper
|
An instance of popper |
Public popoverOptions |
Type : TsPopoverOptions
|
Default value : {
placement: TsPopoverPositions.Bottom,
trigger: TsTriggers.CLICK || TsTriggers.HOVER,
}
|
Options needed for popper.js |
Public popoverViewRef |
Type : ElementRef
|
Decorators :
@ViewChild('popoverViewRef', {static: true})
|
A reference to the popover view |
Public referenceObject |
Type : HTMLElement
|
The element that passed to popper.js |
Public visibility |
Default value : false
|
Whether the element is visible |
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
OnDestroy,
OnInit,
Output,
ViewChild,
ViewEncapsulation,
} from '@angular/core';
import {
createPopper,
Instance as Popper,
} from '@popperjs/core';
import { TS_SPACE_BASE_SMALL_2 } from '@terminus/design-tokens/js/design-tokens';
import { TsUILibraryError } from '@terminus/ui-utilities';
import {
TsPopoverOptions,
TsPopoverPositions,
TsTriggers,
} from '../popover-options';
/**
* A popover component that supports rich HTML
*
* @example
* <ts-popover
* #myPopper
* (onHidden)="myFunction($event)"
* (onUpdate)="myFunction($event)"
* (popoverHidden)="myFunction($event)"
* (popoverShown)="myFunction($event)"
* >
* My popover content
* </ts-popover>
*
* <example-url>https://getterminus.github.io/ui-demos-release/components/popover</example-url>
*/
@Component({
selector: 'ts-popover',
styleUrls: ['./popover.component.scss'],
templateUrl: './popover.component.html',
host: { class: 'ts-popover' },
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
exportAs: 'tsPopoverComponent',
})
export class TsPopoverComponent implements OnDestroy, OnInit {
/**
* The element that passed to popper.js
*/
public referenceObject!: HTMLElement;
/**
* An instance of popper
*/
public popoverInstance!: Popper;
/**
* The display type of the popover element
*/
public displayType = 'none';
/**
* The opacity of popover element
*/
public opacity = 0;
/**
* aria hidden attribute - it requires a string value.
*/
public ariaHidden = 'true';
/**
* Whether the element is visible
*/
public visibility = false;
/**
* ID set by trigger and pass to popover element
*/
public id = '';
/**
* Options needed for popper.js
*/
public popoverOptions: TsPopoverOptions = {
placement: TsPopoverPositions.Bottom,
trigger: TsTriggers.CLICK || TsTriggers.HOVER,
};
/**
* A reference to the popover view
*/
@ViewChild('popoverViewRef', { static: true })
public popoverViewRef!: ElementRef;
/**
* Event emitted when the popover is hidden
*/
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
@Output()
public readonly onHidden = new EventEmitter<Popper>();
/**
* Event emitted when the popover is updated
*/
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
@Output()
public readonly onUpdate = new EventEmitter<Popper>();
/**
* Event emitted when the popover is hidden
*/
@Output()
public readonly popoverHidden = new EventEmitter<Popper>();
/**
* Event emitted when the popover is shown
*/
@Output()
public readonly popoverShown = new EventEmitter<Popper>();
constructor(
private CDR: ChangeDetectorRef,
) {}
/**
* Check whether popper.js has been properly imported.
*/
public ngOnInit(): void {
if (!createPopper) {
throw new TsUILibraryError('TsPopoverComponent: popper.js is not available to reference.');
}
}
/**
* Destroy the instance when component is destroyed.
*/
public ngOnDestroy(): void {
if (this.popoverInstance) {
this.popoverInstance.destroy();
}
}
/**
* When popover is hidden, destroy the instance, toggle visibility to false and emit onHidden event.
*/
public hide(): void {
// istanbul ignore else
if (this.popoverInstance) {
this.popoverInstance.destroy();
}
this.toggleVisibility(false);
this.onHidden.emit();
}
/**
* When popover is shown, instantiate popper instance, does update and toggle visibility.
*
* @param options - PopoverOptions
*/
public show(options: TsPopoverOptions): void {
if (!this.referenceObject) {
return;
}
this.onUpdate.emit(this.popoverInstance);
const margin = TS_SPACE_BASE_SMALL_2;
// Removing last 2 character of 'px' from design token returns.
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
const offset = Number(margin.substring(0, margin.length - 2));
this.popoverInstance = createPopper(
this.referenceObject,
this.popoverViewRef.nativeElement,
{
...options,
modifiers: [{
name: 'offset',
options: { offset: [0, offset] },
}],
},
);
this.scheduleUpdate();
this.toggleVisibility(true);
}
/**
* When popover is scheduled to be updated, call popper.js update
*/
public scheduleUpdate(): void {
this.popoverInstance && this.popoverInstance.update();
}
/**
* Based on visibility, adjust visual settings
*
* @param visibility - boolean
*/
public toggleVisibility(visibility: boolean): void {
if (visibility) {
this.opacity = 1;
this.displayType = 'block';
this.ariaHidden = 'false';
this.visibility = true;
} else {
this.opacity = 0;
this.displayType = 'none';
this.ariaHidden = 'true';
this.visibility = false;
}
// istanbul ignore else
// eslint-disable-next-line dot-notation
if (!this.CDR['destroyed']) {
this.CDR.detectChanges();
}
}
}