140 lines
3.5 KiB
TypeScript
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>
|
|
</>
|
|
);
|
|
};
|