Created
August 17, 2023 17:24
-
-
Save steveruizok/232e9bf621e3d2dfaebd4f198c7e69fc to your computer and use it in GitHub Desktop.
history scrubbing in tldraw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import '@tldraw/tldraw/tldraw.css' | |
import { RecordsDiff, TLRecord, Tldraw, useEditor } from '@tldraw/tldraw' | |
import { useEffect, useRef } from 'react' | |
export default function App() { | |
return ( | |
<div className="tldraw__editor"> | |
<Tldraw autoFocus> | |
<Slider /> | |
</Tldraw> | |
</div> | |
) | |
} | |
function Slider() { | |
const diffs = useRef<RecordsDiff<TLRecord>[]>([]) | |
const pointer = useRef(0) | |
const editor = useEditor() | |
const handleSliderChange = (e) => { | |
const events = diffs.current | |
const curr = pointer.current | |
const prevPct = curr / 10000 | |
const next = e.currentTarget.value | |
const nextPct = next / 10000 | |
const prevIndex = Math.ceil(prevPct * diffs.current.length) | |
const nextIndex = Math.ceil(nextPct * diffs.current.length) | |
if (nextPct === 1 && editor.instanceState.isReadonly) { | |
editor.updateInstanceState({ isReadonly: false }) | |
} else if (nextPct < 1 && !editor.instanceState.isReadonly) { | |
editor.updateInstanceState({ isReadonly: true }) | |
} | |
pointer.current = next | |
editor.store.mergeRemoteChanges(() => { | |
if (nextIndex > prevIndex) { | |
// console.log('redoing', prevIndex, nextIndex) | |
for (let i = prevIndex; i <= nextIndex; i++) { | |
const changes = events[i] | |
if (!changes) continue | |
Object.values(changes.added).forEach((record) => { | |
editor.store.put([record]) | |
}) | |
Object.values(changes.updated).forEach(([prev, next]) => { | |
editor.store.put([next]) | |
}) | |
Object.values(changes.removed).forEach((record) => { | |
editor.store.remove([record.id]) | |
}) | |
} | |
} else if (nextIndex < prevIndex) { | |
// console.log('undoing', prevIndex, nextIndex) | |
for (let i = prevIndex; i >= nextIndex; i--) { | |
const changes = events[i] | |
if (!changes) continue | |
Object.values(changes.added).forEach((record) => { | |
editor.store.remove([record.id]) | |
}) | |
Object.values(changes.updated).forEach(([prev, next]) => { | |
editor.store.put([prev]) | |
}) | |
Object.values(changes.removed).forEach((record) => { | |
editor.store.put([record]) | |
}) | |
} | |
} | |
}) | |
} | |
useEffect(() => { | |
return editor.store.listen(({ changes }) => diffs.current.push(changes), { | |
source: 'user', | |
scope: 'document', | |
}) | |
}, [editor]) | |
return ( | |
<input | |
type="range" | |
defaultValue="10000" | |
onChange={handleSliderChange} | |
style={{ | |
position: 'absolute', | |
top: 64, | |
left: 8, | |
width: 300, | |
zIndex: 999, | |
}} | |
min="0" | |
max="10000" | |
/> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Codepen available for this ?