github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/web/src/BrowserStorage.tsx (about) 1 import React, { Dispatch, SetStateAction, useContext } from "react" 2 import { useStorageState } from "react-storage-hooks" 3 4 export type TiltfileKey = string 5 export const tiltfileKeyContext = React.createContext<TiltfileKey>("unset") 6 7 export function makeKey(tiltfileKey: string, key: string): string { 8 return "tilt-" + JSON.stringify({ tiltfileKey: tiltfileKey, key: key }) 9 } 10 11 export type accessor<S> = { 12 get: () => S | null 13 set: (s: S) => void 14 } 15 16 export function accessorsForTesting<S>(name: string, storage: Storage) { 17 const key = makeKey("test", name) 18 function get(): S | null { 19 const v = storage.getItem(key) 20 if (!v) { 21 return null 22 } 23 return JSON.parse(v) as S 24 } 25 26 function set(s: S): void { 27 storage.setItem(key, JSON.stringify(s)) 28 } 29 30 return { 31 get: get, 32 set: set, 33 } 34 } 35 36 // Like `useState`, but backed by localStorage and namespaced by the tiltfileKey 37 // maybeUpgradeSavedState: transforms any state read from storage - allows, e.g., filling in default values for 38 // fields added since the state was saved 39 export function usePersistentState<S>( 40 name: string, 41 defaultValue: S, 42 maybeUpgradeSavedState?: (state: S) => S 43 ): [state: S, setState: Dispatch<SetStateAction<S>>] { 44 return useBrowserStorageState( 45 name, 46 defaultValue, 47 localStorage, 48 maybeUpgradeSavedState 49 ) 50 } 51 52 // Like `useState`, but backed by sessionStorage and namespaced by the tiltfileKey 53 // maybeUpgradeSavedState: transforms any state read from storage - allows, e.g., filling in default values for 54 // fields added since the state was saved 55 export function useSessionState<S>( 56 name: string, 57 defaultValue: S, 58 maybeUpgradeSavedState?: (state: S) => S 59 ): [state: S, setState: Dispatch<SetStateAction<S>>] { 60 return useBrowserStorageState( 61 name, 62 defaultValue, 63 sessionStorage, 64 maybeUpgradeSavedState 65 ) 66 } 67 68 // Like `useState`, but backed by localStorage and namespaced by the tiltfileKey 69 // maybeUpgradeSavedState: transforms any state read from storage - allows, e.g., filling in default values for 70 // fields added since the state was saved 71 export function useBrowserStorageState<S>( 72 name: string, 73 defaultValue: S, 74 storage: Storage, 75 maybeUpgradeSavedState?: (state: S) => S 76 ): [state: S, setState: Dispatch<SetStateAction<S>>] { 77 const tiltfileKey = useContext(tiltfileKeyContext) 78 let [state, setState] = useStorageState<S>( 79 storage, 80 makeKey(tiltfileKey, name), 81 defaultValue 82 ) 83 if (maybeUpgradeSavedState) { 84 state = maybeUpgradeSavedState(state) 85 } 86 return [state, setState] 87 } 88 89 export function PersistentStateProvider<S>(props: { 90 name: string 91 defaultValue: S 92 maybeUpgradeSavedState?: (state: S) => S 93 children: (state: S, setState: Dispatch<SetStateAction<S>>) => JSX.Element 94 }) { 95 let [state, setState] = usePersistentState( 96 props.name, 97 props.defaultValue, 98 props.maybeUpgradeSavedState 99 ) 100 return props.children(state, setState) 101 }