Files
Modrinth-plus/packages/ui/src/utils/savable.ts
Calum H. 400c571fe6 refactor: project saving logic (#5225)
* fix: project data saving not visually shown immediately

* feat: useSavable improvements

* feat: migrate where possible to useSavable

* fix: gitignore

* feat: use es-toolkit
2026-01-28 16:46:14 +00:00

58 lines
1.3 KiB
TypeScript

import { isEqual } from 'es-toolkit'
import type { ComputedRef, Ref } from 'vue'
import { computed, ref } from 'vue'
export function useSavable<T extends Record<string, unknown>>(
data: () => T,
save: (changes: Partial<T>) => void | Promise<void>,
): {
saved: ComputedRef<T>
current: Ref<T>
changes: ComputedRef<Partial<T>>
hasChanges: ComputedRef<boolean>
saving: Ref<boolean>
reset: () => void
save: () => Promise<void>
} {
const savedValues = computed(data)
const currentValues = ref({ ...data() }) as Ref<T>
const saving = ref(false)
const changes = computed<Partial<T>>(() => {
const values: Partial<T> = {}
const keys = Object.keys(currentValues.value) as (keyof T)[]
for (const key of keys) {
if (!isEqual(savedValues.value[key], currentValues.value[key])) {
values[key] = currentValues.value[key]
}
}
return values
})
const hasChanges = computed(() => Object.keys(changes.value).length > 0)
const reset = () => {
currentValues.value = data()
}
const saveInternal = async () => {
if (!hasChanges.value) return
saving.value = true
try {
await save(changes.value)
} finally {
saving.value = false
}
}
return {
saved: savedValues,
current: currentValues,
changes,
hasChanges,
saving,
reset,
save: saveInternal,
}
}