Skip to content

Commit

Permalink
feat(): support action item drag
Browse files Browse the repository at this point in the history
  • Loading branch information
qiaofengxi committed May 23, 2024
1 parent da60814 commit 0e1cb1f
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 1 deletion.
27 changes: 27 additions & 0 deletions bricks/basic/docs/eo-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,30 @@ events:
args:
- click delete button
```

### item draggable

```yaml preview
brick: eo-actions
properties:
itemDraggable: true
actions:
- text: document
icon:
lib: antd
icon: folder
dragConf:
format: text/plain
data:
category: document
title: 文档
- text: file
icon:
lib: antd
icon: file
dragConf:
format: text/plain
data:
category: file
title: 文件
```
50 changes: 50 additions & 0 deletions bricks/basic/src/actions/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,54 @@ describe("eo-actions", () => {
});
expect(element.shadowRoot?.childNodes.length).toBe(0);
});

test("item draggable", async () => {
const onItemDragStart = jest.fn();
const onItemDragEnd = jest.fn();

const element = document.createElement("eo-actions") as EoActions;
element.itemDraggable = true;
element.actions = [
{
text: "drag item 1",
dragConf: {
format: "text/plain",
data: {
a: 1,
},
},
},
{
text: "drag item 2",
dragConf: {
format: "text/plain",
data: {
a: 2,
},
},
},
];
element.addEventListener("item.drag.start", onItemDragStart);
element.addEventListener("item.drag.start", onItemDragEnd);

expect(element.shadowRoot).toBeFalsy();

act(() => {
document.body.appendChild(element);
});

act(() => {
fireEvent.dragStart(
element.shadowRoot?.querySelectorAll("eo-menu-item")[0] as HTMLElement
);
});
expect(onItemDragStart).toBeCalled();

act(() => {
fireEvent.dragEnd(
element.shadowRoot?.querySelectorAll("eo-menu-item")[0] as HTMLElement
);
});
expect(onItemDragEnd).toBeCalled();
});
});
63 changes: 63 additions & 0 deletions bricks/basic/src/actions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ export interface SimpleAction {
href?: string;
target?: Target;
danger?: boolean;
dragConf?: {
format: string;
data: unknown;
};
}

export interface SubeMenuItemAction extends SimpleAction {
Expand All @@ -148,15 +152,20 @@ export type Action = SimpleAction | Divider | SubeMenuAction;

export interface ActionsProps {
actions?: Action[];
itemDraggable?: boolean;
checkedKeys?: string[];
}

export interface ActionsEvents {
"action.click": CustomEvent<SimpleAction>;
"item.drag.start": CustomEvent<SimpleAction>;
"item.drag.end": CustomEvent<SimpleAction>;
}

export interface ActionsEventsMapping {
onActionClick: "action.click";
onItemDragEnd: "item.drag.end";
onItemDragStart: "item.drag.start";
}

/**
Expand Down Expand Up @@ -185,39 +194,78 @@ class EoActions extends ReactNextElement implements ActionsProps {
})
accessor checkedKeys: string[] = [];

/**
* action中的菜单项是否可拖拽
*/
@property({ type: Boolean })
accessor itemDraggable: boolean | undefined;

/**
* 点击按钮时触发
* @detail 该按钮配置
*/
@event({ type: "action.click" })
accessor #actionClickEvent!: EventEmitter<SimpleAction>;

/**
* 开始拖拽菜单项时触发
*
* @detail 该菜单项动作配置
*/
@event({ type: "item.drag.start" })
accessor #itemDragStartEvent!: EventEmitter<SimpleAction>;

/**
* 完成拖拽菜单项时触发
*
* @detail 该菜单项动作配置
*/
@event({ type: "item.drag.end" })
accessor #itemDragEndEvent!: EventEmitter<SimpleAction>;

#handleActionClick = (action: SimpleAction): void => {
this.#actionClickEvent.emit(action);
if (action.event) {
this.dispatchEvent(new CustomEvent(action.event, { detail: action }));
}
};

#handleItemDragEnd = (action: SimpleAction): void => {
this.#itemDragEndEvent.emit(action);
};

#handleItemDragStart = (action: SimpleAction): void => {
this.#itemDragStartEvent.emit(action);
};

render() {
return (
<EoActionsComponent
actions={this.actions}
itemDraggable={this.itemDraggable}
onActionClick={this.#handleActionClick}
onItemDragStart={this.#handleItemDragStart}
onItemDragEnd={this.#handleItemDragEnd}
checkedKeys={this.checkedKeys}
/>
);
}
}

export interface ActionsComponentProps extends ActionsProps {
itemDraggable?: boolean;
onActionClick?: (action: SimpleAction) => void;
onItemDragEnd?: (action: SimpleAction) => void;
onItemDragStart?: (action: SimpleAction) => void;
}

export function EoActionsComponent({
actions,
checkedKeys,
onActionClick,
itemDraggable,
onItemDragStart,
onItemDragEnd,
}: ActionsComponentProps) {
const filteredActions = useMemo(() => {
return actions?.filter((action) => !action.hidden);
Expand Down Expand Up @@ -248,12 +296,27 @@ export function EoActionsComponent({
className={classnames({
"menu-item-danger": action.danger,
})}
draggable={itemDraggable}
icon={action.icon}
disabled={action.disabled}
onClick={(e: React.MouseEvent) => {
e.stopPropagation();
onActionClick?.(action);
}}
onDragStart={(e: React.DragEvent) => {
if (action.dragConf) {
e.dataTransfer?.setData(
action.dragConf.format,
JSON.stringify(action.dragConf.data)
);
(e.target as HTMLElement).classList.add("dragging");
}
onItemDragStart?.(action);
}}
onDragEnd={(e: React.DragEvent) => {
(e.target as HTMLElement).classList.remove("dragging");
onItemDragEnd?.(action);
}}
>
{action.text}
</WrappedMenuItem>
Expand Down
8 changes: 8 additions & 0 deletions bricks/basic/src/actions/styles.shadow.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ eo-menu-item:not([disabled]):hover::part(menu-item) {
background-color: var(--left-sidebar-item-hover-bg);
}

eo-menu-item.dragging {
opacity: 0.5;
}

eo-menu-item[draggable="true"]::part(menu-item) {
cursor: grab;
}

eo-tooltip {
display: block;
}
Expand Down
43 changes: 43 additions & 0 deletions bricks/basic/src/context-menu/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,47 @@ describe("eo-context-menu", () => {
document.body.removeChild(element);
});
});

test("item draggable", async () => {
const onItemDragStart = jest.fn();
const onItemDragEnd = jest.fn();
const element = document.createElement("eo-context-menu") as EoContextMenu;
element.addEventListener("item.drag.start", (e: Event) =>
onItemDragStart((e as CustomEvent).detail)
);

element.addEventListener("item.drag.end", (e: Event) =>
onItemDragEnd((e as CustomEvent).detail)
);

act(() => {
document.body.appendChild(element);
});

act(() => {
fireEvent(
element.shadowRoot!.querySelector("eo-actions")!,
new CustomEvent("item.drag.start", {
detail: { text: "item", dragConf: { key: "text", data: {} } },
})
);
});
expect(onItemDragStart).toBeCalledWith({
text: "item",
dragConf: { key: "text", data: {} },
});

act(() => {
fireEvent(
element.shadowRoot!.querySelector("eo-actions")!,
new CustomEvent("item.drag.end", {
detail: { text: "item", dragConf: { key: "text", data: {} } },
})
);
});
expect(onItemDragEnd).toBeCalledWith({
text: "item",
dragConf: { key: "text", data: {} },
});
});
});
Loading

0 comments on commit 0e1cb1f

Please sign in to comment.