jiro-ui
Version:
A Mithril.js UI library based from construct-ui
61 lines (47 loc) • 1.73 kB
text/typescript
import m from 'mithril';
import classnames from 'classnames';
import { Classes, IAttrs, safeCall, normalizeStyle } from '../../_shared';
export interface IPortalAttrs extends IAttrs {
/** Callback invoked when the component is mounted */
onContentMount?: (rootElement: HTMLElement) => void;
/** Optional HTML element to mount to */
container?: HTMLElement;
}
export class Portal implements m.Component<IPortalAttrs> {
private rootElement: HTMLElement;
private content: m.Component;
public oncreate({ attrs, children }: m.Vnode<IPortalAttrs>) {
const rootElement = document.createElement('div');
const container = attrs.container || document.body;
container.appendChild(rootElement);
this.rootElement = rootElement;
this.setStyles(attrs);
this.content = { view: () => children };
m.mount(this.rootElement, this.content);
safeCall(attrs.onContentMount, rootElement);
}
public onupdate({ attrs }: m.Vnode<IPortalAttrs>) {
this.setStyles(attrs);
}
public onbeforeupdate({ children }: m.Vnode<IPortalAttrs>) {
if (!this.content) return false;
this.content.view = () => children;
}
public onremove({ attrs }: m.Vnode<IPortalAttrs>) {
const container = attrs.container || document.body;
if (container.contains(this.rootElement)) {
m.mount(this.rootElement, null);
container.removeChild(this.rootElement);
}
}
public view() {
return m.fragment({}, '');
}
private setStyles(attrs: IPortalAttrs) {
this.rootElement.className = classnames(Classes.PORTAL, attrs.class);
this.rootElement.style.cssText = '';
if (attrs.style) {
Object.assign(this.rootElement.style, normalizeStyle(attrs.style));
}
}
}