Skip to content

Commit

Permalink
wip: useRefHistory
Browse files Browse the repository at this point in the history
  • Loading branch information
pei-pay committed May 3, 2024
1 parent 462c4ee commit eb58179
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 3 deletions.
39 changes: 39 additions & 0 deletions App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script setup lang="ts">
import { ref } from 'vue';

Check failure on line 2 in App.vue

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon
import { useRefHistory } from './starter/useRefHistory';

Check failure on line 4 in App.vue

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon
const format = (timestamp: number): string => {

Check failure on line 6 in App.vue

View workflow job for this annotation

GitHub Actions / lint

Top-level functions should be declared with function keyword
const date = new Date(timestamp);

Check failure on line 7 in App.vue

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon
return date.toISOString().slice(0, 19).replace('T', ' ');

Check failure on line 8 in App.vue

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon
}
const count = ref(0);

Check failure on line 11 in App.vue

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon
const { history, canUndo, canRedo, undo, redo } = useRefHistory(count);

Check failure on line 12 in App.vue

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon
</script>

<template>
<div>Count: {{ count }}</div>
<button @click="count++">
Increment
</button>
<button @click="count--">
Decrement
</button>
<span>/</span>
<button :disabled="!canUndo" @click="undo()">
Undo
</button>
<button :disabled="!canRedo" @click="redo()">
Redo
</button>
<br>
<br>
<p>History (limited to 10 records for demo)</p>
<div>
<div v-for="i in history" :key="i.timestamp">
<span>{{ format(i.timestamp) }}</span>
<span>{ value: {{ i.snapshot }} }</span>
</div>
</div>
</template>
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script type="module" src="/main.ts"></script>
</body>
</html>
6 changes: 6 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createApp } from 'vue';

Check failure on line 1 in main.ts

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon
import App from './App.vue';

Check failure on line 2 in main.ts

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon

const app = createApp(App);

Check failure on line 4 in main.ts

View workflow job for this annotation

GitHub Actions / lint

Extra semicolon

app.mount('#app');
2 changes: 1 addition & 1 deletion packages/core/useRefHistory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { type UseManualRefHistoryReturn, useManualRefHistory } from '../useManua

export interface UseRefHistoryReturn<Raw> extends UseManualRefHistoryReturn<Raw> {}

export function useRefHistory<Raw>(source: Ref<Raw>) {
export function useRefHistory<Raw>(source: Ref<Raw>): UseRefHistoryReturn<Raw> {
const { ignoreUpdates } = watchIgnorable(source, commit)

function setSource(source: Ref<Raw>, value: Raw) {
Expand Down
90 changes: 89 additions & 1 deletion packages/ja/starter/useRefHistory.md
Original file line number Diff line number Diff line change
@@ -1 +1,89 @@
# useRefHistory
# useRefHistory

<!-- WIP: 下書き -->

https://vueuse.org/core/useRefHistory/

## どういったコンポーザブルか

ref の変更履歴を自動で追跡し、値を戻したり、戻した値を復活させたりできる関数を提供します。

### Demo

[VueUseの公式サイト](https://vueuse.org/core/useRefHistory/#demo) で実際の動きを確認してみましょう。

#### ポイント
- Increment ボタンを押すと count の値が増え、History にその値と時刻が追加される
- Decrement ボタンを押すと count の値を減り、History にその値と時刻が追加される
- Undo ボタンを押すと、count の値が一つ前の値に戻り、History からもその履歴が消える
- Redo ボタンを押すと、Undo で戻した値に戻り、History にもその履歴が復活する
- この時の時刻は redo で戻した時間ではなく、その履歴が最初に追加された時間になっていることに注意!

## 作り方

### ユーザーのインターフェースを考える

まずはユーザーがこのコンポーザブルをどのように使うか考えてみましょう。デモで確認した通り、カウントの値の変更履歴を管理したいとします。

- ユーザーが提供するもの
- 履歴を管理したいref: count
- ユーザーに提供するもの
- 履歴: history
- 値と時刻(タイムスタンプ)がわかるといい
- 履歴を戻す関数: undo
- 戻した履歴を復活させる関数: redo
- 履歴を戻せるかどうかフラグ: canUndo
- 戻したい履歴があるかどうかフラグ: canRedo

以上のことから下記のような形になれば良さそうです。

```ts
const { history, undo, redo, canUndo, canRedo } = useRefHistory(count)
```

### 型定義してみる

ユーザーのインターフェースが決まったので、今度はコンポーザブルの型を考えます。

- 履歴(history)は値(snapshot)と時刻(timestamp)のオブジェクトの配列
- canUndo と canRedo は boolean
- undo と redo は関数

```ts
import type { Ref } from 'vue'

interface UseRefHistoryRecord<T> {
snapshot: T
timestamp: number
}
interface UseRefHistoryReturn<Raw> {
history: Ref<UseRefHistoryRecord<Raw>[]>
canUndo: Ref<boolean>
canRedo: Ref<boolean>
undo: () => void
redo: () => void
}

export function useRefHistory<Raw>(source: Ref<Raw>): UseRefHistoryReturn<Raw> {

// 中身はこれから実装する

return {
history,
canUndo,
canRedo,
undo,
redo,
}
}
```

### 仕様をまとめてみる

`useRefHistory` がどういったことをするのか実装者の視点で考えてみましょう

- ユーザーから受け取った値 (引数のsource) を監視し、値が変わったら履歴にその時の値と時刻を追加する
- undo を発火したら、履歴から一番最新のものを削除し、source の値を次に最新の値にする
- redo を発火したら、undo で戻したものの中から一番最近のものを、sourceの値にし、履歴に戻す。
- canUndo は履歴あればtrue、ないならfalse
- canRedo は undoで戻したものがあれば true、ないなら false
35 changes: 35 additions & 0 deletions starter/useRefHistory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ref, watch, type Ref } from 'vue'

interface UseRefHistoryRecord<T> {
snapshot: T
timestamp: number
}
interface UseRefHistoryReturn<Raw> {
history: Ref<UseRefHistoryRecord<Raw>[]>
canUndo: Ref<boolean>
canRedo: Ref<boolean>
undo: () => void
redo: () => void
}

export function useRefHistory<Raw>(source: Ref<Raw>): UseRefHistoryReturn<Raw> {

const history: Ref<UseRefHistoryRecord<Raw>[]> = ref([])
const canUndo = ref(false)
const canRedo = ref(false)
const undo = () => {}
const redo = () => {}


watch(source, () => {

})

return {
history,
canUndo,
canRedo,
undo,
redo,
}
}

0 comments on commit eb58179

Please sign in to comment.