import { Portal, Show, render } from "solid-js/web";
import createModel from "../utils/createModel";
import usePortal from "../utils/usePortal";
import { useClassList } from "../utils/useProps";
import { Draggable } from "../Draggable";
import { Icon } from "../Icon";
import { Button } from "../Button";
import { JSXElement, createEffect, createSignal, createUniqueId, untrack } from "solid-js";
import usezIndex from "../utils/usezIndex";
type Position = {
top?: string,
bottom?: string,
left?: string,
right?: string,
}
type ModalProps = {
bounds?: string,
disabled?: boolean,
style?: any,
classList?: any,
class?: string,
title?: any,
bodyStyle?: any,
children?: any,
footer?: boolean,
loading?: boolean | Function[],
onOk?: Function,
onCancel?: Function,
onClosed?: Function,
onClickClose?: Function,
okText?: any,
cancleText?: any,
visible?: boolean | Function[],
defaultPosition?: Position,
mask?: boolean,
maskClosable?: boolean,
resetPostion?: boolean,
hasCloseIcon?: boolean
fullScreen?: boolean
}
export function Modal (props: ModalProps) {
let wrap: any;
let maskEle: any;
let draggable: any;
const [visible, setVisible] = createModel(props, 'visible', false);
const [loading, setLoading] = createSignal(false);
let setOverflow = false;
let originOverflow = '';
const classList = () => useClassList(props, 'cm-modal');
const zindex = usezIndex();
const wrapClass = () => ({
'cm-modal-wrap': true,
'cm-modal-visible': visible(),
'cm-modal-fullscreen': props.fullScreen,
});
const maskClass = () => ({
'cm-modal-mask': true,
'cm-modal-mask-visible': visible()
});
const onClickClose = () => {
props.onClickClose && props.onClickClose();
onClose();
}
const onClose = () => {
props.onClosed && props.onClosed();
setVisible(false);
}
const onCancel = () => {
onClose();
props.onCancel && props.onCancel();
}
const onOk = () => {
props.onOk && props.onOk();
if (props.loading) {
if (!loading()) {
setLoading(true);
}
return;
}
onClose();
}
createEffect(() => {
const show = visible();
if (!show) {
setLoading(false);
if (setOverflow) {
document.body.style.overflow = originOverflow;
setOverflow = false;
}
} else {
if(wrap) {
const wrapH = wrap.getBoundingClientRect().height;
const contentH = wrap.children[0].getBoundingClientRect().height;
// 超出显示内容
if (contentH > wrapH) {
wrap.style.overflow = 'auto';
wrap.children[0].style.top = 0;
const bodyStyle = window.getComputedStyle(document.body, null);
originOverflow = bodyStyle.overflow;
if (originOverflow !== 'hidden') {
document.body.style.overflow = 'hidden';
setOverflow = true;
}
} else {
wrap.style.overflow = 'none';
setOverflow = false;
}
setTimeout(() => {
wrap.focus();
}, 300);
}
if (resetPostion) {
if (draggable) {
draggable.reset();
}
}
}
});
const onMaskClick = (e: any) => {
if (maskClosable) {
if (e.target === maskEle) {
setVisible(false);
}
}
}
const onkeydown = (e: any) => {
// e.preventDefault && e.preventDefault();
// e.stopPropagation && e.stopPropagation();
if (e.keyCode === 27) {
setVisible(false);
}
}
const id = 'cm-modal-portal';
const footer = props.footer ?? true;
const hasCloseIcon = props.hasCloseIcon ?? true;
const modalId = createUniqueId();
const okText = props.okText || '确 定';
const cancleText = props.cancleText || '取 消';
const mask = props.mask ?? true;
const maskClosable = props.maskClosable ?? true;
const resetPostion = props.resetPostion ?? false;
return
}
export interface ModalConfig extends ModalProps{
content?: JSXElement,
status?: 'success'|'info'|'warning'|'error'|'confirm'
}
function ModalFun () {
const [visible, setVisible] = createSignal(true);
let disposeFn: Function;
return {
open (config: ModalConfig) {
setVisible(true);
let icon = '';
if (config.status === 'success') {
icon = 'check-circle'
}
if (config.status === 'info') {
icon = 'info'
}
if (config.status === 'warning') {
icon = 'alert-circle'
}
if (config.status === 'error') {
icon = 'x-circle'
}
if (config.status === 'confirm') {
icon = 'help-circle'
}
const close = (v: boolean) => {
setVisible(v);
setTimeout(() => {
disposeFn?.()
}, 250)
}
config.style = {'min-width': '24vw', ...config.style};
config.visible = [visible, close];
config.defaultPosition = {top: '200px', ...config.defaultPosition};
const ele = usePortal('cm-modal-portal-instance', 'cm-modal-portal');
const disposeFn = render(() =>
{config.content}
, ele);
},
success (config: ModalConfig) {
config.status = 'success';
return this.open(config);
},
info (config: ModalConfig) {
config.status = 'info';
return this.open(config);
},
warning (config: ModalConfig) {
config.status = 'warning';
return this.open(config);
},
error (config: ModalConfig) {
config.status = 'error';
return this.open(config);
},
confirm (config: ModalConfig) {
config.status = 'confirm';
return this.open(config);
},
remove () {
setVisible(false);
setTimeout(() => {
disposeFn?.()
}, 250)
}
}
}
export const modal = ModalFun();