Files
owl/src/portal.ts
T

75 lines
1.9 KiB
TypeScript
Raw Normal View History

import { onWillUnmount } from ".";
import { xml } from "./app/template_set";
2021-11-16 16:47:20 +01:00
import { BDom, text, VNode } from "./blockdom";
import { Component } from "./component/component";
2019-11-15 13:24:07 +01:00
2020-11-26 16:45:25 +01:00
const VText: any = text("").constructor;
2019-11-15 13:24:07 +01:00
class VPortal extends VText implements Partial<VNode<VPortal>> {
2020-11-26 16:45:25 +01:00
// selector: string;
realBDom: BDom | null;
target: HTMLElement | null = null;
2019-11-15 13:24:07 +01:00
2020-11-26 16:45:25 +01:00
constructor(selector: string, realBDom: BDom) {
super("");
this.selector = selector;
this.realBDom = realBDom;
2019-11-15 13:24:07 +01:00
}
2020-11-26 16:45:25 +01:00
mount(parent: HTMLElement, anchor: ChildNode) {
super.mount(parent, anchor);
this.target = document.querySelector(this.selector) as any;
if (!this.target) {
let el: any = this.el;
while (el && el.parentElement instanceof HTMLElement) {
el = el.parentElement;
}
this.target = el && el.querySelector(this.selector);
if (!this.target) {
throw new Error("invalid portal target");
2019-11-15 13:24:07 +01:00
}
}
2020-11-26 16:45:25 +01:00
this.realBDom!.mount(this.target!, null);
2019-11-15 13:24:07 +01:00
}
2020-11-26 16:45:25 +01:00
beforeRemove() {
this.realBDom!.beforeRemove();
2019-11-15 13:24:07 +01:00
}
2020-11-26 16:45:25 +01:00
remove() {
super.remove();
this.realBDom!.remove();
this.realBDom = null;
2019-11-15 13:24:07 +01:00
}
2020-11-26 16:45:25 +01:00
patch(other: VPortal) {
super.patch(other);
if (this.realBDom) {
this.realBDom.patch(other.realBDom!, true);
} else {
this.realBDom = other.realBDom;
this.realBDom!.mount(this.target!, null);
2019-11-15 13:24:07 +01:00
}
2020-11-26 16:45:25 +01:00
}
}
export class Portal extends Component {
static template = xml`<t t-slot="default"/>`;
static props = {
target: {
type: String,
},
slots: true,
};
setup() {
const node = this.__owl__;
const renderFn = node.renderFn;
node.renderFn = () => new VPortal(this.props.target, renderFn());
onWillUnmount(async () => {
await Promise.resolve();
if (node.bdom && (node.bdom as any).realBDom) {
(node.bdom as any).realBDom.remove();
}
});
}
}