@tldraw/state
Version:
tldraw infinite canvas SDK (state).
8 lines (7 loc) • 4.05 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/lib/localStorageAtom.ts"],
"sourcesContent": ["import { deleteFromLocalStorage, getFromLocalStorage, setInLocalStorage } from '@tldraw/utils'\nimport { Atom, atom, AtomOptions } from './Atom'\nimport { react } from './EffectScheduler'\n\n/**\n * Creates a new {@link Atom} that persists its value to localStorage.\n *\n * The atom is automatically synced with localStorage - changes to the atom are saved to localStorage,\n * and the initial value is read from localStorage if it exists. Returns both the atom and a cleanup\n * function that should be called to stop syncing when the atom is no longer needed. If you need to delete\n * the atom, you should do it manually after all cleanup functions have been called.\n *\n * @example\n * ```ts\n * const [theme, cleanup] = localStorageAtom('theme', 'light')\n *\n * theme.get() // 'light' or value from localStorage if it exists\n *\n * theme.set('dark') // updates atom and saves to localStorage\n *\n * // When done:\n * cleanup() // stops syncing to localStorage\n * ```\n *\n * @param name - The localStorage key and atom name. This is used for both localStorage persistence\n * and debugging/profiling purposes.\n * @param initialValue - The initial value of the atom, used if no value exists in localStorage.\n * @param options - Optional atom configuration. See {@link AtomOptions}.\n * @returns A tuple containing the atom and a cleanup function to stop localStorage syncing.\n * @public\n */\nexport function localStorageAtom<Value, Diff = unknown>(\n\tname: string,\n\tinitialValue: Value,\n\toptions?: AtomOptions<Value, Diff>\n): [Atom<Value, Diff>, () => void] {\n\t// Try to restore the initial value from localStorage\n\tlet _initialValue = initialValue\n\n\ttry {\n\t\tconst value = getFromLocalStorage(name)\n\t\tif (value) {\n\t\t\t_initialValue = JSON.parse(value) as Value\n\t\t}\n\t} catch {\n\t\t// If parsing fails, the stored value is corrupted - delete it and use the provided initial value\n\t\tdeleteFromLocalStorage(name)\n\t}\n\n\t// Create the atom with the restored or initial value\n\tconst outAtom = atom(name, _initialValue, options)\n\n\t// Set up automatic syncing: whenever the atom changes, save it to localStorage\n\tconst reactCleanup = react(`save ${name} to localStorage`, () => {\n\t\tsetInLocalStorage(name, JSON.stringify(outAtom.get()))\n\t})\n\n\t// Set up cross-tab sync: listen for storage events from other tabs\n\tconst handleStorageEvent = (event: StorageEvent) => {\n\t\t// Only handle events for this specific key\n\t\tif (event.key !== name) return\n\n\t\t// If the value was deleted in another tab\n\t\tif (event.newValue === null) {\n\t\t\toutAtom.set(initialValue)\n\t\t\treturn\n\t\t}\n\n\t\t// If the value was changed in another tab, update the atom\n\t\ttry {\n\t\t\tconst newValue = JSON.parse(event.newValue) as Value\n\t\t\toutAtom.set(newValue)\n\t\t} catch {\n\t\t\t// If parsing fails, the stored value is corrupted; preserve the existing value\n\t\t}\n\t}\n\n\twindow.addEventListener('storage', handleStorageEvent)\n\n\t// Combined cleanup function\n\tconst cleanup = () => {\n\t\treactCleanup()\n\t\twindow.removeEventListener('storage', handleStorageEvent)\n\t}\n\n\treturn [outAtom, cleanup]\n}\n"],
"mappings": "AAAA,SAAS,wBAAwB,qBAAqB,yBAAyB;AAC/E,SAAe,YAAyB;AACxC,SAAS,aAAa;AA6Bf,SAAS,iBACf,MACA,cACA,SACkC;AAElC,MAAI,gBAAgB;AAEpB,MAAI;AACH,UAAM,QAAQ,oBAAoB,IAAI;AACtC,QAAI,OAAO;AACV,sBAAgB,KAAK,MAAM,KAAK;AAAA,IACjC;AAAA,EACD,QAAQ;AAEP,2BAAuB,IAAI;AAAA,EAC5B;AAGA,QAAM,UAAU,KAAK,MAAM,eAAe,OAAO;AAGjD,QAAM,eAAe,MAAM,QAAQ,IAAI,oBAAoB,MAAM;AAChE,sBAAkB,MAAM,KAAK,UAAU,QAAQ,IAAI,CAAC,CAAC;AAAA,EACtD,CAAC;AAGD,QAAM,qBAAqB,CAAC,UAAwB;AAEnD,QAAI,MAAM,QAAQ,KAAM;AAGxB,QAAI,MAAM,aAAa,MAAM;AAC5B,cAAQ,IAAI,YAAY;AACxB;AAAA,IACD;AAGA,QAAI;AACH,YAAM,WAAW,KAAK,MAAM,MAAM,QAAQ;AAC1C,cAAQ,IAAI,QAAQ;AAAA,IACrB,QAAQ;AAAA,IAER;AAAA,EACD;AAEA,SAAO,iBAAiB,WAAW,kBAAkB;AAGrD,QAAM,UAAU,MAAM;AACrB,iBAAa;AACb,WAAO,oBAAoB,WAAW,kBAAkB;AAAA,EACzD;AAEA,SAAO,CAAC,SAAS,OAAO;AACzB;",
"names": []
}