diff --git a/packages/components/src/draggable/Draggable.tsx b/packages/components/src/draggable/Draggable.tsx index 0b5e989..9c16597 100644 --- a/packages/components/src/draggable/Draggable.tsx +++ b/packages/components/src/draggable/Draggable.tsx @@ -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'], []); @@ -18,18 +20,29 @@ export const _Draggable: FC = 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; const children = useDraggableChildren(props); + const className = getClassNames(cls.root, attrs.className); + + if (transition && children) { + const transitionProps = transition === true ? undefined : transition; + return ( + + {children as ReactElement[]} + + ); + } if (tag === null) return children; return createElement( tag, { ...attrs, - className: getClassNames(cls.root, attrs.className), + className, ref, }, children, diff --git a/packages/components/src/draggable/demo/transition-debug.tsx b/packages/components/src/draggable/demo/transition-debug.tsx new file mode 100644 index 0000000..6b5eaf8 --- /dev/null +++ b/packages/components/src/draggable/demo/transition-debug.tsx @@ -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 ( +
+ + + + +
+ + {state.map((item, index) => ( +
+ {index + 1}. {item.name}{' '} + {item.id} +
+ ))} +
+
+ [ + {state.map((it) => ( +
{JSON.stringify(it)}
+ ))} + ] +
+
+
+ ); +}; + +export default App; diff --git a/packages/components/src/draggable/demo/transition.module.scss b/packages/components/src/draggable/demo/transition.module.scss new file mode 100644 index 0000000..cb6b35b --- /dev/null +++ b/packages/components/src/draggable/demo/transition.module.scss @@ -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; + } + } + } +} diff --git a/packages/components/src/draggable/demo/transition.tsx b/packages/components/src/draggable/demo/transition.tsx new file mode 100644 index 0000000..cd313db --- /dev/null +++ b/packages/components/src/draggable/demo/transition.tsx @@ -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 ( +
+ + + + +
+ + {state.map((item, index) => ( +
+ {index + 1}. {item.name}{' '} + {item.id} +
+ ))} +
+
+ [ + {state.map((it) => ( +
{JSON.stringify(it)}
+ ))} + ] +
+
+
+ ); +}; + +export default App; diff --git a/packages/components/src/draggable/draggable.types.ts b/packages/components/src/draggable/draggable.types.ts index 0388e1b..03a5302 100644 --- a/packages/components/src/draggable/draggable.types.ts +++ b/packages/components/src/draggable/draggable.types.ts @@ -1,7 +1,9 @@ +import type { TransitionGroupProps } from '~/transition-group'; import type { PropsBase } from '@pkg/shared'; import type { ReactElement } from 'react'; export interface DraggableProps extends PropsBase { + transition?: TransitionGroupProps | boolean; tag?: keyof HTMLElementTagNameMap | null; onChange?: (list: T[]) => void; list: T[]; diff --git a/packages/components/src/draggable/hooks/useDraggableChildren.ts b/packages/components/src/draggable/hooks/useDraggableChildren.ts index 6bb8d59..173caad 100644 --- a/packages/components/src/draggable/hooks/useDraggableChildren.ts +++ b/packages/components/src/draggable/hooks/useDraggableChildren.ts @@ -11,9 +11,13 @@ import { cls } from '../Draggable'; export function useDraggableChildren({ children: outerChildren, + transition, onChange, list, -}: Pick): ReactNode { +}: Pick< + DraggableProps, + 'transition' | 'children' | 'onChange' | 'list' +>): ReactNode { const forceUpdate = useForceUpdate(); const childrenRef = useFollowingRef(outerChildren, (v) => Children.toArray(v), @@ -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; diff --git a/packages/components/src/draggable/index.en-US.md b/packages/components/src/draggable/index.en-US.md new file mode 100644 index 0000000..14c82a2 --- /dev/null +++ b/packages/components/src/draggable/index.en-US.md @@ -0,0 +1,34 @@ +--- +category: Components +title: Draggable +atomId: Draggable +demo: + cols: 2 +group: + title: Common +--- + +Draggable 拖拽。 + +## 代码演示 + + + + + + + + +## API + +Draggable 的属性说明如下: + +| 属性 | 说明 | 类型 | 默认值 | 版本 | +| ---------- | ---------------- | --------------------------------------------------------- | ------ | ---- | +| list | 列表对应的数组 | any[] | -- | -- | +| onChange | 列表改动回调 | (list: T[]) => void | -- | -- | +| tag | 组件 html 根元素 | string \| null | 'div' | -- | +| transition | 动画效果 | boolean \| [TransitionGroupProps](./transition-group#api) | 'div' | -- | +| attrs | html 标签属性 | Partial\> | -- | -- | + +其他说明。 diff --git a/packages/components/src/draggable/index.zh-CN.md b/packages/components/src/draggable/index.zh-CN.md index bcf2f81..fc21420 100644 --- a/packages/components/src/draggable/index.zh-CN.md +++ b/packages/components/src/draggable/index.zh-CN.md @@ -16,16 +16,19 @@ Draggable 拖拽。 + + ## API Draggable 的属性说明如下: -| 属性 | 说明 | 类型 | 默认值 | 版本 | -| -------- | ---------------- | ----------------------------------------------- | ------ | ---- | -| list | 列表对应的数组 | any[] | -- | -- | -| onChange | 列表改动回调 | (list: T[]) => void | -- | -- | -| tag | 组件 html 根元素 | string \| null | 'div' | -- | -| attrs | html 标签属性 | Partial\> | -- | -- | +| 属性 | 说明 | 类型 | 默认值 | 版本 | +| ---------- | ---------------- | ------------------------------------------------------------ | ------ | ---- | +| list | 列表对应的数组 | any[] | -- | -- | +| onChange | 列表改动回调 | (list: T[]) => void | -- | -- | +| tag | 组件 html 根元素 | string \| null | 'div' | -- | +| transition | 动画效果 | boolean \| [TransitionGroupProps](./transition-group-cn#api) | 'div' | -- | +| attrs | html 标签属性 | Partial\> | -- | -- | 其他说明。