@highloop/feedback-internal
Version:
192 lines (153 loc) • 5.13 kB
text/typescript
import outsideClick from '@varld/outside-click';
import { HighloopFeedbackCore, events } from '../core';
import type { IData, ITheme } from '../interfaces/data';
import type { IText } from '../interfaces/text';
import { getPopoverWrapper } from '../lib/getPopoverWrapper';
export type DialogWidget = ReturnType<typeof createDialogWidget>;
export type DialogWidgetOpts = Parameters<typeof createDialogWidget>[1];
export type DialogPosition = 'top' | 'bottom' | 'center';
export let createDialogWidget = (
id: string,
opts: {
meta?: any;
apiEndpoint?: string;
theme?: ITheme;
demo?: IData;
text?: IText;
expanded?: boolean;
closeOnOutsideClick?: boolean;
} & (
| {
position?: 'center';
blanket?: boolean;
}
| {
position?: 'top' | 'bottom';
}
) = {}
) => {
if (typeof window == 'undefined') return;
let position = opts.position || 'bottom';
// Setup wrapper element
let wrapper = getPopoverWrapper();
let root = document.createElement('div');
root.style.zIndex = '99998';
root.style.opacity = '0';
root.style.left = '0px';
root.style.right = '0px';
root.style.position = 'fixed';
root.style.pointerEvents = 'none';
root.style.transition = 'all 0.3s';
let inner = document.createElement('div');
inner.style.width = 'min(400px, 100vw)';
inner.style.height = 'fit-content';
inner.style.margin = '0px auto';
inner.style.overflow = 'hidden';
inner.style.boxShadow = '0 8px 30px rgba(0,0,0,0.12)';
inner.style.pointerEvents = 'none';
inner.style.transition = 'all 0.3s';
inner.style.zIndex = '99999';
if (position == 'bottom') {
root.style.bottom = '-30px';
inner.style.borderTopLeftRadius = '14px';
inner.style.borderTopRightRadius = '14px';
}
if (position == 'top') {
root.style.top = '-30px';
inner.style.borderBottomLeftRadius = '14px';
inner.style.borderBottomRightRadius = '14px';
}
if (opts.position == 'center') {
root.style.top = '0px';
root.style.bottom = '0px';
root.style.display = 'flex';
root.style.justifyContent = 'center';
root.style.alignItems = 'center';
inner.style.borderRadius = '14px';
inner.style.transform = 'translateY(20px)';
if (opts.blanket) {
root.style.background = 'rgba(0, 0, 0, 0.4)';
}
}
wrapper.appendChild(root);
root.appendChild(inner);
// Setup widget instance
let instance = new HighloopFeedbackCore(id, {
...opts,
closable: true,
root: inner
});
let hideTo: number;
let open = () => {
if (instance.isMounted) return;
clearTimeout(hideTo);
instance.render();
root.style.opacity = '1';
inner.style.pointerEvents = 'all';
if (position == 'bottom') {
root.style.bottom = '0px';
}
if (position == 'top') {
root.style.top = '0px';
}
if (opts.position == 'center') {
inner.style.transform = 'translateY(0px)';
if (opts.blanket) {
root.style.pointerEvents = 'all';
}
}
};
let close = () => {
if (!instance.isMounted) return;
root.style.opacity = '0';
inner.style.pointerEvents = 'none';
if (position == 'bottom') {
root.style.bottom = '-30px';
}
if (position == 'top') {
root.style.top = '-30px';
}
if (opts.position == 'center') {
inner.style.transform = 'translateY(20px)';
if (opts.blanket) {
root.style.pointerEvents = 'none';
}
}
hideTo = setTimeout(() => instance.destroy(), 300) as unknown as number;
};
let toggle = () => (instance.isMounted ? close() : open());
let unregisterClose = instance.on(events.CLOSE, () => close());
let unregisterSubmit = instance.on(events.SUBMIT, () => setTimeout(() => close(), 3000));
let unregisterOutsideClick = opts.closeOnOutsideClick
? outsideClick([root], () => close())
: undefined;
let escapeHandler = (e: KeyboardEvent) => {
if (e.key === 'Escape') close();
};
document.addEventListener('keyup', escapeHandler);
let innerClick = (e: MouseEvent) => e.stopPropagation();
inner.addEventListener('click', innerClick);
if (opts.position == 'center' && opts.blanket) {
root.addEventListener('click', close);
}
return {
destroy: () => {
document.removeEventListener('keyup', escapeHandler);
if (opts.position == 'center' && opts.blanket) {
root.removeEventListener('click', close);
}
unregisterClose();
unregisterSubmit();
if (unregisterOutsideClick) unregisterOutsideClick();
instance.destroy();
},
instance: instance,
open,
close,
toggle,
setMeta: (meta: any) => instance.setMeta(meta),
setTheme: (theme: ITheme) => instance.setTheme(theme),
on: <T>(type: string, handler: (d: T) => unknown) => instance.on(type, handler),
once: <T>(type: string, handler: (d: T) => unknown) => instance.once(type, handler)
};
};