diff --git a/examples/readme.md b/examples/readme.md
index 2846e07dac..fcaf02341e 100644
--- a/examples/readme.md
+++ b/examples/readme.md
@@ -5,12 +5,14 @@ These steps assume You've forked the repo and created a branch for your PR. For
1. In the CLI, navigate to the `/examples` folder. Start a [new Vite project](https://vitejs.dev/guide/#scaffolding-your-first-vite-project) using the appropiate template (e.g. `react-ts`) and adding the name of the framework at the end of your example's name:
```bash
+cd examples
pnpm create vite@latest my-example-react --template react-ts
```
-2. Install `xstate` and the library-specific beta (e.g. `@xstate/react`):
+2. Navigate to the project you just created and install `xstate` and any related libraries (e.g. `@xstate/react`):
```bash
+cd my-example-react
pnpm i xstate @xstate/react
```
diff --git a/examples/undo-redo/.gitignore b/examples/undo-redo/.gitignore
new file mode 100644
index 0000000000..a547bf36d8
--- /dev/null
+++ b/examples/undo-redo/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/examples/undo-redo/index.html b/examples/undo-redo/index.html
new file mode 100644
index 0000000000..44a933506f
--- /dev/null
+++ b/examples/undo-redo/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + TS
+
+
+
+
+
+
diff --git a/examples/undo-redo/package.json b/examples/undo-redo/package.json
new file mode 100644
index 0000000000..474a862050
--- /dev/null
+++ b/examples/undo-redo/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "undo-redo",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "typescript": "^5.2.2",
+ "vite": "^5.0.8"
+ },
+ "dependencies": {
+ "xstate": "^5.6.0"
+ }
+}
diff --git a/examples/undo-redo/pnpm-lock.yaml b/examples/undo-redo/pnpm-lock.yaml
new file mode 100644
index 0000000000..f9bd3fa265
--- /dev/null
+++ b/examples/undo-redo/pnpm-lock.yaml
@@ -0,0 +1,556 @@
+lockfileVersion: '6.0'
+
+dependencies:
+ xstate:
+ specifier: ^5.6.0
+ version: registry.npmjs.org/xstate@5.6.0
+
+devDependencies:
+ typescript:
+ specifier: ^5.2.2
+ version: registry.npmjs.org/typescript@5.3.3
+ vite:
+ specifier: ^5.0.8
+ version: registry.npmjs.org/vite@5.0.12
+
+packages:
+
+ registry.npmjs.org/@esbuild/aix-ppc64@0.19.12:
+ resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz}
+ name: '@esbuild/aix-ppc64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/android-arm64@0.19.12:
+ resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz}
+ name: '@esbuild/android-arm64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/android-arm@0.19.12:
+ resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz}
+ name: '@esbuild/android-arm'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/android-x64@0.19.12:
+ resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz}
+ name: '@esbuild/android-x64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/darwin-arm64@0.19.12:
+ resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz}
+ name: '@esbuild/darwin-arm64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/darwin-x64@0.19.12:
+ resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz}
+ name: '@esbuild/darwin-x64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/freebsd-arm64@0.19.12:
+ resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz}
+ name: '@esbuild/freebsd-arm64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/freebsd-x64@0.19.12:
+ resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz}
+ name: '@esbuild/freebsd-x64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-arm64@0.19.12:
+ resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz}
+ name: '@esbuild/linux-arm64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-arm@0.19.12:
+ resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz}
+ name: '@esbuild/linux-arm'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-ia32@0.19.12:
+ resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz}
+ name: '@esbuild/linux-ia32'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-loong64@0.19.12:
+ resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz}
+ name: '@esbuild/linux-loong64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-mips64el@0.19.12:
+ resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz}
+ name: '@esbuild/linux-mips64el'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-ppc64@0.19.12:
+ resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz}
+ name: '@esbuild/linux-ppc64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-riscv64@0.19.12:
+ resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz}
+ name: '@esbuild/linux-riscv64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-s390x@0.19.12:
+ resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz}
+ name: '@esbuild/linux-s390x'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/linux-x64@0.19.12:
+ resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz}
+ name: '@esbuild/linux-x64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/netbsd-x64@0.19.12:
+ resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz}
+ name: '@esbuild/netbsd-x64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/openbsd-x64@0.19.12:
+ resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz}
+ name: '@esbuild/openbsd-x64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/sunos-x64@0.19.12:
+ resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz}
+ name: '@esbuild/sunos-x64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/win32-arm64@0.19.12:
+ resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz}
+ name: '@esbuild/win32-arm64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/win32-ia32@0.19.12:
+ resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz}
+ name: '@esbuild/win32-ia32'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@esbuild/win32-x64@0.19.12:
+ resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz}
+ name: '@esbuild/win32-x64'
+ version: 0.19.12
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-android-arm-eabi@4.9.6:
+ resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz}
+ name: '@rollup/rollup-android-arm-eabi'
+ version: 4.9.6
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-android-arm64@4.9.6:
+ resolution: {integrity: sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz}
+ name: '@rollup/rollup-android-arm64'
+ version: 4.9.6
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-darwin-arm64@4.9.6:
+ resolution: {integrity: sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz}
+ name: '@rollup/rollup-darwin-arm64'
+ version: 4.9.6
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-darwin-x64@4.9.6:
+ resolution: {integrity: sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz}
+ name: '@rollup/rollup-darwin-x64'
+ version: 4.9.6
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf@4.9.6:
+ resolution: {integrity: sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz}
+ name: '@rollup/rollup-linux-arm-gnueabihf'
+ version: 4.9.6
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-linux-arm64-gnu@4.9.6:
+ resolution: {integrity: sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz}
+ name: '@rollup/rollup-linux-arm64-gnu'
+ version: 4.9.6
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-linux-arm64-musl@4.9.6:
+ resolution: {integrity: sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz}
+ name: '@rollup/rollup-linux-arm64-musl'
+ version: 4.9.6
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu@4.9.6:
+ resolution: {integrity: sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz}
+ name: '@rollup/rollup-linux-riscv64-gnu'
+ version: 4.9.6
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-linux-x64-gnu@4.9.6:
+ resolution: {integrity: sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz}
+ name: '@rollup/rollup-linux-x64-gnu'
+ version: 4.9.6
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-linux-x64-musl@4.9.6:
+ resolution: {integrity: sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz}
+ name: '@rollup/rollup-linux-x64-musl'
+ version: 4.9.6
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-win32-arm64-msvc@4.9.6:
+ resolution: {integrity: sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz}
+ name: '@rollup/rollup-win32-arm64-msvc'
+ version: 4.9.6
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-win32-ia32-msvc@4.9.6:
+ resolution: {integrity: sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz}
+ name: '@rollup/rollup-win32-ia32-msvc'
+ version: 4.9.6
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@rollup/rollup-win32-x64-msvc@4.9.6:
+ resolution: {integrity: sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz}
+ name: '@rollup/rollup-win32-x64-msvc'
+ version: 4.9.6
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/@types/estree@1.0.5:
+ resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz}
+ name: '@types/estree'
+ version: 1.0.5
+ dev: true
+
+ registry.npmjs.org/esbuild@0.19.12:
+ resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz}
+ name: esbuild
+ version: 0.19.12
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@esbuild/aix-ppc64': registry.npmjs.org/@esbuild/aix-ppc64@0.19.12
+ '@esbuild/android-arm': registry.npmjs.org/@esbuild/android-arm@0.19.12
+ '@esbuild/android-arm64': registry.npmjs.org/@esbuild/android-arm64@0.19.12
+ '@esbuild/android-x64': registry.npmjs.org/@esbuild/android-x64@0.19.12
+ '@esbuild/darwin-arm64': registry.npmjs.org/@esbuild/darwin-arm64@0.19.12
+ '@esbuild/darwin-x64': registry.npmjs.org/@esbuild/darwin-x64@0.19.12
+ '@esbuild/freebsd-arm64': registry.npmjs.org/@esbuild/freebsd-arm64@0.19.12
+ '@esbuild/freebsd-x64': registry.npmjs.org/@esbuild/freebsd-x64@0.19.12
+ '@esbuild/linux-arm': registry.npmjs.org/@esbuild/linux-arm@0.19.12
+ '@esbuild/linux-arm64': registry.npmjs.org/@esbuild/linux-arm64@0.19.12
+ '@esbuild/linux-ia32': registry.npmjs.org/@esbuild/linux-ia32@0.19.12
+ '@esbuild/linux-loong64': registry.npmjs.org/@esbuild/linux-loong64@0.19.12
+ '@esbuild/linux-mips64el': registry.npmjs.org/@esbuild/linux-mips64el@0.19.12
+ '@esbuild/linux-ppc64': registry.npmjs.org/@esbuild/linux-ppc64@0.19.12
+ '@esbuild/linux-riscv64': registry.npmjs.org/@esbuild/linux-riscv64@0.19.12
+ '@esbuild/linux-s390x': registry.npmjs.org/@esbuild/linux-s390x@0.19.12
+ '@esbuild/linux-x64': registry.npmjs.org/@esbuild/linux-x64@0.19.12
+ '@esbuild/netbsd-x64': registry.npmjs.org/@esbuild/netbsd-x64@0.19.12
+ '@esbuild/openbsd-x64': registry.npmjs.org/@esbuild/openbsd-x64@0.19.12
+ '@esbuild/sunos-x64': registry.npmjs.org/@esbuild/sunos-x64@0.19.12
+ '@esbuild/win32-arm64': registry.npmjs.org/@esbuild/win32-arm64@0.19.12
+ '@esbuild/win32-ia32': registry.npmjs.org/@esbuild/win32-ia32@0.19.12
+ '@esbuild/win32-x64': registry.npmjs.org/@esbuild/win32-x64@0.19.12
+ dev: true
+
+ registry.npmjs.org/fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz}
+ name: fsevents
+ version: 2.3.3
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ registry.npmjs.org/nanoid@3.3.7:
+ resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz}
+ name: nanoid
+ version: 3.3.7
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+ dev: true
+
+ registry.npmjs.org/picocolors@1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz}
+ name: picocolors
+ version: 1.0.0
+ dev: true
+
+ registry.npmjs.org/postcss@8.4.33:
+ resolution: {integrity: sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz}
+ name: postcss
+ version: 8.4.33
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: registry.npmjs.org/nanoid@3.3.7
+ picocolors: registry.npmjs.org/picocolors@1.0.0
+ source-map-js: registry.npmjs.org/source-map-js@1.0.2
+ dev: true
+
+ registry.npmjs.org/rollup@4.9.6:
+ resolution: {integrity: sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz}
+ name: rollup
+ version: 4.9.6
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+ dependencies:
+ '@types/estree': registry.npmjs.org/@types/estree@1.0.5
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': registry.npmjs.org/@rollup/rollup-android-arm-eabi@4.9.6
+ '@rollup/rollup-android-arm64': registry.npmjs.org/@rollup/rollup-android-arm64@4.9.6
+ '@rollup/rollup-darwin-arm64': registry.npmjs.org/@rollup/rollup-darwin-arm64@4.9.6
+ '@rollup/rollup-darwin-x64': registry.npmjs.org/@rollup/rollup-darwin-x64@4.9.6
+ '@rollup/rollup-linux-arm-gnueabihf': registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf@4.9.6
+ '@rollup/rollup-linux-arm64-gnu': registry.npmjs.org/@rollup/rollup-linux-arm64-gnu@4.9.6
+ '@rollup/rollup-linux-arm64-musl': registry.npmjs.org/@rollup/rollup-linux-arm64-musl@4.9.6
+ '@rollup/rollup-linux-riscv64-gnu': registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu@4.9.6
+ '@rollup/rollup-linux-x64-gnu': registry.npmjs.org/@rollup/rollup-linux-x64-gnu@4.9.6
+ '@rollup/rollup-linux-x64-musl': registry.npmjs.org/@rollup/rollup-linux-x64-musl@4.9.6
+ '@rollup/rollup-win32-arm64-msvc': registry.npmjs.org/@rollup/rollup-win32-arm64-msvc@4.9.6
+ '@rollup/rollup-win32-ia32-msvc': registry.npmjs.org/@rollup/rollup-win32-ia32-msvc@4.9.6
+ '@rollup/rollup-win32-x64-msvc': registry.npmjs.org/@rollup/rollup-win32-x64-msvc@4.9.6
+ fsevents: registry.npmjs.org/fsevents@2.3.3
+ dev: true
+
+ registry.npmjs.org/source-map-js@1.0.2:
+ resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz}
+ name: source-map-js
+ version: 1.0.2
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ registry.npmjs.org/typescript@5.3.3:
+ resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz}
+ name: typescript
+ version: 5.3.3
+ engines: {node: '>=14.17'}
+ hasBin: true
+ dev: true
+
+ registry.npmjs.org/vite@5.0.12:
+ resolution: {integrity: sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/vite/-/vite-5.0.12.tgz}
+ name: vite
+ version: 5.0.12
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ dependencies:
+ esbuild: registry.npmjs.org/esbuild@0.19.12
+ postcss: registry.npmjs.org/postcss@8.4.33
+ rollup: registry.npmjs.org/rollup@4.9.6
+ optionalDependencies:
+ fsevents: registry.npmjs.org/fsevents@2.3.3
+ dev: true
+
+ registry.npmjs.org/xstate@5.6.0:
+ resolution: {integrity: sha512-l62p4ZHM/fkGl68574s1dFzFmY8B3BeOff9EqBZbuonTSOXGx1fWTnh4SHSrS8Vhr5wyRT9afqWliMoO6Q+hUQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/xstate/-/xstate-5.6.0.tgz}
+ name: xstate
+ version: 5.6.0
+ dev: false
diff --git a/examples/undo-redo/public/vite.svg b/examples/undo-redo/public/vite.svg
new file mode 100644
index 0000000000..e7b8dfb1b2
--- /dev/null
+++ b/examples/undo-redo/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/undo-redo/src/machine.ts b/examples/undo-redo/src/machine.ts
new file mode 100644
index 0000000000..6bc7d9b475
--- /dev/null
+++ b/examples/undo-redo/src/machine.ts
@@ -0,0 +1,94 @@
+import {
+ ActorLogic,
+ AnyActorLogic,
+ EventFrom,
+ InputFrom,
+ SnapshotFrom,
+ assign,
+ setup
+} from 'xstate';
+
+export const machine = setup({
+ types: {
+ context: {} as {
+ items: string[];
+ },
+ events: {} as {
+ type: 'item.add';
+ item: string;
+ }
+ }
+}).createMachine({
+ context: {
+ items: []
+ },
+ on: {
+ 'item.add': {
+ actions: assign({
+ items: ({ context, event }) => {
+ return [...context.items, event.item];
+ }
+ })
+ }
+ }
+});
+
+type ActorLogicWithUndoRedo = ActorLogic<
+ SnapshotFrom & {
+ undoStack: SnapshotFrom[];
+ redoStack: SnapshotFrom[];
+ },
+ EventFrom | { type: 'undo' } | { type: 'redo' },
+ InputFrom,
+ any
+>;
+
+export function withUndoRedo(
+ logic: T
+): ActorLogicWithUndoRedo {
+ return {
+ ...logic,
+ transition(snapshot, event, actorScope) {
+ if (event.type === 'undo') {
+ const previousSnapshot = snapshot.undoStack.pop();
+
+ if (previousSnapshot) {
+ return {
+ ...previousSnapshot,
+ undoStack: snapshot.undoStack,
+ redoStack: [snapshot, ...snapshot.redoStack]
+ };
+ }
+
+ return snapshot;
+ }
+ if (event.type === 'redo') {
+ const nextSnapshot = snapshot.redoStack.pop();
+ if (nextSnapshot) {
+ return {
+ ...nextSnapshot,
+ undoStack: [...snapshot.undoStack, snapshot],
+ redoStack: snapshot.redoStack
+ };
+ }
+
+ return snapshot;
+ }
+
+ const nextSnapshot = logic.transition(snapshot, event, actorScope);
+
+ return {
+ ...nextSnapshot,
+ undoStack: [...snapshot.undoStack, snapshot],
+ redoStack: []
+ };
+ },
+ getInitialSnapshot(...args) {
+ return {
+ ...logic.getInitialSnapshot(...args),
+ undoStack: [],
+ redoStack: []
+ };
+ }
+ } satisfies ActorLogicWithUndoRedo;
+}
diff --git a/examples/undo-redo/src/main.ts b/examples/undo-redo/src/main.ts
new file mode 100644
index 0000000000..55cf987c9e
--- /dev/null
+++ b/examples/undo-redo/src/main.ts
@@ -0,0 +1,14 @@
+import './style.css';
+import { machine, withUndoRedo } from './machine.ts';
+import { createActor } from 'xstate';
+
+const logic = withUndoRedo(machine);
+const actor = createActor(logic);
+actor.subscribe((s) => console.log(s.context.items));
+actor.start();
+actor.send({ type: 'item.add', item: 'first' });
+actor.send({ type: 'item.add', item: 'second' });
+actor.send({ type: 'item.add', item: 'third' });
+actor.send({ type: 'undo' });
+actor.send({ type: 'undo' });
+actor.send({ type: 'redo' });
diff --git a/examples/undo-redo/src/style.css b/examples/undo-redo/src/style.css
new file mode 100644
index 0000000000..f9c7350248
--- /dev/null
+++ b/examples/undo-redo/src/style.css
@@ -0,0 +1,96 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: filter 300ms;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.vanilla:hover {
+ filter: drop-shadow(0 0 2em #3178c6aa);
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/examples/undo-redo/src/vite-env.d.ts b/examples/undo-redo/src/vite-env.d.ts
new file mode 100644
index 0000000000..11f02fe2a0
--- /dev/null
+++ b/examples/undo-redo/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/undo-redo/tsconfig.json b/examples/undo-redo/tsconfig.json
new file mode 100644
index 0000000000..75abdef265
--- /dev/null
+++ b/examples/undo-redo/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}