{"version":3,"sources":["../../src/use-manual-state-history/index.ts"],"sourcesContent":["import { defaultCloneFn } from '../use-cloned-state'\nimport { useDebouncedFn } from '../use-debounced-fn'\nimport { useLatest } from '../use-latest'\nimport { useSetState } from '../use-set-state'\nimport { useStableFn } from '../use-stable-fn'\nimport { useThrottledFn } from '../use-throttled-fn'\nimport { isFunction, isNumber, timestamp } from '../utils/basic'\n\nimport type { CloneFn } from '../use-cloned-state'\nimport type { UseDebouncedFnOptions } from '../use-debounced-fn'\nimport type { UseThrottledFnOptions } from '../use-throttled-fn'\n\nexport interface UseRefHistoryRecord<T> {\n  /**\n   * The serialized snapshot\n   */\n  snapshot: T\n  /**\n   * The timestamp\n   */\n  timestamp: number\n}\n\nexport interface UseManualStateHistoryOptions<Raw, Serialized = Raw> {\n  /**\n   * The capacity of the history records\n   *\n   * @defaultValue Number.POSITIVE_INFINITY\n   */\n  capacity?: number\n  /**\n   * Whether to clone the source state\n   *\n   * @defaultValue false\n   */\n  clone?: boolean | CloneFn<Raw>\n  /**\n   * The throttle options\n   *\n   * @defaultValue undefined\n   */\n  throttle?: number | UseThrottledFnOptions\n  /**\n   * The debounce options\n   *\n   * @defaultValue undefined\n   */\n  debounce?: number | UseDebouncedFnOptions\n  /**\n   * The dump function to serialize the source state\n   *\n   * @defaultValue (v) => v\n   */\n  dump?: (v: Raw) => Serialized\n  /**\n   * The parse function to deserialize the serialized state\n   *\n   * @defaultValue (v) => v\n   */\n  parse?: (v: Serialized) => Raw\n}\n\nexport interface UseManualStateHistoryReturns<Raw, Serialized> {\n  /**\n   * The source state\n   */\n  source: Raw\n  /**\n   * The history records\n   */\n  history: UseRefHistoryRecord<Serialized>[]\n  /**\n   * The last history record\n   */\n  last: UseRefHistoryRecord<Serialized>\n  /**\n   * The undo stack\n   */\n  undoStack: UseRefHistoryRecord<Serialized>[]\n  /**\n   * The redo stack\n   */\n  redoStack: UseRefHistoryRecord<Serialized>[]\n  /**\n   * Whether can undo or redo\n   */\n  canUndo: boolean\n  /**\n   * Whether can redo or undo\n   */\n  canRedo: boolean\n  /**\n   * Undo the last change\n   */\n  undo(): void\n  /**\n   * Redo the last change\n   */\n  redo(): void\n  /**\n   * Clear all history records\n   */\n  clear(): void\n  /**\n   * Commit the current source state to history\n   */\n  commit(): void\n}\n\ntype FnCloneOrBypass<F, T> = (v: F) => T\n\nconst fnBypass = <F, T>(v: F) => v as unknown as T\n\nfunction defaultDump<R, S>(clone?: boolean | CloneFn<R>) {\n  return (clone ? (isFunction(clone) ? clone : defaultCloneFn) : fnBypass) as unknown as FnCloneOrBypass<R, S>\n}\n\nfunction defaultParse<R, S>(clone?: boolean | CloneFn<R>) {\n  return (clone ? (isFunction(clone) ? clone : defaultCloneFn) : fnBypass) as unknown as FnCloneOrBypass<S, R>\n}\n\n/**\n * A React Hook that allows you to manage the state history manually.\n */\nexport function useManualStateHistory<Raw, Serialized = Raw>(\n  source: Raw,\n  options: UseManualStateHistoryOptions<Raw, Serialized> = {},\n): UseManualStateHistoryReturns<Raw, Serialized> {\n  const {\n    clone = false,\n    dump = defaultDump<Raw, Serialized>(clone),\n    parse = defaultParse<Raw, Serialized>(clone),\n    capacity = Number.POSITIVE_INFINITY,\n    throttle,\n    debounce,\n  } = options\n\n  const latest = useLatest({ source, dump, parse, capacity })\n\n  const createHistoryRecord = useStableFn(() => {\n    const { dump, source } = latest.current\n\n    return {\n      snapshot: dump(source),\n      timestamp: timestamp(),\n    }\n  })\n\n  const [state, _setState] = useSetState({\n    last: createHistoryRecord(),\n    undoStack: [] as UseRefHistoryRecord<Serialized>[],\n    redoStack: [] as UseRefHistoryRecord<Serialized>[],\n  })\n\n  const commit = useStableFn(() => {\n    _setState((pre) => {\n      const capacity = latest.current.capacity - 1 // history = [last, ...undoStack]\n\n      const addedUndoStack = [pre.last, ...pre.undoStack]\n      const isCapReached = capacity && addedUndoStack.length >= capacity\n      const newUndoStack = isCapReached ? addedUndoStack.slice(0, capacity) : addedUndoStack\n\n      return {\n        redoStack: [],\n        undoStack: newUndoStack,\n        last: createHistoryRecord(),\n      }\n    })\n  })\n\n  const throttleOpts = isNumber(throttle) ? { wait: throttle } : throttle\n  const debounceOpts = isNumber(debounce) ? { wait: debounce } : debounce\n\n  const throttledCommit = useThrottledFn(commit, throttleOpts)\n  const debouncedCommit = useDebouncedFn(commit, debounceOpts)\n\n  const limitedCommit = throttleOpts ? throttledCommit : debounceOpts ? debouncedCommit : commit\n\n  const clear = useStableFn(() => _setState({ undoStack: [], redoStack: [] }))\n\n  const undo = useStableFn(() => {\n    _setState((pre) => {\n      const state = pre.undoStack[0]\n      if (!state) return pre\n\n      return {\n        undoStack: pre.undoStack.slice(1),\n        redoStack: [pre.last, ...pre.redoStack],\n        last: state,\n      }\n    })\n  })\n\n  const redo = useStableFn(() => {\n    _setState((pre) => {\n      const state = pre.redoStack[0]\n      if (!state) return pre\n\n      return {\n        redoStack: pre.redoStack.slice(1),\n        undoStack: [pre.last, ...pre.undoStack],\n        last: state,\n      }\n    })\n  })\n\n  const history = [state.last, ...state.undoStack]\n  const canUndo = state.undoStack.length > 0\n  const canRedo = state.redoStack.length > 0\n\n  return {\n    ...state,\n    source,\n    history,\n    canUndo,\n    canRedo,\n    clear,\n    undo,\n    redo,\n    commit: limitedCommit,\n  }\n}\n"],"names":["useManualStateHistory","fnBypass","v","defaultDump","clone","isFunction","defaultCloneFn","defaultParse","source","options","dump","parse","capacity","Number","POSITIVE_INFINITY","throttle","debounce","latest","useLatest","createHistoryRecord","useStableFn","current","snapshot","timestamp","useSetState","last","undoStack","redoStack","state","_setState","commit","pre","addedUndoStack","isCapReached","length","newUndoStack","slice","throttleOpts","isNumber","wait","debounceOpts","throttledCommit","useThrottledFn","debouncedCommit","useDebouncedFn","limitedCommit","clear","undo","redo","history","canUndo","canRedo"],"mappings":";;;;+BA4HgBA;;;eAAAA;;;8BA5He;8BACA;yBACL;2BACE;2BACA;8BACG;qBACiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyGhD,IAAMC,WAAW,SAAOC;WAASA;;AAEjC,SAASC,YAAkBC,KAA4B;IACrD,OAAQA,QAASC,IAAAA,iBAAU,EAACD,SAASA,QAAQE,8BAAc,GAAIL;AACjE;AAEA,SAASM,aAAmBH,KAA4B;IACtD,OAAQA,QAASC,IAAAA,iBAAU,EAACD,SAASA,QAAQE,8BAAc,GAAIL;AACjE;AAKO,SAASD,sBACdQ,MAAW;QACXC,UAAAA,iEAAyD,CAAC;IAE1D,qBAOIA,QANFL,OAAAA,oCAAQ,wCAMNK,QALFC,MAAAA,kCAAOP,YAA6BC,yCAKlCK,QAJFE,OAAAA,oCAAQJ,aAA8BH,6CAIpCK,QAHFG,UAAAA,0CAAWC,OAAOC,iBAAiB,sBACnCC,WAEEN,QAFFM,UACAC,WACEP,QADFO;IAGF,IAAMC,SAASC,IAAAA,oBAAS,EAAC;QAAEV,QAAAA;QAAQE,MAAAA;QAAMC,OAAAA;QAAOC,UAAAA;IAAS;IAEzD,IAAMO,sBAAsBC,IAAAA,wBAAW,EAAC;QACtC,IAAyBH,kBAAAA,OAAOI,OAAO,EAA/BX,OAAiBO,gBAAjBP,MAAMF,WAAWS,gBAAXT;QAEd,OAAO;YACLc,UAAUZ,KAAKF;YACfe,WAAWA,IAAAA,gBAAS;QACtB;IACF;IAEA,IAA2BC,gCAAAA,IAAAA,wBAAW,EAAC;QACrCC,MAAMN;QACNO,WAAW,EAAE;QACbC,WAAW,EAAE;IACf,QAJOC,QAAoBJ,iBAAbK,YAAaL;IAM3B,IAAMM,SAASV,IAAAA,wBAAW,EAAC;QACzBS,UAAU,SAACE;YACT,IAAMnB,WAAWK,OAAOI,OAAO,CAACT,QAAQ,GAAG,EAAE,iCAAiC;;YAE9E,IAAMoB,iBAAiB;gBAACD,IAAIN,IAAI;aAAmB,CAA5B,OAAW,qBAAGM,IAAIL,SAAS;YAClD,IAAMO,eAAerB,YAAYoB,eAAeE,MAAM,IAAItB;YAC1D,IAAMuB,eAAeF,eAAeD,eAAeI,KAAK,CAAC,GAAGxB,YAAYoB;YAExE,OAAO;gBACLL,WAAW,EAAE;gBACbD,WAAWS;gBACXV,MAAMN;YACR;QACF;IACF;IAEA,IAAMkB,eAAeC,IAAAA,eAAQ,EAACvB,YAAY;QAAEwB,MAAMxB;IAAS,IAAIA;IAC/D,IAAMyB,eAAeF,IAAAA,eAAQ,EAACtB,YAAY;QAAEuB,MAAMvB;IAAS,IAAIA;IAE/D,IAAMyB,kBAAkBC,IAAAA,8BAAc,EAACZ,QAAQO;IAC/C,IAAMM,kBAAkBC,IAAAA,8BAAc,EAACd,QAAQU;IAE/C,IAAMK,gBAAgBR,eAAeI,kBAAkBD,eAAeG,kBAAkBb;IAExF,IAAMgB,QAAQ1B,IAAAA,wBAAW,EAAC;eAAMS,UAAU;YAAEH,WAAW,EAAE;YAAEC,WAAW,EAAE;QAAC;;IAEzE,IAAMoB,OAAO3B,IAAAA,wBAAW,EAAC;QACvBS,UAAU,SAACE;YACT,IAAMH,QAAQG,IAAIL,SAAS,CAAC,EAAE;YAC9B,IAAI,CAACE,OAAO,OAAOG;YAEnB,OAAO;gBACLL,WAAWK,IAAIL,SAAS,CAACU,KAAK,CAAC;gBAC/BT,WAAW;oBAACI,IAAIN,IAAI;iBAAmB,CAA5B,OAAW,qBAAGM,IAAIJ,SAAS;gBACtCF,MAAMG;YACR;QACF;IACF;IAEA,IAAMoB,OAAO5B,IAAAA,wBAAW,EAAC;QACvBS,UAAU,SAACE;YACT,IAAMH,QAAQG,IAAIJ,SAAS,CAAC,EAAE;YAC9B,IAAI,CAACC,OAAO,OAAOG;YAEnB,OAAO;gBACLJ,WAAWI,IAAIJ,SAAS,CAACS,KAAK,CAAC;gBAC/BV,WAAW;oBAACK,IAAIN,IAAI;iBAAmB,CAA5B,OAAW,qBAAGM,IAAIL,SAAS;gBACtCD,MAAMG;YACR;QACF;IACF;IAEA,IAAMqB,UAAU;QAACrB,MAAMH,IAAI;KAAqB,CAAhC,OAAa,qBAAGG,MAAMF,SAAS;IAC/C,IAAMwB,UAAUtB,MAAMF,SAAS,CAACQ,MAAM,GAAG;IACzC,IAAMiB,UAAUvB,MAAMD,SAAS,CAACO,MAAM,GAAG;IAEzC,OAAO,wCACFN;QACHpB,QAAAA;QACAyC,SAAAA;QACAC,SAAAA;QACAC,SAAAA;QACAL,OAAAA;QACAC,MAAAA;QACAC,MAAAA;QACAlB,QAAQe;;AAEZ"}