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