feat: improve dnd
This commit is contained in:
parent
8a2ab9f86b
commit
3b5f43ea09
@ -1,19 +1,11 @@
|
|||||||
import { useDroppable } from '@dnd-kit/core';
|
import { useDndMonitor, useDroppable } from '@dnd-kit/core';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { DndContext } from '../../common/dnd-context';
|
import { DndContext } from '../../common/dnd-context';
|
||||||
|
|
||||||
export const Grid: any = observer((props) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<DndContext>{props.children}</DndContext>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const ColDivider = (props) => {
|
const ColDivider = (props) => {
|
||||||
const { isOver, setNodeRef } = useDroppable({
|
const { isOver, setNodeRef } = useDroppable({
|
||||||
id: props.id,
|
id: props.id,
|
||||||
@ -27,6 +19,88 @@ const ColDivider = (props) => {
|
|||||||
return <div ref={setNodeRef} style={{ width: 24, ...droppableStyle }}></div>;
|
return <div ref={setNodeRef} style={{ width: 24, ...droppableStyle }}></div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const RowDivider = (props) => {
|
||||||
|
const { isOver, setNodeRef } = useDroppable({
|
||||||
|
id: props.id,
|
||||||
|
data: props.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
const droppableStyle = {};
|
||||||
|
|
||||||
|
if (isOver) {
|
||||||
|
droppableStyle['backgroundColor'] = 'green';
|
||||||
|
}
|
||||||
|
|
||||||
|
const [active, setActive] = useState(false);
|
||||||
|
|
||||||
|
useDndMonitor({
|
||||||
|
onDragStart(event) {
|
||||||
|
setActive(true);
|
||||||
|
},
|
||||||
|
onDragMove(event) {},
|
||||||
|
onDragOver(event) {},
|
||||||
|
onDragEnd(event) {
|
||||||
|
setActive(false);
|
||||||
|
},
|
||||||
|
onDragCancel(event) {
|
||||||
|
setActive(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={setNodeRef}
|
||||||
|
style={{
|
||||||
|
zIndex: active ? 1000 : 0,
|
||||||
|
height: 24,
|
||||||
|
width: '100%',
|
||||||
|
position: 'absolute',
|
||||||
|
marginTop: -24,
|
||||||
|
...droppableStyle,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Grid: any = observer((props) => {
|
||||||
|
const field = useField();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const addr = field.address.toString();
|
||||||
|
const wrapSchema = (schema: Schema) => {
|
||||||
|
const row = new Schema({
|
||||||
|
type: 'void',
|
||||||
|
name: `row_${uid()}`,
|
||||||
|
'x-uid': uid(),
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
});
|
||||||
|
const col = row.addProperty(uid(), {
|
||||||
|
type: 'void',
|
||||||
|
'x-uid': uid(),
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
});
|
||||||
|
if (Schema.isSchemaInstance(schema)) {
|
||||||
|
schema.parent = col;
|
||||||
|
}
|
||||||
|
col.addProperty(schema.name, schema);
|
||||||
|
return row;
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className={'nb-grid'} style={{ position: 'relative' }}>
|
||||||
|
<DndContext>
|
||||||
|
<RowDivider id={`${addr}_0`} data={{ wrapSchema, insertAdjacent: 'afterBegin', schema: fieldSchema }} />
|
||||||
|
{fieldSchema.mapProperties((schema, key, index) => {
|
||||||
|
return (
|
||||||
|
<React.Fragment key={key}>
|
||||||
|
<RecursionField name={key} schema={schema} />
|
||||||
|
<RowDivider id={`${addr}_${index + 1}`} data={{ wrapSchema, insertAdjacent: 'afterEnd', schema }} />
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</DndContext>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Grid.Row = observer((props) => {
|
Grid.Row = observer((props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
@ -58,6 +132,8 @@ Grid.Row = observer((props) => {
|
|||||||
css`
|
css`
|
||||||
margin: 0 -24px;
|
margin: 0 -24px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
`,
|
`,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@ -81,5 +157,17 @@ Grid.Row = observer((props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Grid.Col = observer((props) => {
|
Grid.Col = observer((props) => {
|
||||||
return <div className={cls('nb-grid-col')}>{props.children}</div>;
|
return (
|
||||||
|
<div
|
||||||
|
className={cls(
|
||||||
|
'nb-grid-col',
|
||||||
|
css`
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { DndContext as DndKitContext, DragEndEvent } from '@dnd-kit/core';
|
import { DndContext as DndKitContext, DragEndEvent, rectIntersection } from '@dnd-kit/core';
|
||||||
import { observer } from '@formily/react';
|
import { observer } from '@formily/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createDesignable, useDesignable } from '../../hooks';
|
import { createDesignable, useDesignable } from '../../hooks';
|
||||||
@ -12,12 +12,15 @@ const useDragEnd = () => {
|
|||||||
const overSchema = over?.data?.current?.schema;
|
const overSchema = over?.data?.current?.schema;
|
||||||
const insertAdjacent = over?.data?.current?.insertAdjacent;
|
const insertAdjacent = over?.data?.current?.insertAdjacent;
|
||||||
const wrapSchema = over?.data?.current?.wrapSchema;
|
const wrapSchema = over?.data?.current?.wrapSchema;
|
||||||
const onInsertAdjacent = over?.data?.current?.onInsertAdjacent;
|
|
||||||
|
|
||||||
if (!activeSchema || !overSchema) {
|
if (!activeSchema || !overSchema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (activeSchema === overSchema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const dn = createDesignable({
|
const dn = createDesignable({
|
||||||
current: overSchema,
|
current: overSchema,
|
||||||
});
|
});
|
||||||
@ -30,21 +33,19 @@ const useDragEnd = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (insertAdjacent) {
|
if (insertAdjacent) {
|
||||||
console.log('removeIfChildrenEmpty', activeSchema);
|
|
||||||
dn.insertAdjacent(insertAdjacent, activeSchema, {
|
dn.insertAdjacent(insertAdjacent, activeSchema, {
|
||||||
wrap: wrapSchema,
|
wrap: wrapSchema,
|
||||||
removeEmptyParents: true,
|
removeEmptyParents: true,
|
||||||
});
|
});
|
||||||
// onInsertAdjacent && onInsertAdjacent({
|
|
||||||
// dn,
|
|
||||||
// orginDraggedParentSchema,
|
|
||||||
// draggedSchema: activeSchema,
|
|
||||||
// });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DndContext = observer((props) => {
|
export const DndContext = observer((props) => {
|
||||||
return <DndKitContext onDragEnd={useDragEnd()}>{props.children}</DndKitContext>;
|
return (
|
||||||
|
<DndKitContext collisionDetection={rectIntersection} onDragEnd={useDragEnd()}>
|
||||||
|
{props.children}
|
||||||
|
</DndKitContext>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export * from './dnd-context';
|
export * from './dnd-context';
|
||||||
export * from './sortable-item';
|
export * from './sortable-item';
|
||||||
|
|
||||||
|
@ -47,15 +47,40 @@ export const SortableItem = observer((props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const DragHandler = () => {
|
export const DragHandler = () => {
|
||||||
const { attributes, listeners, setNodeRef, transform } = useContext(DraggableContext);
|
const { isDragging, attributes, listeners, setNodeRef, transform } = useContext(DraggableContext);
|
||||||
const style = transform
|
const style = transform
|
||||||
? {
|
? {
|
||||||
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
|
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={setNodeRef} style={{ ...style, display: 'inline-block' }} {...listeners} {...attributes}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: isDragging ? 'inline-block' : 'none', fontSize: 10, position: 'absolute', zIndex: 0 }}>
|
||||||
Drag
|
Drag
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
ref={setNodeRef}
|
||||||
|
style={{
|
||||||
|
...style,
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 1,
|
||||||
|
backgroundColor: '#333',
|
||||||
|
lineHeight: 0,
|
||||||
|
height: 2,
|
||||||
|
width: 2,
|
||||||
|
fontSize: 0,
|
||||||
|
display: 'inline-block',
|
||||||
|
}}
|
||||||
|
{...listeners}
|
||||||
|
{...attributes}
|
||||||
|
>
|
||||||
|
<div style={{ fontSize: 10 }}>Drag</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -86,11 +86,10 @@ export class Designable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeIfChildrenEmpty(schema?: Schema, options: { recursive?: boolean } = {}) {
|
removeIfChildrenEmpty(schema?: Schema) {
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { recursive } = options;
|
|
||||||
let s = schema;
|
let s = schema;
|
||||||
const count = Object.keys(s.properties || {}).length;
|
const count = Object.keys(s.properties || {}).length;
|
||||||
console.log('removeIfChildrenEmpty', count, s.properties);
|
console.log('removeIfChildrenEmpty', count, s.properties);
|
||||||
@ -100,9 +99,6 @@ export class Designable {
|
|||||||
let removed;
|
let removed;
|
||||||
while (s.parent) {
|
while (s.parent) {
|
||||||
removed = s.parent.removeProperty(s.name);
|
removed = s.parent.removeProperty(s.name);
|
||||||
if (!recursive) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const count = Object.keys(s.parent.properties || {}).length;
|
const count = Object.keys(s.parent.properties || {}).length;
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
break;
|
break;
|
||||||
@ -254,6 +250,7 @@ export class Designable {
|
|||||||
const { wrap = defaultWrap, removeEmptyParents } = options;
|
const { wrap = defaultWrap, removeEmptyParents } = options;
|
||||||
if (Schema.isSchemaInstance(schema)) {
|
if (Schema.isSchemaInstance(schema)) {
|
||||||
schema.parent.removeProperty(schema.name);
|
schema.parent.removeProperty(schema.name);
|
||||||
|
console.log('insertAfterEnd', removeEmptyParents)
|
||||||
if (removeEmptyParents) {
|
if (removeEmptyParents) {
|
||||||
this.removeIfChildrenEmpty(schema.parent);
|
this.removeIfChildrenEmpty(schema.parent);
|
||||||
}
|
}
|
||||||
@ -327,8 +324,8 @@ export function useDesignable() {
|
|||||||
remove() {
|
remove() {
|
||||||
dn.remove();
|
dn.remove();
|
||||||
},
|
},
|
||||||
insertAdjacent(position: Position, schema: ISchema) {
|
insertAdjacent(position: Position, schema: ISchema, options: InsertAdjacentOptions = {}) {
|
||||||
dn.insertAdjacent(position, schema);
|
dn.insertAdjacent(position, schema, options);
|
||||||
},
|
},
|
||||||
insertBeforeBegin(schema: ISchema) {
|
insertBeforeBegin(schema: ISchema) {
|
||||||
dn.insertBeforeBegin(schema);
|
dn.insertBeforeBegin(schema);
|
||||||
|
Loading…
Reference in New Issue
Block a user