{"_id":"@bagaking/history.tsx","_rev":"2-ca50dca5cde3305d75ec4aa5ad54763c","name":"@bagaking/history.tsx","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.0":{"name":"@bagaking/history.tsx","version":"1.0.0","keywords":["undo","redo","history","snapshot","react","typescript","branching","time-travel","state-management","version-control"],"author":{"name":"bagaking","email":"kinghand@foxmail.com"},"license":"MIT","_id":"@bagaking/history.tsx@1.0.0","maintainers":[{"name":"kinghand","email":"kinghand@foxmail.com"}],"homepage":"https://github.com/bagaking/history.tsx#readme","bugs":{"url":"https://github.com/bagaking/history.tsx/issues"},"dist":{"shasum":"be68868a2e5d78db7ec3b4772826ff01798e6f51","tarball":"https://registry.npmjs.org/@bagaking/history.tsx/-/history.tsx-1.0.0.tgz","fileCount":22,"integrity":"sha512-m0l22OKHyPi3DdPZLLI0x6WqcxGmIzEDGvPMSec1xUU9JkP28QoQOc7WYaRLLBrL/aIJ2+O9T9qIEK/sz1V/qQ==","signatures":[{"sig":"MEYCIQDYOIruDp99OEC8A6lRjz1UPJWeSWgfSY8d0P2AB7N1VAIhAJnxEFvrBqrcCziWADa2y3B5//NQfiUA7qrEaFu4wbIb","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":61503},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"53157c015309fbe1f9a4794754f2f10a25cdd781","scripts":{"dev":"tsc --watch","demo":"cd examples/demo && npm install && npm run dev","lint":"eslint src --ext .ts","test":"jest","build":"tsc","clean":"rm -rf dist","prepack":"npm run build","release":"npm run prepublishOnly && npm publish","lint:fix":"eslint src --ext .ts --fix","validate":"npm run lint && npm run check-types && npm run test","demo:build":"cd examples/demo && npm install && npm run build","test:watch":"jest --watch","check-types":"tsc --noEmit","publish:major":"npm version major && npm publish","publish:minor":"npm version minor && npm publish","publish:patch":"npm version patch && npm publish","prepublishOnly":"npm run clean && npm run build && npm run test"},"_npmUser":{"name":"kinghand","email":"kinghand@foxmail.com"},"repository":{"url":"git+https://github.com/bagaking/history.tsx.git","type":"git"},"_npmVersion":"10.9.0","description":"Elegant TypeScript undo/redo management system with branching, time travel, and React integration","directories":{},"_nodeVersion":"22.12.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","eslint":"^8.0.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/react":"^18.0.0","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/history.tsx_1.0.0_1752947690985_0.08224512947470686","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@bagaking/history.tsx","version":"1.1.0","description":"Elegant TypeScript undo/redo management system with branching, time travel, and React integration","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","dev":"tsc --watch","test":"jest","test:watch":"jest --watch","lint":"eslint src --ext .ts","lint:fix":"eslint src --ext .ts --fix","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build && npm run test","prepack":"npm run build","publish:patch":"npm version patch && npm publish","publish:minor":"npm version minor && npm publish","publish:major":"npm version major && npm publish","release":"npm run prepublishOnly && npm publish","demo":"cd examples/demo && npm install && npm run dev","demo:build":"cd examples/demo && npm install && npm run build","check-types":"tsc --noEmit","validate":"npm run lint && npm run check-types && npm run test"},"keywords":["undo","redo","history","snapshot","react","typescript","branching","time-travel","state-management","version-control"],"author":{"name":"bagaking","email":"kinghand@foxmail.com"},"license":"MIT","devDependencies":{"@types/jest":"^29.5.0","@types/node":"^20.0.0","@types/react":"^18.0.0","@typescript-eslint/eslint-plugin":"^6.0.0","@typescript-eslint/parser":"^6.0.0","eslint":"^8.0.0","jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"repository":{"type":"git","url":"git+https://github.com/bagaking/history.tsx.git"},"bugs":{"url":"https://github.com/bagaking/history.tsx/issues"},"homepage":"https://github.com/bagaking/history.tsx#readme","engines":{"node":">=16.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_id":"@bagaking/history.tsx@1.1.0","gitHead":"d8e5b2042fad22c18dde2187cb3e99b6e6e194a1","_nodeVersion":"22.12.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-f6tDFrda5Y9Yy+FeciOs6fkNnRap+ACtx8AT+xgaV2ftEloWNvS2DPYsJ/XW3tH5KP1/WxIQtJu8lDd/53VUSw==","shasum":"6889b6478d862668aed2bb72ece5f4068743795c","tarball":"https://registry.npmjs.org/@bagaking/history.tsx/-/history.tsx-1.1.0.tgz","fileCount":30,"unpackedSize":72934,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC3PGSCIkinsUViBGypMoBvkao9jI5vxFp72mJK5jJk1gIgHIc+Dz/yKItCgDtXCgTI5AkEXpdz5VOwAQ/hK9Aiokw="}]},"_npmUser":{"name":"kinghand","email":"kinghand@foxmail.com"},"directories":{},"maintainers":[{"name":"kinghand","email":"kinghand@foxmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/history.tsx_1.1.0_1753023260299_0.841646776230051"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-19T17:54:50.938Z","modified":"2025-07-20T14:54:20.724Z","1.0.0":"2025-07-19T17:54:51.194Z","1.1.0":"2025-07-20T14:54:20.510Z"},"bugs":{"url":"https://github.com/bagaking/history.tsx/issues"},"author":{"name":"bagaking","email":"kinghand@foxmail.com"},"license":"MIT","homepage":"https://github.com/bagaking/history.tsx#readme","keywords":["undo","redo","history","snapshot","react","typescript","branching","time-travel","state-management","version-control"],"repository":{"type":"git","url":"git+https://github.com/bagaking/history.tsx.git"},"description":"Elegant TypeScript undo/redo management system with branching, time travel, and React integration","maintainers":[{"name":"kinghand","email":"kinghand@foxmail.com"}],"readme":"# History.tsx\n\n<p align=\"center\">\n  <strong>Universal undo/redo management for TypeScript applications</strong>\n</p>\n\n<p align=\"center\">\n  <em>优雅、高性能的历史状态管理，支持分支、时间旅行和 React 集成</em>\n</p>\n\n## Features ✨\n\n- **🌍 Universal**: Works in browser and Node.js environments\n- **⚛️ React Ready**: Dedicated hooks for seamless React integration\n- **🌿 Branching**: Auto-branching when inserting mid-history\n- **🎯 Time Travel**: Jump to any point in history with hash-based navigation\n- **⚡ Debounce**: Built-in debouncing for rapid changes\n- **🏷️ Metadata**: Rich metadata support for each history entry\n- **🔍 Query**: Powerful querying capabilities\n- **📡 Events**: Real-time event notifications\n- **🎛️ Configurable**: Flexible configuration options\n- **📦 TypeScript**: Full TypeScript support with excellent type inference\n\n## Quick Start 🚀\n\n### Installation\n\n```bash\nnpm install @bagaking/history.tsx\n```\n\n### Try Demo\n\n```bash\nnpm run demo\n```\n\n### Basic Usage\n\n```typescript\nimport { UniversalHistoryManager } from '@bagaking/history.tsx'\n\n// Create history manager\nconst history = new UniversalHistoryManager<string>()\n\n// Record states\nhistory.record('Hello')\nhistory.record('Hello World')\nhistory.record('Hello World!')\n\n// Undo/Redo\nhistory.undo()  // Back to 'Hello World'\nhistory.redo()  // Forward to 'Hello World!'\n\n// Time travel\nconst entries = history.query(() => true)\nhistory.jumpTo(entries[0].hash)  // Jump to first entry\n```\n\n### React Integration\n\n```tsx\nimport { useHistory, useUndo } from '@bagaking/history.tsx'\n\nfunction TextEditor() {\n  const history = useHistory<string>({\n    initialData: 'Hello World',\n    debounceDelay: 500\n  })\n\n  return (\n    <div>\n      <textarea\n        value={history.current || ''}\n        onChange={(e) => history.record(e.target.value)}\n      />\n      <button onClick={history.undo} disabled={!history.canUndo}>\n        Undo\n      </button>\n      <button onClick={history.redo} disabled={!history.canRedo}>\n        Redo\n      </button>\n    </div>\n  )\n}\n```\n\n## Core Concepts 🧠\n\n### History Structure\n\n```\nMain Branch:      [A] → [B] → [C] → [D]\n                              ↓\nFeature Branch:            [C'] → [D'] → [E']\n```\n\n- **unified_data**: Your application state as a snapshot\n- **snapshot**: Immutable data record with hash, timestamp, and metadata  \n- **history**: Chronological sequence of snapshots\n- **branches**: Parallel timelines created when inserting mid-history\n\n### Philosophy: unified_data → snapshot → history → undo/redo\n\n1. **unified_data**: Your app state (any serializable data)\n2. **snapshot**: Immutable record with unique hash\n3. **history**: Collection of snapshots in branches\n4. **undo/redo**: Higher-level operations using time-travel\n\n## API Reference 📚\n\n### UniversalHistoryManager\n\n#### Configuration\n\n```typescript\nconst history = new UniversalHistoryManager({\n  maxEntries: 1000,        // Maximum entries per branch\n  debounceDelay: 300,      // Debounce delay in ms\n  enableCompression: true, // Enable data compression\n  autoCleanup: true        // Auto cleanup old entries\n})\n```\n\n#### Core Methods\n\n```typescript\n// Record new state\nrecord(data: T, options?: RecordOptions): string\n\n// Navigate history\nundo(): HistoryEntry<T> | null\nredo(): HistoryEntry<T> | null\njumpTo(hash: string, options?: TimeravelOptions): HistoryEntry<T> | null\njumpToPosition(position: number, branchName?: string): HistoryEntry<T> | null\n\n// Branch management\ncreateBranch(name: string, fromHash?: string): boolean\nswitchBranch(name: string): boolean\n\n// Query and state\nquery(predicate: (entry: HistoryEntry<T>) => boolean): readonly HistoryEntry<T>[]\ngetState(): HistoryState<T>\ngetCurrent(): HistoryEntry<T> | null\ncanUndo(): boolean\ncanRedo(): boolean\n\n// Events\non(listener: HistoryListener<T>): () => void\n```\n\n### React Hooks\n\n#### useHistory\n\nFull-featured history management:\n\n```typescript\nconst {\n  current,        // Current data\n  state,         // Full history state\n  record,        // Record new state\n  undo,          // Undo operation\n  redo,          // Redo operation\n  jumpTo,        // Time travel\n  createBranch,  // Create branch\n  switchBranch,  // Switch branch\n  canUndo,       // Can undo?\n  canRedo,       // Can redo?\n  query,         // Query entries\n  clear,         // Clear history\n  manager        // Raw manager instance\n} = useHistory<T>(options)\n```\n\n#### useUndo\n\nSimplified undo/redo:\n\n```typescript\nconst {\n  data,     // Current data\n  record,   // Record new state\n  undo,     // Undo\n  redo,     // Redo  \n  canUndo,  // Can undo?\n  canRedo,  // Can redo?\n  clear     // Clear history\n} = useUndo<T>(options)\n```\n\n#### useHistoryState\n\nRead-only state observer:\n\n```typescript\nconst {\n  current,      // Current data\n  state,        // Full state\n  canUndo,      // Can undo?\n  canRedo,      // Can redo?\n  branches,     // Branch names\n  activeBranch  // Active branch\n} = useHistoryState(manager)\n```\n\n## Advanced Features 🔧\n\n### Time Travel Modes\n\n```typescript\n// Readonly mode - just move cursor\nhistory.jumpTo(hash, { mode: 'readonly' })\n\n// Branch mode - create new branch from target\nhistory.jumpTo(hash, { mode: 'branch', branchName: 'experiment' })\n```\n\n### Metadata Support\n\n```typescript\nhistory.record(data, {\n  metadata: {\n    user: 'alice',\n    action: 'edit_text',\n    timestamp: Date.now()\n  }\n})\n```\n\n### Debouncing\n\n```typescript\n// These rapid changes will be debounced\nhistory.record('t')\nhistory.record('te') \nhistory.record('tes')\nhistory.record('test')  // Only this will be recorded\n```\n\n### Event System\n\n```typescript\nhistory.on(event => {\n  console.log(event.type)  // 'record' | 'undo' | 'redo' | 'jump' | ...\n  console.log(event.entry) // History entry\n  console.log(event.metadata) // Event metadata\n})\n```\n\n### Querying\n\n```typescript\n// Find all entries with specific data\nconst textEntries = history.query(entry => \n  entry.data.text?.includes('hello')\n)\n\n// Find entries by time range\nconst recentEntries = history.query(entry =>\n  entry.timestamp > Date.now() - 3600000 // Last hour\n)\n\n// Find entries by metadata\nconst userEntries = history.query(entry =>\n  entry.metadata?.user === 'alice'\n)\n```\n\n## Examples 💡\n\nSee the `/examples` directory for complete examples:\n\n- [`universal-usage.ts`](examples/universal-usage.ts) - Core API usage\n- [`react-usage.tsx`](examples/react-usage.tsx) - React integration examples\n\n### Text Editor\n\n```tsx\nfunction TextEditor() {\n  const history = useHistory<string>({ \n    initialData: '',\n    debounceDelay: 500 \n  })\n\n  return (\n    <div>\n      <textarea\n        value={history.current || ''}\n        onChange={(e) => history.record(e.target.value)}\n      />\n      <div>\n        <button onClick={history.undo} disabled={!history.canUndo}>\n          ⟲ Undo\n        </button>\n        <button onClick={history.redo} disabled={!history.canRedo}>\n          ⟳ Redo\n        </button>\n      </div>\n    </div>\n  )\n}\n```\n\n### Todo App with Branching\n\n```tsx\nfunction TodoApp() {\n  const history = useHistory<TodoState>({\n    initialData: { todos: [], filter: 'all' }\n  })\n\n  const addTodo = (text: string) => {\n    const newState = {\n      ...history.current,\n      todos: [...history.current.todos, { id: Date.now(), text, done: false }]\n    }\n    history.record(newState, { \n      metadata: { action: 'add_todo' } \n    })\n  }\n\n  const createExperiment = () => {\n    history.createBranch('experiment')\n    history.switchBranch('experiment')\n  }\n\n  // ... rest of component\n}\n```\n\n## Performance 🚀\n\n- **Immutable snapshots**: No accidental mutations\n- **Efficient cloning**: JSON-based deep cloning with optional compression\n- **Memory management**: Auto-cleanup with configurable limits\n- **Debounced recording**: Prevents excessive history entries\n- **Hash-based navigation**: O(1) lookup for time travel\n- **Event-driven updates**: Minimal re-renders in React\n\n## Browser Support 🌐\n\n- Modern browsers (ES2020+)\n- Node.js 14+\n- React 16.8+ (for hooks)\n\n## Design Philosophy 🎨\n\nBased on the principles of:\n\n- **Immutability**: All snapshots are immutable\n- **Predictability**: Deterministic behavior with pure functions\n- **Flexibility**: Support for complex workflows and branching\n- **Performance**: Optimized for real-world usage patterns\n- **Developer Experience**: Intuitive APIs with excellent TypeScript support\n- **Modular Architecture**: High-cohesion, low-coupling design with specialized managers\n\nThe design follows the flow: `unified_data → snapshot → history → undo/redo`, where each step adds structure and capabilities while maintaining simplicity.\n\n**v1.1.0+ Architecture**: The core system now uses a modular approach with `CursorManager` for intelligent cursor validation and `BranchManager` for branch operations, ensuring robust state management with automatic error correction.\n\n## Contributing 🤝\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n## License 📄\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n---\n\n<p align=\"center\">\n  Made with ❤️ for developers who care about user experience\n</p>","readmeFilename":"README.md"}