diff --git a/.gitignore b/.gitignore
index 3670bc7d..2907fdce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.cache
+.expo
.next
build
coverage
diff --git a/apps/animated-example/app.json b/apps/animated-example/app.json
new file mode 100644
index 00000000..b905d9ee
--- /dev/null
+++ b/apps/animated-example/app.json
@@ -0,0 +1,33 @@
+{
+ "expo": {
+ "name": "animated-example",
+ "slug": "animated-example",
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "userInterfaceStyle": "light",
+ "newArchEnabled": true,
+ "splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#1a1a2e"
+ },
+ "assetBundlePatterns": [
+ "**/*"
+ ],
+ "android": {
+ "adaptiveIcon": {
+ "foregroundImage": "./assets/adaptive-icon.png",
+ "backgroundColor": "#ffffff"
+ }
+ },
+ "ios": {
+ "supportsTablet": true,
+ "bundleIdentifier": "com.anonymous.animated-example"
+ },
+ "web": {
+ "bundler": "metro",
+ "favicon": "./assets/favicon.png"
+ }
+ }
+}
diff --git a/apps/animated-example/assets/adaptive-icon.png b/apps/animated-example/assets/adaptive-icon.png
new file mode 100644
index 00000000..03d6f6b6
Binary files /dev/null and b/apps/animated-example/assets/adaptive-icon.png differ
diff --git a/apps/animated-example/assets/favicon.png b/apps/animated-example/assets/favicon.png
new file mode 100644
index 00000000..e75f697b
Binary files /dev/null and b/apps/animated-example/assets/favicon.png differ
diff --git a/apps/animated-example/assets/icon.png b/apps/animated-example/assets/icon.png
new file mode 100644
index 00000000..a0b1526f
Binary files /dev/null and b/apps/animated-example/assets/icon.png differ
diff --git a/apps/animated-example/assets/splash.png b/apps/animated-example/assets/splash.png
new file mode 100644
index 00000000..0e89705a
Binary files /dev/null and b/apps/animated-example/assets/splash.png differ
diff --git a/apps/animated-example/babel.config.js b/apps/animated-example/babel.config.js
new file mode 100644
index 00000000..e00459c9
--- /dev/null
+++ b/apps/animated-example/babel.config.js
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+const reactStrictPreset = require('react-strict-dom/babel-preset');
+
+function getPlatform(caller) {
+ return caller && caller.platform;
+}
+
+function getIsDev(caller) {
+ if (caller?.isDev != null) return caller.isDev;
+ // https://babeljs.io/docs/options#envname
+ return (
+ process.env.BABEL_ENV === 'development' ||
+ process.env.NODE_ENV === 'development'
+ );
+}
+
+module.exports = function (api) {
+ //api.cache(true);
+
+ const platform = api.caller(getPlatform);
+ const dev = api.caller(getIsDev);
+
+ const plugins = [];
+ const presets = [
+ 'babel-preset-expo',
+ [reactStrictPreset, { debug: true, dev, platform }]
+ ];
+
+ return {
+ plugins,
+ presets
+ };
+};
diff --git a/apps/animated-example/metro.config.js b/apps/animated-example/metro.config.js
new file mode 100644
index 00000000..29d51f46
--- /dev/null
+++ b/apps/animated-example/metro.config.js
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// Learn more https://docs.expo.dev/guides/monorepos
+const { getDefaultConfig } = require('expo/metro-config');
+
+// Find the project and workspace directories
+const projectRoot = __dirname;
+
+const config = getDefaultConfig(projectRoot);
+
+module.exports = config;
diff --git a/apps/animated-example/package.json b/apps/animated-example/package.json
new file mode 100644
index 00000000..2f9834b8
--- /dev/null
+++ b/apps/animated-example/package.json
@@ -0,0 +1,30 @@
+{
+ "private": true,
+ "name": "animated-example",
+ "version": "0.0.1",
+ "main": "./src/app/index.js",
+ "scripts": {
+ "dev": "expo start --clear",
+ "dev:android": "expo start --android --clear",
+ "dev:ios": "expo start --ios --clear",
+ "dev:web": "expo start --web --clear",
+ "android": "expo run:android",
+ "ios": "expo run:ios"
+ },
+ "dependencies": {
+ "@expo/metro-runtime": "~5.0.4",
+ "expo": "^53.0.11",
+ "expo-build-properties": "~0.14.6",
+ "expo-status-bar": "~2.2.3",
+ "react": "~19.0.0",
+ "react-dom": "~19.0.0",
+ "react-native": "~0.79.5",
+ "react-native-web": "~0.20.0",
+ "react-strict-dom": "0.0.54",
+ "react-strict-animated": "0.0.55",
+ "react-native-safe-area-context": "5.4.0"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.27.3"
+ }
+}
diff --git a/apps/animated-example/postcss.config.js b/apps/animated-example/postcss.config.js
new file mode 100644
index 00000000..de2f9fd0
--- /dev/null
+++ b/apps/animated-example/postcss.config.js
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+module.exports = {
+ plugins: [
+ require('react-strict-dom/postcss-plugin')({
+ include: [
+ 'src/**/*.{js,jsx,mjs,ts,tsx}',
+ '../../node_modules/example-ui/**/*.jsx',
+ '../../node_modules/react-strict-animated/**/*.js'
+ ]
+ }),
+ require('autoprefixer')
+ ]
+};
diff --git a/apps/animated-example/src/app/index.js b/apps/animated-example/src/app/index.js
new file mode 100644
index 00000000..105cc09f
--- /dev/null
+++ b/apps/animated-example/src/app/index.js
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// Required for CSS to work on Expo Web.
+import './strict.css';
+// Required for Fast Refresh to work on Expo Web
+import '@expo/metro-runtime';
+
+import { LogBox } from 'react-native';
+import { registerRootComponent } from 'expo';
+import App from '../components/App';
+
+if (LogBox != null) {
+ LogBox.ignoreLogs([
+ // /React Strict DOM: .*/,
+ // /Failed prop type: .*/,
+ ]);
+}
+
+registerRootComponent(App);
diff --git a/apps/animated-example/src/app/strict.css b/apps/animated-example/src/app/strict.css
new file mode 100644
index 00000000..a0d2b13a
--- /dev/null
+++ b/apps/animated-example/src/app/strict.css
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+html, body {
+ height: initial;
+}
+
+html {
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+}
+
+body {
+ overflow: auto;
+}
+
+#root {
+ flex-direction: column;
+}
+
+/**
+ * This directive is used by the react-strict-dom postcss plugin.
+ * It is automatically replaced with generated CSS during builds.
+ */
+
+@react-strict-dom;
diff --git a/apps/animated-example/src/components/App.js b/apps/animated-example/src/components/App.js
new file mode 100644
index 00000000..804b296a
--- /dev/null
+++ b/apps/animated-example/src/components/App.js
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { SafeAreaProvider } from 'react-native-safe-area-context';
+
+import RootLayout from './RootLayout';
+import TimingDemo from './demos/TimingDemo';
+import SpringDemo from './demos/SpringDemo';
+import ParallelDemo from './demos/ParallelDemo';
+import SequenceDemo from './demos/SequenceDemo';
+import DelayDemo from './demos/DelayDemo';
+import InterpolationDemo from './demos/InterpolationDemo';
+import TransformDemo from './demos/TransformDemo';
+import CombinedTransformDemo from './demos/CombinedTransformDemo';
+import InterruptibleDemo from './demos/InterruptibleDemo';
+
+const demos = [
+ {
+ name: 'Timing',
+ description: 'Animate opacity with duration-based easing',
+ component: TimingDemo,
+ color: '#3B82F6'
+ },
+ {
+ name: 'Spring',
+ description: 'Physics-based spring animation',
+ component: SpringDemo,
+ color: '#8B5CF6'
+ },
+ {
+ name: 'Parallel',
+ description: 'Multiple animations running together',
+ component: ParallelDemo,
+ color: '#EF4444'
+ },
+ {
+ name: 'Sequence',
+ description: 'Chained animations in order',
+ component: SequenceDemo,
+ color: '#14B8A6'
+ },
+ {
+ name: 'Delay',
+ description: 'Staggered animations with delays',
+ component: DelayDemo,
+ color: '#F59E0B'
+ },
+ {
+ name: 'Interpolation',
+ description: 'Map values to rotation and scale',
+ component: InterpolationDemo,
+ color: '#EC4899'
+ },
+ {
+ name: 'Transform',
+ description: 'Rotation transform animation',
+ component: TransformDemo,
+ color: '#F97316'
+ },
+ {
+ name: 'Combined',
+ description: 'Multiple transforms animated together',
+ component: CombinedTransformDemo,
+ color: '#10B981'
+ },
+ {
+ name: 'Interruptible',
+ description: 'Stop and restart animations mid-flight',
+ component: InterruptibleDemo,
+ color: '#A855F7'
+ }
+];
+
+console.log(RootLayout);
+
+export default function App() {
+ return (
+
+
+
+
+
+
+ React Strict Animated
+
+ A declarative animation library for react-strict-dom
+
+
+
+ {demos.map((demo) => (
+
+
+
+ {demo.name}
+
+
+ {demo.description}
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+}
+
+const styles = css.create({
+ root: {
+ backgroundColor: '#1a1a2e'
+ },
+ container: {
+ minHeight: '100vh',
+ padding: 32
+ },
+ header: {
+ textAlign: 'center',
+ marginBottom: 48,
+ paddingTop: 24
+ },
+ title: {
+ fontSize: 42,
+ fontWeight: '700',
+ color: '#ffffff',
+ marginBottom: 12,
+ letterSpacing: -1
+ },
+ subtitle: {
+ fontSize: 18,
+ color: 'rgba(255, 255, 255, 0.6)',
+ fontWeight: '400'
+ },
+ demoGrid: {
+ display: 'flex',
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ justifyContent: 'center',
+ gap: 24,
+ maxWidth: 1400,
+ marginInline: 'auto'
+ },
+ demoCard: {
+ display: 'flex',
+ flexDirection: 'column',
+ backgroundColor: 'rgba(255, 255, 255, 0.05)',
+ borderRadius: 20,
+ padding: 24,
+ width: 320,
+ minHeight: 280,
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(255, 255, 255, 0.1)'
+ },
+ cardHeader: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 10,
+ marginBottom: 8
+ },
+ colorDot: {
+ width: 10,
+ height: 10,
+ borderRadius: 5
+ },
+ demoTitle: {
+ fontSize: 20,
+ fontWeight: '600',
+ color: '#ffffff'
+ },
+ demoDescription: {
+ fontSize: 14,
+ color: 'rgba(255, 255, 255, 0.5)',
+ marginBottom: 24,
+ lineHeight: 1.4
+ },
+ demoContent: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ flex: 1,
+ paddingTop: 16,
+ rowGap: 16
+ }
+});
diff --git a/apps/animated-example/src/components/RootLayout.native.js b/apps/animated-example/src/components/RootLayout.native.js
new file mode 100644
index 00000000..30b65071
--- /dev/null
+++ b/apps/animated-example/src/components/RootLayout.native.js
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { ScrollView } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+
+export default function RootLayout(props) {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/apps/animated-example/src/components/RootLayout.web.js b/apps/animated-example/src/components/RootLayout.web.js
new file mode 100644
index 00000000..ea25ab23
--- /dev/null
+++ b/apps/animated-example/src/components/RootLayout.web.js
@@ -0,0 +1,10 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+export default function RootLayout(props) {
+ return props.children;
+}
diff --git a/apps/animated-example/src/components/demos/CombinedTransformDemo.js b/apps/animated-example/src/components/demos/CombinedTransformDemo.js
new file mode 100644
index 00000000..c38a7c62
--- /dev/null
+++ b/apps/animated-example/src/components/demos/CombinedTransformDemo.js
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function CombinedTransformDemo() {
+ const translateX = Animation.useValue(0);
+ const translateY = Animation.useValue(0);
+ const scale = Animation.useValue(1);
+ const rotate = Animation.useValue(0);
+ const [isAnimating, setIsAnimating] = React.useState(false);
+
+ const rotateInterpolated = Animation.interpolate(rotate, {
+ inputRange: [0, 1],
+ outputRange: ['0deg', '180deg']
+ });
+
+ const runAnimation = () => {
+ if (isAnimating) return;
+ setIsAnimating(true);
+
+ Animation.sequence([
+ Animation.parallel([
+ Animation.timing(translateX, { toValue: 25, duration: 700 }),
+ Animation.timing(translateY, { toValue: -18, duration: 700 }),
+ Animation.timing(scale, { toValue: 1.25, duration: 700 }),
+ Animation.timing(rotate, { toValue: 1, duration: 700 })
+ ]),
+ Animation.parallel([
+ Animation.timing(translateX, { toValue: 0, duration: 700 }),
+ Animation.timing(translateY, { toValue: 0, duration: 700 }),
+ Animation.timing(scale, { toValue: 1, duration: 700 }),
+ Animation.timing(rotate, { toValue: 0, duration: 700 })
+ ])
+ ]).start(() => {
+ setIsAnimating(false);
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {isAnimating ? 'Animating...' : 'Combined Transform'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ box: {
+ width: 50,
+ height: 50,
+ backgroundColor: '#10B981',
+ borderRadius: 12
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(16, 185, 129, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(16, 185, 129, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#10B981',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/apps/animated-example/src/components/demos/DelayDemo.js b/apps/animated-example/src/components/demos/DelayDemo.js
new file mode 100644
index 00000000..33e6839f
--- /dev/null
+++ b/apps/animated-example/src/components/demos/DelayDemo.js
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function DelayDemo() {
+ const opacity1 = Animation.useValue(0.2);
+ const opacity2 = Animation.useValue(0.2);
+ const opacity3 = Animation.useValue(0.2);
+ const [isAnimating, setIsAnimating] = React.useState(false);
+
+ const runAnimation = () => {
+ if (isAnimating) return;
+ setIsAnimating(true);
+
+ Animation.sequence([
+ Animation.parallel([
+ Animation.sequence([
+ Animation.timing(opacity1, { toValue: 1, duration: 300 }),
+ Animation.delay(700)
+ ]),
+ Animation.sequence([
+ Animation.delay(200),
+ Animation.timing(opacity2, { toValue: 1, duration: 300 }),
+ Animation.delay(500)
+ ]),
+ Animation.sequence([
+ Animation.delay(400),
+ Animation.timing(opacity3, { toValue: 1, duration: 300 }),
+ Animation.delay(300)
+ ])
+ ]),
+ Animation.parallel([
+ Animation.timing(opacity1, { toValue: 0.2, duration: 400 }),
+ Animation.timing(opacity2, { toValue: 0.2, duration: 400 }),
+ Animation.timing(opacity3, { toValue: 0.2, duration: 400 })
+ ])
+ ]).start(() => {
+ setIsAnimating(false);
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ {isAnimating ? 'Staggering...' : 'Staggered Fade'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ row: {
+ display: 'flex',
+ flexDirection: 'row',
+ gap: 16
+ },
+ circle1: {
+ width: 36,
+ height: 36,
+ borderRadius: 18,
+ backgroundColor: '#EF4444'
+ },
+ circle2: {
+ width: 36,
+ height: 36,
+ borderRadius: 18,
+ backgroundColor: '#F59E0B'
+ },
+ circle3: {
+ width: 36,
+ height: 36,
+ borderRadius: 18,
+ backgroundColor: '#22C55E'
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(245, 158, 11, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(245, 158, 11, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#F59E0B',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/apps/animated-example/src/components/demos/InterpolationDemo.js b/apps/animated-example/src/components/demos/InterpolationDemo.js
new file mode 100644
index 00000000..7c7fd9e0
--- /dev/null
+++ b/apps/animated-example/src/components/demos/InterpolationDemo.js
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function InterpolationDemo() {
+ const progress = Animation.useValue(0);
+ const [isAnimating, setIsAnimating] = React.useState(false);
+
+ const rotate = Animation.interpolate(progress, {
+ inputRange: [0, 1],
+ outputRange: ['0deg', '360deg']
+ });
+
+ const scale = Animation.interpolate(progress, {
+ inputRange: [0, 0.5, 1],
+ outputRange: [1, 1.25, 1]
+ });
+
+ const runAnimation = () => {
+ if (isAnimating) return;
+ setIsAnimating(true);
+
+ Animation.timing(progress, {
+ toValue: 1,
+ duration: 1200
+ }).start(() => {
+ progress.setValue(0);
+ setIsAnimating(false);
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {isAnimating ? 'Interpolating...' : 'Interpolate'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ box: {
+ width: 55,
+ height: 55,
+ backgroundColor: '#EC4899',
+ borderRadius: 12
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(236, 72, 153, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(236, 72, 153, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#EC4899',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/apps/animated-example/src/components/demos/InterruptibleDemo.js b/apps/animated-example/src/components/demos/InterruptibleDemo.js
new file mode 100644
index 00000000..f1299b43
--- /dev/null
+++ b/apps/animated-example/src/components/demos/InterruptibleDemo.js
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function InterruptibleDemo() {
+ const translateX = Animation.useValue(0);
+ const [isLeft, setIsLeft] = React.useState(true);
+
+ const toggle = () => {
+ const targetX = isLeft ? 80 : 0;
+ setIsLeft(!isLeft);
+
+ // Starting a new animation automatically interrupts any running animation
+ // on the same value and starts from the current position
+ Animation.spring(translateX, {
+ toValue: targetX,
+ stiffness: 180,
+ damping: 12
+ }).start();
+ };
+
+ return (
+ <>
+
+
+
+
+
+ Tap rapidly to interrupt
+
+
+ {isLeft ? 'Move Right' : 'Move Left'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ track: {
+ width: 120,
+ height: 44,
+ backgroundColor: 'rgba(168, 85, 247, 0.15)',
+ borderRadius: 22,
+ padding: 4,
+ display: 'flex',
+ alignItems: 'center'
+ },
+ box: {
+ width: 36,
+ height: 36,
+ backgroundColor: '#A855F7',
+ borderRadius: 18
+ },
+ hint: {
+ fontSize: 12,
+ color: 'rgba(168, 85, 247, 0.7)',
+ textAlign: 'center',
+ marginBottom: 8
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(168, 85, 247, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(168, 85, 247, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#A855F7',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/apps/animated-example/src/components/demos/ParallelDemo.js b/apps/animated-example/src/components/demos/ParallelDemo.js
new file mode 100644
index 00000000..a3ac900d
--- /dev/null
+++ b/apps/animated-example/src/components/demos/ParallelDemo.js
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function ParallelDemo() {
+ const translateX = Animation.useValue(0);
+ const translateY = Animation.useValue(0);
+ const opacity = Animation.useValue(1);
+ const [isAnimating, setIsAnimating] = React.useState(false);
+
+ const runAnimation = () => {
+ if (isAnimating) return;
+ setIsAnimating(true);
+
+ Animation.sequence([
+ Animation.parallel([
+ Animation.timing(translateX, { toValue: 40, duration: 600 }),
+ Animation.timing(translateY, { toValue: -25, duration: 600 }),
+ Animation.timing(opacity, { toValue: 0.5, duration: 600 })
+ ]),
+ Animation.parallel([
+ Animation.timing(translateX, { toValue: 0, duration: 600 }),
+ Animation.timing(translateY, { toValue: 0, duration: 600 }),
+ Animation.timing(opacity, { toValue: 1, duration: 600 })
+ ])
+ ]).start(() => {
+ setIsAnimating(false);
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {isAnimating ? 'Moving...' : 'Move Diagonally'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ box: {
+ width: 55,
+ height: 55,
+ backgroundColor: '#EF4444',
+ borderRadius: 12
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(239, 68, 68, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(239, 68, 68, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#EF4444',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/apps/animated-example/src/components/demos/SequenceDemo.js b/apps/animated-example/src/components/demos/SequenceDemo.js
new file mode 100644
index 00000000..761cd69e
--- /dev/null
+++ b/apps/animated-example/src/components/demos/SequenceDemo.js
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function SequenceDemo() {
+ const translateX = Animation.useValue(0);
+ const [isAnimating, setIsAnimating] = React.useState(false);
+
+ const runAnimation = () => {
+ if (isAnimating) return;
+ setIsAnimating(true);
+
+ Animation.parallel([
+ Animation.sequence([
+ Animation.timing(translateX, { toValue: 60, duration: 350 }),
+ Animation.timing(translateX, { toValue: -60, duration: 700 }),
+ Animation.timing(translateX, { toValue: 0, duration: 350 })
+ ])
+ ]).start(() => {
+ setIsAnimating(false);
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {isAnimating ? 'Moving...' : 'Move in Sequence'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ box: {
+ width: 55,
+ height: 55,
+ backgroundColor: '#14B8A6',
+ borderRadius: 12
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(20, 184, 166, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(20, 184, 166, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#14B8A6',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/apps/animated-example/src/components/demos/SpringDemo.js b/apps/animated-example/src/components/demos/SpringDemo.js
new file mode 100644
index 00000000..fcf8197d
--- /dev/null
+++ b/apps/animated-example/src/components/demos/SpringDemo.js
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function SpringDemo() {
+ const scale = Animation.useValue(1);
+ const [isAnimating, setIsAnimating] = React.useState(false);
+
+ const runAnimation = () => {
+ if (isAnimating) return;
+ setIsAnimating(true);
+
+ Animation.sequence([
+ Animation.spring(scale, {
+ toValue: 1.4,
+ stiffness: 300,
+ damping: 10
+ }),
+ Animation.spring(scale, {
+ toValue: 1,
+ stiffness: 300,
+ damping: 10
+ })
+ ]).start(() => {
+ setIsAnimating(false);
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {isAnimating ? 'Bouncing...' : 'Spring Bounce'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ box: {
+ width: 60,
+ height: 60,
+ backgroundColor: '#8B5CF6',
+ borderRadius: 12
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(139, 92, 246, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(139, 92, 246, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#8B5CF6',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/apps/animated-example/src/components/demos/TimingDemo.js b/apps/animated-example/src/components/demos/TimingDemo.js
new file mode 100644
index 00000000..8427ab15
--- /dev/null
+++ b/apps/animated-example/src/components/demos/TimingDemo.js
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function TimingDemo() {
+ const opacity = Animation.useValue(0.3);
+ const [isAnimating, setIsAnimating] = React.useState(false);
+
+ const runAnimation = () => {
+ if (isAnimating) return;
+ setIsAnimating(true);
+
+ Animation.sequence([
+ Animation.timing(opacity, { toValue: 1, duration: 500 }),
+ Animation.timing(opacity, { toValue: 0.3, duration: 500 })
+ ]).start(() => {
+ setIsAnimating(false);
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {isAnimating ? 'Animating...' : 'Fade In/Out'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ box: {
+ width: 70,
+ height: 70,
+ backgroundColor: '#3B82F6',
+ borderRadius: 12,
+ opacity: 0.3
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(59, 130, 246, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(59, 130, 246, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#3B82F6',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/apps/animated-example/src/components/demos/TransformDemo.js b/apps/animated-example/src/components/demos/TransformDemo.js
new file mode 100644
index 00000000..eeee56fa
--- /dev/null
+++ b/apps/animated-example/src/components/demos/TransformDemo.js
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import * as React from 'react';
+import { css, html } from 'react-strict-dom';
+import { animated, Animation } from 'react-strict-animated';
+
+export default function TransformDemo() {
+ const rotate = Animation.useValue(0);
+ const [isAnimating, setIsAnimating] = React.useState(false);
+
+ const rotateInterpolated = Animation.interpolate(rotate, {
+ inputRange: [0, 1],
+ outputRange: ['0deg', '360deg']
+ });
+
+ const runAnimation = () => {
+ if (isAnimating) return;
+ setIsAnimating(true);
+
+ Animation.timing(rotate, {
+ toValue: 1,
+ duration: 800
+ }).start(() => {
+ rotate.setValue(0);
+ setIsAnimating(false);
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {isAnimating ? 'Rotating...' : 'Rotate 360°'}
+
+
+ >
+ );
+}
+
+const styles = css.create({
+ boxContainer: {
+ display: 'flex',
+ height: 100,
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ box: {
+ width: 55,
+ height: 55,
+ backgroundColor: '#F97316',
+ borderRadius: 12
+ },
+ button: {
+ display: 'flex',
+ backgroundColor: 'rgba(249, 115, 22, 0.2)',
+ borderWidth: 1,
+ borderStyle: 'solid',
+ borderColor: 'rgba(249, 115, 22, 0.4)',
+ paddingBlock: 10,
+ paddingInline: 20,
+ borderRadius: 10,
+ cursor: 'pointer',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ buttonText: {
+ color: '#F97316',
+ fontWeight: '600',
+ fontSize: 14
+ }
+});
diff --git a/package-lock.json b/package-lock.json
index 7b795bee..44839ccb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -51,6 +51,75 @@
"npm": ">=10.0.0"
}
},
+ "apps/animated-example": {
+ "version": "0.0.1",
+ "dependencies": {
+ "@expo/metro-runtime": "~5.0.4",
+ "expo": "^53.0.11",
+ "expo-build-properties": "~0.14.6",
+ "expo-status-bar": "~2.2.3",
+ "react": "~19.0.0",
+ "react-dom": "~19.0.0",
+ "react-native": "~0.79.5",
+ "react-native-safe-area-context": "5.4.0",
+ "react-native-web": "~0.20.0",
+ "react-strict-animated": "0.0.55",
+ "react-strict-dom": "0.0.54"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.27.3"
+ }
+ },
+ "apps/animated-example/node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "apps/animated-example/node_modules/postcss-react-strict-dom": {
+ "version": "0.0.54",
+ "resolved": "https://registry.npmjs.org/postcss-react-strict-dom/-/postcss-react-strict-dom-0.0.54.tgz",
+ "integrity": "sha512-z2TiEQ9hC5XL1SZvJrbI9P2idMxoljpN5ipJlda1/ckLQrD6708y/1wES+HoLTL0ndrLc4rNCY14gy6Nqx9clQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.26.8",
+ "@stylexjs/babel-plugin": "^0.15.4",
+ "fast-glob": "^3.3.2",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.49"
+ }
+ },
+ "apps/animated-example/node_modules/react-strict-dom": {
+ "version": "0.0.54",
+ "resolved": "https://registry.npmjs.org/react-strict-dom/-/react-strict-dom-0.0.54.tgz",
+ "integrity": "sha512-Nzl8kF6k0VxnUeFFXIl55Eoq2OwA3OVRH+Hqj5a9pKDN9sbakt2IjEXfcLM0CodMmV6rJ98iTA7WPkjrGMiWLQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.24.7",
+ "@stylexjs/babel-plugin": "^0.15.4",
+ "@stylexjs/stylex": "^0.15.4",
+ "postcss-react-strict-dom": "0.0.54",
+ "postcss-value-parser": "^4.1.0",
+ "styleq": "^0.2.1"
+ },
+ "engines": {
+ "node": ">=20.11.0"
+ },
+ "peerDependencies": {
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "react-native": ">=0.79.5"
+ }
+ },
"apps/example-ui": {
"version": "0.0.55"
},
@@ -393,6 +462,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -580,6 +650,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"dev": true,
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -825,6 +896,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -836,6 +908,7 @@
"version": "19.2.1",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -877,6 +950,7 @@
"version": "7.2.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.6.tgz",
"integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==",
+ "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
@@ -1122,6 +1196,7 @@
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.29.0.tgz",
"integrity": "sha512-cZ0Iq3OzFUPpgszzDr1G1aJV5UMIZ4VygJ2Az252q4Rdf5cQMhYEIKArWY/oUjMhQmosM8ygOovNq7gvA9CdCg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@algolia/client-common": "5.29.0",
"@algolia/requester-browser-xhr": "5.29.0",
@@ -1298,6 +1373,7 @@
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -3505,6 +3581,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -3527,6 +3604,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -3607,6 +3685,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -3970,6 +4049,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -4970,6 +5050,7 @@
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.8.1.tgz",
"integrity": "sha512-oByRkSZzeGNQByCMaX+kif5Nl2vmtj2IHQI2fWjCfCootsdKZDPFLonhIp5s3IGJO7PLUfe0POyw0Xh/RrGXJA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@docusaurus/core": "3.8.1",
"@docusaurus/logger": "3.8.1",
@@ -8313,6 +8394,7 @@
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz",
"integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/mdx": "^2.0.0"
},
@@ -9464,6 +9546,32 @@
"micromark-util-symbol": "^1.0.1"
}
},
+ "node_modules/@stylexjs/babel-plugin": {
+ "version": "0.15.4",
+ "resolved": "https://registry.npmjs.org/@stylexjs/babel-plugin/-/babel-plugin-0.15.4.tgz",
+ "integrity": "sha512-QfL2j3VCU+KTyIEoPBhdwq8KW1Gv0FVvwSzfjjdQ0J2Ei/DJBx2AXVsDYzBcVw0WI+KsEfQUHFZ1Fk2t1U/9Iw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.26.8",
+ "@babel/helper-module-imports": "^7.25.9",
+ "@babel/traverse": "^7.26.8",
+ "@babel/types": "^7.26.8",
+ "@dual-bundle/import-meta-resolve": "^4.1.0",
+ "@stylexjs/stylex": "0.15.4",
+ "postcss-value-parser": "^4.1.0"
+ }
+ },
+ "node_modules/@stylexjs/stylex": {
+ "version": "0.15.4",
+ "resolved": "https://registry.npmjs.org/@stylexjs/stylex/-/stylex-0.15.4.tgz",
+ "integrity": "sha512-UQT75p3qxwCIsVpH87YfgHvzWGDyMbQcFKhguj4noBZCc+npEh5h7J4BIHMgrxpyJa9mislLfXv+M5TmP2YH5A==",
+ "license": "MIT",
+ "dependencies": {
+ "css-mediaquery": "^0.1.2",
+ "invariant": "^2.2.4",
+ "styleq": "0.2.1"
+ }
+ },
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
@@ -9623,6 +9731,7 @@
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0",
@@ -9772,7 +9881,6 @@
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -9793,7 +9901,6 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=10"
},
@@ -9807,7 +9914,6 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -9822,8 +9928,7 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@testing-library/react": {
"version": "16.3.0",
@@ -9888,14 +9993,14 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7",
@@ -10242,6 +10347,7 @@
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
+ "peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -11447,6 +11553,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -11530,6 +11637,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -11594,6 +11702,7 @@
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.29.0.tgz",
"integrity": "sha512-E2l6AlTWGznM2e7vEE6T6hzObvEyXukxMOlBmVlMyixZyK1umuO/CiVc6sDBbzVH0oEviCE5IfVY1oZBmccYPQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@algolia/client-abtesting": "5.29.0",
"@algolia/client-analytics": "5.29.0",
@@ -11625,6 +11734,10 @@
"algoliasearch": ">= 3.1 < 6"
}
},
+ "node_modules/animated-example": {
+ "resolved": "apps/animated-example",
+ "link": true
+ },
"node_modules/anser": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz",
@@ -11766,7 +11879,6 @@
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"dequal": "^2.0.3"
}
@@ -12788,6 +12900,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -14184,6 +14297,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -15233,8 +15347,7 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/dom-converter": {
"version": "0.2.0",
@@ -15847,6 +15960,7 @@
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -15961,6 +16075,7 @@
"integrity": "sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.44.0",
"@typescript-eslint/types": "8.44.0",
@@ -16253,6 +16368,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -16944,6 +17060,7 @@
"resolved": "https://registry.npmjs.org/expo/-/expo-53.0.22.tgz",
"integrity": "sha512-sJ2I4W/e5iiM4u/wYCe3qmW4D7WPCRqByPDD0hJcdYNdjc9HFFFdO4OAudZVyC/MmtoWZEIH5kTJP1cw9FjzYA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.20.0",
"@expo/cli": "0.24.21",
@@ -17082,6 +17199,7 @@
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-13.3.2.tgz",
"integrity": "sha512-wUlMdpqURmQ/CNKK/+BIHkDA5nGjMqNlYmW0pJFXY/KE/OG80Qcavdu2sHsL4efAIiNGvYdBS10WztuQYU4X0A==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fontfaceobserver": "^2.1.0"
},
@@ -19066,6 +19184,7 @@
"integrity": "sha512-3ljktN2ek+bRRsPAcMeqMEJou6s2MRe6VuLkLsXDXuVrJfRZ7V2VUw41T9uAt9lcA2xaJP4yykYAnMg15nsRPw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esrecurse": "^4.3.0",
"hermes-estree": "0.32.1",
@@ -22720,7 +22839,6 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -27414,6 +27532,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -28329,6 +28448,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -28881,6 +29001,7 @@
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.0.tgz",
"integrity": "sha512-ujSB9uXHJKzM/2GBuE0hBOUgC77CN3Bnpqa+g80bkv3T3A93wL/xlzDATHhnhkzifz/UE2SNOvmbTz5hSkDlHw==",
"license": "MIT",
+ "peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -28897,6 +29018,7 @@
"integrity": "sha512-B5vzcDyTA/T0R7LGMSkLTp3VtRCEe1NItzsM6L/4gDOBGzDDMMMOwxRxogwL9xL07GPBOJrzlggwFaSQOhLVLw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"hermes-estree": "0.25.0",
"hermes-parser": "0.25.0",
@@ -29302,6 +29424,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -29342,6 +29465,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
"integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.25.0"
},
@@ -29403,6 +29527,7 @@
"resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz",
"integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/react": "*"
},
@@ -29431,6 +29556,7 @@
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.79.5.tgz",
"integrity": "sha512-jVihwsE4mWEHZ9HkO1J2eUZSwHyDByZOqthwnGrVZCh6kTQBCm4v8dicsyDa6p0fpWNE5KicTcpX/XXl0ASJFg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@jest/create-cache-key-function": "^29.7.0",
"@react-native/assets-registry": "0.79.5",
@@ -29505,6 +29631,15 @@
"react-native": "*"
}
},
+ "node_modules/react-native-safe-area-context": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.4.0.tgz",
+ "integrity": "sha512-JaEThVyJcLhA+vU0NU8bZ0a1ih6GiF4faZ+ArZLqpYbL6j7R3caRqj+mE3lEtKCuHgwjLg3bCxLL1GPUJZVqUA==",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/react-native-web": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.20.0.tgz",
@@ -29662,6 +29797,7 @@
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
"integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.12.13",
"history": "^4.9.0",
@@ -31082,6 +31218,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -33070,6 +33207,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -33489,6 +33627,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
"integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -33554,6 +33693,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz",
"integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.48.1",
"@typescript-eslint/types": "8.48.1",
@@ -34519,6 +34659,7 @@
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz",
"integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.6",
@@ -35358,6 +35499,7 @@
"integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
"devOptional": true,
"license": "ISC",
+ "peer": true,
"engines": {
"node": ">= 14"
}
@@ -35446,6 +35588,7 @@
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
@@ -35541,32 +35684,6 @@
"postcss": "^8.4.49"
}
},
- "packages/postcss-react-strict-dom/node_modules/@stylexjs/babel-plugin": {
- "version": "0.15.4",
- "resolved": "https://registry.npmjs.org/@stylexjs/babel-plugin/-/babel-plugin-0.15.4.tgz",
- "integrity": "sha512-QfL2j3VCU+KTyIEoPBhdwq8KW1Gv0FVvwSzfjjdQ0J2Ei/DJBx2AXVsDYzBcVw0WI+KsEfQUHFZ1Fk2t1U/9Iw==",
- "license": "MIT",
- "dependencies": {
- "@babel/core": "^7.26.8",
- "@babel/helper-module-imports": "^7.25.9",
- "@babel/traverse": "^7.26.8",
- "@babel/types": "^7.26.8",
- "@dual-bundle/import-meta-resolve": "^4.1.0",
- "@stylexjs/stylex": "0.15.4",
- "postcss-value-parser": "^4.1.0"
- }
- },
- "packages/postcss-react-strict-dom/node_modules/@stylexjs/stylex": {
- "version": "0.15.4",
- "resolved": "https://registry.npmjs.org/@stylexjs/stylex/-/stylex-0.15.4.tgz",
- "integrity": "sha512-UQT75p3qxwCIsVpH87YfgHvzWGDyMbQcFKhguj4noBZCc+npEh5h7J4BIHMgrxpyJa9mislLfXv+M5TmP2YH5A==",
- "license": "MIT",
- "dependencies": {
- "css-mediaquery": "^0.1.2",
- "invariant": "^2.2.4",
- "styleq": "0.2.1"
- }
- },
"packages/postcss-react-strict-dom/node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -35632,32 +35749,6 @@
"react-native": ">=0.79.5"
}
},
- "packages/react-strict-dom/node_modules/@stylexjs/babel-plugin": {
- "version": "0.15.4",
- "resolved": "https://registry.npmjs.org/@stylexjs/babel-plugin/-/babel-plugin-0.15.4.tgz",
- "integrity": "sha512-QfL2j3VCU+KTyIEoPBhdwq8KW1Gv0FVvwSzfjjdQ0J2Ei/DJBx2AXVsDYzBcVw0WI+KsEfQUHFZ1Fk2t1U/9Iw==",
- "license": "MIT",
- "dependencies": {
- "@babel/core": "^7.26.8",
- "@babel/helper-module-imports": "^7.25.9",
- "@babel/traverse": "^7.26.8",
- "@babel/types": "^7.26.8",
- "@dual-bundle/import-meta-resolve": "^4.1.0",
- "@stylexjs/stylex": "0.15.4",
- "postcss-value-parser": "^4.1.0"
- }
- },
- "packages/react-strict-dom/node_modules/@stylexjs/stylex": {
- "version": "0.15.4",
- "resolved": "https://registry.npmjs.org/@stylexjs/stylex/-/stylex-0.15.4.tgz",
- "integrity": "sha512-UQT75p3qxwCIsVpH87YfgHvzWGDyMbQcFKhguj4noBZCc+npEh5h7J4BIHMgrxpyJa9mislLfXv+M5TmP2YH5A==",
- "license": "MIT",
- "dependencies": {
- "css-mediaquery": "^0.1.2",
- "invariant": "^2.2.4",
- "styleq": "0.2.1"
- }
- },
"packages/scripts": {
"name": "react-strict-dom-scripts",
"version": "0.0.55",