diff --git a/docs/utilities/animations.md b/docs/utilities/animations.md
index a71aeee59c2..87b67c482b7 100644
--- a/docs/utilities/animations.md
+++ b/docs/utilities/animations.md
@@ -275,323 +275,11 @@ import Chain from '@site/static/usage/v7/animations/chain/index.md';
Ionic Animations gives developers the ability to create powerful gesture-based animations by integrating seamlessly with [Ionic Gestures](gestures.md).
-### Usage
-
-````mdx-code-block
-
-
-
-```javascript
-let initialStep = 0;
-let started = false;
-
-const square = document.querySelector('.square');
-const MAX_TRANSLATE = 400;
-
-const animation = createAnimation()
- .addElement(square)
- .duration(1000)
- .fromTo('transform', 'translateX(0)', `translateX(${MAX_TRANSLATE}px)`);
-
-const gesture = createGesture({
- el: square,
- threshold: 0,
- gestureName: 'square-drag',
- onMove: ev => onMove(ev),
- onEnd: ev => onEnd(ev)
-})
-
-gesture.enable(true);
-
-const onMove = (ev): {
- if (!started) {
- animation.progressStart();
- started = true;
- }
-
- animation.progressStep(getStep(ev));
-}
-
-const onEnd = (ev): {
- if (!started) { return; }
-
- gesture.enable(false);
-
- const step = getStep(ev);
- const shouldComplete = step > 0.5;
-
- animation
- .progressEnd((shouldComplete) ? 1 : 0, step)
- .onFinish((): { gesture.enable(true); });
-
- initialStep = (shouldComplete) ? MAX_TRANSLATE : 0;
- started = false;
-}
-
-const clamp = (min, n, max): {
- return Math.max(min, Math.min(n, max));
-};
-
-const getStep = (ev): {
- const delta = initialStep + ev.deltaX;
- return clamp(0, delta / MAX_TRANSLATE, 1);
-}
-```
-
-
-
-```tsx
-private animation?: Animation;
-private gesture?: Gesture;
-
-private started: boolean = false;
-private initialStep: number = 0;
-private MAX_TRANSLATE: number = 400;
-
-ngOnInit() {
- this.animation = this.animationCtrl.create()
- .addElement(this.square.nativeElement)
- .duration(1000)
- .fromTo('transform', 'translateX(0)', `translateX(${this.MAX_TRANSLATE}px)`);
-
- this.gesture = this.gestureCtrl.create({
- el: this.square.nativeElement,
- threshold: 0,
- gestureName: 'square-drag',
- onMove: ev => this.onMove(ev),
- onEnd: ev => this.onEnd(ev)
- })
-
- this.gesture.enable(true);
-}
-
-private onMove(ev) {
- if (!started) {
- this.animation.progressStart();
- this.started = true;
- }
-
- this.animation.progressStep(this.getStep(ev));
-}
-
-private onEnd(ev) {
- if (!this.started) { return; }
-
- this.gesture.enable(false);
-
- const step = this.getStep(ev);
- const shouldComplete = step > 0.5;
-
- this.animation
- .progressEnd((shouldComplete) ? 1 : 0, step)
- .onFinish((): { this.gesture.enable(true); });
-
- this.initialStep = (shouldComplete) ? this.MAX_TRANSLATE : 0;
- this.started = false;
-}
-
-private clamp(min, n, max) {
- return Math.max(min, Math.min(n, max));
-}
-
-private getStep(ev) {
- const delta = this.initialStep + ev.deltaX;
- return this.clamp(0, delta / this.MAX_TRANSLATE, 1);
-}
-```
-
-
-
-```javascript
-import { createGesture, CreateAnimation, Gesture, GestureDetail } from '@ionic/react';
-import React from 'react';
-
-const MAX_TRANSLATE = 400;
-
-class MyComponent extends React.Component<{}, any> {
- private animation: React.RefObject = React.createRef();
- private gesture?: Gesture;
- private started: boolean = false;
- private initialStep: number = 0;
-
- constructor(props: any) {
- super(props);
-
- this.state = {
- progressStart: undefined,
- progressStep: undefined,
- progressEnd: undefined,
- onFinish: undefined
- };
- }
-
- componentDidMount() {
- const square = Array.from(this.animation.current!.nodes.values())[0];
-
- this.gesture = createGesture({
- el: square,
- gestureName: 'square-drag',
- threshold: 0,
- onMove: ev => this.onMove(ev),
- onEnd: ev => this.onEnd(ev)
- });
-
- this.gesture.enable(true);
- }
-
- private onMove(ev: GestureDetail) {
- if (!this.started) {
- this.setState({
- ...this.state,
- progressStart: { forceLinearEasing: true }
- });
- this.started = true;
- }
-
- this.setState({
- ...this.state,
- progressStep: { step: this.getStep(ev) }
- });
- }
-
- private onEnd(ev: GestureDetail) {
- if (!this.started) { return; }
-
- this.gesture!.enable(false);
-
- const step = this.getStep(ev);
- const shouldComplete = step > 0.5;
-
- this.setState({
- ...this.state,
- progressEnd: { playTo: (shouldComplete) ? 1 : 0, step },
- onFinish: { callback: () => {
- this.gesture!.enable(true);
- this.setState({
- progressStart: undefined,
- progressStep: undefined,
- progressEnd: undefined
- })
- }, opts: { oneTimeCallback: true }}
- });
-
- this.initialStep = (shouldComplete) ? MAX_TRANSLATE : 0;
- this.started = false;
- }
-
- private getStep(ev: GestureDetail) {
- const delta = this.initialStep + ev.deltaX;
- return this.clamp(0, delta / MAX_TRANSLATE, 1);
- }
-
- private clamp(min: number, n: number, max: number) {
- return Math.max(min, Math.min(n, max));
- }
-
- render() {
- return (
- <>
-
- >
- );
- }
-}
-```
-
-
-
-```javascript
-import { createAnimation, createGesture } from '@ionic/vue';
-import { ref } from 'vue';
-
-...
-
-let initialStep = 0;
-let started = false;
-
-const squareRef = ref();
-const MAX_TRANSLATE = 400;
-
-const animation = createAnimation()
- .addElement(squareRef.value)
- .duration(1000)
- .fromTo('transform', 'translateX(0)', `translateX(${MAX_TRANSLATE}px)`);
-
-const gesture = createGesture({
- el: squareRef.value,
- threshold: 0,
- gestureName: 'square-drag',
- onMove: ev => onMove(ev),
- onEnd: ev => onEnd(ev)
-})
-
-gesture.enable(true);
-
-const onMove = (ev): {
- if (!started) {
- animation.progressStart();
- started = true;
- }
-
- animation.progressStep(getStep(ev));
-}
-
-const onEnd = (ev): {
- if (!started) { return; }
-
- gesture.enable(false);
-
- const step = getStep(ev);
- const shouldComplete = step > 0.5;
-
- animation
- .progressEnd((shouldComplete) ? 1 : 0, step)
- .onFinish((): { gesture.enable(true); });
-
- initialStep = (shouldComplete) ? MAX_TRANSLATE : 0;
- started = false;
-}
-
-const clamp = (min, n, max): {
- return Math.max(min, Math.min(n, max));
-};
-
-const getStep = (ev): {
- const delta = initialStep + ev.deltaX;
- return clamp(0, delta / MAX_TRANSLATE, 1);
-}
-```
-
-
-````
+In the following example we are creating a track along which we can drag the card element. Our `animation` object will take care of moving the card element either left or right, and our `gesture` object will instruct the `animation` object which direction to move in.
-In this example we are creating a track along which we can drag the `.square` element. Our `animation` object will take care of moving the `.square` element either left or right, and our `gesture` object will instruct the `animation` object which direction to move in.
+import Gesture from '@site/static/usage/v7/animations/gesture/index.md';
-
+
## Preference-Based Animations
diff --git a/static/code/stackblitz/v7/html/index.ts b/static/code/stackblitz/v7/html/index.ts
index c820961c828..071bc801d6c 100644
--- a/static/code/stackblitz/v7/html/index.ts
+++ b/static/code/stackblitz/v7/html/index.ts
@@ -1,6 +1,6 @@
import { defineCustomElements } from '@ionic/core/loader';
-import { createAnimation, loadingController, modalController, pickerController, toastController } from '@ionic/core';
+import { createAnimation, createGesture, loadingController, modalController, pickerController, toastController } from '@ionic/core';
/* Core CSS required for Ionic components to work properly */
import '@ionic/core/css/core.css';
@@ -28,3 +28,4 @@ defineCustomElements();
(window as any).pickerController = pickerController;
(window as any).toastController = toastController;
(window as any).createAnimation = createAnimation;
+(window as any).createGesture = createGesture;
diff --git a/static/usage/v7/animations/gesture/angular/example_component_css.md b/static/usage/v7/animations/gesture/angular/example_component_css.md
new file mode 100644
index 00000000000..c06ce353f7c
--- /dev/null
+++ b/static/usage/v7/animations/gesture/angular/example_component_css.md
@@ -0,0 +1,17 @@
+```css
+.container {
+ flex-direction: column;
+}
+
+.track {
+ width: 344px;
+ background: var(--ion-color-medium);
+ padding: 16px;
+}
+
+ion-card {
+ width: 100px;
+ box-shadow: none;
+ margin: 0px;
+}
+```
diff --git a/static/usage/v7/animations/gesture/angular/example_component_html.md b/static/usage/v7/animations/gesture/angular/example_component_html.md
new file mode 100644
index 00000000000..56b2deacd70
--- /dev/null
+++ b/static/usage/v7/animations/gesture/angular/example_component_html.md
@@ -0,0 +1,11 @@
+```html
+
+
+
+ Card
+
+
+
+
Drag the square along the track.
+
+```
diff --git a/static/usage/v7/animations/gesture/angular/example_component_ts.md b/static/usage/v7/animations/gesture/angular/example_component_ts.md
new file mode 100644
index 00000000000..7b9aadccf5e
--- /dev/null
+++ b/static/usage/v7/animations/gesture/angular/example_component_ts.md
@@ -0,0 +1,82 @@
+```ts
+import { Component, ElementRef, ViewChildren, ViewChild } from '@angular/core';
+import { AnimationController, GestureController, IonCard } from '@ionic/angular';
+import type { Animation, Gesture, GestureDetail } from '@ionic/angular';
+
+@Component({
+ selector: 'app-example',
+ templateUrl: 'example.component.html',
+ styleUrls: ['example.component.css'],
+})
+export class ExampleComponent {
+ @ViewChild(IonCard, { read: ElementRef }) card: ElementRef;
+
+ private animation: Animation;
+ private gesture: Gesture;
+ private started = false;
+ private initialStep = 0;
+
+ /**
+ * The track is 344px wide.
+ * The card is 100px wide.
+ * We want 16px of margin on each end of the track.
+ */
+ private readonly MAX_TRANSLATE = 344 - 100 - 32;
+
+ constructor(private animationCtrl: AnimationController, private gestureCtrl: GestureController) {}
+
+ private onMove(ev: GestureDetail) {
+ if (!this.started) {
+ this.animation.progressStart();
+ this.started = true;
+ }
+
+ this.animation.progressStep(this.getStep(ev));
+ }
+
+ private onEnd(ev: GestureDetail) {
+ if (!this.started) {
+ return;
+ }
+
+ this.gesture.enable(false);
+
+ const step = this.getStep(ev);
+ const shouldComplete = step > 0.5;
+
+ this.animation.progressEnd(shouldComplete ? 1 : 0, step).onFinish(() => {
+ this.gesture.enable(true);
+ });
+
+ this.initialStep = shouldComplete ? this.MAX_TRANSLATE : 0;
+ this.started = false;
+ }
+
+ private clamp(min: number, n: number, max: number) {
+ return Math.max(min, Math.min(n, max));
+ }
+
+ private getStep(ev: GestureDetail) {
+ const delta = this.initialStep + ev.deltaX;
+ return this.clamp(0, delta / this.MAX_TRANSLATE, 1);
+ }
+
+ ngAfterViewInit() {
+ this.animation = this.animationCtrl
+ .create()
+ .addElement(this.card.nativeElement)
+ .duration(1000)
+ .fromTo('transform', 'translateX(0)', `translateX(${this.MAX_TRANSLATE}px)`);
+
+ const gesture = (this.gesture = this.gestureCtrl.create({
+ el: this.card.nativeElement,
+ threshold: 0,
+ gestureName: 'card-drag',
+ onMove: (ev) => this.onMove(ev),
+ onEnd: (ev) => this.onEnd(ev),
+ }));
+
+ gesture.enable(true);
+ }
+}
+```
diff --git a/static/usage/v7/animations/gesture/demo.html b/static/usage/v7/animations/gesture/demo.html
new file mode 100644
index 00000000000..88aa10c5c38
--- /dev/null
+++ b/static/usage/v7/animations/gesture/demo.html
@@ -0,0 +1,113 @@
+
+
+
+
+
+ Animation
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Card
+
+
+
+
Drag the square along the track.
+
+
+
diff --git a/static/usage/v7/animations/gesture/index.md b/static/usage/v7/animations/gesture/index.md
new file mode 100644
index 00000000000..b3e53d6d8f3
--- /dev/null
+++ b/static/usage/v7/animations/gesture/index.md
@@ -0,0 +1,35 @@
+import Playground from '@site/src/components/global/Playground';
+
+import javascript from './javascript.md';
+
+import react_main_tsx from './react/main_tsx.md';
+import react_main_css from './react/main_css.md';
+
+import vue from './vue.md';
+
+import angular_example_component_html from './angular/example_component_html.md';
+import angular_example_component_ts from './angular/example_component_ts.md';
+import angular_example_component_css from './angular/example_component_css.md';
+
+
diff --git a/static/usage/v7/animations/gesture/javascript.md b/static/usage/v7/animations/gesture/javascript.md
new file mode 100644
index 00000000000..3535705d5eb
--- /dev/null
+++ b/static/usage/v7/animations/gesture/javascript.md
@@ -0,0 +1,98 @@
+```html
+
+
+Drag the square along the track.
+
+
+
+
+```
diff --git a/static/usage/v7/animations/gesture/react/main_css.md b/static/usage/v7/animations/gesture/react/main_css.md
new file mode 100644
index 00000000000..c06ce353f7c
--- /dev/null
+++ b/static/usage/v7/animations/gesture/react/main_css.md
@@ -0,0 +1,17 @@
+```css
+.container {
+ flex-direction: column;
+}
+
+.track {
+ width: 344px;
+ background: var(--ion-color-medium);
+ padding: 16px;
+}
+
+ion-card {
+ width: 100px;
+ box-shadow: none;
+ margin: 0px;
+}
+```
diff --git a/static/usage/v7/animations/gesture/react/main_tsx.md b/static/usage/v7/animations/gesture/react/main_tsx.md
new file mode 100644
index 00000000000..73fca7dfe22
--- /dev/null
+++ b/static/usage/v7/animations/gesture/react/main_tsx.md
@@ -0,0 +1,92 @@
+```tsx
+import React, { useEffect, useRef } from 'react';
+import { IonCard, IonCardContent, createAnimation, createGesture } from '@ionic/react';
+import type { Animation, Gesture, GestureDetail } from '@ionic/react';
+
+import './main.css';
+
+function Example() {
+ const cardEl = useRef(null);
+ const animation = useRef(null);
+ const gesture = useRef(null);
+ const initialStep = useRef(0);
+ const started = useRef(false);
+
+ useEffect(() => {
+ if (animation.current === null) {
+ /**
+ * The track is 344px wide.
+ * The card is 100px wide.
+ * We want 16px of margin on each end of the track.
+ */
+ const MAX_TRANSLATE = 344 - 100 - 32;
+
+ animation.current = createAnimation()
+ .addElement(cardEl.current!)
+ .duration(1000)
+ .fromTo('transform', 'translateX(0)', `translateX(${MAX_TRANSLATE}px)`);
+
+ gesture.current = createGesture({
+ el: cardEl.current!,
+ threshold: 0,
+ gestureName: 'card-drag',
+ onMove: (ev) => onMove(ev),
+ onEnd: (ev) => onEnd(ev),
+ });
+
+ gesture.current.enable(true);
+
+ const onMove = (ev: GestureDetail) => {
+ if (!started.current) {
+ animation.current!.progressStart();
+ started.current = true;
+ }
+
+ animation.current!.progressStep(getStep(ev));
+ };
+
+ const onEnd = (ev: GestureDetail) => {
+ if (!started.current) {
+ return;
+ }
+
+ gesture.current!.enable(false);
+
+ const step = getStep(ev);
+ const shouldComplete = step > 0.5;
+
+ animation.current!.progressEnd(shouldComplete ? 1 : 0, step).onFinish(() => {
+ gesture.current!.enable(true);
+ });
+
+ initialStep.current = shouldComplete ? MAX_TRANSLATE : 0;
+ started.current = false;
+ };
+
+ const clamp = (min: number, n: number, max: number) => {
+ return Math.max(min, Math.min(n, max));
+ };
+
+ const getStep = (ev: GestureDetail) => {
+ const delta = initialStep.current + ev.deltaX;
+ return clamp(0, delta / MAX_TRANSLATE, 1);
+ };
+ }
+ }, [cardEl]);
+
+ return (
+ <>
+
+
+
+ Card
+
+
+
+
Drag the square along the track.
+
+ >
+ );
+}
+export default Example;
+```
diff --git a/static/usage/v7/animations/gesture/vue.md b/static/usage/v7/animations/gesture/vue.md
new file mode 100644
index 00000000000..9555355fe48
--- /dev/null
+++ b/static/usage/v7/animations/gesture/vue.md
@@ -0,0 +1,112 @@
+```html
+
+
+
+
+ Card
+
+
+
+
Drag the square along the track.
+
+
+
+
+
+
+```