demo-react-animated-list/src/AnimatedListDemo.tsx

140 lines
3.5 KiB
TypeScript

import React, { useReducer } from 'react';
import { useAnimatedListItems } from './useAnimatedListItems';
type Mutation = 'reverse' | 'randomize' | 'insert' | 'remove';
function getRandomChar(): string {
return String.fromCharCode(98 + Math.floor(Math.random() * 25));
}
function getRandomItemName(): string {
return `Serial Number - ${new Array(16)
.fill('')
.map(() => getRandomChar())
.join('')}`;
}
/**
* Randomizer function shamelessly copied unmodified from https://stackoverflow.com/a/12646864
*
* License: https://creativecommons.org/licenses/by-sa/4.0/
*
* Author(s):
* - https://stackoverflow.com/users/310500/laurens-holst
* - https://stackoverflow.com/users/8112776/ashleedawg
*/
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
function insertRandomlyIntoArray(array: string[]): string[] {
const insertBefore = Math.floor(Math.random() * (array.length + 1));
const newItem = getRandomItemName();
if (insertBefore === 0) {
return [newItem, ...array];
}
return [
...array.slice(0, insertBefore),
newItem,
...array.slice(insertBefore),
];
}
function removeRandomlyFromArray(array: string[]): string[] {
const removeIndex = Math.floor(Math.random() * array.length);
if (removeIndex === 0) {
return [...array.slice(1)];
}
if (removeIndex === array.length) {
return [...array.slice(0, -1)];
}
return [...array.slice(0, removeIndex), ...array.slice(removeIndex + 1)];
}
export const AnimatedListDemo = () => {
const [items, mutateItems] = useReducer(
(prevState: string[], mutation: Mutation) => {
let newState: string[] = [...prevState];
switch (mutation) {
case 'reverse':
newState.reverse();
break;
case 'randomize':
shuffleArray(newState);
break;
case 'insert':
newState = insertRandomlyIntoArray(newState);
break;
case 'remove':
newState = removeRandomlyFromArray(newState);
break;
default:
return prevState;
}
return newState;
},
new Array(4).fill('').map(() => getRandomItemName()),
);
const { updateItemRef, updateItemPositions, itemStyles } =
useAnimatedListItems({ keys: items });
return (
<>
<div className="buttons">
<button
type="button"
onClick={() => {
updateItemPositions();
mutateItems('reverse');
}}
>
Reverse
</button>
<button
type="button"
onClick={() => {
updateItemPositions();
mutateItems('randomize');
}}
>
Randomize
</button>
<button
type="button"
onClick={() => {
updateItemPositions();
mutateItems('insert');
}}
>
Insert
</button>
<button
type="button"
onClick={() => {
updateItemPositions();
mutateItems('remove');
}}
>
Remove
</button>
</div>
<ol>
{items.map((item) => {
return (
<li
key={item}
ref={(li) => updateItemRef(item, li)}
style={itemStyles[item]}
>
{item}
</li>
);
})}
</ol>
</>
);
};