jiro-ui
Version:
A Mithril.js UI library based from construct-ui
151 lines (122 loc) • 3.56 kB
text/typescript
import m from 'mithril';
import classnames from 'classnames';
import { Classes, IAttrs, safeCall } from '../../_shared';
import { AbstractComponent } from '../abstract-component';
import { IToastAttrs, Toast } from './Toast';
import { Overlay } from '../overlay';
export type IToastOptions = IToastAttrs & { key?: string };
export const ToasterPosition = {
TOP: 'top' as 'top',
TOP_START: 'top-start' as 'top-start',
TOP_END: 'top-end' as 'top-end',
BOTTOM: 'bottom' as 'bottom',
BOTTOM_START: 'bottom-start' as 'bottom-start',
BOTTOM_END: 'bottom-end' as 'bottom-end'
};
export type ToasterPosition = typeof ToasterPosition[keyof typeof ToasterPosition];
export interface IToaster {
/** Show toast */
show(attrs: IToastAttrs): string;
/** Update toast attrs by key */
update(key: string, attrs: IToastAttrs): void;
/** Dismiss toast by key */
dismiss(key: string): void;
/** Clear all toasts */
clear(): void;
/** Get array of toasts */
getToasts(): IToastOptions[];
}
export interface IToasterAttrs extends IAttrs {
/**
* Clears all toasts on ESCAPE key
* @default true
*/
clearOnEscapeKey?: boolean;
/** Renders component relative to parent container */
inline?: boolean;
/**
* Position of each toast item
* @default 'top'
*/
position?: ToasterPosition;
/** Array of `Toast` items when used in declarative mode */
toasts?: m.Vnode<IToastAttrs, any>[];
}
export class Toaster extends AbstractComponent<IToasterAttrs> {
private toasts: IToastOptions[] = [];
private toastId: number = 0;
public getDefaultAttrs() {
return {
clearOnEscapeKey: true,
position: 'top'
} as IToasterAttrs;
}
public view() {
const {
class: className,
position,
inline,
toasts,
clearOnEscapeKey,
style
} = this.attrs;
const classes = classnames(
Classes.TOASTER,
`${Classes.TOASTER}-${position}`,
inline && Classes.TOASTER_INLINE,
className
);
const renderedToasts = this.isControlled()
? toasts || []
: this.toasts.map(toastOptions => this.renderToast(toastOptions));
return m(Overlay, {
closeOnEscapeKey: clearOnEscapeKey,
closeOnOutsideClick: false,
class: classes,
content: renderedToasts,
hasBackdrop: false,
inline,
isOpen: renderedToasts.length > 0,
transitionDuration: 0,
addToStack: false,
onClose: () => this.clear(),
style
});
}
public onremove() {
this.clear();
}
public show(attrs: IToastAttrs) {
const toastOptions = { ...attrs, key: `cui-toast-${this.toastId++}` };
this.toasts.push(toastOptions);
return toastOptions.key;
}
public update(key: string | number, attrs: IToastOptions) {
const index = this.toasts.findIndex(x => x.key === key);
this.toasts[index] = {
...this.toasts[index],
...attrs
};
}
public dismiss = (key: string | number, timedOut: boolean = false) => {
const index = this.toasts.findIndex(x => x.key === key);
const toast = this.toasts[index];
if (toast) {
safeCall(toast.onDismiss, timedOut);
this.toasts.splice(index, 1);
}
}
public clear() {
this.toasts.map((x) => safeCall(x.onDismiss, false));
this.toasts.length = 0;
}
public getToasts() {
return this.toasts;
}
private renderToast(attrs: IToastOptions) {
return m(Toast, { ...attrs, onDismiss: this.dismiss });
}
private isControlled() {
return this.attrs.toasts != null;
}
}