Compare commits
No commits in common. "a9f96781335bb0771e9279fc6c1ffafd8d494b96" and "b70759fa4b76d9737aed35883e58887015b9eeb2" have entirely different histories.
a9f9678133
...
b70759fa4b
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
node_modules
|
|
||||||
public/scripts
|
|
||||||
dist
|
|
@ -1 +0,0 @@
|
|||||||
nodejs 22.5.1
|
|
@ -1,133 +0,0 @@
|
|||||||
import React, { useReducer } from 'react';
|
|
||||||
import { useAnimatedListItems } from './useAnimatedListItems';
|
|
||||||
|
|
||||||
type Mutation = 'reverse' | 'randomize' | 'insert' | 'remove';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 = `Serial Number ${crypto.randomUUID()}`;
|
|
||||||
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;
|
|
||||||
},
|
|
||||||
[
|
|
||||||
`Serial Number ${crypto.randomUUID()}`,
|
|
||||||
`Serial Number ${crypto.randomUUID()}`,
|
|
||||||
`Serial Number ${crypto.randomUUID()}`,
|
|
||||||
`Serial Number ${crypto.randomUUID()}`,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
const { updateItemRef, updateItemPositions, itemStyles } =
|
|
||||||
useAnimatedListItems({ keys: items });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<main>
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
{items.map((item) => {
|
|
||||||
return (
|
|
||||||
<li
|
|
||||||
key={item}
|
|
||||||
ref={(li) => updateItemRef(item, li)}
|
|
||||||
style={itemStyles[item]}
|
|
||||||
>
|
|
||||||
{item}
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ol>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
};
|
|
20
index.tsx
20
index.tsx
@ -1,20 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Root, createRoot } from 'react-dom/client';
|
|
||||||
import { AnimatedListDemo } from './AnimatedListDemo';
|
|
||||||
|
|
||||||
class AnimatedListComponent extends HTMLElement {
|
|
||||||
root: Root;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
const rootNode = document.createElement('main');
|
|
||||||
this.appendChild(rootNode);
|
|
||||||
this.root = createRoot(rootNode);
|
|
||||||
this.root.render(<AnimatedListDemo />);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define('react-animated-list-demo', AnimatedListComponent);
|
|
557
package-lock.json
generated
557
package-lock.json
generated
@ -1,557 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "demo-react-animated-list",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"name": "demo-react-animated-list",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"react": "18.3.1",
|
|
||||||
"react-dom": "18.3.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/react": "18.3.3",
|
|
||||||
"@types/react-dom": "18.3.0",
|
|
||||||
"esbuild": "0.23.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==",
|
|
||||||
"cpu": [
|
|
||||||
"ppc64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"aix"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/android-arm": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"android"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/android-arm64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"android"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/android-x64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"android"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-arm": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==",
|
|
||||||
"cpu": [
|
|
||||||
"ia32"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==",
|
|
||||||
"cpu": [
|
|
||||||
"loong64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==",
|
|
||||||
"cpu": [
|
|
||||||
"mips64el"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==",
|
|
||||||
"cpu": [
|
|
||||||
"ppc64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==",
|
|
||||||
"cpu": [
|
|
||||||
"riscv64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==",
|
|
||||||
"cpu": [
|
|
||||||
"s390x"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-x64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"netbsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/openbsd-arm64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"openbsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"openbsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"sunos"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==",
|
|
||||||
"cpu": [
|
|
||||||
"ia32"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/win32-x64": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/prop-types": {
|
|
||||||
"version": "15.7.12",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
|
||||||
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@types/react": {
|
|
||||||
"version": "18.3.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
|
|
||||||
"integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/prop-types": "*",
|
|
||||||
"csstype": "^3.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/react-dom": {
|
|
||||||
"version": "18.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz",
|
|
||||||
"integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/react": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/csstype": {
|
|
||||||
"version": "3.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/esbuild": {
|
|
||||||
"version": "0.23.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz",
|
|
||||||
"integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==",
|
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"esbuild": "bin/esbuild"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@esbuild/aix-ppc64": "0.23.0",
|
|
||||||
"@esbuild/android-arm": "0.23.0",
|
|
||||||
"@esbuild/android-arm64": "0.23.0",
|
|
||||||
"@esbuild/android-x64": "0.23.0",
|
|
||||||
"@esbuild/darwin-arm64": "0.23.0",
|
|
||||||
"@esbuild/darwin-x64": "0.23.0",
|
|
||||||
"@esbuild/freebsd-arm64": "0.23.0",
|
|
||||||
"@esbuild/freebsd-x64": "0.23.0",
|
|
||||||
"@esbuild/linux-arm": "0.23.0",
|
|
||||||
"@esbuild/linux-arm64": "0.23.0",
|
|
||||||
"@esbuild/linux-ia32": "0.23.0",
|
|
||||||
"@esbuild/linux-loong64": "0.23.0",
|
|
||||||
"@esbuild/linux-mips64el": "0.23.0",
|
|
||||||
"@esbuild/linux-ppc64": "0.23.0",
|
|
||||||
"@esbuild/linux-riscv64": "0.23.0",
|
|
||||||
"@esbuild/linux-s390x": "0.23.0",
|
|
||||||
"@esbuild/linux-x64": "0.23.0",
|
|
||||||
"@esbuild/netbsd-x64": "0.23.0",
|
|
||||||
"@esbuild/openbsd-arm64": "0.23.0",
|
|
||||||
"@esbuild/openbsd-x64": "0.23.0",
|
|
||||||
"@esbuild/sunos-x64": "0.23.0",
|
|
||||||
"@esbuild/win32-arm64": "0.23.0",
|
|
||||||
"@esbuild/win32-ia32": "0.23.0",
|
|
||||||
"@esbuild/win32-x64": "0.23.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/js-tokens": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/loose-envify": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"loose-envify": "cli.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react": {
|
|
||||||
"version": "18.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
|
||||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"loose-envify": "^1.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-dom": {
|
|
||||||
"version": "18.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
|
||||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"loose-envify": "^1.1.0",
|
|
||||||
"scheduler": "^0.23.2"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^18.3.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/scheduler": {
|
|
||||||
"version": "0.23.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
|
||||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"loose-envify": "^1.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
26
package.json
26
package.json
@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "demo-react-animated-list",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "A demo of an implementation of an animated list in React Typescript.",
|
|
||||||
"main": "index.tsx",
|
|
||||||
"scripts": {
|
|
||||||
"build": "esbuild index.tsx --bundle --sourcemap --outfile=./dist/demo-react-animated-list.js",
|
|
||||||
"dev": "esbuild index.tsx --bundle --watch --serve --outdir=./public/scripts --servedir=./public",
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://scm.matthewcardarelli.com/mcsolutions/demo-react-animated-list.git"
|
|
||||||
},
|
|
||||||
"author": "Matthew Cardarelli",
|
|
||||||
"license": "MIT",
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/react": "18.3.3",
|
|
||||||
"@types/react-dom": "18.3.0",
|
|
||||||
"esbuild": "0.23.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"react": "18.3.1",
|
|
||||||
"react-dom": "18.3.1"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>React animated list demo</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script src="./scripts/index.js"></script>
|
|
||||||
<react-animated-list-demo />
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"jsx": "preserve",
|
|
||||||
"target": "ESNext",
|
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "Bundler",
|
|
||||||
"lib": ["DOM", "ESNext"],
|
|
||||||
"noEmit": true,
|
|
||||||
"alwaysStrict": true
|
|
||||||
},
|
|
||||||
"include": ["*.ts", "*.tsx"]
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
import { useLayoutEffect, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
interface ItemTops {
|
|
||||||
[id: string]: number | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ListItemRefsById {
|
|
||||||
[id: string]: HTMLLIElement | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ItemOffsets {
|
|
||||||
[id: string]: number | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ItemStyles {
|
|
||||||
position: 'relative';
|
|
||||||
top: number;
|
|
||||||
transition: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UseAnimatedListItemArgs {
|
|
||||||
/**
|
|
||||||
* **IMPORTANT - This list must be memoized. The array reference should only change when the
|
|
||||||
* list of items changes.**
|
|
||||||
*
|
|
||||||
* The list of item keys. Each key should uniquely identify a `<ListItem>` component, and
|
|
||||||
* should be the same value passed to the `ListItem`'s `key` prop.
|
|
||||||
*/
|
|
||||||
keys: string[] | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UseAnimatedListItemReturns {
|
|
||||||
/**
|
|
||||||
* Item styles that should be passed to the `sx` prop of each `ListItem`. The styles are
|
|
||||||
* mapped per item key.
|
|
||||||
*/
|
|
||||||
itemStyles: { [key: string]: ItemStyles | undefined };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function that must be called within the `ref` callback prop of each `ListItem`.
|
|
||||||
*
|
|
||||||
* @param {string} key - the `ListItem`'s unique key.
|
|
||||||
* @param {HTMLLIElement} li - the list item element reference.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
updateItemRef: (key: string, li: HTMLLIElement | null) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function that must be called within each and every callback that causes the list of items
|
|
||||||
* to refresh or update. This is used to take a "snapshot" of the items current positions prior
|
|
||||||
* to any change.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
updateItemPositions: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This hook can be plugged into a MUI <List> to animate the <ListItem> components whenever
|
|
||||||
* change their order.
|
|
||||||
*/
|
|
||||||
export const useAnimatedListItems = ({
|
|
||||||
keys,
|
|
||||||
}: UseAnimatedListItemArgs): UseAnimatedListItemReturns => {
|
|
||||||
const itemRefs = useRef<ListItemRefsById>({});
|
|
||||||
const itemTops = useRef<ItemTops>({});
|
|
||||||
const [itemOffsets, setItemOffsets] = useState<ItemOffsets>({});
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (!keys) return;
|
|
||||||
const newItemOffsets: ItemOffsets = {};
|
|
||||||
keys.forEach((key) => {
|
|
||||||
const itemRef = itemRefs.current[key];
|
|
||||||
if (itemRef) {
|
|
||||||
const currentTop = itemRef.getBoundingClientRect().top;
|
|
||||||
const prevTop = itemTops.current[key] || 0;
|
|
||||||
const offset = -(currentTop - prevTop);
|
|
||||||
newItemOffsets[key] = offset;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setItemOffsets(newItemOffsets);
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
setItemOffsets({});
|
|
||||||
});
|
|
||||||
}, [keys]);
|
|
||||||
|
|
||||||
let itemStyles: UseAnimatedListItemReturns['itemStyles'] = {};
|
|
||||||
keys?.forEach((key) => {
|
|
||||||
itemStyles[key] = {
|
|
||||||
position: 'relative',
|
|
||||||
top: itemOffsets[key] || 0,
|
|
||||||
transition:
|
|
||||||
!itemTops.current[key] || itemOffsets[key] ? 'top 0s' : 'top 1s',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
itemStyles,
|
|
||||||
updateItemRef: (key, li) => {
|
|
||||||
li === null ? delete itemRefs.current[key] : (itemRefs.current[key] = li);
|
|
||||||
},
|
|
||||||
updateItemPositions: () => {
|
|
||||||
keys?.forEach((key) => {
|
|
||||||
const itemRef = itemRefs.current[key];
|
|
||||||
if (itemRef) {
|
|
||||||
itemTops.current[key] = itemRef.getBoundingClientRect().top;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user