-
Notifications
You must be signed in to change notification settings - Fork 362
/
overlay.ts
93 lines (80 loc) 路 3.43 KB
/
overlay.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { DOCUMENT } from '@angular/common';
import { ApplicationRef, ComponentFactoryResolver, inject, Inject, Injectable } from '@angular/core';
import { DomPortalHost } from '../portal/dom-portal-host';
import { ToastContainerDirective } from '../toastr/toast.directive';
import { OverlayContainer } from './overlay-container';
import { OverlayRef } from './overlay-ref';
/**
* Service to create Overlays. Overlays are dynamically added pieces of floating UI, meant to be
* used as a low-level building building block for other components. Dialogs, tooltips, menus,
* selects, etc. can all be built using overlays. The service should primarily be used by authors
* of re-usable components rather than developers building end-user applications.
*
* An overlay *is* a PortalHost, so any kind of Portal can be loaded into one.
*/
@Injectable({ providedIn: 'root' })
export class Overlay {
private _overlayContainer = inject(OverlayContainer);
private _componentFactoryResolver = inject(ComponentFactoryResolver);
private _appRef = inject(ApplicationRef);
private _document = inject(DOCUMENT);
// Namespace panes by overlay container
private _paneElements: Map<ToastContainerDirective, Record<string, HTMLElement>> = new Map();
/**
* Creates an overlay.
* @returns A reference to the created overlay.
*/
create(positionClass?: string, overlayContainer?: ToastContainerDirective): OverlayRef {
// get existing pane if possible
return this._createOverlayRef(this.getPaneElement(positionClass, overlayContainer));
}
getPaneElement(
positionClass: string = '',
overlayContainer?: ToastContainerDirective,
): HTMLElement {
if (!this._paneElements.get(overlayContainer as ToastContainerDirective)) {
this._paneElements.set(overlayContainer as ToastContainerDirective, {});
}
if (!this._paneElements.get(overlayContainer as ToastContainerDirective)![positionClass]) {
this._paneElements.get(overlayContainer as ToastContainerDirective)![
positionClass
] = this._createPaneElement(positionClass, overlayContainer);
}
return this._paneElements.get(overlayContainer as ToastContainerDirective)![positionClass];
}
/**
* Creates the DOM element for an overlay and appends it to the overlay container.
* @returns Newly-created pane element
*/
private _createPaneElement(
positionClass: string,
overlayContainer?: ToastContainerDirective,
): HTMLElement {
const pane = this._document.createElement('div');
pane.id = 'toast-container';
pane.classList.add(positionClass);
pane.classList.add('toast-container');
if (!overlayContainer) {
this._overlayContainer.getContainerElement().appendChild(pane);
} else {
overlayContainer.getContainerElement().appendChild(pane);
}
return pane;
}
/**
* Create a DomPortalHost into which the overlay content can be loaded.
* @param pane The DOM element to turn into a portal host.
* @returns A portal host for the given DOM element.
*/
private _createPortalHost(pane: HTMLElement): DomPortalHost {
return new DomPortalHost(pane, this._componentFactoryResolver, this._appRef);
}
/**
* Creates an OverlayRef for an overlay in the given DOM element.
* @param pane DOM element for the overlay
*/
private _createOverlayRef(pane: HTMLElement): OverlayRef {
return new OverlayRef(this._createPortalHost(pane));
}
}