Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draggable 新增动画功能 #110

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions packages/components/src/draggable/Draggable.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// import EnUS from './locale/en-US';
import type { DraggableProps, DraggableFC } from './draggable.types';
import { createElement, forwardRef, FC } from 'react';
// import { useLocale } from '~/config-provider/useLocale';
import type { RequiredPart } from '@tool-pack/types';
import { TransitionGroup } from '~/transition-group';
import { createElement, forwardRef } from 'react';
import { getClassNames } from '@tool-pack/basic';
import { useDraggableChildren } from './hooks';
import type { ReactElement, FC } from 'react';
import { getClasses } from '@pkg/shared';

export const cls = getClasses('draggable', ['ghost', 'item'], []);
Expand All @@ -18,18 +20,29 @@ export const _Draggable: FC<DraggableProps> = forwardRef<
DraggableProps
>((props, ref) => {
// const locale = useLocale('draggable', EnUS);
const { attrs = {}, tag } = props as RequiredPart<
DraggableProps,
keyof typeof defaultProps
>;
const {
transition,
attrs = {},
tag,
} = props as RequiredPart<DraggableProps, keyof typeof defaultProps>;
const children = useDraggableChildren(props);
const className = getClassNames(cls.root, attrs.className);

if (transition && children) {
const transitionProps = transition === true ? undefined : transition;
return (
<TransitionGroup {...transitionProps} className={className} tag={tag}>
{children as ReactElement[]}
</TransitionGroup>
);
}

if (tag === null) return children;
return createElement(
tag,
{
...attrs,
className: getClassNames(cls.root, attrs.className),
className,
ref,
},
children,
Expand Down
55 changes: 55 additions & 0 deletions packages/components/src/draggable/demo/transition-debug.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* title: transition debug
* debug: true
* description: 开启 transition 动画。
*/

import { ButtonGroup, Draggable, Button } from '@tool-pack/react-ui';
import styles from './transition.module.scss';
import React from 'react';

const App: React.FC = () => {
const [state, setState] = React.useState<{ name: string; id: number }[]>([
{ name: 'John', id: 1 },
{ name: 'Joao', id: 2 },
{ name: 'Jean', id: 3 },
{ name: 'Gerard', id: 4 },
]);
return (
<div className={styles['root']}>
<ButtonGroup>
<Button
onClick={() => {
const id = state.length + 1;
setState([...state, { name: 'anyone', id }]);
}}
type="primary"
>
添加
</Button>
<Button onClick={() => setState(state.slice(0, -1))} type="success">
删减
</Button>
</ButtonGroup>
<div className="main">
<Draggable onChange={setState} list={state} tag={null} transition>
{state.map((item, index) => (
<div className="draggable-item" key={item.id}>
<span>{index + 1}.</span> <span>{item.name}</span>{' '}
<span>{item.id}</span>
</div>
))}
</Draggable>
<div className="data">
[
{state.map((it) => (
<div key={it.id}>{JSON.stringify(it)}</div>
))}
]
</div>
</div>
</div>
);
};

export default App;
37 changes: 37 additions & 0 deletions packages/components/src/draggable/demo/transition.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.root {
:global {
.main {
display: flex;
margin-top: 1rem;
}
.t-draggable {
flex: 1;
}
.draggable-item {
padding: 0 0.5rem;
border: 1px solid #e6e6e6;
background: #fff1d7;
line-height: 32px;
}
.data {
flex: 1;
padding: 0 20px;
white-space: pre-wrap;
}
.t-group {
&-enter-active,
&-leave-active,
&-move-active {
transition: all 0.3s ease;
}
&-enter-from {
transform: translateY(-100%);
opacity: 0;
}
&-leave-to {
transform: translateY(100%);
opacity: 0;
}
}
}
}
54 changes: 54 additions & 0 deletions packages/components/src/draggable/demo/transition.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* title: transition
* description: 开启 transition 动画。
*/

import { ButtonGroup, Draggable, Button } from '@tool-pack/react-ui';
import styles from './transition.module.scss';
import React from 'react';

const App: React.FC = () => {
const [state, setState] = React.useState<{ name: string; id: number }[]>([
{ name: 'John', id: 1 },
{ name: 'Joao', id: 2 },
{ name: 'Jean', id: 3 },
{ name: 'Gerard', id: 4 },
]);
return (
<div className={styles['root']}>
<ButtonGroup>
<Button
onClick={() => {
const id = state.length + 1;
setState([...state, { name: 'anyone', id }]);
}}
type="primary"
>
添加
</Button>
<Button onClick={() => setState(state.slice(0, -1))} type="success">
删减
</Button>
</ButtonGroup>
<div className="main">
<Draggable onChange={setState} list={state} transition>
{state.map((item, index) => (
<div className="draggable-item" key={item.id}>
<span>{index + 1}.</span> <span>{item.name}</span>{' '}
<span>{item.id}</span>
</div>
))}
</Draggable>
<div className="data">
[
{state.map((it) => (
<div key={it.id}>{JSON.stringify(it)}</div>
))}
]
</div>
</div>
</div>
);
};

export default App;
2 changes: 2 additions & 0 deletions packages/components/src/draggable/draggable.types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { TransitionGroupProps } from '~/transition-group';
import type { PropsBase } from '@pkg/shared';
import type { ReactElement } from 'react';

export interface DraggableProps<T = unknown> extends PropsBase<HTMLDivElement> {
transition?: TransitionGroupProps | boolean;
tag?: keyof HTMLElementTagNameMap | null;
onChange?: (list: T[]) => void;
list: T[];
Expand Down
12 changes: 9 additions & 3 deletions packages/components/src/draggable/hooks/useDraggableChildren.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ import { cls } from '../Draggable';

export function useDraggableChildren({
children: outerChildren,
transition,
onChange,
list,
}: Pick<DraggableProps, 'children' | 'onChange' | 'list'>): ReactNode {
}: Pick<
DraggableProps,
'transition' | 'children' | 'onChange' | 'list'
>): ReactNode {
const forceUpdate = useForceUpdate();
const childrenRef = useFollowingRef(outerChildren, (v) =>
Children.toArray(v),
Expand Down Expand Up @@ -62,12 +66,14 @@ export function useDraggableChildren({
onChange?.(listRef.current.slice());
e.preventDefault();
},
onDragEnter: () => {
onDragEnterCapture(e: DragEvent) {
const target = e.target as HTMLElement;
const chosen = chosenRef.current;
if (
!chosen ||
chosen.overIndex === index ||
el.props.draggable === false
el.props.draggable === false ||
(transition && target.className.includes('move-active'))
)
return;

Expand Down
34 changes: 34 additions & 0 deletions packages/components/src/draggable/index.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
category: Components
title: Draggable
atomId: Draggable
demo:
cols: 2
group:
title: Common
---

Draggable 拖拽。

## 代码演示

<!-- prettier-ignore -->
<code src="./demo/basic.tsx"></code>
<code src="./demo/draggable.tsx"></code>
<code src="./demo/tag.tsx"></code>
<code src="./demo/transition.tsx"></code>
<code src="./demo/transition-debug.tsx"></code>

## API

Draggable 的属性说明如下:

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

其他说明。
15 changes: 9 additions & 6 deletions packages/components/src/draggable/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@ Draggable 拖拽。
<code src="./demo/basic.tsx"></code>
<code src="./demo/draggable.tsx"></code>
<code src="./demo/tag.tsx"></code>
<code src="./demo/transition.tsx"></code>
<code src="./demo/transition-debug.tsx"></code>

## API

Draggable 的属性说明如下:

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

其他说明。