Skip to content

Commit

Permalink
Merge pull request #33 from js-tool-pack/fix-transition-group
Browse files Browse the repository at this point in the history
Fix transition group
  • Loading branch information
mengxinssfd committed Jul 27, 2023
2 parents 1bbf909 + 9dd4014 commit d682b67
Show file tree
Hide file tree
Showing 29 changed files with 537 additions and 337 deletions.
4 changes: 4 additions & 0 deletions packages/components/src/button/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ $r: Name.$button;
// transition-property: all;
transition-timing-function: ease-in-out;
transition-duration: var(--t-transition-duration);
& > span {
display: inline-flex;
align-items: center;
}
&:not([disabled]):hover {
--t-btn-color: var(--t-btn-hover-color);
--t-btn-bg-color: var(--t-btn-hover-bg-color);
Expand Down
8 changes: 6 additions & 2 deletions packages/components/src/message/Message.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { useEffect, useRef } from 'react';
import type { MessageProps } from './message.types';
import type { RequiredPart } from '@tool-pack/types';
import { getComponentClass, useForwardRef, useTimeDown } from '@pkg/shared';
Expand Down Expand Up @@ -40,9 +40,13 @@ export const Message: React.FC<MessageProps> = React.forwardRef<
const [time, stop] = useTimeDown(duration);
const rootRef = useForwardRef(ref);

const isTimeout = useRef(false);

useEffect(() => {
if (isTimeout.current) return;
if (duration > 0 && time <= 0) {
onLeave?.();
isTimeout.current = true;
}
}, [time, onLeave]);

Expand All @@ -69,7 +73,7 @@ export const Message: React.FC<MessageProps> = React.forwardRef<
{children}
{showClose && (
<Button size="small" plain="text" onClick={onLeave}>
<Icon>
<Icon size="0.8em">
<Close />
</Icon>
</Button>
Expand Down
26 changes: 17 additions & 9 deletions packages/components/src/message/MessageQueue.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useCallback, useImperativeHandle, useRef } from 'react';
import { createPortal } from 'react-dom';
import { TransitionGroup, TransitionGroupCB } from '../transition-group';
import { TransitionGroup } from '../transition-group';
import { getComponentClass, useForceUpdate } from '@pkg/shared';
import { getClassNames } from '@tool-pack/basic';
import { Message } from './Message';
Expand All @@ -9,7 +9,12 @@ import type {
MessageQueueProps,
MessageQueueRef,
} from './message.types';
import { TRANSITION_STATUS, TRANSITION_LIFE_CIRCLE } from '../transition';
import {
Transition,
type TransitionCB,
TRANSITION_STATUS,
TRANSITION_LIFE_CIRCLE,
} from '../transition';
import LeaveQueue from './LeaveQueue';

const rootClass = getComponentClass('message-queue');
Expand Down Expand Up @@ -50,7 +55,7 @@ export const MessageQueue: React.FC<MessageQueueProps> = React.forwardRef<
// 需要维护一个离开动画队列,否则离开动画会堆叠在一起,
const queue = useRef(new LeaveQueue(remove));

const on: TransitionGroupCB = useCallback((_, status, lifeCircle) => {
const on: TransitionCB = useCallback((_, status, lifeCircle) => {
if (
status === TRANSITION_STATUS.hide &&
lifeCircle === TRANSITION_LIFE_CIRCLE.after
Expand All @@ -62,21 +67,24 @@ export const MessageQueue: React.FC<MessageQueueProps> = React.forwardRef<
return createPortal(
<TransitionGroup
{...rest}
on={on}
name={rootClass}
tag="ul"
className={getClassNames(rootClass, className)}>
{MsgList.current.map((it) => {
const { key, content, ...rest } = it;
return (
<li key={key}>
<Message {...rest} onLeave={() => queue.current.push(it)}>
{content}
</Message>
</li>
<Transition key={key} on={on}>
<li>
<Message {...rest} onLeave={() => queue.current.push(it)}>
{content}
</Message>
</li>
</Transition>
);
})}
</TransitionGroup>,
document.body,
);
});

MessageQueue.displayName = 'MessageQueue';
1 change: 0 additions & 1 deletion packages/components/src/message/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ $q: '#{$r}-queue';
transition-timing-function: linear;
}
&-leave-active {
position: absolute;
width: 100%;
}
&-enter-from,
Expand Down
66 changes: 31 additions & 35 deletions packages/components/src/transition-group/TransitionGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,38 @@
import React, { memo, useRef } from 'react';
import { Transition } from '../transition/index';
import { ChildStatus } from './transition-group.enums';
import { useDispatcher } from './transition-gorup.hooks';
import { TransitionGroupProps } from './transition-group.types';
import React from 'react';
import { useFlips } from './useFlips';
import { useWrapper } from './useWrapper';
import { useChildMap } from './useChildMap';
import type { TransitionGroupProps } from './transition-group.types';
import { RequiredPart } from '@tool-pack/types';

const TransitionGroup: React.FC<TransitionGroupProps> = (
props,
): React.ReactElement => {
const { mode, name, on, tag, appear, children, ...rest } = props;
const containerRef = useRef<HTMLElement>(null);
/**
* v1 版有部分 bug 不好解决。
*
* v2版参考了 {@link https://github.com/peoplesing1832/react-transition/blob/npm/src/v4/TransitionGroup.tsx} 该实现。
*
* 相比 v1 版, v2 需要元素外部套 Transition 组件,可随机插入(v1不行),动画更流畅。
*
* 目前还是不够完美,以后需要再次优化。。。
*/

const [_children, _appear] = useDispatcher(
containerRef,
name,
children,
appear,
on,
);
const defaultProps = {
tag: 'div',
name: 't-group',
} satisfies TransitionGroupProps;

return React.createElement(
tag as string,
{ ...rest, ref: containerRef },
_children.map((child) => {
return (
<Transition
name={name}
mode={mode}
appear={child.status === ChildStatus.enter && _appear}
key={child.component.key}
on={child.on}>
{child.status === ChildStatus.leave ? undefined : child.component}
</Transition>
);
}),
);
const TransitionGroup: React.FC<TransitionGroupProps> = (props) => {
const { name, children, ...rest } = props as RequiredPart<
TransitionGroupProps,
keyof typeof defaultProps
>;

const childMap = useChildMap(children, name);
const [wrapper, parentRef] = useWrapper(childMap, rest);
useFlips(parentRef, name);
return wrapper;
};

TransitionGroup.defaultProps = { tag: 'div' };
TransitionGroup.defaultProps = defaultProps;
TransitionGroup.displayName = 'TransitionGroup';

export default memo(TransitionGroup);
export default React.memo(TransitionGroup);
3 changes: 0 additions & 3 deletions packages/components/src/transition-group/demo/all.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ $name: 'group';
&-move-active {
transition: all 1s ease;
}
&-leave-active {
position: absolute;
}
&-enter-from {
transform: scaleY(0.01) translate(0, -100%);
opacity: 0;
Expand Down
13 changes: 9 additions & 4 deletions packages/components/src/transition-group/demo/all.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
*/

import React, { useCallback, useRef, useState } from 'react';
import { TransitionGroup, Button, Space } from '@tool-pack/react-ui';
import {
TransitionGroup,
Button,
Space,
Transition,
} from '@tool-pack/react-ui';
import styles from './all.module.scss';

const App: React.FC = () => {
Expand Down Expand Up @@ -56,9 +61,9 @@ const App: React.FC = () => {
<TransitionGroup name="group" tag="section" className="group-container">
{children.current.map((item) => {
return (
<button key={item} onClick={() => removeChild(item)}>
{item}
</button>
<Transition key={item}>
<button onClick={() => removeChild(item)}>{item}</button>
</Transition>
);
})}
</TransitionGroup>
Expand Down
12 changes: 6 additions & 6 deletions packages/components/src/transition-group/demo/flip.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ $name: 'group';
&-move-active {
transition: all 1s ease;
}
&-leave-active {
position: absolute;
}
}
.group-container {
margin: auto;
width: 300px;
width: 250px;
font-size: 0;
text-align: left;
button {
display: inline-block;
width: 60px;
height: 40px;
width: 50px;
height: 50px;
font-size: 16px;
border: 1px solid gray;
border-radius: 0;
background: none;
}
}
button {
Expand Down
15 changes: 12 additions & 3 deletions packages/components/src/transition-group/demo/flip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@
*/

import React, { useCallback, useRef, useState } from 'react';
import { TransitionGroup, Button, Space } from '@tool-pack/react-ui';
import {
TransitionGroup,
Button,
Space,
Transition,
} from '@tool-pack/react-ui';
import styles from './flip.module.scss';

const App: React.FC = () => {
const [, update] = useState({});
const forceUpdate = useCallback(() => update({}), []);

const children = useRef<number[]>([...Array.from({ length: 30 }).keys()]);
const children = useRef<number[]>([...Array.from({ length: 25 }).keys()]);

function shuffle() {
const list = children.current;
Expand All @@ -32,7 +37,11 @@ const App: React.FC = () => {
<br />
<TransitionGroup name="group" tag="section" className="group-container">
{children.current.map((item) => {
return <button key={item}>{item}</button>;
return (
<Transition key={item}>
<button>{item}</button>
</Transition>
);
})}
</TransitionGroup>
</div>
Expand Down
10 changes: 4 additions & 6 deletions packages/components/src/transition-group/demo/list.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@ $name: 'group';
&-enter-active,
&-leave-active,
&-move-active {
transition: all 1s ease;
}
&-leave-active {
position: absolute;
transition: all 0.8s ease;
}
&-enter-from {
transform: translate(0, -100%);
transform: scaleY(0.01) translateY(-100%);
opacity: 0;
}
&-leave-to {
transform: translate(0, 100%);
// tips: scaleY 如果为 0 会退出不彻底
transform: scaleY(0.01) translateY(100%);
opacity: 0;
}
}
Expand Down
18 changes: 15 additions & 3 deletions packages/components/src/transition-group/demo/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
*/

import React, { useCallback, useRef, useState } from 'react';
import { TransitionGroup, Button, Space } from '@tool-pack/react-ui';
import {
TransitionGroup,
Transition,
Button,
Space,
} from '@tool-pack/react-ui';
import styles from './list.module.scss';

const App: React.FC = () => {
Expand All @@ -14,7 +19,10 @@ const App: React.FC = () => {

const index = useRef(children.current.length);
function addChild() {
children.current.push(index.current);
const list = children.current;
const splice = list.splice(~~(Math.random() * list.length), list.length);
list.push(index.current);
list.push(...splice);
forceUpdate();
index.current++;
}
Expand All @@ -41,7 +49,11 @@ const App: React.FC = () => {
<br />
<TransitionGroup name="group" tag="section" className="group-container">
{children.current.map((item) => {
return <div key={item}>{item}</div>;
return (
<Transition key={item}>
<div>{item}</div>
</Transition>
);
})}
</TransitionGroup>
</div>
Expand Down
12 changes: 5 additions & 7 deletions packages/components/src/transition-group/demo/mixed.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@ $name: 'group';
&-move-active {
transition: all 1s ease;
}
&-leave-active {
position: absolute;
}
&-enter-from {
transform: scaleY(0.01) translate(0, -100%);
transform: scaleY(0.1) translateX(-100%);
opacity: 0;
}
&-leave-to {
transform: scaleY(0.01) translate(0, 100%);
transform: scaleY(0.1) translateX(100%);
opacity: 0;
}
}
.group-container {
white-space: nowrap;
div {
display: inline-block;
padding: 6px;
border: 1px solid white;
color: whitesmoke;
background-color: #f56c6c;
}
}
}
Expand Down
Loading

0 comments on commit d682b67

Please sign in to comment.