import { isEqual } from 'es-toolkit' import type { ComputedRef, Ref } from 'vue' import { computed, ref } from 'vue' export function useSavable>( data: () => T, save: (changes: Partial) => void | Promise, ): { saved: ComputedRef current: Ref changes: ComputedRef> hasChanges: ComputedRef saving: Ref reset: () => void save: () => Promise } { const savedValues = computed(data) const currentValues = ref({ ...data() }) as Ref const saving = ref(false) const changes = computed>(() => { const values: Partial = {} 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, } }