| 50 | * @returns Reference to the created overlay. |
| 51 | */ |
| 52 | export function createOverlayRef(injector: Injector, config?: OverlayConfig): OverlayRef { |
| 53 | // This is done in the overlay container as well, but we have it here |
| 54 | // since it's common to mock out the overlay container in tests. |
| 55 | injector.get(_CdkPrivateStyleLoader).load(_CdkOverlayStyleLoader); |
| 56 | |
| 57 | const overlayContainer = injector.get(OverlayContainer); |
| 58 | const doc = injector.get(DOCUMENT); |
| 59 | const idGenerator = injector.get(_IdGenerator); |
| 60 | const appRef = injector.get(ApplicationRef); |
| 61 | const directionality = injector.get(Directionality); |
| 62 | const renderer = |
| 63 | injector.get(Renderer2, null, {optional: true}) || |
| 64 | injector.get(RendererFactory2).createRenderer(null, null); |
| 65 | |
| 66 | const overlayConfig = new OverlayConfig(config); |
| 67 | const defaultUsePopover = |
| 68 | injector.get(OVERLAY_DEFAULT_CONFIG, null, {optional: true})?.usePopover ?? true; |
| 69 | |
| 70 | overlayConfig.direction = overlayConfig.direction || directionality.value; |
| 71 | |
| 72 | // `document.body` can be null during page navigation or unload cycles per the WHATWG spec |
| 73 | // (https://html.spec.whatwg.org/multipage/dom.html#dom-document-body), even though TypeScript |
| 74 | // types it as non-nullable. Guard against it to avoid "Cannot use 'in' operator ... in null". |
| 75 | if (!doc.body || !('showPopover' in doc.body)) { |
| 76 | overlayConfig.usePopover = false; |
| 77 | } else { |
| 78 | overlayConfig.usePopover = config?.usePopover ?? defaultUsePopover; |
| 79 | } |
| 80 | |
| 81 | const pane = doc.createElement('div'); |
| 82 | const host = doc.createElement('div'); |
| 83 | pane.id = idGenerator.getId('cdk-overlay-'); |
| 84 | pane.classList.add('cdk-overlay-pane'); |
| 85 | host.appendChild(pane); |
| 86 | |
| 87 | if (overlayConfig.usePopover) { |
| 88 | host.setAttribute('popover', 'manual'); |
| 89 | host.classList.add('cdk-overlay-popover'); |
| 90 | } |
| 91 | |
| 92 | const customInsertionPoint = overlayConfig.usePopover |
| 93 | ? overlayConfig.positionStrategy?.getPopoverInsertionPoint?.() |
| 94 | : null; |
| 95 | |
| 96 | if (isElement(customInsertionPoint)) { |
| 97 | customInsertionPoint.after(host); |
| 98 | } else if (customInsertionPoint?.type === 'parent') { |
| 99 | customInsertionPoint.element.appendChild(host); |
| 100 | } else { |
| 101 | overlayContainer.getContainerElement().appendChild(host); |
| 102 | } |
| 103 | |
| 104 | return new OverlayRef( |
| 105 | new DomPortalOutlet(pane, appRef, injector), |
| 106 | host, |
| 107 | pane, |
| 108 | overlayConfig, |
| 109 | injector.get(NgZone), |