mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-27 21:28:14 +00:00
* feat: popup可以接受外部参数 目前配置都是固定的,对于一些简单定制化的需求无法满足 * feat: 增加类型约束,固定可修改项 * Revert "feat: 增加类型约束,固定可修改项" This reverts commit 7e3b4dd1fafce56bfb94d7f77fda729eec4066d0. * feat: 添加类型
207 lines
5.2 KiB
TypeScript
207 lines
5.2 KiB
TypeScript
import { createContext, ReactNode, Component, PureComponent } from 'react';
|
|
import { Drawer, ConfigProvider } from '@alifd/next';
|
|
import { uniqueId } from '@alilc/lowcode-utils';
|
|
import { IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
|
|
import './style.less';
|
|
|
|
export interface PopupExtProps {
|
|
width?: number;
|
|
hasMask?: boolean;
|
|
trigger?: ReactNode;
|
|
canCloseByOutSideClick?: boolean
|
|
className?: string;
|
|
safeNode?: string[];
|
|
}
|
|
|
|
interface PopupProps extends PopupExtProps{
|
|
content?: ReactNode,
|
|
title?: ReactNode,
|
|
actionKey?: string
|
|
}
|
|
|
|
|
|
export const PopupContext = createContext<PopupPipe>({} as any);
|
|
|
|
export class PopupPipe {
|
|
private emitter: IEventBus = createModuleEventBus('PopupPipe');
|
|
|
|
private currentId?: string;
|
|
|
|
create(props?: PopupExtProps): {
|
|
send: (content: ReactNode, title: ReactNode) => void;
|
|
show: (target: Element) => void;
|
|
} {
|
|
let sendContent: ReactNode = null;
|
|
let sendTitle: ReactNode = null;
|
|
const id = uniqueId('popup');
|
|
return {
|
|
send: (content: ReactNode, title: ReactNode) => {
|
|
sendContent = content;
|
|
sendTitle = title;
|
|
if (this.currentId === id) {
|
|
this.popup({
|
|
...props,
|
|
content,
|
|
title,
|
|
});
|
|
}
|
|
},
|
|
show: (target: Element, actionKey?: string) => {
|
|
this.currentId = id;
|
|
this.popup(
|
|
{
|
|
...props,
|
|
actionKey,
|
|
content: sendContent,
|
|
title: sendTitle,
|
|
},
|
|
target,
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
private popup(props: PopupProps, target?: Element) {
|
|
Promise.resolve().then(() => {
|
|
this.emitter.emit('popupchange', props, target);
|
|
});
|
|
}
|
|
|
|
onPopupChange(fn: (props: PopupProps, target?: Element) => void): () => void {
|
|
this.emitter.on('popupchange', fn);
|
|
return () => {
|
|
this.emitter.removeListener('popupchange', fn);
|
|
};
|
|
}
|
|
|
|
purge() {
|
|
this.emitter.removeAllListeners();
|
|
}
|
|
}
|
|
|
|
export default class PopupService extends Component<{
|
|
popupPipe?: PopupPipe;
|
|
actionKey?: string;
|
|
safeId?: string;
|
|
popupContainer?: string;
|
|
}> {
|
|
private popupPipe = this.props.popupPipe || new PopupPipe();
|
|
|
|
componentWillUnmount() {
|
|
this.popupPipe.purge();
|
|
}
|
|
|
|
render() {
|
|
const { children, actionKey, safeId, popupContainer } = this.props;
|
|
return (
|
|
<PopupContext.Provider value={this.popupPipe}>
|
|
{children}
|
|
<PopupContent key={`pop${actionKey}`} safeId={safeId} popupContainer={popupContainer} />
|
|
</PopupContext.Provider>
|
|
);
|
|
}
|
|
}
|
|
|
|
interface StateType extends PopupProps {
|
|
visible?: boolean,
|
|
offsetX?: number,
|
|
pos?: {top: number, height: number}
|
|
}
|
|
export class PopupContent extends PureComponent<{ safeId?: string; popupContainer?: string }> {
|
|
static contextType = PopupContext;
|
|
|
|
popupContainerId = uniqueId('popupContainer');
|
|
|
|
state: StateType = {
|
|
visible: false,
|
|
offsetX: -300,
|
|
};
|
|
|
|
private dispose = (this.context as PopupPipe).onPopupChange((props, target) => {
|
|
const state: StateType = {
|
|
...props,
|
|
visible: true,
|
|
};
|
|
if (target) {
|
|
const rect = target.getBoundingClientRect();
|
|
state.pos = {
|
|
top: rect.top,
|
|
height: rect.height,
|
|
};
|
|
// todo: compute the align method
|
|
}
|
|
this.setState(state);
|
|
});
|
|
|
|
componentDidMount() {
|
|
const clientWidth = document.documentElement.clientWidth || document.body.clientWidth;
|
|
if (clientWidth >= 1860) {
|
|
this.setState({
|
|
offsetX: -400,
|
|
});
|
|
}
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.dispose();
|
|
}
|
|
|
|
onClose = () => {
|
|
this.setState({
|
|
visible: false,
|
|
});
|
|
};
|
|
|
|
render() {
|
|
const { content, visible, title, actionKey, pos, offsetX, width = 360, hasMask = false, canCloseByOutSideClick = true, safeNode = [] } = this.state;
|
|
if (!visible) {
|
|
return null;
|
|
}
|
|
|
|
let avoidLaterHidden = true;
|
|
setTimeout(() => {
|
|
avoidLaterHidden = false;
|
|
}, 10);
|
|
|
|
const id = uniqueId('ball');
|
|
|
|
return (
|
|
<Drawer
|
|
width={width}
|
|
visible={visible}
|
|
offset={[offsetX, 0]}
|
|
hasMask={hasMask}
|
|
onVisibleChange={(_visible, type) => {
|
|
if (avoidLaterHidden) {
|
|
return;
|
|
}
|
|
if (!_visible && type === 'closeClick') {
|
|
this.setState({ visible: false });
|
|
}
|
|
}}
|
|
trigger={<div className="lc-popup-placeholder" style={pos} />}
|
|
triggerType="click"
|
|
canCloseByOutSideClick={canCloseByOutSideClick}
|
|
animation={false}
|
|
onClose={this.onClose}
|
|
id={this.props.safeId}
|
|
safeNode={[id, ...safeNode]}
|
|
closeable
|
|
container={this.props.popupContainer}
|
|
>
|
|
<div className="lc-ballon-title">{title}</div>
|
|
<div className="lc-ballon-content">
|
|
<PopupService actionKey={actionKey} safeId={id} popupContainer={this.popupContainerId}>
|
|
<ConfigProvider popupContainer={this.popupContainerId}>
|
|
{content}
|
|
</ConfigProvider>
|
|
</PopupService>
|
|
</div>
|
|
<div id={this.popupContainerId} />
|
|
<div id="engine-variable-setter-dialog" />
|
|
<div id="engine-popup-container" />
|
|
</Drawer>
|
|
);
|
|
}
|
|
}
|