feat: improve dnd

This commit is contained in:
chenos 2022-02-07 21:51:29 +08:00
parent 8a2ab9f86b
commit 3b5f43ea09
5 changed files with 142 additions and 30 deletions

View File

@ -1,19 +1,11 @@
import { useDroppable } from '@dnd-kit/core';
import { useDndMonitor, useDroppable } from '@dnd-kit/core';
import { css } from '@emotion/css';
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
import { uid } from '@formily/shared';
import cls from 'classnames';
import React from 'react';
import React, { useState } from 'react';
import { DndContext } from '../../common/dnd-context';
export const Grid: any = observer((props) => {
return (
<div>
<DndContext>{props.children}</DndContext>
</div>
);
});
const ColDivider = (props) => {
const { isOver, setNodeRef } = useDroppable({
id: props.id,
@ -27,6 +19,88 @@ const ColDivider = (props) => {
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) => {
const field = useField();
const fieldSchema = useFieldSchema();
@ -58,6 +132,8 @@ Grid.Row = observer((props) => {
css`
margin: 0 -24px;
display: flex;
position: relative;
z-index: 0;
`,
)}
>
@ -81,5 +157,17 @@ Grid.Row = 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>
);
});

View File

@ -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 React from 'react';
import { createDesignable, useDesignable } from '../../hooks';
@ -12,12 +12,15 @@ const useDragEnd = () => {
const overSchema = over?.data?.current?.schema;
const insertAdjacent = over?.data?.current?.insertAdjacent;
const wrapSchema = over?.data?.current?.wrapSchema;
const onInsertAdjacent = over?.data?.current?.onInsertAdjacent;
if (!activeSchema || !overSchema) {
return;
}
if (activeSchema === overSchema) {
return;
}
const dn = createDesignable({
current: overSchema,
});
@ -30,21 +33,19 @@ const useDragEnd = () => {
}
if (insertAdjacent) {
console.log('removeIfChildrenEmpty', activeSchema);
dn.insertAdjacent(insertAdjacent, activeSchema, {
wrap: wrapSchema,
removeEmptyParents: true,
});
// onInsertAdjacent && onInsertAdjacent({
// dn,
// orginDraggedParentSchema,
// draggedSchema: activeSchema,
// });
return;
}
};
};
export const DndContext = observer((props) => {
return <DndKitContext onDragEnd={useDragEnd()}>{props.children}</DndKitContext>;
return (
<DndKitContext collisionDetection={rectIntersection} onDragEnd={useDragEnd()}>
{props.children}
</DndKitContext>
);
});

View File

@ -1,2 +1,3 @@
export * from './dnd-context';
export * from './sortable-item';

View File

@ -47,15 +47,40 @@ export const SortableItem = observer((props) => {
});
export const DragHandler = () => {
const { attributes, listeners, setNodeRef, transform } = useContext(DraggableContext);
const { isDragging, attributes, listeners, setNodeRef, transform } = useContext(DraggableContext);
const style = transform
? {
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
}
: undefined;
return (
<div ref={setNodeRef} style={{ ...style, display: 'inline-block' }} {...listeners} {...attributes}>
Drag
<div
style={{
display: 'inline-block',
}}
>
<div style={{ display: isDragging ? 'inline-block' : 'none', fontSize: 10, position: 'absolute', zIndex: 0 }}>
Drag
</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>
);
};

View File

@ -86,11 +86,10 @@ export class Designable {
}
}
removeIfChildrenEmpty(schema?: Schema, options: { recursive?: boolean } = {}) {
removeIfChildrenEmpty(schema?: Schema) {
if (!schema) {
return;
}
const { recursive } = options;
let s = schema;
const count = Object.keys(s.properties || {}).length;
console.log('removeIfChildrenEmpty', count, s.properties);
@ -100,9 +99,6 @@ export class Designable {
let removed;
while (s.parent) {
removed = s.parent.removeProperty(s.name);
if (!recursive) {
break;
}
const count = Object.keys(s.parent.properties || {}).length;
if (count > 0) {
break;
@ -254,6 +250,7 @@ export class Designable {
const { wrap = defaultWrap, removeEmptyParents } = options;
if (Schema.isSchemaInstance(schema)) {
schema.parent.removeProperty(schema.name);
console.log('insertAfterEnd', removeEmptyParents)
if (removeEmptyParents) {
this.removeIfChildrenEmpty(schema.parent);
}
@ -327,8 +324,8 @@ export function useDesignable() {
remove() {
dn.remove();
},
insertAdjacent(position: Position, schema: ISchema) {
dn.insertAdjacent(position, schema);
insertAdjacent(position: Position, schema: ISchema, options: InsertAdjacentOptions = {}) {
dn.insertAdjacent(position, schema, options);
},
insertBeforeBegin(schema: ISchema) {
dn.insertBeforeBegin(schema);