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  }