Skip to content

Commit 3535e56

Browse files
authored
Merge pull request #110 from js-tool-pack/draggable-transition
Draggable 新增动画功能
2 parents 5e5235f + 7df6414 commit 3535e56

File tree

8 files changed

+219
-15
lines changed

8 files changed

+219
-15
lines changed

packages/components/src/draggable/Draggable.tsx

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// import EnUS from './locale/en-US';
22
import type { DraggableProps, DraggableFC } from './draggable.types';
3-
import { createElement, forwardRef, FC } from 'react';
43
// import { useLocale } from '~/config-provider/useLocale';
54
import type { RequiredPart } from '@tool-pack/types';
5+
import { TransitionGroup } from '~/transition-group';
6+
import { createElement, forwardRef } from 'react';
67
import { getClassNames } from '@tool-pack/basic';
78
import { useDraggableChildren } from './hooks';
9+
import type { ReactElement, FC } from 'react';
810
import { getClasses } from '@pkg/shared';
911

1012
export const cls = getClasses('draggable', ['ghost', 'item'], []);
@@ -18,18 +20,29 @@ export const _Draggable: FC<DraggableProps> = forwardRef<
1820
DraggableProps
1921
>((props, ref) => {
2022
// const locale = useLocale('draggable', EnUS);
21-
const { attrs = {}, tag } = props as RequiredPart<
22-
DraggableProps,
23-
keyof typeof defaultProps
24-
>;
23+
const {
24+
transition,
25+
attrs = {},
26+
tag,
27+
} = props as RequiredPart<DraggableProps, keyof typeof defaultProps>;
2528
const children = useDraggableChildren(props);
29+
const className = getClassNames(cls.root, attrs.className);
30+
31+
if (transition && children) {
32+
const transitionProps = transition === true ? undefined : transition;
33+
return (
34+
<TransitionGroup {...transitionProps} className={className} tag={tag}>
35+
{children as ReactElement[]}
36+
</TransitionGroup>
37+
);
38+
}
2639

2740
if (tag === null) return children;
2841
return createElement(
2942
tag,
3043
{
3144
...attrs,
32-
className: getClassNames(cls.root, attrs.className),
45+
className,
3346
ref,
3447
},
3548
children,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* title: transition debug
3+
* debug: true
4+
* description: 开启 transition 动画。
5+
*/
6+
7+
import { ButtonGroup, Draggable, Button } from '@tool-pack/react-ui';
8+
import styles from './transition.module.scss';
9+
import React from 'react';
10+
11+
const App: React.FC = () => {
12+
const [state, setState] = React.useState<{ name: string; id: number }[]>([
13+
{ name: 'John', id: 1 },
14+
{ name: 'Joao', id: 2 },
15+
{ name: 'Jean', id: 3 },
16+
{ name: 'Gerard', id: 4 },
17+
]);
18+
return (
19+
<div className={styles['root']}>
20+
<ButtonGroup>
21+
<Button
22+
onClick={() => {
23+
const id = state.length + 1;
24+
setState([...state, { name: 'anyone', id }]);
25+
}}
26+
type="primary"
27+
>
28+
添加
29+
</Button>
30+
<Button onClick={() => setState(state.slice(0, -1))} type="success">
31+
删减
32+
</Button>
33+
</ButtonGroup>
34+
<div className="main">
35+
<Draggable onChange={setState} list={state} tag={null} transition>
36+
{state.map((item, index) => (
37+
<div className="draggable-item" key={item.id}>
38+
<span>{index + 1}.</span> <span>{item.name}</span>{' '}
39+
<span>{item.id}</span>
40+
</div>
41+
))}
42+
</Draggable>
43+
<div className="data">
44+
[
45+
{state.map((it) => (
46+
<div key={it.id}>{JSON.stringify(it)}</div>
47+
))}
48+
]
49+
</div>
50+
</div>
51+
</div>
52+
);
53+
};
54+
55+
export default App;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
.root {
2+
:global {
3+
.main {
4+
display: flex;
5+
margin-top: 1rem;
6+
}
7+
.t-draggable {
8+
flex: 1;
9+
}
10+
.draggable-item {
11+
padding: 0 0.5rem;
12+
border: 1px solid #e6e6e6;
13+
background: #fff1d7;
14+
line-height: 32px;
15+
}
16+
.data {
17+
flex: 1;
18+
padding: 0 20px;
19+
white-space: pre-wrap;
20+
}
21+
.t-group {
22+
&-enter-active,
23+
&-leave-active,
24+
&-move-active {
25+
transition: all 0.3s ease;
26+
}
27+
&-enter-from {
28+
transform: translateY(-100%);
29+
opacity: 0;
30+
}
31+
&-leave-to {
32+
transform: translateY(100%);
33+
opacity: 0;
34+
}
35+
}
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* title: transition
3+
* description: 开启 transition 动画。
4+
*/
5+
6+
import { ButtonGroup, Draggable, Button } from '@tool-pack/react-ui';
7+
import styles from './transition.module.scss';
8+
import React from 'react';
9+
10+
const App: React.FC = () => {
11+
const [state, setState] = React.useState<{ name: string; id: number }[]>([
12+
{ name: 'John', id: 1 },
13+
{ name: 'Joao', id: 2 },
14+
{ name: 'Jean', id: 3 },
15+
{ name: 'Gerard', id: 4 },
16+
]);
17+
return (
18+
<div className={styles['root']}>
19+
<ButtonGroup>
20+
<Button
21+
onClick={() => {
22+
const id = state.length + 1;
23+
setState([...state, { name: 'anyone', id }]);
24+
}}
25+
type="primary"
26+
>
27+
添加
28+
</Button>
29+
<Button onClick={() => setState(state.slice(0, -1))} type="success">
30+
删减
31+
</Button>
32+
</ButtonGroup>
33+
<div className="main">
34+
<Draggable onChange={setState} list={state} transition>
35+
{state.map((item, index) => (
36+
<div className="draggable-item" key={item.id}>
37+
<span>{index + 1}.</span> <span>{item.name}</span>{' '}
38+
<span>{item.id}</span>
39+
</div>
40+
))}
41+
</Draggable>
42+
<div className="data">
43+
[
44+
{state.map((it) => (
45+
<div key={it.id}>{JSON.stringify(it)}</div>
46+
))}
47+
]
48+
</div>
49+
</div>
50+
</div>
51+
);
52+
};
53+
54+
export default App;

packages/components/src/draggable/draggable.types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type { TransitionGroupProps } from '~/transition-group';
12
import type { PropsBase } from '@pkg/shared';
23
import type { ReactElement } from 'react';
34

45
export interface DraggableProps<T = unknown> extends PropsBase<HTMLDivElement> {
6+
transition?: TransitionGroupProps | boolean;
57
tag?: keyof HTMLElementTagNameMap | null;
68
onChange?: (list: T[]) => void;
79
list: T[];

packages/components/src/draggable/hooks/useDraggableChildren.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ import { cls } from '../Draggable';
1111

1212
export function useDraggableChildren({
1313
children: outerChildren,
14+
transition,
1415
onChange,
1516
list,
16-
}: Pick<DraggableProps, 'children' | 'onChange' | 'list'>): ReactNode {
17+
}: Pick<
18+
DraggableProps,
19+
'transition' | 'children' | 'onChange' | 'list'
20+
>): ReactNode {
1721
const forceUpdate = useForceUpdate();
1822
const childrenRef = useFollowingRef(outerChildren, (v) =>
1923
Children.toArray(v),
@@ -62,12 +66,14 @@ export function useDraggableChildren({
6266
onChange?.(listRef.current.slice());
6367
e.preventDefault();
6468
},
65-
onDragEnter: () => {
69+
onDragEnterCapture(e: DragEvent) {
70+
const target = e.target as HTMLElement;
6671
const chosen = chosenRef.current;
6772
if (
6873
!chosen ||
6974
chosen.overIndex === index ||
70-
el.props.draggable === false
75+
el.props.draggable === false ||
76+
(transition && target.className.includes('move-active'))
7177
)
7278
return;
7379

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
category: Components
3+
title: Draggable
4+
atomId: Draggable
5+
demo:
6+
cols: 2
7+
group:
8+
title: Common
9+
---
10+
11+
Draggable 拖拽。
12+
13+
## 代码演示
14+
15+
<!-- prettier-ignore -->
16+
<code src="./demo/basic.tsx"></code>
17+
<code src="./demo/draggable.tsx"></code>
18+
<code src="./demo/tag.tsx"></code>
19+
<code src="./demo/transition.tsx"></code>
20+
<code src="./demo/transition-debug.tsx"></code>
21+
22+
## API
23+
24+
Draggable 的属性说明如下:
25+
26+
| 属性 | 说明 | 类型 | 默认值 | 版本 |
27+
| ---------- | ---------------- | --------------------------------------------------------- | ------ | ---- |
28+
| list | 列表对应的数组 | any[] | -- | -- |
29+
| onChange | 列表改动回调 | (list: T[]) => void | -- | -- |
30+
| tag | 组件 html 根元素 | string \| null | 'div' | -- |
31+
| transition | 动画效果 | boolean \| [TransitionGroupProps](./transition-group#api) | 'div' | -- |
32+
| attrs | html 标签属性 | Partial\<React.HTMLAttributes\<HTMLDivElement>> | -- | -- |
33+
34+
其他说明。

packages/components/src/draggable/index.zh-CN.md

+9-6
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@ Draggable 拖拽。
1616
<code src="./demo/basic.tsx"></code>
1717
<code src="./demo/draggable.tsx"></code>
1818
<code src="./demo/tag.tsx"></code>
19+
<code src="./demo/transition.tsx"></code>
20+
<code src="./demo/transition-debug.tsx"></code>
1921

2022
## API
2123

2224
Draggable 的属性说明如下:
2325

24-
| 属性 | 说明 | 类型 | 默认值 | 版本 |
25-
| -------- | ---------------- | ----------------------------------------------- | ------ | ---- |
26-
| list | 列表对应的数组 | any[] | -- | -- |
27-
| onChange | 列表改动回调 | (list: T[]) => void | -- | -- |
28-
| tag | 组件 html 根元素 | string \| null | 'div' | -- |
29-
| attrs | html 标签属性 | Partial\<React.HTMLAttributes\<HTMLDivElement>> | -- | -- |
26+
| 属性 | 说明 | 类型 | 默认值 | 版本 |
27+
| ---------- | ---------------- | ------------------------------------------------------------ | ------ | ---- |
28+
| list | 列表对应的数组 | any[] | -- | -- |
29+
| onChange | 列表改动回调 | (list: T[]) => void | -- | -- |
30+
| tag | 组件 html 根元素 | string \| null | 'div' | -- |
31+
| transition | 动画效果 | boolean \| [TransitionGroupProps](./transition-group-cn#api) | 'div' | -- |
32+
| attrs | html 标签属性 | Partial\<React.HTMLAttributes\<HTMLDivElement>> | -- | -- |
3033

3134
其他说明。

0 commit comments

Comments
 (0)