UNPKG

vuetify-editable-data-grid

Version:

A highly customizable and interactive editable data table component built with Vue 3 and Vuetify 3. This component supports inline editing, undo/redo functionality, column visibility filters, drag-to-fill (like Excel), and more.

89 lines (88 loc) 3.27 kB
/** * useRefHistory - A Vue composable for tracking the history of a reactive ref value with undo/redo support. * * This utility allows you to store snapshots of a reactive `ref` (primitive or object), enabling undo/redo functionality. * Useful for form state, drawing apps, editors, etc. * * @param {Ref} source - The reactive ref to track history for. * @param {Object} options - Configuration options. * @param {boolean} [options.deep=false] - Whether to watch deeply nested changes. * @param {number} [options.capacity=Infinity] - Maximum number of history entries to keep. * @param {Function} [options.clone] - Function to clone a value (default: JSON deep clone). * * @returns {Object} { * history: Ref<Array>, // List of snapshots * pointer: Ref<number>, // Current position in the history * canUndo: Ref<boolean>, // Whether undo is possible * canRedo: Ref<boolean>, // Whether redo is possible * undo: Function, // Undo the last change * redo: Function // Redo a previously undone change * } * @author Rahul Rawat * Notes: * - Uses `v-watch` to track changes, with optional deep watch. * - Automatically trims history to respect `capacity`. * - Skips tracking during undo/redo to prevent recursive updates. */ import { ref, watch } from 'vue'; export function useRefHistory(source, options = {}) { const { deep = false, capacity = Infinity, clone = (v) => JSON.parse(JSON.stringify(v)) } = options; const history = ref([]); const pointer = ref(-1); const pauseTracking = ref(false); const canUndo = ref(false); const canRedo = ref(false); const updateMeta = () => { canUndo.value = pointer.value > 0; canRedo.value = pointer.value < history.value.length - 1; }; const pushSnapshot = (value) => { const snapshot = clone(value); // Clear redo history if changed mid-way if (pointer.value < history.value.length - 1) history.value.splice(pointer.value + 1); history.value.push(snapshot); pointer.value++; // Trim oldest if over capacity if (history.value.length > capacity) { history.value.shift(); pointer.value--; } updateMeta(); }; const undo = () => { if (!canUndo.value) return; source.value = clone(history.value[pointer.value]); pointer.value--; source.value = clone(history.value[pointer.value]); pauseTracking.value = false; updateMeta(); }; const redo = () => { if (!canRedo.value) return; pauseTracking.value = true; pointer.value++; source.value = clone(history.value[pointer.value]); pauseTracking.value = false; updateMeta(); }; // Track changes automatically watch(source, (newVal) => { if (pauseTracking.value) return; const newStr = JSON.stringify(newVal); const oldStr = JSON.stringify(history.value[pointer.value]); if (newStr !== oldStr) pushSnapshot(newVal); }, { deep, immediate: true }); return { history, pointer, canUndo, canRedo, undo, redo }; }