change pkg
This commit is contained in:
201
packages/dooringx-lib/src/components/blocks.tsx
Normal file
201
packages/dooringx-lib/src/components/blocks.tsx
Normal file
@@ -0,0 +1,201 @@
|
||||
import { IBlockType } from '../core/store/storetype';
|
||||
import { CSSProperties, PropsWithChildren, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { innerDrag } from '../core/innerDrag';
|
||||
import { BlockResizer } from '../core/resizeHandler';
|
||||
import { contextMenuEvent } from '../core/contextMenu';
|
||||
import React from 'react';
|
||||
import { transfer } from '../core/transfer';
|
||||
import { UserConfig } from '../config';
|
||||
import styles from '../index.less';
|
||||
interface BlockProps {
|
||||
data: IBlockType;
|
||||
context: 'edit' | 'preview';
|
||||
config: UserConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 用来从component里拿到渲染进行渲染,由于异步拉代码,所以需要等待代码拉取完毕
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
function Blocks(props: PropsWithChildren<BlockProps>) {
|
||||
const [state, setState] = useState<JSX.Element | null>(null);
|
||||
|
||||
const [previewState, setPreviewState] = useState({
|
||||
top: props.data.top,
|
||||
left: props.data.left,
|
||||
height: props.data.height,
|
||||
width: props.data.width,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const fn = () => props.config.getComponentRegister().getComp(props.data.name);
|
||||
const data = fn();
|
||||
let unregist = () => {};
|
||||
let newdata = { ...props.data };
|
||||
if (props.context === 'preview') {
|
||||
newdata = {
|
||||
...props.data,
|
||||
top: previewState.top,
|
||||
left: previewState.left,
|
||||
height: previewState.height,
|
||||
width: previewState.width,
|
||||
};
|
||||
}
|
||||
|
||||
if (data) {
|
||||
setState(data.render(newdata, props.context, props.config.getStore(), props.config));
|
||||
} else {
|
||||
const callback = () => {
|
||||
const tmp = fn();
|
||||
setState(tmp.render(newdata, props.context, props.config.getStore(), props.config));
|
||||
unregist();
|
||||
};
|
||||
unregist = props.config.getComponentRegister().on(props.data.name, callback);
|
||||
}
|
||||
return () => {
|
||||
unregist();
|
||||
};
|
||||
}, [props.data, props.context, props.config, previewState]);
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const innerDragData = useMemo(() => {
|
||||
return { ...innerDrag(props.data, ref) };
|
||||
}, [props.data]);
|
||||
|
||||
useEffect(() => {
|
||||
const fn = () => {
|
||||
const { top, left, width, height } = transfer(
|
||||
props.data.top,
|
||||
props.data.left,
|
||||
props.data.height,
|
||||
props.data.width,
|
||||
props.data.fixed
|
||||
);
|
||||
|
||||
setPreviewState({ top, left, width, height });
|
||||
};
|
||||
fn();
|
||||
window.addEventListener('resize', fn);
|
||||
return () => {
|
||||
window.removeEventListener('resize', fn);
|
||||
};
|
||||
}, [
|
||||
previewState.height,
|
||||
previewState.left,
|
||||
previewState.top,
|
||||
previewState.width,
|
||||
props.data.height,
|
||||
props.data.left,
|
||||
props.data.top,
|
||||
props.data.width,
|
||||
props.data.fixed,
|
||||
]);
|
||||
|
||||
const animatecss = useMemo(() => {
|
||||
const animate = props.data.animate;
|
||||
if (Object.keys(animate).length > 0) {
|
||||
return `animate__animated ${animate.animate ?? ''} ${animate.delay ?? ''} ${
|
||||
animate.speed ?? ''
|
||||
}`;
|
||||
}
|
||||
return '';
|
||||
}, [
|
||||
props.data.animate.animate,
|
||||
props.data.animate.delay,
|
||||
// props.data.animate.duration,
|
||||
props.data.animate.speed,
|
||||
]);
|
||||
const animateCount = useMemo(() => {
|
||||
const animate = props.data.animate;
|
||||
|
||||
if (Object.keys(animate).length > 0) {
|
||||
return { animationIterationCount: animate.animationIterationCount };
|
||||
}
|
||||
return { animationIterationCount: 1 };
|
||||
}, [props.data.animate.animationIterationCount]);
|
||||
|
||||
const render = useMemo(() => {
|
||||
// 如果是编辑模式下,则需要包裹不能选中层,位移层,缩放控制层,平面移动层。
|
||||
if (state && props.context === 'edit') {
|
||||
const style: CSSProperties = props.data.canDrag ? { pointerEvents: 'none' } : {};
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={
|
||||
props.data.focus && props.data.position !== 'static' ? styles.yh_block_focus : ''
|
||||
}
|
||||
style={{
|
||||
position: props.data.position,
|
||||
top: props.data.top,
|
||||
left: props.data.left,
|
||||
width: props.data.width,
|
||||
height: props.data.height,
|
||||
zIndex: props.data.zIndex,
|
||||
display: props.data.display,
|
||||
}}
|
||||
{...innerDragData}
|
||||
onContextMenu={(e) => {
|
||||
if (props.data.name !== 'modalMask') {
|
||||
contextMenuEvent(e, ref);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{props.data.position !== 'static' && (
|
||||
<div className={animatecss} style={{ ...style, ...animateCount }}>
|
||||
{state}
|
||||
</div>
|
||||
)}
|
||||
{/* 这里暂不考虑布局影响 */}
|
||||
{props.data.position === 'static' && props.data.display !== 'inline' && (
|
||||
<div
|
||||
className={animatecss}
|
||||
style={{
|
||||
pointerEvents: 'none',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
...animateCount,
|
||||
}}
|
||||
>
|
||||
{state}
|
||||
</div>
|
||||
)}
|
||||
{props.data.position === 'static' && props.data.display === 'inline' && (
|
||||
<span style={{ pointerEvents: 'none' }}>{state}</span>
|
||||
)}
|
||||
<BlockResizer data={props.data} rect={ref}></BlockResizer>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
className={animatecss}
|
||||
style={{
|
||||
position: props.data.fixed ? 'fixed' : props.data.position,
|
||||
top: previewState.top,
|
||||
left: previewState.left,
|
||||
width: previewState.width,
|
||||
height: previewState.height,
|
||||
zIndex: props.data.zIndex,
|
||||
display: props.data.display,
|
||||
...animateCount,
|
||||
}}
|
||||
>
|
||||
{state}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}, [
|
||||
state,
|
||||
props.context,
|
||||
props.data,
|
||||
innerDragData,
|
||||
previewState.top,
|
||||
previewState.left,
|
||||
previewState.width,
|
||||
previewState.height,
|
||||
]);
|
||||
return render;
|
||||
}
|
||||
export default Blocks;
|
131
packages/dooringx-lib/src/components/container.tsx
Normal file
131
packages/dooringx-lib/src/components/container.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import { containerDragResolve } from '../core/crossDrag';
|
||||
import { containerFocusRemove } from '../core/focusHandler';
|
||||
import { innerContainerDrag } from '../core/innerDrag';
|
||||
import { NormalMarkLineRender } from '../core/markline';
|
||||
import { scaleState } from '../core/scale/state';
|
||||
import { IStoreData } from '../core/store/storetype';
|
||||
import { wrapperMoveState } from './wrapperMove/event';
|
||||
import { CSSProperties, PropsWithChildren, useMemo } from 'react';
|
||||
import Blocks from './blocks';
|
||||
import { containerResizer } from '../core/resizeHandler/containerResizer';
|
||||
import React from 'react';
|
||||
import UserConfig from '../config';
|
||||
import styles from '../index.less';
|
||||
import { getRealHeight } from '../core/transfer';
|
||||
import { IconFont } from '../core/utils/icon';
|
||||
interface ContainerProps {
|
||||
state: IStoreData;
|
||||
context: 'edit' | 'preview';
|
||||
config: UserConfig;
|
||||
editContainerStyle?: CSSProperties;
|
||||
previewContainerStyle?: CSSProperties;
|
||||
}
|
||||
function Container(props: PropsWithChildren<ContainerProps>) {
|
||||
const { editContainerStyle, previewContainerStyle } = props;
|
||||
|
||||
const transform = useMemo(() => {
|
||||
if (props.context === 'edit') {
|
||||
return `scale(${scaleState.value}) translate(${wrapperMoveState.needX}px, ${wrapperMoveState.needY}px)`;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}, [props.context]);
|
||||
|
||||
const bgColor = () => {
|
||||
const isEdit = props.config.getStoreChanger().isEdit();
|
||||
if (isEdit) {
|
||||
return 'rgba(255,255,255,1)';
|
||||
} else {
|
||||
return props.state.globalState.containerColor;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{props.context === 'edit' && (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
height: `${props.state.container.height + 60}px`,
|
||||
width: `${props.state.container.width}px`,
|
||||
transform: `scale(${scaleState.value}) translate(${wrapperMoveState.needX}px, ${wrapperMoveState.needY}px)`,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div
|
||||
id="yh-container"
|
||||
className={styles.yh_container}
|
||||
style={{
|
||||
height: `${props.state.container.height}px`,
|
||||
width: `${props.state.container.width}px`,
|
||||
backgroundColor: bgColor(),
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
...editContainerStyle,
|
||||
}}
|
||||
{...(props.context === 'edit' ? containerDragResolve : null)}
|
||||
{...(props.context === 'edit' ? innerContainerDrag() : null)}
|
||||
{...(props.context === 'edit' ? containerFocusRemove() : null)}
|
||||
>
|
||||
{props.context === 'edit' && <NormalMarkLineRender></NormalMarkLineRender>}
|
||||
{props.state.block.map((v) => {
|
||||
return (
|
||||
<Blocks
|
||||
config={props.config}
|
||||
key={v.id}
|
||||
data={v}
|
||||
context={props.context}
|
||||
></Blocks>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
height: '50px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
width: `${props.state.container.width}px`,
|
||||
}}
|
||||
>
|
||||
<IconFont
|
||||
type="icon-suofang"
|
||||
onMouseDown={containerResizer.onMousedown}
|
||||
style={{ fontSize: '20px', cursor: 's-resize' }}
|
||||
></IconFont>
|
||||
{/* <BoxPlotFilled
|
||||
onMouseDown={containerResizer.onMousedown}
|
||||
style={{ fontSize: '20px', cursor: 's-resize' }}
|
||||
rotate={90}
|
||||
/> */}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{props.context === 'preview' && (
|
||||
<div
|
||||
id="yh-container-preview"
|
||||
className={styles.yh_container_preview}
|
||||
style={{
|
||||
height: `${getRealHeight(props.state.container.height)}px`,
|
||||
width: `100%`,
|
||||
position: 'relative' as 'absolute' | 'relative',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: bgColor(),
|
||||
transform: transform,
|
||||
...previewContainerStyle,
|
||||
}}
|
||||
>
|
||||
{props.state.block.map((v) => {
|
||||
return (
|
||||
<Blocks key={v.id} config={props.config} data={v} context={props.context}></Blocks>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default Container;
|
281
packages/dooringx-lib/src/components/control.tsx
Normal file
281
packages/dooringx-lib/src/components/control.tsx
Normal file
@@ -0,0 +1,281 @@
|
||||
import {
|
||||
CompressOutlined,
|
||||
DeleteOutlined,
|
||||
FullscreenExitOutlined,
|
||||
FullscreenOutlined,
|
||||
GatewayOutlined,
|
||||
MenuOutlined,
|
||||
SyncOutlined,
|
||||
UnorderedListOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Button, Divider, Form, Input, List, Modal, Popconfirm, Popover } from 'antd';
|
||||
import React, { CSSProperties, PropsWithChildren, useState } from 'react';
|
||||
import { UserConfig } from '..';
|
||||
import { IBlockType, IStoreData } from '../core/store/storetype';
|
||||
import { deepCopy, arrayMove, changeItem, changeLayer, focusEle } from '../core/utils';
|
||||
|
||||
import { SortEnd, SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
|
||||
import { wrapperMoveState } from './wrapperMove/event';
|
||||
export interface ControlProps {
|
||||
config: UserConfig;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
const DragHandle = SortableHandle(() => <MenuOutlined />);
|
||||
const SortableItem = SortableElement(
|
||||
({ value }: { value: { value: IBlockType; config: UserConfig } }) => (
|
||||
<div
|
||||
style={{
|
||||
userSelect: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: 430,
|
||||
}}
|
||||
>
|
||||
<div style={{ width: 30, textAlign: 'center', cursor: 'move' }}>
|
||||
<DragHandle></DragHandle>
|
||||
</div>
|
||||
<Divider type="vertical"></Divider>
|
||||
<div style={{ width: 100, textAlign: 'center' }}>
|
||||
{value.config.getComponentRegister().getMap()[value.value.name].display}
|
||||
</div>
|
||||
<Divider type="vertical"></Divider>
|
||||
<div style={{ width: 50, textAlign: 'center' }}>{value.value.id.slice(-6)}</div>
|
||||
<Divider type="vertical"></Divider>
|
||||
<div style={{ width: 50, textAlign: 'center' }}>{value.value.position}</div>
|
||||
<Divider type="vertical"></Divider>
|
||||
<div style={{ width: 200 }}>
|
||||
<Popconfirm
|
||||
title="确认变更为绝对定位吗?"
|
||||
onConfirm={() => {
|
||||
changeItem(value.config.getStore(), value.value.id, 'position', 'absolute');
|
||||
}}
|
||||
>
|
||||
<Button type="link" title="切换绝对定位" icon={<FullscreenOutlined />}></Button>
|
||||
</Popconfirm>
|
||||
<Popconfirm
|
||||
title="确认变更为静态定位吗?"
|
||||
onConfirm={() => {
|
||||
changeItem(value.config.getStore(), value.value.id, 'position', 'static');
|
||||
}}
|
||||
>
|
||||
<Button type="link" title="切换静态定位" icon={<FullscreenExitOutlined />}></Button>
|
||||
</Popconfirm>
|
||||
<Button
|
||||
type="link"
|
||||
title="选中聚焦"
|
||||
icon={<CompressOutlined />}
|
||||
onClick={() => {
|
||||
focusEle(value.config.getStore(), value.value.id);
|
||||
}}
|
||||
></Button>
|
||||
<Popconfirm
|
||||
title="确认删除操作吗?"
|
||||
onConfirm={() => {
|
||||
changeLayer(value.config.getStore(), value.value.id, 'delete');
|
||||
}}
|
||||
>
|
||||
<Button icon={<DeleteOutlined />} title="删除" type="link"></Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
const SortableList = SortableContainer(
|
||||
({ items }: { items: { data: IBlockType[]; config: UserConfig } }) => {
|
||||
return (
|
||||
<div>
|
||||
{items.data.map((value, index: number) => (
|
||||
<SortableItem key={value.id} index={index} value={{ value, config: items.config }} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export function Control(props: PropsWithChildren<ControlProps>) {
|
||||
const { style } = props;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [configVisible, setConfigVisible] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const data = props.config.getStore().getData().block;
|
||||
|
||||
const onSortEnd = (sort: SortEnd) => {
|
||||
const { oldIndex, newIndex } = sort;
|
||||
const newblocks: IBlockType[] = arrayMove(data, oldIndex, newIndex);
|
||||
// 这里要判断是否edit ,如果edit时,只要看第一个是不是container,不是则不移动
|
||||
const isEdit = props.config.getStoreChanger().isEdit();
|
||||
if (isEdit) {
|
||||
const firstType = newblocks[0].name;
|
||||
if (firstType !== 'modalMask') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const store = props.config.getStore();
|
||||
const cloneData: IStoreData = deepCopy(store.getData());
|
||||
cloneData.block = newblocks;
|
||||
store.setData(cloneData);
|
||||
};
|
||||
|
||||
const content =
|
||||
data.length === 0 ? (
|
||||
<div>暂时没有组件</div>
|
||||
) : (
|
||||
<div style={{ maxHeight: 300, overflow: 'auto' }}>
|
||||
<SortableList
|
||||
distance={2}
|
||||
useDragHandle
|
||||
items={{
|
||||
data,
|
||||
config: props.config,
|
||||
}}
|
||||
onSortEnd={onSortEnd}
|
||||
axis="y"
|
||||
></SortableList>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="ant-menu"
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
<Popover style={{ minWidth: '208px' }} content={content} trigger="click">
|
||||
<Button icon={<UnorderedListOutlined />}></Button>
|
||||
</Popover>
|
||||
|
||||
{/* <Button icon={<FolderOpenOutlined />}></Button> */}
|
||||
<Popover
|
||||
placement="left"
|
||||
content={
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
新建弹窗
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setConfigVisible(true);
|
||||
}}
|
||||
>
|
||||
弹窗配置
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Button icon={<GatewayOutlined />}></Button>
|
||||
</Popover>
|
||||
|
||||
<Button
|
||||
icon={<SyncOutlined />}
|
||||
onClick={() => {
|
||||
wrapperMoveState.needX = 0;
|
||||
wrapperMoveState.needY = 0;
|
||||
props.config.getStore().forceUpdate();
|
||||
}}
|
||||
></Button>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
title="弹窗配置"
|
||||
visible={configVisible}
|
||||
onOk={() => setConfigVisible(false)}
|
||||
onCancel={() => setConfigVisible(false)}
|
||||
footer={null}
|
||||
>
|
||||
<List>
|
||||
{props.config.getStoreChanger().getState().modalEditName !== '' && (
|
||||
<div>请退出编辑弹窗后再打开该配置</div>
|
||||
)}
|
||||
{props.config.getStoreChanger().getState().modalEditName === '' &&
|
||||
Object.keys(props.config.getStore().getData().modalMap).map((v) => {
|
||||
return (
|
||||
<List.Item
|
||||
key={v}
|
||||
actions={[
|
||||
<Popconfirm
|
||||
title="是否切换至该弹窗并进行编辑?"
|
||||
onConfirm={() => {
|
||||
props.config.getStoreChanger().updateModal(props.config.getStore(), v);
|
||||
setConfigVisible(false);
|
||||
}}
|
||||
okText={'是'}
|
||||
cancelText={'否'}
|
||||
>
|
||||
<Button type="link">修改</Button>
|
||||
</Popconfirm>,
|
||||
|
||||
<Popconfirm
|
||||
title="您确定要删除这个弹窗吗?"
|
||||
onConfirm={() => {
|
||||
props.config.getStoreChanger().removeModal(props.config.getStore(), v);
|
||||
setConfigVisible(false);
|
||||
}}
|
||||
okText={'是'}
|
||||
cancelText={'否'}
|
||||
>
|
||||
<Button type="link">删除</Button>
|
||||
</Popconfirm>,
|
||||
]}
|
||||
>
|
||||
{v}
|
||||
</List.Item>
|
||||
);
|
||||
})}
|
||||
{props.config.getStoreChanger().getState().modalEditName === '' &&
|
||||
Object.keys(props.config.getStore().getData().modalMap).length === 0 && (
|
||||
<div style={{ textAlign: 'center' }}>暂时没有弹窗</div>
|
||||
)}
|
||||
</List>
|
||||
</Modal>
|
||||
<Modal
|
||||
onOk={() => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((values) => {
|
||||
form.resetFields();
|
||||
const modalName = values.modalName;
|
||||
props.config.getStoreChanger().newModalMap(props.config.getStore(), modalName);
|
||||
setVisible(false);
|
||||
})
|
||||
.catch((info) => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
}}
|
||||
title="新增弹窗"
|
||||
onCancel={() => setVisible(false)}
|
||||
visible={visible}
|
||||
>
|
||||
<Form layout="vertical" name="basic" form={form}>
|
||||
<Form.Item
|
||||
label="弹窗名称"
|
||||
name="modalName"
|
||||
rules={[{ required: true, message: '请输入弹窗名称!' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Control;
|
185
packages/dooringx-lib/src/components/leftConfig.tsx
Normal file
185
packages/dooringx-lib/src/components/leftConfig.tsx
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* @Author: yehuozhili
|
||||
* @Date: 2021-02-04 10:32:45
|
||||
* @LastEditors: yehuozhili
|
||||
* @LastEditTime: 2021-07-06 23:55:37
|
||||
* @FilePath: \dooringv2\packages\dooring-v2-lib\src\components\leftConfig.tsx
|
||||
*/
|
||||
import React, { ReactNode, useEffect, useMemo, useState } from 'react';
|
||||
import { Input, Menu } from 'antd';
|
||||
import { dragEventResolve, LeftRegistComponentMapItem } from '../core/crossDrag';
|
||||
import UserConfig from '../config';
|
||||
import { DoubleLeftOutlined, DoubleRightOutlined, SearchOutlined } from '@ant-design/icons';
|
||||
|
||||
import styles from '../index.less';
|
||||
|
||||
interface LeftConfigProps {
|
||||
config: UserConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 注册加载左侧组件方法,由于异步拉取,所以要异步加载
|
||||
* 不同tab页可以使用不同type区分
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
function LeftConfig(props: LeftConfigProps) {
|
||||
const [menuSelect, setMenuSelect] = useState('0');
|
||||
const [leftRender, setLeftRender] = useState<ReactNode | null>(null);
|
||||
const leftMapRenderListCategory = useMemo(() => {
|
||||
return props.config.getConfig().leftRenderListCategory;
|
||||
}, [props.config]);
|
||||
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
let cache: LeftRegistComponentMapItem[] = [];
|
||||
const type = leftMapRenderListCategory[parseInt(menuSelect, 10)]?.type;
|
||||
const isCustom = leftMapRenderListCategory[parseInt(menuSelect, 10)]?.custom;
|
||||
if (!isCustom) {
|
||||
const config = props.config.getConfig();
|
||||
cache = config.leftAllRegistMap.filter((k) => k.type === type);
|
||||
cache.forEach((v) => props.config.asyncRegistComponent(v.component));
|
||||
setLeftRender(
|
||||
<div className={styles.leftco}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: '10px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: 100,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
height: 32,
|
||||
lineHeight: '32px',
|
||||
marginRight: '10px',
|
||||
fontSize: '14px',
|
||||
fontFamily: 'PingFangSC-Medium, PingFang SC',
|
||||
fontWeight: 600,
|
||||
userSelect: 'none',
|
||||
}}
|
||||
>
|
||||
{leftMapRenderListCategory[parseInt(menuSelect, 10)].displayName}
|
||||
</div>
|
||||
<Input
|
||||
style={{
|
||||
borderRadius: '40px',
|
||||
}}
|
||||
allowClear
|
||||
value={search}
|
||||
onChange={(e) => {
|
||||
setSearch(e.target.value);
|
||||
}}
|
||||
prefix={<SearchOutlined />}
|
||||
/>
|
||||
</div>
|
||||
{search &&
|
||||
search !== '' &&
|
||||
cache
|
||||
.reduce<LeftRegistComponentMapItem[]>((prev, next) => {
|
||||
//筛选搜索条件,name或者displayName存在即显示
|
||||
if (next.displayName.includes(search) || next.component.includes(search)) {
|
||||
prev.push(next);
|
||||
}
|
||||
return prev;
|
||||
}, [])
|
||||
.map((v, index) => (
|
||||
<div className={styles.coitem} key={index} {...dragEventResolve(v)}>
|
||||
<div className={styles.redbox}>
|
||||
{v.imgCustom ? v.imgCustom : <img src={v.img}></img>}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
lineHeight: '20px',
|
||||
height: '20px',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{v.displayName}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{(!search || search === '') &&
|
||||
cache.map((v, index) => (
|
||||
<div className={styles.coitem} key={index} {...dragEventResolve(v)}>
|
||||
<div className={styles.redbox}>
|
||||
{v.imgCustom ? v.imgCustom : <img src={v.img}></img>}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
lineHeight: '20px',
|
||||
height: '20px',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{v.displayName}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
const render = leftMapRenderListCategory[parseInt(menuSelect, 10)]?.customRender;
|
||||
setLeftRender(<div className={styles.leftco}>{render}</div>);
|
||||
}
|
||||
}, [menuSelect, props.config, leftMapRenderListCategory, search]);
|
||||
|
||||
const [isCollapse, setCollapse] = useState(false);
|
||||
const [renderCollapse, setRenderCollaspe] = useState(false);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', height: '100%' }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Menu style={{ flex: 1 }} defaultSelectedKeys={[menuSelect]} mode="vertical">
|
||||
{leftMapRenderListCategory.map((v, i) => {
|
||||
return (
|
||||
<Menu.Item key={i} onClick={() => setMenuSelect(i + '')} icon={v.icon}></Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
<Menu selectedKeys={[]}>
|
||||
<Menu.Item
|
||||
key="1"
|
||||
onClick={() =>
|
||||
setCollapse((pre) => {
|
||||
if (pre) {
|
||||
setTimeout(() => {
|
||||
setRenderCollaspe(false);
|
||||
}, 300);
|
||||
return !pre;
|
||||
} else {
|
||||
setRenderCollaspe(true);
|
||||
return !pre;
|
||||
}
|
||||
})
|
||||
}
|
||||
className={styles.menu_footer}
|
||||
icon={isCollapse ? <DoubleRightOutlined /> : <DoubleLeftOutlined />}
|
||||
></Menu.Item>
|
||||
</Menu>
|
||||
</div>
|
||||
<div
|
||||
className={`${styles.yhLeftrender} ant-menu scrollbar`}
|
||||
style={{
|
||||
width: isCollapse ? 0 : 270,
|
||||
paddingRight: isCollapse ? 0 : 7, // 这个是滚动条宽度
|
||||
overflowX: 'hidden',
|
||||
}}
|
||||
>
|
||||
{!renderCollapse && leftRender}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LeftConfig;
|
112
packages/dooringx-lib/src/components/modalRender.tsx
Normal file
112
packages/dooringx-lib/src/components/modalRender.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { IStoreData } from '../core/store/storetype';
|
||||
import React, { useMemo } from 'react';
|
||||
import Blocks from './blocks';
|
||||
import UserConfig from '../config';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { deepCopy } from '../core/utils';
|
||||
|
||||
interface ModalRenderProps {
|
||||
data: IStoreData;
|
||||
name: string; //传递的modal名字
|
||||
config: UserConfig; //需要拿到componentRegister
|
||||
parentDom: HTMLDivElement;
|
||||
rootDom: HTMLDivElement;
|
||||
}
|
||||
|
||||
export const unmountMap: Map<string, Function> = new Map();
|
||||
|
||||
export function ModalRender(props: ModalRenderProps) {
|
||||
//先获取数据
|
||||
const storeData: IStoreData = useMemo(() => {
|
||||
const z = props.data.modalMap[props.name];
|
||||
if (z) {
|
||||
const data = deepCopy(z);
|
||||
//需要把第一个mask扔了手动写一个
|
||||
data.block.shift();
|
||||
return data;
|
||||
}
|
||||
return { block: [] };
|
||||
}, [props.data.modalMap, props.name]);
|
||||
const { parentDom, rootDom } = props;
|
||||
|
||||
//这里还要添加个关闭函数,
|
||||
const unmount = useMemo(() => {
|
||||
return () => {
|
||||
if (parentDom && rootDom) {
|
||||
ReactDOM.unmountComponentAtNode(parentDom);
|
||||
rootDom.removeChild(parentDom);
|
||||
rootDom.parentElement?.removeChild(rootDom);
|
||||
}
|
||||
};
|
||||
}, [parentDom, rootDom]);
|
||||
|
||||
unmountMap.set(props.name, unmount);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="yh-container-modal"
|
||||
style={{
|
||||
height: `100%`,
|
||||
width: `100%`,
|
||||
position: 'fixed',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{storeData.block.map((v) => {
|
||||
return <Blocks key={v.id} config={props.config} data={v} context={'preview'}></Blocks>;
|
||||
})}
|
||||
<div
|
||||
onClick={() => {
|
||||
unmount();
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: '#716f6f9e',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
let wrap: HTMLDivElement | null;
|
||||
|
||||
export const createModal = (name: string, data: IStoreData, config: UserConfig) => {
|
||||
if (wrap) {
|
||||
wrap = null;
|
||||
}
|
||||
|
||||
if (!wrap) {
|
||||
wrap = document.createElement('div');
|
||||
wrap.style.cssText = `line-height:
|
||||
1.5;text-align:
|
||||
center;color: #333;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: fixed;
|
||||
z-index: 100000;
|
||||
width: 100%;
|
||||
height:100%;
|
||||
top:0;
|
||||
left: 0;`;
|
||||
if (wrap) {
|
||||
document.body.appendChild(wrap);
|
||||
}
|
||||
}
|
||||
const divs = document.createElement('div');
|
||||
wrap.appendChild(divs);
|
||||
ReactDOM.render(
|
||||
<ModalRender
|
||||
name={name}
|
||||
data={data}
|
||||
config={config}
|
||||
parentDom={divs}
|
||||
rootDom={wrap}
|
||||
></ModalRender>,
|
||||
divs
|
||||
);
|
||||
};
|
55
packages/dooringx-lib/src/components/preview.tsx
Normal file
55
packages/dooringx-lib/src/components/preview.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* @Author: yehuozhili
|
||||
* @Date: 2021-03-14 05:40:37
|
||||
* @LastEditors: yehuozhili
|
||||
* @LastEditTime: 2021-07-08 20:44:45
|
||||
* @FilePath: \DooringV2\packages\dooringx-lib\src\components\preview.tsx
|
||||
*/
|
||||
import Container from './container';
|
||||
import React, { ReactElement, ReactNode, useEffect, useState } from 'react';
|
||||
import UserConfig from '../config';
|
||||
|
||||
function Preview(props: { config: UserConfig; loadText?: ReactNode }): ReactElement {
|
||||
const isEdit = props.config.getStoreChanger().isEdit();
|
||||
/// 这里需要在渲染组件之前必须把所有config加载完成,否则会导致先运行的函数无法运行
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// 链接数据
|
||||
props.config
|
||||
.getDataCenter()
|
||||
.initAddToDataMap(props.config.getStore().getData(), props.config.getStoreChanger());
|
||||
// 链接事件
|
||||
props.config
|
||||
.getEventCenter()
|
||||
.syncEventMap(props.config.getStore().getData(), props.config.getStoreChanger());
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, [props.config]);
|
||||
|
||||
if (isEdit) {
|
||||
// 正常情况不会走这
|
||||
const state = props.config.getStoreChanger().getOrigin()!.now;
|
||||
return (
|
||||
<>
|
||||
<Container config={props.config} context="preview" state={state}></Container>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
if (loading) {
|
||||
return <div>{props.loadText ? props.loadText : 'loading'}</div>;
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<Container
|
||||
config={props.config}
|
||||
context="preview"
|
||||
state={props.config.getStore().getData()}
|
||||
></Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
export default Preview;
|
239
packages/dooringx-lib/src/components/rightConfig.tsx
Normal file
239
packages/dooringx-lib/src/components/rightConfig.tsx
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* @Author: yehuozhili
|
||||
* @Date: 2021-03-14 05:42:13
|
||||
* @LastEditors: yehuozhili
|
||||
* @LastEditTime: 2021-07-05 23:35:05
|
||||
* @FilePath: \DooringV2\packages\dooring-v2-lib\src\components\rightConfig.tsx
|
||||
*/
|
||||
import { CreateOptionsRes } from '../core/components/formTypes';
|
||||
import { IBlockType, IStoreData } from '../core/store/storetype';
|
||||
import { store } from '../runtime/store';
|
||||
import { PropsWithChildren, useEffect, useMemo, useState } from 'react';
|
||||
import React from 'react';
|
||||
import { Tabs, Input, Row, Col } from 'antd';
|
||||
import UserConfig from '../config';
|
||||
import { RGBColor, SketchPicker } from 'react-color';
|
||||
import { rgba2Obj } from '../core/utils';
|
||||
import deepcopy from 'deepcopy';
|
||||
|
||||
interface RightConfigProps {
|
||||
state: IStoreData;
|
||||
config: UserConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 这里一个需要异步拿取当前注册组件的配置项,另外需要异步加载所需的配置项。
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
function RightConfig(props: PropsWithChildren<RightConfigProps>) {
|
||||
const [menuSelect, setMenuSelect] = useState('0');
|
||||
const [current, setCurrent] = useState<IBlockType | null>(null);
|
||||
const rightMapRenderListCategory = useMemo(() => {
|
||||
return props.config.getConfig().rightRenderListCategory;
|
||||
}, [props.config]);
|
||||
useEffect(() => {
|
||||
const fn = () => {
|
||||
let item: IBlockType | undefined;
|
||||
store.getData().block.some((v) => {
|
||||
if (v.focus) {
|
||||
item = v;
|
||||
}
|
||||
return v.focus === true;
|
||||
});
|
||||
if (item) {
|
||||
setCurrent({ ...item });
|
||||
} else {
|
||||
setCurrent(null);
|
||||
}
|
||||
};
|
||||
const unregist = store.subscribe(fn);
|
||||
return () => {
|
||||
unregist();
|
||||
};
|
||||
}, []);
|
||||
const render = useMemo(() => {
|
||||
return (type: string, current: IBlockType) => {
|
||||
const fn = () => props.config.getComponentRegister().getComp(current.name);
|
||||
const data = fn();
|
||||
// 这里不可能拿不到组件,因为点击的那个组件已经渲染出来了
|
||||
if (data) {
|
||||
const renderList = data.props[type];
|
||||
if (renderList) {
|
||||
return renderList.map((v, i) => {
|
||||
const Component = props.config.getFormRegister().formMap[v.type];
|
||||
if (!Component) {
|
||||
console.error(`you might forgot to regist form component ${v.type}`);
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Component
|
||||
key={i}
|
||||
data={v as CreateOptionsRes<any, any>}
|
||||
current={current}
|
||||
config={props.config}
|
||||
></Component>
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return <div>还没有配置属性</div>;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}, [props.config]);
|
||||
|
||||
const initColor = useMemo(() => {
|
||||
return props.config.getStoreChanger().isEdit()
|
||||
? rgba2Obj(props.config.getStoreChanger().getOrigin()?.now.globalState.containerColor)
|
||||
: rgba2Obj(props.config.getStore().getData().globalState.containerColor);
|
||||
}, [props.config]);
|
||||
const [color, setColor] = useState<RGBColor>(initColor);
|
||||
const [colorPickerVisible, setColorPickerVisible] = useState(false);
|
||||
const initTitle = useMemo(() => {
|
||||
const title = props.config.getStoreChanger().isEdit()
|
||||
? props.config.getStoreChanger().getOrigin()?.now.globalState.title
|
||||
: props.config.getStore().getData().globalState.title;
|
||||
return title;
|
||||
}, [props.config]);
|
||||
const [title, setTitle] = useState(initTitle);
|
||||
|
||||
const customGlobal = props.config.getConfig().rightGlobalCustom;
|
||||
return (
|
||||
<div
|
||||
className="ant-menu"
|
||||
style={{
|
||||
height: '100%',
|
||||
width: '400px',
|
||||
overflow: 'auto',
|
||||
padding: '0 10px',
|
||||
lineHeight: 1.5715,
|
||||
}}
|
||||
>
|
||||
{current && (
|
||||
<Tabs
|
||||
activeKey={menuSelect}
|
||||
style={{ width: '100%' }}
|
||||
onChange={(e) => {
|
||||
setMenuSelect(e);
|
||||
}}
|
||||
>
|
||||
{rightMapRenderListCategory.map((v, i) => {
|
||||
return (
|
||||
<Tabs.TabPane tab={v.icon} key={i + ''}>
|
||||
<div
|
||||
className="scrollbar"
|
||||
style={{
|
||||
height: 'calc(100vh - 110px)',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
{v.custom && v.customRender && v.customRender(v.type, current)}
|
||||
{!v.custom && render(v.type, current)}
|
||||
</div>
|
||||
</Tabs.TabPane>
|
||||
);
|
||||
})}
|
||||
</Tabs>
|
||||
)}
|
||||
{!current && !customGlobal && (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<Row style={{ padding: '10 0 20px 0', fontWeight: 'bold' }}>全局设置</Row>
|
||||
<Row style={{ padding: '10px 0' }}>
|
||||
<Col span={6}>标题</Col>
|
||||
<Col span={18}>
|
||||
<Input
|
||||
value={title}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
setTitle(val);
|
||||
const isEdit = props.config.getStoreChanger().isEdit();
|
||||
if (isEdit) {
|
||||
const originData: IStoreData = deepcopy(
|
||||
props.config.getStoreChanger().getOrigin()!.now
|
||||
);
|
||||
originData.globalState.title = val;
|
||||
props.config.getStoreChanger().updateOrigin(originData);
|
||||
} else {
|
||||
const originData = deepcopy(props.config.getStore().getData());
|
||||
originData.globalState.title = val;
|
||||
props.config.getStore().setData(originData);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{ padding: '10px 0' }}>
|
||||
<Col span={6}>容器底色</Col>
|
||||
<Col span={18}>
|
||||
{
|
||||
<div style={{ position: 'relative' }}>
|
||||
<div
|
||||
onClick={() => {
|
||||
setColorPickerVisible((pre) => !pre);
|
||||
}}
|
||||
style={{
|
||||
background: '#fff',
|
||||
borderRadius: '1px',
|
||||
boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
|
||||
cursor: 'pointer',
|
||||
display: 'inline-block',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
borderRadius: '2px',
|
||||
background: `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{colorPickerVisible && (
|
||||
<>
|
||||
<div style={{ position: 'absolute', zIndex: 2000 }}>
|
||||
<SketchPicker
|
||||
color={color}
|
||||
onChange={(c) => {
|
||||
const newcolor = c.rgb;
|
||||
setColor(newcolor);
|
||||
const isEdit = props.config.getStoreChanger().isEdit();
|
||||
if (isEdit) {
|
||||
const originData: IStoreData = deepcopy(
|
||||
props.config.getStoreChanger().getOrigin()!.now
|
||||
);
|
||||
originData.globalState.containerColor = `rgba(${newcolor.r}, ${newcolor.g}, ${newcolor.b}, ${newcolor.a})`;
|
||||
props.config.getStoreChanger().updateOrigin(originData);
|
||||
} else {
|
||||
const originData = deepcopy(props.config.getStore().getData());
|
||||
originData.globalState.containerColor = `rgba(${newcolor.r}, ${newcolor.g}, ${newcolor.b}, ${newcolor.a})`;
|
||||
props.config.getStore().setData(originData);
|
||||
}
|
||||
}}
|
||||
></SketchPicker>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: '0px',
|
||||
right: '0px',
|
||||
bottom: '0px',
|
||||
left: '0px',
|
||||
zIndex: 1000,
|
||||
}}
|
||||
onClick={() => setColorPickerVisible(false)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
)}
|
||||
{!current && customGlobal && customGlobal}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default RightConfig;
|
68
packages/dooringx-lib/src/components/wrapperMove/event.ts
Normal file
68
packages/dooringx-lib/src/components/wrapperMove/event.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* @Author: yehuozhili
|
||||
* @Date: 2021-02-21 22:17:29
|
||||
* @LastEditors: yehuozhili
|
||||
* @LastEditTime: 2021-04-05 18:24:27
|
||||
* @FilePath: \dooringv2\src\components\wrapperMove\event.ts
|
||||
*/
|
||||
import { store } from '../../runtime/store';
|
||||
import { RefObject } from 'react';
|
||||
import { containerResizer } from '../../core/resizeHandler/containerResizer';
|
||||
import { contextMenuState } from '../../core/contextMenu';
|
||||
|
||||
export interface WrapperMoveStateProps {
|
||||
isDrag: boolean;
|
||||
startX: number;
|
||||
startY: number;
|
||||
needX: number;
|
||||
needY: number;
|
||||
ref: null | RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export const wrapperMoveState: WrapperMoveStateProps = {
|
||||
isDrag: false,
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
needX: 0,
|
||||
needY: 0,
|
||||
ref: null,
|
||||
};
|
||||
|
||||
export const wrapperEvent = (ref: RefObject<HTMLDivElement>) => {
|
||||
return {
|
||||
onMouseDown: (e: React.MouseEvent) => {
|
||||
// e.preventDefault();// 不能使用preventDefault 否则弹窗输入框焦点无法触发
|
||||
contextMenuState.unmountContextMenu();
|
||||
if (e.target !== ref.current) {
|
||||
} else {
|
||||
wrapperMoveState.isDrag = true;
|
||||
wrapperMoveState.startX = e.clientX;
|
||||
wrapperMoveState.startY = e.clientY;
|
||||
if (ref.current) {
|
||||
ref.current.style.cursor = 'grab';
|
||||
wrapperMoveState.ref = ref;
|
||||
}
|
||||
}
|
||||
},
|
||||
onMouseMove: (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
if (wrapperMoveState.isDrag) {
|
||||
const diffX = e.clientX - wrapperMoveState.startX;
|
||||
const diffY = e.clientY - wrapperMoveState.startY;
|
||||
wrapperMoveState.needX = wrapperMoveState.needX + diffX;
|
||||
wrapperMoveState.needY = wrapperMoveState.needY + diffY;
|
||||
wrapperMoveState.startX = e.clientX;
|
||||
wrapperMoveState.startY = e.clientY;
|
||||
store.forceUpdate();
|
||||
}
|
||||
containerResizer.onMouseMove(e);
|
||||
},
|
||||
};
|
||||
};
|
||||
export const wrapperMoveMouseUp = () => {
|
||||
if (wrapperMoveState.ref && wrapperMoveState.ref.current) {
|
||||
wrapperMoveState.ref.current.style.cursor = 'default';
|
||||
}
|
||||
containerResizer.onMouseUp();
|
||||
wrapperMoveState.isDrag = false;
|
||||
};
|
44
packages/dooringx-lib/src/components/wrapperMove/index.tsx
Normal file
44
packages/dooringx-lib/src/components/wrapperMove/index.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* @Author: yehuozhili
|
||||
* @Date: 2021-03-14 04:29:09
|
||||
* @LastEditors: yehuozhili
|
||||
* @LastEditTime: 2021-03-14 04:58:51
|
||||
* @FilePath: \dooring-v2\src\core\wrapperMove\index.tsx
|
||||
*/
|
||||
import { AllHTMLAttributes, CSSProperties, PropsWithChildren, useRef } from 'react';
|
||||
import { wrapperEvent } from './event';
|
||||
import { onWheelEvent } from '../../core/scale';
|
||||
import React from 'react';
|
||||
|
||||
export interface ContainerWrapperProps extends AllHTMLAttributes<HTMLDivElement> {
|
||||
classNames?: string;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
function ContainerWrapper(props: PropsWithChildren<ContainerWrapperProps>) {
|
||||
const { children, style, classNames, ...rest } = props;
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
return (
|
||||
<div
|
||||
className={`ant-menu ${classNames}`}
|
||||
ref={ref}
|
||||
style={{
|
||||
backgroundColor: '#f0f0f0',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
...style,
|
||||
}}
|
||||
{...wrapperEvent(ref)}
|
||||
{...onWheelEvent}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default ContainerWrapper;
|
Reference in New Issue
Block a user