# @ktsn/spring [English](./README.md) | 日本語 直感的で動作の予測がしやすい CSS トランジションベースのスプリングアニメーションライブラリです。WWDC 2023 の [Animate with springs](https://developer.apple.com/videos/play/wwdc2023/10158/) にインスパイアされて開発されています。このライブラリの特徴は以下の通りです。 - CSS トランジションを使ったスプリングアニメーションの実装 - オプションが直感的で動作を予測しやすい - `bounce`: アニメーションのバウンス度合い - `duration`: アニメーションの長さ - ライブラリで使っている機能をサポートしていないブラウザに対しては `requestAnimationFrame` を使ったグレースフルデグラデーションでアニメーションを実行 ## Getting Started Vue 用のバインディングがあります。npm (または yarn, pnpm) でインストールします。 ```sh $ npm install @ktsn/spring ``` ` ``` `spring.` の後のプロパティ名が描画される要素名になります。例えば、`` は `
` 要素を描画します。要素は `:spring-style` プロパティで指定されたスタイルを持ちます。`:spring-style` プロパティの値が変更されるとスプリングアニメーションが実行されます。 ## Bounce と Duration `bounce` と `duration` オプションはバウンスの度合いとアニメーションの長さを指定するために使われます。 **bounce**
アニメーションのバウンス度合いを指定します。値は -1 から 1 の間で指定します。デフォルト値は 0 です。 **duration**
アニメーションの長さ(ミリ秒)を指定します。デフォルト値は 1000 です。 ## `disabled` 時の挙動 `` コンポーネントには `disabled` オプションを指定できます。`disabled` が `true` の間は、スタイル変更でアニメーションを発火させずに値だけを即座に更新します。`disabled` にしても実行中のアニメーションは**停止しません**。進行中のアニメーションはそのまま最後まで進みます。実行中のアニメーションを止めたい場合は、スタイル値を明示的に代入してください。`disabled` 中はその値へ即座にスナップします。 アニメーションが再開する際の初速は、以前の速度から自動的に引き継がれます。`disabled` 中に要素をドラッグなどで手動で動かした場合は、直近のスタイル更新から速度が推定され、離した瞬間にその勢いを引き継いだスプリングアニメーションになります。[Swipe](./demo/swipe/) デモがその例です。アニメーション中に要素をワープさせる場合も同様に勢いが保たれます。[Picker](./demo/picker/) デモでは、ホイールでピッカーを反対側へワープさせつつ回転の勢いを維持しています。 ## スタイル指定時の注意点 スタイルに含まれる数値はすべて同じ単位で、同じ順番で現れる必要があります。例えば、以下のような `:spring-style` の値は正しく動作しません。 ```vue ``` これはライブラリがスタイル内の数値をパースして、それぞれの数値ごとにアニメーションを計算しているためです。ライブラリは `translate` や `scale` の意味を解釈しませんし、`100%` と `100px` の違いも予測できません。上記の例を正しく動作させるには、`:spring-style` に含まれる数値がすべて同じ単位、同じ順番で現れるようにする必要があります。 ```vue ``` ## `springValue` と `springComputed` `springValue` はアニメーションするスタイル内の数値を管理する値で、`target` にセットした値へのアニメーションが自動的に実装されます。`sv` タグ付きテンプレートと組み合わせることで CSS 値の中に埋め込めます。 ```vue ``` Vue の `ref` を使って通常のテンプレートリテラルで CSS 値を構築してもアニメーションは実行されますが、`springValue` を使うことでアニメーション中の実際の値や速度を取得することができます。 ```ts const x = springValue(0) // 呼び出した時点のアニメーション中の実際の値と速度を取得する(リアクティブではない) x.current() x.velocity() ``` `springComputed` は Vue の `computed` の Spring Value 版です。`computed` と同様に他のリアクティブな値から Spring Value を導出できます。 ```vue ``` ## How It Works このライブラリはアニメーションの対象となるスタイルのプロパティに、経過時間のカスタムプロパティを含む、スプリングアニメーションの数式をセットしています(そのカスタムプロパティを `--t` とします)。そして、[`CSS.registerProperty`](https://developer.mozilla.org/en-US/docs/Web/API/CSS/registerProperty_static) を使って `--t` を登録し、そのプロパティに対して CSS トランジションを適用します。スプリングアニメーションの擬似コードは以下のようになります。 ```js // --t を登録 CSS.registerProperty({ name: '--t', syntax: '', inherits: false, initialValue: 0, }) // 初期状態を設定 el.style.setProperty('--t', 0) // --t を含むスプリングアニメーションの数式をセット el.style.translate = 'calc(P * (A * var(--t) + B) * exp(-C * var(--t)) - Q)' // 再描画を実行させる requestAnimationFrame(() => { // アニメーションの開始 el.style.setProperty('--t', 1) el.style.transition = '--t 1000ms linear' }) ``` また、このライブラリは `CSS.registerProperty` や CSS の `exp()` 関数をサポートしていないブラウザに対しては、CSS トランジションを使わず、`requestAnimationFrame` を使ったグレースフルデグラデーションでアニメーションを実行します。 ## API リファレンス ### `` コンポーネント `` コンポーネントは、プロパティ名と同じタグ名のネイティブ HTML 要素を描画します(例えば、`` は `
` 要素を描画します)。 **プロパティ** - `spring-style`: アニメーションさせるスタイルオブジェクト - `bounce` - `duration` - `disabled` **イベント** - `spring-finish`: アニメーションが視覚的に完了したとき (duration が経過した時) に発火します。 - `spring-settle`: アニメーションが完全に減衰して停止したときに発火します。 イベントはアニメーションサイクル単位で、最新のサイクルに対してのみ発火します。アニメーション中に `spring-style` が再設定されて以前のサイクルが中断された場合、そのサイクルのイベントは発火しません。`disabled` 中も発火しません。 ```vue ``` ### `` コンポーネント `` は Vue の [`` コンポーネント](https://ja.vuejs.org/guide/built-ins/transition.html)のスプリングアニメーション版です。enter 時には `enter-from` のスタイルから `spring-style` へ、leave 時には `spring-style` から `leave-to` のスタイルへとアニメーションを行います。 **プロパティ** - `spring-style`: 子要素のデフォルトスタイル - `enter-from`: enter 前の子要素のスタイル - `leave-to`: leave 後の子要素のスタイル。指定されていない場合は `enter-from` のスタイルが使われます。 - `bounce` - `duration` - Vue の `` コンポーネントから引き継いでいる props: - `name` - `mode` - `enterFromClass` - `enterActiveClass` - `enterToClass` - `leaveFromClass` - `leaveActiveClass` - `leaveToClass` **イベント** - `before-enter` - `after-enter` - `enter-cancelled` - `before-leave` - `after-leave` - `leave-cancelled` ```vue ``` ### `` コンポーネント `` は Vue の [`` コンポーネント](https://ja.vuejs.org/guide/built-ins/transition-group.html)のスプリングアニメーション版です。`` と同じように `spring-style`、`enter-from`、`leave-to` のスタイルを指定できます。 **Props** - `spring-style`: 子要素のデフォルトスタイル - `enter-from`: enter 前の子要素のスタイル - `leave-to`: leave 後の子要素のスタイル。指定されていない場合は `enter-from` のスタイルが使われます。 - `bounce` - `duration` - Vue の `` コンポーネントから引き継いでいる props: - `tag` - `name` - `enterFromClass` - `enterActiveClass` - `enterToClass` - `leaveFromClass` - `leaveActiveClass` - `leaveToClass` **Events** - `before-enter` - `after-enter` - `enter-cancelled` - `before-leave` - `after-leave` - `leave-cancelled` ```vue ``` ### `springValue(initial)` 単一の数値をアニメーションするためのリアクティブな値オブジェクトを作成します。`sv` タグ付きテンプレートを介して `` 要素にバインドして使用します。 **戻り値** のオブジェクトの API: - `target` (number, リアクティブ値、読み書き可) — アニメーションの destination 値。`` 要素にバインドされている状態で代入するとアニメーションが起動します。バインド先の要素が `disabled: true` の場合は即座にスタイルが反映されます。 - `current(): number` — 呼び出し時点の現在値を返すスナップショットメソッド。バインド中は spring 要素から現在値を読み、未バインド時は `target` の値を返します。 - `velocity(): number` — 呼び出し時点の速度を返すスナップショットメソッド。バインド中はアニメーションの速度を、未バインド時は `0` を返します。 ### `springComputed(getter)` `springValue` の computed 版。Vue の `computed` と同じく値を導出する関数を受け取り、Spring Value を返します。インターフェースは `springValue` の値と同じですが、`target` が読み取り専用になり、getter のリアクティブな依存先から自動的に算出されます。 ### `sv` タグ付きテンプレート `springValue` / `springComputed` の値を埋め込んだ CSS 値を構築し、`:spring-style` 用の値を返すタグ付きテンプレートです。 ### `v-spring-style`, `v-spring-options` ディレクティブ `v-spring-style` ディレクティブはアニメーションさせるスタイルを指定するために使います。`v-spring-options` ディレクティブはアニメーションのオプションを指定するために使います。 `