Buckets:
| import { createStore, produce } from "solid-js/store" | |
| export type SessionScroll = { | |
| x: number | |
| y: number | |
| } | |
| type ScrollMap = Record<string, SessionScroll> | |
| type Options = { | |
| debounceMs?: number | |
| getSnapshot: (sessionKey: string) => ScrollMap | undefined | |
| onFlush: (sessionKey: string, scroll: ScrollMap) => void | |
| } | |
| export function createScrollPersistence(opts: Options) { | |
| const wait = opts.debounceMs ?? 200 | |
| const [cache, setCache] = createStore<Record<string, ScrollMap>>({}) | |
| const dirty = new Set<string>() | |
| const timers = new Map<string, ReturnType<typeof setTimeout>>() | |
| function clone(input?: ScrollMap) { | |
| const out: ScrollMap = {} | |
| if (!input) return out | |
| for (const key of Object.keys(input)) { | |
| const pos = input[key] | |
| if (!pos) continue | |
| out[key] = { x: pos.x, y: pos.y } | |
| } | |
| return out | |
| } | |
| function seed(sessionKey: string) { | |
| const next = clone(opts.getSnapshot(sessionKey)) | |
| const current = cache[sessionKey] | |
| if (!current) { | |
| setCache(sessionKey, next) | |
| return | |
| } | |
| if (Object.keys(current).length > 0) return | |
| if (Object.keys(next).length === 0) return | |
| setCache(sessionKey, next) | |
| } | |
| function scroll(sessionKey: string, tab: string) { | |
| seed(sessionKey) | |
| return cache[sessionKey]?.[tab] ?? opts.getSnapshot(sessionKey)?.[tab] | |
| } | |
| function schedule(sessionKey: string) { | |
| const prev = timers.get(sessionKey) | |
| if (prev) clearTimeout(prev) | |
| timers.set( | |
| sessionKey, | |
| setTimeout(() => flush(sessionKey), wait), | |
| ) | |
| } | |
| function setScroll(sessionKey: string, tab: string, pos: SessionScroll) { | |
| seed(sessionKey) | |
| const prev = cache[sessionKey]?.[tab] | |
| if (prev?.x === pos.x && prev?.y === pos.y) return | |
| setCache(sessionKey, tab, { x: pos.x, y: pos.y }) | |
| dirty.add(sessionKey) | |
| schedule(sessionKey) | |
| } | |
| function flush(sessionKey: string) { | |
| const timer = timers.get(sessionKey) | |
| if (timer) clearTimeout(timer) | |
| timers.delete(sessionKey) | |
| if (!dirty.has(sessionKey)) return | |
| dirty.delete(sessionKey) | |
| opts.onFlush(sessionKey, clone(cache[sessionKey])) | |
| } | |
| function flushAll() { | |
| const keys = Array.from(dirty) | |
| if (keys.length === 0) return | |
| for (const key of keys) { | |
| flush(key) | |
| } | |
| } | |
| function drop(keys: string[]) { | |
| if (keys.length === 0) return | |
| for (const key of keys) { | |
| const timer = timers.get(key) | |
| if (timer) clearTimeout(timer) | |
| timers.delete(key) | |
| dirty.delete(key) | |
| } | |
| setCache( | |
| produce((draft) => { | |
| for (const key of keys) { | |
| delete draft[key] | |
| } | |
| }), | |
| ) | |
| } | |
| function dispose() { | |
| drop(Array.from(timers.keys())) | |
| } | |
| return { | |
| cache, | |
| drop, | |
| flush, | |
| flushAll, | |
| scroll, | |
| seed, | |
| setScroll, | |
| dispose, | |
| } | |
| } | |
Xet Storage Details
- Size:
- 2.82 kB
- Xet hash:
- 6a3d8d1814bd03306c49006b9cb440fde051274b7064e7016508da4cc59a9b29
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.