Skip to content

Commit

Permalink
feat: init useTransitionGroup (not finished)
Browse files Browse the repository at this point in the history
  • Loading branch information
iamyoki committed Dec 27, 2021
1 parent 659a809 commit 77da14d
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './useTransition';
export * from './useSwitchTransition';
export * from './useTransitionGroup';
export * from './Transition';
export * from './SwitchTransition';
75 changes: 75 additions & 0 deletions src/useTransitionGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {Fragment, useEffect, useState} from 'react';
import {Stage} from '..';
import {setAnimationFrameTimeout} from '../helpers/setAnimationFrameTimeout';

type RenderCallback<Item> = (item: Item, stage: Stage) => React.ReactNode;

type ListItem<Item> = {
item: Item;
key: number;
stage: Stage;
};

export function useTransitionGroup<Item>(list: Array<Item>, timeout: number) {
// change list to our list form with extra information.
const initialList: Array<ListItem<Item>> = list.map((item, key) => ({
item,
key,
stage: 'enter',
}));

const [listState, setListState] = useState(initialList);

useEffect(
function handleListChange() {
// add new item
if (list.length > listState.length) {
const newItems: Array<ListItem<Item>> = list
.filter((item) => !listState.some((item2) => item2.item === item))
.map((item, index) => ({
item,
key: index + listState.length,
stage: 'from',
}));

setListState((prev) => prev.concat(newItems));
setAnimationFrameTimeout(() => {
setListState((prev) =>
prev.map((item) => ({
...item,
stage: item.stage === 'from' ? 'enter' : item.stage,
}))
);
});
}

// remove item
if (list.length < listState.length) {
const removeItems = listState.filter(
(item) => !list.includes(item.item)
);
setListState((prev) =>
prev.map((item) =>
removeItems.includes(item) ? {...item, stage: 'leave'} : item
)
);
setAnimationFrameTimeout(() => {
setListState((prev) =>
prev.filter((item) => !removeItems.includes(item))
);
}, timeout);
}
},
[list, listState, timeout]
);

function transition(renderCallback: RenderCallback<Item>) {
return listState.map((item) => (
<Fragment key={item.key}>
{renderCallback(item.item, item.stage)}
</Fragment>
));
}

return transition;
}

0 comments on commit 77da14d

Please sign in to comment.