173 lines
4.9 KiB
TypeScript
173 lines
4.9 KiB
TypeScript
import React, { createContext, useContext, useState } from 'react';
|
|
import {
|
|
connect,
|
|
mapProps,
|
|
mapReadPretty,
|
|
observer,
|
|
SchemaOptionsContext,
|
|
useField,
|
|
useFieldSchema,
|
|
} from '@formily/react';
|
|
import { FormItem as FormilyFormItem } from '@formily/antd';
|
|
import { Dropdown, Menu, Space } from 'antd';
|
|
import classNames from 'classnames';
|
|
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
|
import './style.less';
|
|
import get from 'lodash/get';
|
|
import { GridBlockContext } from '../grid';
|
|
import { uid } from '@formily/shared';
|
|
import { useDesignable, useSchemaPath } from '../DesignableSchemaField';
|
|
import { AddNew } from '../add-new';
|
|
import { Card } from 'antd';
|
|
import {
|
|
mergeRefs,
|
|
DraggableBlockContext,
|
|
useBlockDragAndDrop,
|
|
useDragDropUID,
|
|
} from '../../components/drag-and-drop';
|
|
import cls from 'classnames';
|
|
|
|
function Blank() {
|
|
return null;
|
|
}
|
|
|
|
function useDesignableBar() {
|
|
const schema = useFieldSchema();
|
|
const options = useContext(SchemaOptionsContext);
|
|
const DesignableBar = get(options.components, schema['x-designable-bar']);
|
|
|
|
return {
|
|
DesignableBar: DesignableBar || Blank,
|
|
};
|
|
}
|
|
|
|
const DraggableBlock = (props) => {
|
|
const { children, ...others } = props;
|
|
const { DesignableBar } = useDesignableBar();
|
|
const { isDragging, dragRef, previewRef, isOver, onTopHalf, dropRef } =
|
|
useBlockDragAndDrop();
|
|
const schema = useFieldSchema();
|
|
const [active, setActive] = useState(false);
|
|
return (
|
|
<DraggableBlockContext.Provider value={{ dragRef }}>
|
|
<div
|
|
onMouseEnter={(e) => {
|
|
setActive(true);
|
|
console.log('e.onMouseEnter', new Date().toString());
|
|
}}
|
|
onMouseMove={(event) => {
|
|
let dropElement = document.elementFromPoint(
|
|
event.clientX,
|
|
event.clientY,
|
|
);
|
|
const dropIds = [];
|
|
while (dropElement) {
|
|
if (!dropElement.getAttribute) {
|
|
dropElement = dropElement.parentNode as HTMLElement;
|
|
continue;
|
|
}
|
|
const dropId = dropElement.getAttribute('data-drop-id');
|
|
if (dropId) {
|
|
dropIds.push(dropId);
|
|
}
|
|
// if (dropId && dropId !== schema.name) {
|
|
// setActive(false);
|
|
// break;
|
|
// }
|
|
dropElement = dropElement.parentNode as HTMLElement;
|
|
}
|
|
if (dropIds.length > 0) {
|
|
setActive(dropIds[0] === schema.name);
|
|
}
|
|
console.log('e.onMouseMove', dropIds, schema.name);
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
setActive(false);
|
|
console.log('e.onMouseLeave', new Date().toString());
|
|
}}
|
|
ref={mergeRefs([previewRef, dropRef])}
|
|
className={cls('nb-grid-block', 'designable-form-item', {
|
|
'top-half': onTopHalf,
|
|
hover: isOver,
|
|
active,
|
|
dragging: isDragging,
|
|
})}
|
|
style={{ marginBottom: 24 }}
|
|
>
|
|
{children}
|
|
<DesignableBar />
|
|
</div>
|
|
</DraggableBlockContext.Provider>
|
|
);
|
|
};
|
|
|
|
const Block = (props) => {
|
|
return (
|
|
<div className={cls('nb-grid-block', 'designable-form-item')}>
|
|
{props.children}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const BlockItem: any = observer((props) => {
|
|
const uid = useDragDropUID();
|
|
return React.createElement(uid ? DraggableBlock : Block, props);
|
|
});
|
|
|
|
// export const BlockItem: any = connect((props) => {
|
|
// const { children, ...others } = props;
|
|
// const { DesignableBar } = useDesignableBar();
|
|
// return (
|
|
// <div {...others} style={{marginBottom: 24}} className={'designable-form-item'}>
|
|
// {children}
|
|
// <DesignableBar />
|
|
// </div>
|
|
// );
|
|
// });
|
|
|
|
BlockItem.DesignableBar = () => {
|
|
const field = useField();
|
|
const { schema, refresh } = useDesignable();
|
|
const [visible, setVisible] = useState(false);
|
|
const { dragRef } = useContext(DraggableBlockContext);
|
|
return (
|
|
<div className={classNames('designable-bar', { active: visible })}>
|
|
<span
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
}}
|
|
className={classNames('designable-bar-actions', { active: visible })}
|
|
>
|
|
<Space size={'small'}>
|
|
<AddNew.BlockItem defaultAction={'insertAfter'} ghost />
|
|
{dragRef && <DragOutlined ref={dragRef} />}
|
|
<Dropdown
|
|
trigger={['click']}
|
|
visible={visible}
|
|
onVisibleChange={(visible) => {
|
|
setVisible(visible);
|
|
}}
|
|
overlay={
|
|
<Menu>
|
|
<Menu.Item
|
|
onClick={(e) => {
|
|
const title = uid();
|
|
schema.title = title;
|
|
field.title = title;
|
|
setVisible(false);
|
|
refresh();
|
|
}}
|
|
>
|
|
点击修改按钮文案
|
|
</Menu.Item>
|
|
</Menu>
|
|
}
|
|
>
|
|
<MenuOutlined />
|
|
</Dropdown>
|
|
</Space>
|
|
</span>
|
|
</div>
|
|
);
|
|
};
|