-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: panxiaoliang <panxiaoliang>
- Loading branch information
1 parent
932eb71
commit d73836c
Showing
13 changed files
with
754 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/** | ||
* title: Basic usage | ||
* desc: The drop area can accept files, uri, text or one of the boxes below. | ||
* | ||
* title.zh-CN: 基础用法 | ||
* desc.zh-CN: 拖拽区域可以接受文件,链接,文字,和下方的 box 节点。 | ||
*/ | ||
|
||
import React, { useRef, useState } from "react"; | ||
import { useDrag } from "../../src"; | ||
import { useDrop } from "../../../useDrop/src"; | ||
const DragItem = ({ data }) => { | ||
const dragRef = useRef(null); | ||
|
||
const [dragging, setDragging] = useState(false); | ||
|
||
useDrag(data, dragRef, { | ||
onDragStart: () => { | ||
setDragging(true); | ||
}, | ||
onDragEnd: () => { | ||
setDragging(false); | ||
}, | ||
}); | ||
|
||
return ( | ||
<div | ||
ref={dragRef} | ||
style={{ | ||
border: "1px solid #e8e8e8", | ||
padding: 16, | ||
width: 80, | ||
textAlign: "center", | ||
marginRight: 16, | ||
}} | ||
> | ||
{dragging ? "dragging" : `box-${data}`} | ||
</div> | ||
); | ||
}; | ||
|
||
export default () => { | ||
const [isHovering, setIsHovering] = useState(false); | ||
|
||
const dropRef = useRef(null); | ||
|
||
useDrop(dropRef, { | ||
onText: (text, e) => { | ||
console.log(e); | ||
alert(`'text: ${text}' dropped`); | ||
}, | ||
onFiles: (files, e) => { | ||
console.log(e, files); | ||
alert(`${files.length} file dropped`); | ||
}, | ||
onUri: (uri, e) => { | ||
console.log(e); | ||
alert(`uri: ${uri} dropped`); | ||
}, | ||
onDom: (content: string, e) => { | ||
alert(`custom: ${content} dropped`); | ||
}, | ||
onDragEnter: () => setIsHovering(true), | ||
onDragLeave: () => setIsHovering(false), | ||
}); | ||
|
||
return ( | ||
<div> | ||
<div | ||
ref={dropRef} | ||
style={{ | ||
border: "1px dashed #e8e8e8", | ||
padding: 16, | ||
textAlign: "center", | ||
}} | ||
> | ||
{isHovering ? "release here" : "drop here"} | ||
</div> | ||
|
||
<div style={{ display: "flex", marginTop: 8, overflow: "auto" }}> | ||
{["1", "2", "3", "4", "5"].map((e) => ( | ||
<DragItem key={e} data={e} /> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/** | ||
* title: Customize Image | ||
* desc: Customize image that follow the mouse pointer during dragging. | ||
* | ||
* title.zh-CN: 自定义拖拽图像 | ||
* desc.zh-CN: 自定义拖拽过程中跟随鼠标指针的图像。 | ||
*/ | ||
|
||
import React, { useRef } from "react"; | ||
import { useDrag } from "../../src"; | ||
|
||
const COMMON_STYLE: React.CSSProperties = { | ||
border: "1px solid #e8e8e8", | ||
height: "50px", | ||
lineHeight: "50px", | ||
padding: "16px", | ||
textAlign: "center", | ||
marginRight: "16px", | ||
}; | ||
|
||
export default () => { | ||
const dragRef = useRef(null); | ||
|
||
useDrag("", dragRef, { | ||
dragImage: { | ||
image: "/logo.svg", | ||
}, | ||
}); | ||
|
||
return ( | ||
<div ref={dragRef} style={{ display: "flex" }}> | ||
<img style={COMMON_STYLE} src="/logo.svg" /> | ||
<div style={COMMON_STYLE}>drag me</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
--- | ||
title: useDrop & useDrag | ||
group: | ||
title: Dom | ||
order: 70 | ||
|
||
--- | ||
|
||
# useDrop & useDrag | ||
|
||
处理元素拖拽的 Hook。 | ||
|
||
> useDrop 可以单独使用来接收文件、文字和网址的拖拽。 | ||
> | ||
> useDrag 允许一个 DOM 节点被拖拽,需要配合 useDrop 使用。 | ||
> | ||
> 向节点内触发粘贴动作也会被视为拖拽。 | ||
## 代码演示 | ||
|
||
### 基础用法 | ||
|
||
<code src="./demo/demo1.tsx" ></code> | ||
|
||
### 自定义拖拽图像 | ||
|
||
<code src="./demo/demo2.tsx" ></code> | ||
|
||
## API | ||
|
||
### useDrag | ||
|
||
```typescript | ||
useDrag<T>( | ||
data: any, | ||
target: (() => Element) | Element | MutableRefObject<Element>, | ||
options?: DragOptions | ||
); | ||
``` | ||
|
||
#### Params | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
| ------- | --------------------- | ----------------------------------------------------------- | ------ | | ||
| data | 拖拽的内容 | `any` | - | | ||
| target | DOM 节点或者 Ref 对象 | `() => Element` \| `Element` \| `MutableRefObject<Element>` | - | | ||
| options | 额外的配置项 | `DragOptions` | - | | ||
|
||
#### DragOptions | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
| ----------- | ---------------------------------- | ------------------------------ | ------ | | ||
| onDragStart | 开始拖拽的回调 | `(e: React.DragEvent) => void` | - | | ||
| onDragEnd | 结束拖拽的回调 | `(e: React.DragEvent) => void` | - | | ||
| dragImage | 自定义拖拽过程中跟随鼠标指针的图像 | `DragImageOptions` | - | | ||
|
||
#### DragImageOptions | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | ------ | | ||
| image | 拖拽过程中跟随鼠标指针的图像。图像通常是一个 [`<img>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) 元素,但也可以是 [`<canvas>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas) 或任何其他图像元素。 | `string \| Element` | - | | ||
| offsetX | 水平偏移 | `number` | 0 | | ||
| offsetY | 垂直偏移 | `number` | 0 | | ||
|
||
### useDrop | ||
|
||
```typescript | ||
useDrop<T>( | ||
target: (() => Element) | Element | MutableRefObject<Element>, | ||
options?: DropOptions | ||
); | ||
``` | ||
|
||
#### Params | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
| ------- | --------------------- | ----------------------------------------------------------- | ------ | | ||
| target | DOM 节点或者 Ref 对象 | `() => Element` \| `Element` \| `MutableRefObject<Element>` | - | | ||
| options | 额外的配置项 | `DragOptions` | - | | ||
|
||
#### DropOptions | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
| ----------- | ------------------------------ | --------------------------------------------- | ------ | | ||
| onText | 拖拽/粘贴文字的回调 | `(text: string, e: React.DragEvent) => void` | - | | ||
| onFiles | 拖拽/粘贴文件的回调 | `(files: File[], e: React.DragEvent) => void` | - | | ||
| onUri | 拖拽/粘贴链接的回调 | `(text: string, e: React.DragEvent) => void` | - | | ||
| onDom | 拖拽/粘贴自定义 DOM 节点的回调 | `(content: any, e: React.DragEvent) => void` | - | | ||
| onDrop | 拖拽任意内容的回调 | `(e: React.DragEvent) => void` | - | | ||
| onPaste | 粘贴内容的回调 | `(e: React.DragEvent) => void` | - | | ||
| onDragEnter | 拖拽进入 | `(e: React.DragEvent) => void` | - | | ||
| onDragOver | 拖拽中 | `(e: React.DragEvent) => void` | - | | ||
| onDragLeave | 拖拽出去 | `(e: React.DragEvent) => void` | - | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"name": "@pansy/use-drag", | ||
"description": "useDrag 允许一个 DOM 节点被拖拽,需要配合 useDrop 使用。", | ||
"version": "1.0.0", | ||
"main": "lib/index.js", | ||
"module": "es/index.js", | ||
"types": "es/index.d.ts", | ||
"files": [ | ||
"es", | ||
"lib", | ||
"dist" | ||
], | ||
"scripts": { | ||
"dev": "redbud dev", | ||
"build": "redbud build" | ||
}, | ||
"peerDependencies": { | ||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0" | ||
}, | ||
"publishConfig": { | ||
"registry": "https://registry.npmjs.org", | ||
"access": "public" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { useRef } from "react"; | ||
import React from "react"; | ||
import { useLatest } from "@pansy/use-latest"; | ||
import { useMount } from "@pansy/use-mount"; | ||
import { isString } from "@pansy/shared"; | ||
import type { BasicTarget } from "@pansy/shared/react"; | ||
import { getTargetElement } from "@pansy/shared/react"; | ||
import { useEffectWithTarget } from "@pansy/hook-utils"; | ||
|
||
export interface Options { | ||
onDragStart?: (event: React.DragEvent) => void; | ||
onDragEnd?: (event: React.DragEvent) => void; | ||
dragImage?: { | ||
image: string | Element; | ||
offsetX?: number; | ||
offsetY?: number; | ||
}; | ||
} | ||
|
||
export const useDrag = <T>( | ||
data: T, | ||
target: BasicTarget, | ||
options: Options = {} | ||
) => { | ||
const optionsRef = useLatest(options); | ||
const dataRef = useLatest(data); | ||
const imageElementRef = useRef<Element>(); | ||
|
||
const { dragImage } = optionsRef.current; | ||
|
||
useMount(() => { | ||
if (dragImage?.image) { | ||
const { image } = dragImage; | ||
|
||
if (isString(image)) { | ||
const imageElement = new Image(); | ||
|
||
imageElement.src = image; | ||
imageElementRef.current = imageElement; | ||
} else { | ||
imageElementRef.current = image; | ||
} | ||
} | ||
}); | ||
|
||
useEffectWithTarget( | ||
() => { | ||
const targetElement = getTargetElement(target) as Element; | ||
if (!targetElement?.addEventListener) { | ||
return; | ||
} | ||
|
||
const onDragStart = (event: React.DragEvent) => { | ||
optionsRef.current.onDragStart?.(event); | ||
event.dataTransfer.setData("custom", JSON.stringify(dataRef.current)); | ||
|
||
if (dragImage?.image && imageElementRef.current) { | ||
const { offsetX = 0, offsetY = 0 } = dragImage; | ||
|
||
event.dataTransfer.setDragImage( | ||
imageElementRef.current, | ||
offsetX, | ||
offsetY | ||
); | ||
} | ||
}; | ||
|
||
const onDragEnd = (event: React.DragEvent) => { | ||
optionsRef.current.onDragEnd?.(event); | ||
}; | ||
|
||
targetElement?.setAttribute?.("draggable", "true"); | ||
|
||
targetElement.addEventListener("dragstart", onDragStart as any); | ||
targetElement.addEventListener("dragend", onDragEnd as any); | ||
|
||
return () => { | ||
targetElement.removeEventListener("dragstart", onDragStart as any); | ||
targetElement.removeEventListener("dragend", onDragEnd as any); | ||
}; | ||
}, | ||
[], | ||
target | ||
); | ||
}; |
Oops, something went wrong.