refactor: drag and drop
This commit is contained in:
parent
7d604cdf9a
commit
2e8fe58246
@ -43,12 +43,12 @@ export function DragHandle(props) {
|
|||||||
const Icon = component || DragOutlined;
|
const Icon = component || DragOutlined;
|
||||||
return (
|
return (
|
||||||
<SortableItemContext.Consumer>
|
<SortableItemContext.Consumer>
|
||||||
{({ setDraggableNodeRef, attributes, listeners }) =>
|
{({ draggable, setDraggableNodeRef, attributes, listeners }) =>
|
||||||
setDraggableNodeRef && (
|
setDraggableNodeRef && (
|
||||||
<Icon
|
<Icon
|
||||||
ref={setDraggableNodeRef}
|
ref={setDraggableNodeRef}
|
||||||
{...others}
|
{...others}
|
||||||
{...attributes}
|
// {...attributes}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@ -57,7 +57,14 @@ export function DragHandle(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Droppable(props) {
|
export interface DroppableProps {
|
||||||
|
id: any;
|
||||||
|
data?: any;
|
||||||
|
component?: any;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Droppable(props: DroppableProps) {
|
||||||
const { id, data = {}, className, component, children, ...others } = props;
|
const { id, data = {}, className, component, children, ...others } = props;
|
||||||
const { isOver, setNodeRef: setDroppableNodeRef } = useDroppable({
|
const { isOver, setNodeRef: setDroppableNodeRef } = useDroppable({
|
||||||
id: `droppable-${id}`,
|
id: `droppable-${id}`,
|
||||||
@ -81,8 +88,24 @@ export function Droppable(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SortableItem(props) {
|
export interface SortableItemProps {
|
||||||
const { id, data = {}, className, component, children, ...others } = props;
|
id: any;
|
||||||
|
data?: any;
|
||||||
|
component?: any;
|
||||||
|
draggable?: boolean;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SortableItem(props: SortableItemProps) {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
data = {},
|
||||||
|
draggable,
|
||||||
|
className,
|
||||||
|
component,
|
||||||
|
children,
|
||||||
|
...others
|
||||||
|
} = props;
|
||||||
const previewRef = useRef<HTMLElement>();
|
const previewRef = useRef<HTMLElement>();
|
||||||
const { isOver, setNodeRef: setDroppableNodeRef } = useDroppable({
|
const { isOver, setNodeRef: setDroppableNodeRef } = useDroppable({
|
||||||
id: `droppable-${id}`,
|
id: `droppable-${id}`,
|
||||||
@ -104,10 +127,14 @@ export function SortableItem(props) {
|
|||||||
previewRef,
|
previewRef,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
if (draggable) {
|
||||||
|
Object.assign(others, listeners);
|
||||||
|
}
|
||||||
const Component = component || Div;
|
const Component = component || Div;
|
||||||
return (
|
return (
|
||||||
<Component
|
<Component
|
||||||
{...others}
|
{...others}
|
||||||
|
{...attributes}
|
||||||
className={cls(className, `droppable-${id}`, {
|
className={cls(className, `droppable-${id}`, {
|
||||||
isOver,
|
isOver,
|
||||||
isDragging,
|
isDragging,
|
||||||
@ -115,10 +142,13 @@ export function SortableItem(props) {
|
|||||||
ref={(el: HTMLElement) => {
|
ref={(el: HTMLElement) => {
|
||||||
previewRef.current = el;
|
previewRef.current = el;
|
||||||
setDroppableNodeRef(el);
|
setDroppableNodeRef(el);
|
||||||
|
if (draggable) {
|
||||||
|
setDraggableNodeRef(el);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SortableItemContext.Provider
|
<SortableItemContext.Provider
|
||||||
value={{ setDraggableNodeRef, attributes, listeners }}
|
value={{ draggable, setDraggableNodeRef, attributes, listeners }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</SortableItemContext.Provider>
|
</SortableItemContext.Provider>
|
||||||
|
@ -446,12 +446,24 @@ function generateCardItemSchema(component) {
|
|||||||
name: uid(),
|
name: uid(),
|
||||||
'x-decorator': 'Form',
|
'x-decorator': 'Form',
|
||||||
'x-component': 'Kanban.Card',
|
'x-component': 'Kanban.Card',
|
||||||
'x-designable-bar': 'Kanban.Card.DesignableBar',
|
|
||||||
'x-read-pretty': true,
|
'x-read-pretty': true,
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
useResource: '{{ Kanban.useResource }}',
|
useResource: '{{ Kanban.useResource }}',
|
||||||
},
|
},
|
||||||
properties: {},
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'BlockItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
draggable: false,
|
||||||
|
},
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-designable-bar': 'Kanban.Card.DesignableBar',
|
||||||
|
// 'x-component-props': {
|
||||||
|
// addNewComponent: 'AddNew.FormItem',
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
view1: {
|
view1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
@ -14,7 +14,6 @@ import classNames from 'classnames';
|
|||||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { GridBlockContext } from '../grid';
|
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { useDesignable, useSchemaPath } from '../';
|
import { useDesignable, useSchemaPath } from '../';
|
||||||
import { AddNew } from '../add-new';
|
import { AddNew } from '../add-new';
|
||||||
@ -26,89 +25,45 @@ import {
|
|||||||
useDragDropUID,
|
useDragDropUID,
|
||||||
} from '../../components/drag-and-drop';
|
} from '../../components/drag-and-drop';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
|
import { Droppable, SortableItem } from '../../components/Sortable';
|
||||||
|
import { useDndContext } from '@dnd-kit/core';
|
||||||
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
|
|
||||||
const DraggableBlock = (props) => {
|
const DraggableBlock = (props) => {
|
||||||
const { children, ...others } = props;
|
const { className, children, ...others } = props;
|
||||||
const { DesignableBar } = useDesignable();
|
const { DesignableBar, schema } = useDesignable();
|
||||||
const { isDragging, dragRef, previewRef, isOver, onTopHalf, dropRef } =
|
|
||||||
useBlockDragAndDrop();
|
|
||||||
const schema = useFieldSchema();
|
|
||||||
const [active, setActive] = useState(false);
|
|
||||||
return (
|
return (
|
||||||
<DraggableBlockContext.Provider value={{ dragRef }}>
|
<SortableItem
|
||||||
<div
|
id={schema.name}
|
||||||
// onMouseEnter={(e) => {
|
className={cls('nb-block-item', className)}
|
||||||
// setActive(true);
|
data={{
|
||||||
// // console.log('e.onMouseEnter', new Date().toString());
|
type: 'block',
|
||||||
// }}
|
path: getSchemaPath(schema),
|
||||||
// onMouseMove={(event) => {
|
}}
|
||||||
// let dropElement = document.elementFromPoint(
|
{...others}
|
||||||
// event.clientX,
|
>
|
||||||
// event.clientY,
|
{children}
|
||||||
// );
|
<DesignableBar />
|
||||||
// const dropIds = [];
|
</SortableItem>
|
||||||
// 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) => {
|
const Block = (props) => {
|
||||||
const { DesignableBar } = useDesignable();
|
const { DesignableBar } = useDesignable();
|
||||||
const [active, setActive] = useState(false);
|
const { className, children, ...others } = props;
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={cls('nb-block-item', className)} {...others}>
|
||||||
onMouseEnter={(e) => {
|
{children}
|
||||||
setActive(true);
|
|
||||||
// console.log('e.onMouseEnter', new Date().toString());
|
|
||||||
}}
|
|
||||||
onMouseLeave={(e) => {
|
|
||||||
setActive(false);
|
|
||||||
// console.log('e.onMouseLeave', new Date().toString());
|
|
||||||
}}
|
|
||||||
className={cls('nb-grid-block', 'designable-form-item', { active })}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
<DesignableBar />
|
<DesignableBar />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BlockItem: any = observer((props) => {
|
export const BlockItem: any = observer((props: any) => {
|
||||||
const uid = useDragDropUID();
|
const { draggable = true } = props;
|
||||||
return React.createElement(uid ? DraggableBlock : Block, props);
|
const ctx = useDndContext();
|
||||||
|
return React.createElement(
|
||||||
|
draggable && ctx.activators?.length > 0 ? DraggableBlock : Block,
|
||||||
|
props,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.designable-form-item {
|
.nb-block-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
&:hover,
|
&:hover,
|
||||||
&.active {
|
&.active {
|
||||||
@ -45,4 +45,7 @@
|
|||||||
right: -5px;
|
right: -5px;
|
||||||
bottom: -5px;
|
bottom: -5px;
|
||||||
}
|
}
|
||||||
}
|
&.nb-card-item {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ import { useCollection, useCollectionContext } from '../../constate';
|
|||||||
import { useTable } from '../table';
|
import { useTable } from '../table';
|
||||||
import { fieldsToFilterColumns } from './';
|
import { fieldsToFilterColumns } from './';
|
||||||
import { set } from 'lodash';
|
import { set } from 'lodash';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
export const DesignableBar = observer((props) => {
|
export const DesignableBar = observer((props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -60,7 +61,7 @@ export const DesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={2}>
|
<Space size={2}>
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -14,7 +14,6 @@ import classNames from 'classnames';
|
|||||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||||
// import './style.less';
|
// import './style.less';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { GridBlockContext } from '../grid';
|
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { useDesignable } from '../';
|
import { useDesignable } from '../';
|
||||||
import { AddNew } from '../add-new';
|
import { AddNew } from '../add-new';
|
||||||
@ -26,7 +25,7 @@ export const CardItem: any = connect((props) => {
|
|||||||
const { schema } = useDesignable();
|
const { schema } = useDesignable();
|
||||||
return (
|
return (
|
||||||
<BlockSchemaContext.Provider value={schema}>
|
<BlockSchemaContext.Provider value={schema}>
|
||||||
<BlockItem>
|
<BlockItem className={'nb-card-item'}>
|
||||||
<Card bordered={false} {...props}>
|
<Card bordered={false} {...props}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -20,6 +20,7 @@ import { removeSchema, updateSchema } from '..';
|
|||||||
import { isGridRowOrCol } from '../grid';
|
import { isGridRowOrCol } from '../grid';
|
||||||
import G2Plot from './G2Plot';
|
import G2Plot from './G2Plot';
|
||||||
import { Column, Line, Pie, Bar } from '@antv/g2plot';
|
import { Column, Line, Pie, Bar } from '@antv/g2plot';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
export const Chart: any = {};
|
export const Chart: any = {};
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ Chart.DesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={'small'}>
|
<Space size={'small'}>
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.designable-bar {
|
.designable-bar {
|
||||||
|
z-index: 50 !important;
|
||||||
border-radius: 2px !important;
|
border-radius: 2px !important;
|
||||||
// border: 2px solid @bgcolor !important;
|
// border: 2px solid @bgcolor !important;
|
||||||
border: 0 !important;
|
border: 0 !important;
|
||||||
|
@ -14,12 +14,12 @@ import classNames from 'classnames';
|
|||||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||||
// import './style.less';
|
// import './style.less';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { GridBlockContext } from '../grid';
|
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { useDesignable } from '../';
|
import { useDesignable } from '../';
|
||||||
import { AddNew } from '../add-new';
|
import { AddNew } from '../add-new';
|
||||||
import { BlockItem } from '../block-item';
|
import { BlockItem } from '../block-item';
|
||||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
export const FormItem: any = connect((props) => {
|
export const FormItem: any = connect((props) => {
|
||||||
return (
|
return (
|
||||||
@ -44,7 +44,7 @@ FormItem.DesignableBar = () => {
|
|||||||
>
|
>
|
||||||
<Space size={'small'}>
|
<Space size={'small'}>
|
||||||
<AddNew.FormItem defaultAction={'insertAfter'} ghost />
|
<AddNew.FormItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -29,6 +29,7 @@ import { getSchemaPath } from '../../components/schema-renderer';
|
|||||||
import { useCollection, useCollectionContext } from '../../constate';
|
import { useCollection, useCollectionContext } from '../../constate';
|
||||||
import { useTable } from '../table';
|
import { useTable } from '../table';
|
||||||
import { BlockSchemaContext } from '../../context';
|
import { BlockSchemaContext } from '../../context';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
export const DesignableBar = observer((props) => {
|
export const DesignableBar = observer((props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -52,7 +53,7 @@ export const DesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={2}>
|
<Space size={2}>
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -35,6 +35,7 @@ import { getSchemaPath } from '../../components/schema-renderer';
|
|||||||
import { RandomNameContext } from '.';
|
import { RandomNameContext } from '.';
|
||||||
import { useCollectionContext, useDisplayedMapContext } from '../../constate';
|
import { useCollectionContext, useDisplayedMapContext } from '../../constate';
|
||||||
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
import SwitchMenuItem from '../../components/SwitchMenuItem';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
export const FieldDesignableBar = observer((props) => {
|
export const FieldDesignableBar = observer((props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -64,7 +65,7 @@ export const FieldDesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={2}>
|
<Space size={2}>
|
||||||
<AddNew.FormItem defaultAction={'insertAfter'} ghost />
|
<AddNew.FormItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placement={'bottomRight'}
|
placement={'bottomRight'}
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
|
@ -2,13 +2,13 @@ import React from 'react';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import {
|
import {
|
||||||
observer,
|
observer,
|
||||||
ISchema,
|
|
||||||
FormProvider,
|
FormProvider,
|
||||||
useFieldSchema,
|
useFieldSchema,
|
||||||
RecursionField,
|
RecursionField,
|
||||||
useField,
|
useField,
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import { SchemaRenderer } from '../..';
|
import { ISchema, SchemaRenderer } from '../..';
|
||||||
|
import { Grid } from '..';
|
||||||
|
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -104,13 +104,13 @@ const schema: ISchema = {
|
|||||||
[`row_${uid()}`]: {
|
[`row_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Row',
|
'x-component': 'Grid.Row',
|
||||||
|
'x-component-props': {
|
||||||
|
colsize: [30, 70],
|
||||||
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[`col_${uid()}`]: {
|
[`col_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
'x-component-props': {
|
|
||||||
width: 30,
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -124,9 +124,6 @@ const schema: ISchema = {
|
|||||||
[`col_${uid()}`]: {
|
[`col_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
'x-component-props': {
|
|
||||||
width: 70,
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -190,6 +187,6 @@ const schema: ISchema = {
|
|||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return (
|
return (
|
||||||
<SchemaRenderer schema={schema} />
|
<SchemaRenderer components={{ Grid }} schema={schema} />
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,111 +1,166 @@
|
|||||||
import React, {
|
import {
|
||||||
FC,
|
DndContext,
|
||||||
CSSProperties,
|
DragOverlay,
|
||||||
useRef,
|
useDndContext,
|
||||||
createContext,
|
closestCorners,
|
||||||
useContext,
|
rectIntersection,
|
||||||
useEffect,
|
closestCenter,
|
||||||
useState,
|
useSensors,
|
||||||
} from 'react';
|
useSensor,
|
||||||
// import { DndProvider, useDrag, useDragDropManager } from 'react-dnd';
|
PointerSensor,
|
||||||
// import { HTML5Backend } from 'react-dnd-html5-backend';
|
MouseSensor
|
||||||
|
} from '@dnd-kit/core';
|
||||||
|
import { observer, RecursionField } from '@formily/react';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { createContext } from 'react';
|
||||||
|
import {
|
||||||
|
findPropertyByPath,
|
||||||
|
getSchemaPath,
|
||||||
|
useDesignable,
|
||||||
|
useSchemaComponent,
|
||||||
|
} from '../../components/schema-renderer';
|
||||||
|
import { Droppable, SortableItem } from '../../components/Sortable';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import {
|
|
||||||
observer,
|
|
||||||
ISchema,
|
|
||||||
FormProvider,
|
|
||||||
useFieldSchema,
|
|
||||||
RecursionField,
|
|
||||||
useField,
|
|
||||||
} from '@formily/react';
|
|
||||||
import './style.less';
|
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
|
import './style.less';
|
||||||
import { createSchema, removeSchema, useDesignable, useSchemaPath } from '../';
|
|
||||||
import {
|
import {
|
||||||
useDrag,
|
createSchema,
|
||||||
useDrop,
|
FormilyISchema,
|
||||||
mergeRefs,
|
ISchema,
|
||||||
useColResizer,
|
removeSchema,
|
||||||
useDragDropUID,
|
updateSchema,
|
||||||
DragDropManagerProvider,
|
} from '..';
|
||||||
} from '../../components/drag-and-drop';
|
|
||||||
import { useSchemaComponent } from '../../components/schema-renderer';
|
|
||||||
|
|
||||||
const ColumnSizeContext = createContext(null);
|
const GridRowContext = createContext<any>(null);
|
||||||
|
const GridColContext = createContext<any>(null);
|
||||||
|
|
||||||
export const GridBlockContext = createContext({
|
export function isGridRowOrCol(schema: ISchema | FormilyISchema) {
|
||||||
dragRef: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
export function isGridRowOrCol(schema: ISchema) {
|
|
||||||
return ['Grid.Row', 'Grid.Col'].includes(schema['x-component']);
|
return ['Grid.Row', 'Grid.Col'].includes(schema['x-component']);
|
||||||
}
|
}
|
||||||
|
|
||||||
const RowDivider = ({ name, onDrop }) => {
|
|
||||||
const uid = useDragDropUID();
|
|
||||||
const { isOver, dropRef } = useDrop({
|
|
||||||
uid: `row_divider_${name}`,
|
|
||||||
accept: uid,
|
|
||||||
shallow: true,
|
|
||||||
onDrop,
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={dropRef}
|
|
||||||
className={cls('nb-grid-row-divider', { hover: isOver })}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ColDivider = (props: any) => {
|
|
||||||
const { name, onDragEnd, resizable, onDrop } = props;
|
|
||||||
const uid = useDragDropUID();
|
|
||||||
const { isDragging, dragRef } = useColResizer({ onDragEnd });
|
|
||||||
const { isOver, dropRef } = useDrop({
|
|
||||||
uid: `col_divider_${name}`,
|
|
||||||
accept: uid,
|
|
||||||
shallow: true,
|
|
||||||
onDrop,
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
data-type={'col-divider'}
|
|
||||||
ref={mergeRefs([dragRef, dropRef])}
|
|
||||||
style={{ width: 24 }}
|
|
||||||
className={cls('nb-grid-col-divider', {
|
|
||||||
resizable,
|
|
||||||
hover: isOver,
|
|
||||||
dragging: isDragging,
|
|
||||||
})}
|
|
||||||
></div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Grid: any = observer((props: any) => {
|
export const Grid: any = observer((props: any) => {
|
||||||
|
const { designable, root, schema, deepRemove, ...methods } = useDesignable();
|
||||||
|
const [dragOverlayContent, setDragOverlayContent] = useState('');
|
||||||
|
const [style, setStyle] = useState({});
|
||||||
|
const [active, setActive] = useState(false);
|
||||||
|
const [clientWidths, setClientWidths] = useState([0, 0]);
|
||||||
const { addNewComponent } = props;
|
const { addNewComponent } = props;
|
||||||
const AddNewComponent = useSchemaComponent(addNewComponent);
|
const AddNewComponent = useSchemaComponent(addNewComponent);
|
||||||
const ref = useRef();
|
const sensors = useSensors(
|
||||||
// const schema = useFieldSchema();
|
useSensor(MouseSensor),
|
||||||
const gridPath = useSchemaPath();
|
);
|
||||||
const {
|
|
||||||
designable,
|
|
||||||
schema,
|
|
||||||
schema: designableSchema,
|
|
||||||
insertAfter,
|
|
||||||
prepend,
|
|
||||||
deepRemove,
|
|
||||||
} = useDesignable();
|
|
||||||
return (
|
return (
|
||||||
<DragDropManagerProvider uid={schema.name}>
|
<div className={cls('nb-grid', { active })}>
|
||||||
<div ref={ref} className={'nb-grid'}>
|
<DndContext
|
||||||
<RowDivider
|
autoScroll
|
||||||
key={`${schema.name}_0`}
|
sensors={sensors}
|
||||||
name={`${schema.name}_0`}
|
collisionDetection={rectIntersection}
|
||||||
onDrop={async (e) => {
|
onDragStart={(event) => {
|
||||||
const blockSchema = e.dragItem.schema;
|
setActive(true);
|
||||||
const path = [...e.dragItem.path];
|
const el = event?.active?.data?.current?.previewRef
|
||||||
const data = prepend({
|
?.current as HTMLElement;
|
||||||
|
console.log(event, el);
|
||||||
|
setDragOverlayContent(el?.outerHTML);
|
||||||
|
setStyle({ width: el.clientWidth });
|
||||||
|
const activeType = event?.active?.data?.current?.type;
|
||||||
|
if (activeType === 'col-resize') {
|
||||||
|
const prev = el.previousElementSibling as HTMLDivElement;
|
||||||
|
const next = el.nextElementSibling as HTMLDivElement;
|
||||||
|
setClientWidths([prev.clientWidth, next.clientWidth]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragCancel={() => {
|
||||||
|
setActive(false);
|
||||||
|
}}
|
||||||
|
onDragMove={(event) => {
|
||||||
|
const activeType = event?.active?.data?.current?.type;
|
||||||
|
const el = event?.active?.data?.current?.previewRef
|
||||||
|
?.current as HTMLElement;
|
||||||
|
if (activeType === 'col-resize') {
|
||||||
|
const prev = el.previousElementSibling as HTMLDivElement;
|
||||||
|
const next = el.nextElementSibling as HTMLDivElement;
|
||||||
|
prev.style.width = `calc(${clientWidths[0]}px + ${event.delta.x}px)`;
|
||||||
|
next.style.width = `calc(${clientWidths[1]}px - ${event.delta.x}px)`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragOver={(event) => {
|
||||||
|
const activeType = event?.active?.data?.current?.type;
|
||||||
|
console.log({ event });
|
||||||
|
if (activeType === 'col-resize') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragEnd={async (event) => {
|
||||||
|
setActive(false);
|
||||||
|
const activeType = event?.active?.data?.current?.type;
|
||||||
|
const sourcePath = event?.active?.data?.current?.path;
|
||||||
|
const targetPath = event?.over?.data?.current?.path;
|
||||||
|
const method = event?.over?.data?.current?.method;
|
||||||
|
const type = event?.over?.data?.current?.type;
|
||||||
|
if (activeType === 'col-resize') {
|
||||||
|
const parentPath = event?.active?.data?.current?.parentPath;
|
||||||
|
const el = event?.active?.data?.current?.previewRef
|
||||||
|
?.current as HTMLElement;
|
||||||
|
const els = el.parentElement.querySelectorAll(
|
||||||
|
':scope > .nb-grid-col',
|
||||||
|
);
|
||||||
|
const size = [];
|
||||||
|
const gap = el.clientWidth;
|
||||||
|
els.forEach((el: HTMLDivElement) => {
|
||||||
|
// const w = (100 * el.clientWidth) / el.parentElement.clientWidth;
|
||||||
|
const w2 =
|
||||||
|
(100 * (el.clientWidth + gap + gap / els.length)) /
|
||||||
|
el.parentElement.clientWidth;
|
||||||
|
size.push(w2);
|
||||||
|
// el.style.width = `${w}%`;
|
||||||
|
});
|
||||||
|
const parent = findPropertyByPath(root, parentPath);
|
||||||
|
parent['x-component-props'] = parent['x-component-props'] || {};
|
||||||
|
parent['x-component-props']['colsize'] = size;
|
||||||
|
await updateSchema({
|
||||||
|
key: parent['key'],
|
||||||
|
'x-component-props': {
|
||||||
|
colsize: size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!sourcePath || !targetPath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sourcePath === targetPath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let fn = methods[method];
|
||||||
|
if (!fn && type === 'block') {
|
||||||
|
fn = methods.insertAfter;
|
||||||
|
}
|
||||||
|
console.log({ event, sourcePath, targetPath, method, type });
|
||||||
|
if (!fn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const sourceSchema = findPropertyByPath(root, sourcePath);
|
||||||
|
if (!sourceSchema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let data;
|
||||||
|
if (['col-divider', 'col-resize'].includes(type)) {
|
||||||
|
data = {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
properties: {
|
||||||
|
[sourceSchema.name]: sourceSchema.toJSON(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else if (['block', 'col'].includes(type)) {
|
||||||
|
data = sourceSchema.toJSON();
|
||||||
|
} else if (['row-divider', 'row'].includes(type)) {
|
||||||
|
data = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Row',
|
'x-component': 'Grid.Row',
|
||||||
properties: {
|
properties: {
|
||||||
@ -113,166 +168,149 @@ export const Grid: any = observer((props: any) => {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
properties: {
|
properties: {
|
||||||
[blockSchema.name]: blockSchema,
|
[sourceSchema.name]: sourceSchema.toJSON(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
await createSchema(data);
|
}
|
||||||
console.log('prepend', data);
|
if (data) {
|
||||||
const removed = deepRemove(path);
|
const removed = deepRemove(sourcePath);
|
||||||
const last = removed.pop();
|
const last = removed.pop();
|
||||||
if (isGridRowOrCol(last)) {
|
if (isGridRowOrCol(last)) {
|
||||||
await removeSchema(last);
|
await removeSchema(last);
|
||||||
}
|
}
|
||||||
}}
|
const s = fn(data, targetPath);
|
||||||
/>
|
if (['block', 'col'].includes(type)) {
|
||||||
{schema.mapProperties((property, key, index) => {
|
await updateSchema(s);
|
||||||
return (
|
} else {
|
||||||
<>
|
await createSchema(s);
|
||||||
<div style={{ display: 'flex' }} className={'nb-grid-row'}>
|
}
|
||||||
<RecursionField name={property.name} schema={property} />
|
|
||||||
</div>
|
|
||||||
<RowDivider
|
|
||||||
key={`${schema.name}_${index + 1}`}
|
|
||||||
name={`${schema.name}_${index + 1}`}
|
|
||||||
onDrop={async (e) => {
|
|
||||||
const blockSchema = e.dragItem.schema;
|
|
||||||
const path = [...e.dragItem.path];
|
|
||||||
const data = insertAfter(
|
|
||||||
{
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid.Row',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid.Col',
|
|
||||||
properties: {
|
|
||||||
[blockSchema.name]: blockSchema,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[...gridPath, key],
|
|
||||||
);
|
|
||||||
await createSchema(data);
|
|
||||||
const removed = deepRemove(path);
|
|
||||||
const last = removed.pop();
|
|
||||||
if (isGridRowOrCol(last)) {
|
|
||||||
await removeSchema(last);
|
|
||||||
}
|
|
||||||
console.log('insertAfter', data, removed);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{designable && AddNewComponent && <AddNewComponent />}
|
|
||||||
</div>
|
|
||||||
</DragDropManagerProvider>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Grid.Row = observer((props) => {
|
|
||||||
const field = useField();
|
|
||||||
// const schema = useFieldSchema();
|
|
||||||
const rowPath = useSchemaPath();
|
|
||||||
const {
|
|
||||||
schema,
|
|
||||||
schema: designableSchema,
|
|
||||||
refresh,
|
|
||||||
insertAfter,
|
|
||||||
appendChild,
|
|
||||||
prepend,
|
|
||||||
remove,
|
|
||||||
deepRemove,
|
|
||||||
} = useDesignable();
|
|
||||||
const len = Object.keys(designableSchema.properties || {}).length;
|
|
||||||
// console.log({ len, schema, designableSchema });
|
|
||||||
return (
|
|
||||||
<ColumnSizeContext.Provider value={len}>
|
|
||||||
<ColDivider
|
|
||||||
name={`${schema.name}_0`}
|
|
||||||
onDrop={async (e) => {
|
|
||||||
const blockSchema = e.dragItem.schema;
|
|
||||||
const data = prepend({
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid.Col',
|
|
||||||
properties: {
|
|
||||||
[blockSchema.name]: blockSchema,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await createSchema(data);
|
|
||||||
const path = [...e.dragItem.path];
|
|
||||||
const removed = deepRemove(path);
|
|
||||||
const last = removed.pop();
|
|
||||||
if (isGridRowOrCol(last)) {
|
|
||||||
await removeSchema(last);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
{schema.mapProperties((property, key, index) => {
|
<DragOverlay
|
||||||
return (
|
// style={{ pointerEvents: 'none' }}
|
||||||
<>
|
>
|
||||||
<RecursionField name={property.name} schema={property} />
|
<div
|
||||||
<ColDivider
|
className={'nb-grid-drag-overlay'}
|
||||||
name={`${schema.name}_${index + 1}`}
|
style={{
|
||||||
resizable={index < len - 1}
|
...style,
|
||||||
onDrop={async (e) => {
|
transform: 'translate(calc(-100% + 30px), 2px)',
|
||||||
const blockSchema = e.dragItem.schema;
|
}}
|
||||||
const data = insertAfter(
|
dangerouslySetInnerHTML={{ __html: dragOverlayContent }}
|
||||||
{
|
/>
|
||||||
type: 'void',
|
</DragOverlay>
|
||||||
'x-component': 'Grid.Col',
|
<Droppable
|
||||||
properties: {
|
id={`${schema.name}-row-divider`}
|
||||||
[blockSchema.name]: blockSchema,
|
className={'nb-grid-row-divider'}
|
||||||
},
|
data={{
|
||||||
},
|
type: 'row-divider',
|
||||||
[...rowPath, key],
|
method: 'prepend',
|
||||||
);
|
path: getSchemaPath(schema),
|
||||||
console.log('ColDivider', data);
|
}}
|
||||||
await createSchema(data);
|
/>
|
||||||
const path = [...e.dragItem.path];
|
{schema.mapProperties((property) => {
|
||||||
const removed = deepRemove(path);
|
return <RecursionField name={property.name} schema={property} />;
|
||||||
const last = removed.pop();
|
})}
|
||||||
if (isGridRowOrCol(last)) {
|
</DndContext>
|
||||||
await removeSchema(last);
|
{designable && AddNewComponent && <AddNewComponent />}
|
||||||
}
|
|
||||||
}}
|
|
||||||
onDragEnd={(e) => {
|
|
||||||
designableSchema.mapProperties((s, key, index) => {
|
|
||||||
s['x-component-props'] = s['x-component-props'] || {};
|
|
||||||
s['x-component-props']['width'] = e.data.size[index];
|
|
||||||
return s;
|
|
||||||
});
|
|
||||||
schema.mapProperties((s, key, index) => {
|
|
||||||
s['x-component-props'] = s['x-component-props'] || {};
|
|
||||||
s['x-component-props']['width'] = e.data.size[index];
|
|
||||||
field.query(`.${schema.name}.${key}`).take((f) => {
|
|
||||||
f.componentProps['width'] = e.data.size[index];
|
|
||||||
});
|
|
||||||
return s;
|
|
||||||
});
|
|
||||||
// refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ColumnSizeContext.Provider>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Grid.Col = observer((props) => {
|
|
||||||
const field = useField();
|
|
||||||
const width = field.componentProps['width'];
|
|
||||||
const size = useContext(ColumnSizeContext);
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{ width: `calc(${width || 100 / size}% - 24px - 24px / ${size})` }}
|
|
||||||
className={'nb-grid-col'}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Grid.Row = observer((props: any) => {
|
||||||
|
const { schema } = useDesignable();
|
||||||
|
const columns = Object.values(schema.properties || {}).filter((item) => {
|
||||||
|
return !item['x-hidden'];
|
||||||
|
});
|
||||||
|
const columnCount = columns.length;
|
||||||
|
const path = getSchemaPath(schema);
|
||||||
|
let size = schema['x-component-props']?.['colsize'] || [];
|
||||||
|
if (size?.length !== columnCount) {
|
||||||
|
size = [];
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<GridRowContext.Provider value={{ columnCount }}>
|
||||||
|
<Droppable
|
||||||
|
id={schema.name}
|
||||||
|
className={'nb-grid-row'}
|
||||||
|
data={{
|
||||||
|
type: 'row',
|
||||||
|
method: 'appendChild',
|
||||||
|
path,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Droppable
|
||||||
|
id={`${schema.name}-first`}
|
||||||
|
className={'nb-grid-col-divider'}
|
||||||
|
data={{
|
||||||
|
type: 'col-divider',
|
||||||
|
method: 'prepend',
|
||||||
|
path: [...path],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{columns.map((property, index) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{index > 0 && (
|
||||||
|
<SortableItem
|
||||||
|
draggable
|
||||||
|
id={`${schema.name}-${index}`}
|
||||||
|
data={{
|
||||||
|
type: 'col-resize',
|
||||||
|
method: 'insertBefore',
|
||||||
|
parentPath: [...path],
|
||||||
|
path: [...path, property.name],
|
||||||
|
}}
|
||||||
|
className={cls('nb-grid-col-divider', 'resizable')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<GridColContext.Provider value={{ index, width: size[index] }}>
|
||||||
|
<RecursionField name={property.name} schema={property} />
|
||||||
|
</GridColContext.Provider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Droppable
|
||||||
|
id={`${schema.name}-last`}
|
||||||
|
className={'nb-grid-col-divider'}
|
||||||
|
data={{
|
||||||
|
type: 'col-divider',
|
||||||
|
method: 'appendChild',
|
||||||
|
path: [...path],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Droppable>
|
||||||
|
</GridRowContext.Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Grid.Col = observer((props: any) => {
|
||||||
|
const { schema } = useDesignable();
|
||||||
|
// const { width } = props;
|
||||||
|
const { columnCount } = useContext(GridRowContext);
|
||||||
|
const { width } = useContext(GridColContext);
|
||||||
|
return (
|
||||||
|
<Droppable
|
||||||
|
id={schema.name}
|
||||||
|
className={'nb-grid-col'}
|
||||||
|
style={{
|
||||||
|
width: `calc(${
|
||||||
|
width || 100 / columnCount
|
||||||
|
}% - 24px - 24px / ${columnCount})`,
|
||||||
|
}}
|
||||||
|
data={{
|
||||||
|
type: 'col',
|
||||||
|
method: 'appendChild',
|
||||||
|
path: getSchemaPath(schema),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <Droppable
|
||||||
|
id={`${schema.name}-divider`}
|
||||||
|
className={'nb-grid-row-divider'}
|
||||||
|
/> */}
|
||||||
|
{props.children}
|
||||||
|
</Droppable>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
}
|
}
|
||||||
.nb-grid-row {
|
.nb-grid-row {
|
||||||
margin: 0px -24px;
|
margin: 0px -24px;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// .nb-grid {
|
// .nb-grid {
|
||||||
@ -96,3 +97,62 @@ body.dragging {
|
|||||||
.anticon-drag {
|
.anticon-drag {
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nb-block-item {
|
||||||
|
position: relative;
|
||||||
|
&.isDragging {
|
||||||
|
opacity: .3;
|
||||||
|
}
|
||||||
|
&.isOver::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -24px;
|
||||||
|
height: 20px;
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(241, 139, 98, 0.1) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nb-grid-row,
|
||||||
|
.nb-grid-col {
|
||||||
|
position: relative;
|
||||||
|
&.isOver::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 20px;
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(241, 139, 98, 0.1) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nb-grid-row-divider.isOver,
|
||||||
|
.nb-grid-col-divider.isOver {
|
||||||
|
background: rgba(241, 139, 98, 0.1) !important;
|
||||||
|
}
|
||||||
|
.nb-grid-drag-overlay {
|
||||||
|
opacity: 0.6;
|
||||||
|
.designable-bar {
|
||||||
|
background: rgba(241, 139, 98, 0.1) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nb-grid-row-divider {
|
||||||
|
// background-color: #ddd;
|
||||||
|
height: 24px;
|
||||||
|
width: 100%;
|
||||||
|
top: -24px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 20;
|
||||||
|
// opacity: 0.5;
|
||||||
|
// background: #e6f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nb-grid-col-divider {
|
||||||
|
&.resizable {
|
||||||
|
cursor: col-resize;
|
||||||
|
&:hover {
|
||||||
|
background: rgba(241, 139, 98, 0.1) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ import { DraggableBlockContext } from '../../components/drag-and-drop';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { removeSchema, updateSchema } from '..';
|
import { removeSchema, updateSchema } from '..';
|
||||||
import { isGridRowOrCol } from '../grid';
|
import { isGridRowOrCol } from '../grid';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
type ComposedInput = React.FC<InputProps> & {
|
type ComposedInput = React.FC<InputProps> & {
|
||||||
TextArea?: React.FC<TextAreaProps>
|
TextArea?: React.FC<TextAreaProps>
|
||||||
@ -59,7 +60,7 @@ Input.DesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={'small'}>
|
<Space size={'small'}>
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -42,9 +42,8 @@ import SwitchMenuItem from '../../components/SwitchMenuItem';
|
|||||||
|
|
||||||
export const CardDesignableBar = observer((props) => {
|
export const CardDesignableBar = observer((props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const { designable, schema, appendChild, deepRemove } = useDesignable();
|
const { schema, appendChild, deepRemove } = useDesignable();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { dragRef } = useContext(DraggableBlockContext);
|
|
||||||
const { collection, fields } = useCollectionContext();
|
const { collection, fields } = useCollectionContext();
|
||||||
const displayed = useDisplayedMapContext();
|
const displayed = useDisplayedMapContext();
|
||||||
console.log('useDisplayedMapContext', schema);
|
console.log('useDisplayedMapContext', schema);
|
||||||
|
@ -28,6 +28,7 @@ import { uid } from '@formily/shared';
|
|||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
import { useCollection, useCollectionContext } from '../../constate';
|
import { useCollection, useCollectionContext } from '../../constate';
|
||||||
import { useTable } from '../table';
|
import { useTable } from '../table';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
export const DesignableBar = observer((props) => {
|
export const DesignableBar = observer((props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -48,7 +49,7 @@ export const DesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={2}>
|
<Space size={2}>
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
observer,
|
observer,
|
||||||
RecursionField,
|
RecursionField,
|
||||||
@ -38,6 +38,7 @@ import { CardDesignableBar } from './CardDesignableBar';
|
|||||||
import { VisibleContext } from '../../context';
|
import { VisibleContext } from '../../context';
|
||||||
|
|
||||||
export function SortableItem(props) {
|
export function SortableItem(props) {
|
||||||
|
const nodeRef = useRef<any>();
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
listeners,
|
listeners,
|
||||||
@ -49,6 +50,7 @@ export function SortableItem(props) {
|
|||||||
id: props.id,
|
id: props.id,
|
||||||
data: {
|
data: {
|
||||||
type: props.type,
|
type: props.type,
|
||||||
|
nodeRef,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,7 +62,10 @@ export function SortableItem(props) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cls({ isDragging }, props.className)}
|
className={cls({ isDragging }, props.className)}
|
||||||
ref={setNodeRef}
|
ref={(el) => {
|
||||||
|
setNodeRef(el);
|
||||||
|
nodeRef.current = el;
|
||||||
|
}}
|
||||||
style={style}
|
style={style}
|
||||||
{...attributes}
|
{...attributes}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
@ -155,6 +160,10 @@ const InternalKanban = observer((props: any) => {
|
|||||||
sort: 'sort',
|
sort: 'sort',
|
||||||
});
|
});
|
||||||
}, [props.defaultFilter]);
|
}, [props.defaultFilter]);
|
||||||
|
const [dragOverlayContent, setDragOverlayContent] = useState('');
|
||||||
|
const [style, setStyle] = useState({});
|
||||||
|
const containerRef = useRef<HTMLDivElement>();
|
||||||
|
console.log({ style })
|
||||||
return (
|
return (
|
||||||
<KanbanContext.Provider value={{ field, resource, service, props }}>
|
<KanbanContext.Provider value={{ field, resource, service, props }}>
|
||||||
<div>
|
<div>
|
||||||
@ -162,8 +171,15 @@ const InternalKanban = observer((props: any) => {
|
|||||||
<Button>筛选</Button>
|
<Button>筛选</Button>
|
||||||
</div> */}
|
</div> */}
|
||||||
<div className={'kanban'}>
|
<div className={'kanban'}>
|
||||||
<div className={'kanban-container'}>
|
<div ref={containerRef} className={'kanban-container'}>
|
||||||
<DndContext
|
<DndContext
|
||||||
|
onDragStart={(event) => {
|
||||||
|
const el = event?.active?.data?.current?.nodeRef
|
||||||
|
?.current as HTMLElement;
|
||||||
|
console.log(event, el);
|
||||||
|
setDragOverlayContent(el?.outerHTML);
|
||||||
|
setStyle({ width: el.clientWidth, height: containerRef.current?.clientHeight });
|
||||||
|
}}
|
||||||
// collisionDetection={closestCorners}
|
// collisionDetection={closestCorners}
|
||||||
onDragEnd={({ active, over }) => {
|
onDragEnd={({ active, over }) => {
|
||||||
const source = values.find((item) => item.id === active?.id);
|
const source = values.find((item) => item.id === active?.id);
|
||||||
@ -208,7 +224,17 @@ const InternalKanban = observer((props: any) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DragOverlay style={{ pointerEvents: 'none' }}>aaa</DragOverlay>
|
<DragOverlay
|
||||||
|
// style={{ pointerEvents: 'none' }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={'nb-kanban-drag-overlay'}
|
||||||
|
style={{
|
||||||
|
...style,
|
||||||
|
}}
|
||||||
|
dangerouslySetInnerHTML={{ __html: dragOverlayContent }}
|
||||||
|
/>
|
||||||
|
</DragOverlay>
|
||||||
|
|
||||||
<SortableContext
|
<SortableContext
|
||||||
strategy={horizontalListSortingStrategy}
|
strategy={horizontalListSortingStrategy}
|
||||||
@ -288,7 +314,9 @@ const InternalKanban = observer((props: any) => {
|
|||||||
className={'column add-column'}
|
className={'column add-column'}
|
||||||
>
|
>
|
||||||
{/* <span className={'add-column-plus'}/> */}
|
{/* <span className={'add-column-plus'}/> */}
|
||||||
<span><PlusOutlined/> 添加列表</span>
|
<span>
|
||||||
|
<PlusOutlined /> 添加列表
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
&.isDragging {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
&.add-column {
|
&.add-column {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
@ -35,6 +38,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nb-kanban-drag-overlay {
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
|
||||||
.column-title {
|
.column-title {
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -47,8 +54,7 @@
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
.item {
|
.item {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 50px;
|
// background: #f1f1f1;
|
||||||
background: #f1f1f1;
|
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
&.isDragging {
|
&.isDragging {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
@ -68,6 +74,15 @@
|
|||||||
|
|
||||||
.kanban .ant-card-body {
|
.kanban .ant-card-body {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
> .nb-block-item {
|
||||||
|
padding: 12px;
|
||||||
|
min-height: 50px;
|
||||||
|
}
|
||||||
|
.nb-grid-block, .ant-formily-item {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
> .designable-bar {
|
> .designable-bar {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -21,6 +21,7 @@ import { uid } from '@formily/shared';
|
|||||||
import { removeSchema, updateSchema } from '..';
|
import { removeSchema, updateSchema } from '..';
|
||||||
import { isGridRowOrCol } from '../grid';
|
import { isGridRowOrCol } from '../grid';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
export const Markdown: any = connect(
|
export const Markdown: any = connect(
|
||||||
AntdInput.TextArea,
|
AntdInput.TextArea,
|
||||||
@ -121,7 +122,7 @@ Markdown.Void.DesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={'small'}>
|
<Space size={'small'}>
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
@ -182,7 +183,7 @@ Markdown.DesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={'small'}>
|
<Space size={'small'}>
|
||||||
<AddNew.FormItem defaultAction={'insertAfter'} ghost />
|
<AddNew.FormItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -33,6 +33,7 @@ import { useEffect } from 'react';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { getSchemaPath } from '../../components/schema-renderer';
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
import { set } from 'lodash';
|
import { set } from 'lodash';
|
||||||
|
import { DragHandle } from '../../components/Sortable';
|
||||||
|
|
||||||
export const SimpleDesignableBar = observer((props) => {
|
export const SimpleDesignableBar = observer((props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
@ -54,7 +55,7 @@ export const SimpleDesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={'small'}>
|
<Space size={'small'}>
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -2015,7 +2015,7 @@ Table.DesignableBar = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Space size={2}>
|
<Space size={2}>
|
||||||
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
{dragRef && <DragOutlined ref={dragRef} />}
|
<DragHandle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
Loading…
Reference in New Issue
Block a user